|
|
@@ -375,53 +375,71 @@ func (m *Model) NeedSize(folder string) (nfiles int, bytes int64) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-// NeedFiles returns the list of currently needed files in progress, queued,
|
|
|
-// and to be queued on next puller iteration. Also takes a soft cap which is
|
|
|
-// only respected when adding files from the model rather than the runner queue.
|
|
|
-func (m *Model) NeedFolderFiles(folder string, max int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated) {
|
|
|
+// NeedFiles returns paginated list of currently needed files in progress, queued,
|
|
|
+// and to be queued on next puller iteration, as well as the total number of
|
|
|
+// files currently needed.
|
|
|
+func (m *Model) NeedFolderFiles(folder string, page, perpage int) ([]db.FileInfoTruncated, []db.FileInfoTruncated, []db.FileInfoTruncated, int) {
|
|
|
m.fmut.RLock()
|
|
|
defer m.fmut.RUnlock()
|
|
|
|
|
|
- if rf, ok := m.folderFiles[folder]; ok {
|
|
|
- var progress, queued, rest []db.FileInfoTruncated
|
|
|
- var seen map[string]bool
|
|
|
+ total := 0
|
|
|
|
|
|
- runner, ok := m.folderRunners[folder]
|
|
|
- if ok {
|
|
|
- progressNames, queuedNames := runner.Jobs()
|
|
|
+ rf, ok := m.folderFiles[folder]
|
|
|
+ if !ok {
|
|
|
+ return nil, nil, nil, 0
|
|
|
+ }
|
|
|
|
|
|
- progress = make([]db.FileInfoTruncated, len(progressNames))
|
|
|
- queued = make([]db.FileInfoTruncated, len(queuedNames))
|
|
|
- seen = make(map[string]bool, len(progressNames)+len(queuedNames))
|
|
|
+ var progress, queued, rest []db.FileInfoTruncated
|
|
|
+ var seen map[string]struct{}
|
|
|
|
|
|
- for i, name := range progressNames {
|
|
|
- if f, ok := rf.GetGlobalTruncated(name); ok {
|
|
|
- progress[i] = f
|
|
|
- seen[name] = true
|
|
|
- }
|
|
|
- }
|
|
|
+ skip := (page - 1) * perpage
|
|
|
+ get := perpage
|
|
|
|
|
|
- for i, name := range queuedNames {
|
|
|
- if f, ok := rf.GetGlobalTruncated(name); ok {
|
|
|
- queued[i] = f
|
|
|
- seen[name] = true
|
|
|
- }
|
|
|
+ runner, ok := m.folderRunners[folder]
|
|
|
+ if ok {
|
|
|
+ allProgressNames, allQueuedNames := runner.Jobs()
|
|
|
+
|
|
|
+ var progressNames, queuedNames []string
|
|
|
+ progressNames, skip, get = getChunk(allProgressNames, skip, get)
|
|
|
+ queuedNames, skip, get = getChunk(allQueuedNames, skip, get)
|
|
|
+
|
|
|
+ progress = make([]db.FileInfoTruncated, len(progressNames))
|
|
|
+ queued = make([]db.FileInfoTruncated, len(queuedNames))
|
|
|
+ seen = make(map[string]struct{}, len(progressNames)+len(queuedNames))
|
|
|
+
|
|
|
+ for i, name := range progressNames {
|
|
|
+ if f, ok := rf.GetGlobalTruncated(name); ok {
|
|
|
+ progress[i] = f
|
|
|
+ seen[name] = struct{}{}
|
|
|
}
|
|
|
}
|
|
|
- left := max - len(progress) - len(queued)
|
|
|
- if max < 1 || left > 0 {
|
|
|
- rf.WithNeedTruncated(protocol.LocalDeviceID, func(f db.FileIntf) bool {
|
|
|
- left--
|
|
|
- ft := f.(db.FileInfoTruncated)
|
|
|
- if !seen[ft.Name] {
|
|
|
- rest = append(rest, ft)
|
|
|
- }
|
|
|
- return max < 1 || left > 0
|
|
|
- })
|
|
|
+
|
|
|
+ for i, name := range queuedNames {
|
|
|
+ if f, ok := rf.GetGlobalTruncated(name); ok {
|
|
|
+ queued[i] = f
|
|
|
+ seen[name] = struct{}{}
|
|
|
+ }
|
|
|
}
|
|
|
- return progress, queued, rest
|
|
|
}
|
|
|
- return nil, nil, nil
|
|
|
+
|
|
|
+ rest = make([]db.FileInfoTruncated, 0, perpage)
|
|
|
+ rf.WithNeedTruncated(protocol.LocalDeviceID, func(f db.FileIntf) bool {
|
|
|
+ total++
|
|
|
+ if skip > 0 {
|
|
|
+ skip--
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if get > 0 {
|
|
|
+ ft := f.(db.FileInfoTruncated)
|
|
|
+ if _, ok := seen[ft.Name]; !ok {
|
|
|
+ rest = append(rest, ft)
|
|
|
+ get--
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+
|
|
|
+ return progress, queued, rest, total
|
|
|
}
|
|
|
|
|
|
// Index is called when a new device is connected and we receive their full index.
|
|
|
@@ -1616,3 +1634,17 @@ func symlinkInvalid(isLink bool) bool {
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
+
|
|
|
+// Skips `skip` elements and retrieves up to `get` elements from a given slice.
|
|
|
+// Returns the resulting slice, plus how much elements are left to skip or
|
|
|
+// copy to satisfy the values which were provided, given the slice is not
|
|
|
+// big enough.
|
|
|
+func getChunk(data []string, skip, get int) ([]string, int, int) {
|
|
|
+ l := len(data)
|
|
|
+ if l <= skip {
|
|
|
+ return []string{}, skip - l, get
|
|
|
+ } else if l < skip+get {
|
|
|
+ return data[skip:l], 0, get - (l - skip)
|
|
|
+ }
|
|
|
+ return data[skip : skip+get], 0, 0
|
|
|
+}
|