175 lines
4.8 KiB
Go
175 lines
4.8 KiB
Go
|
|
package notify
|
||
|
|
|
||
|
|
import "sync"
|
||
|
|
|
||
|
|
const defaultFileTransferCompletedLimit = 128
|
||
|
|
|
||
|
|
type fileTransferMonitor struct {
|
||
|
|
mu sync.Mutex
|
||
|
|
active map[string]fileTransferSnapshot
|
||
|
|
completed map[string]fileTransferSnapshot
|
||
|
|
runtimeActive map[string]fileTransferSnapshot
|
||
|
|
runtimeCompleted map[string]fileTransferSnapshot
|
||
|
|
completedLimit int
|
||
|
|
}
|
||
|
|
|
||
|
|
func newFileTransferMonitor() *fileTransferMonitor {
|
||
|
|
return newFileTransferMonitorWithConfig(defaultFileTransferConfig())
|
||
|
|
}
|
||
|
|
|
||
|
|
func newFileTransferMonitorWithConfig(cfg fileTransferConfig) *fileTransferMonitor {
|
||
|
|
cfg = normalizeFileTransferConfig(cfg)
|
||
|
|
return newFileTransferMonitorWithCompletedLimit(cfg.MonitorCompletedLimit)
|
||
|
|
}
|
||
|
|
|
||
|
|
func newFileTransferMonitorWithCompletedLimit(limit int) *fileTransferMonitor {
|
||
|
|
if limit <= 0 {
|
||
|
|
limit = defaultFileTransferCompletedLimit
|
||
|
|
}
|
||
|
|
return &fileTransferMonitor{
|
||
|
|
active: make(map[string]fileTransferSnapshot),
|
||
|
|
completed: make(map[string]fileTransferSnapshot),
|
||
|
|
runtimeActive: make(map[string]fileTransferSnapshot),
|
||
|
|
runtimeCompleted: make(map[string]fileTransferSnapshot),
|
||
|
|
completedLimit: limit,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) applyConfig(cfg fileTransferConfig) {
|
||
|
|
if m == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
cfg = normalizeFileTransferConfig(cfg)
|
||
|
|
m.mu.Lock()
|
||
|
|
m.completedLimit = cfg.MonitorCompletedLimit
|
||
|
|
m.trimCompletedLocked()
|
||
|
|
m.mu.Unlock()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) observe(direction fileTransferDirection, event FileEvent) {
|
||
|
|
if m == nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if !isFileTransferObservable(event.Kind) {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
snapshot := fileTransferSnapshotFromEvent(direction, event)
|
||
|
|
key := fileTransferMonitorKey(direction, snapshot.Scope, snapshot.FileID)
|
||
|
|
runtimeKey := fileTransferRuntimeMonitorKey(direction, snapshot.RuntimeScope, snapshot.FileID)
|
||
|
|
if key == "" || runtimeKey == "" {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
if isFileTransferTerminal(snapshot.Kind) {
|
||
|
|
delete(m.active, key)
|
||
|
|
m.completed[key] = snapshot
|
||
|
|
delete(m.runtimeActive, runtimeKey)
|
||
|
|
m.runtimeCompleted[runtimeKey] = snapshot
|
||
|
|
m.trimCompletedLocked()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
delete(m.completed, key)
|
||
|
|
m.active[key] = snapshot
|
||
|
|
delete(m.runtimeCompleted, runtimeKey)
|
||
|
|
m.runtimeActive[runtimeKey] = snapshot
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) activeSnapshots() []fileTransferSnapshot {
|
||
|
|
if m == nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
return sortedFileTransferSnapshots(m.active)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) activeSnapshotsByDirection(direction fileTransferDirection) []fileTransferSnapshot {
|
||
|
|
if m == nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
return filteredFileTransferSnapshots(m.active, direction)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) completedSnapshots() []fileTransferSnapshot {
|
||
|
|
if m == nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
return sortedFileTransferSnapshots(m.completed)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) completedSnapshotsByDirection(direction fileTransferDirection) []fileTransferSnapshot {
|
||
|
|
if m == nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
return filteredFileTransferSnapshots(m.completed, direction)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) latestSnapshot(direction fileTransferDirection, scope string, fileID string) (fileTransferSnapshot, bool) {
|
||
|
|
if m == nil {
|
||
|
|
return fileTransferSnapshot{}, false
|
||
|
|
}
|
||
|
|
key := fileTransferMonitorKey(direction, scope, fileID)
|
||
|
|
if key == "" {
|
||
|
|
return fileTransferSnapshot{}, false
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
if snapshot, ok := m.active[key]; ok {
|
||
|
|
return snapshot, true
|
||
|
|
}
|
||
|
|
snapshot, ok := m.completed[key]
|
||
|
|
return snapshot, ok
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) snapshotsByFileID(fileID string) []fileTransferSnapshot {
|
||
|
|
if m == nil || fileID == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
latest := latestFileTransferSnapshotsLocked(m.active, m.completed)
|
||
|
|
return filterFileTransferSnapshotsByFileID(latest, fileID)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) snapshotsByDirectionAndFileID(direction fileTransferDirection, fileID string) []fileTransferSnapshot {
|
||
|
|
if m == nil || fileID == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
m.mu.Lock()
|
||
|
|
defer m.mu.Unlock()
|
||
|
|
latest := latestFileTransferSnapshotsLocked(m.active, m.completed)
|
||
|
|
return filterFileTransferSnapshotsByDirectionAndFileID(latest, direction, fileID)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (m *fileTransferMonitor) trimCompletedLocked() {
|
||
|
|
trimFileTransferSnapshotsLocked(m.completed, m.completedLimit)
|
||
|
|
trimFileTransferSnapshotsLocked(m.runtimeCompleted, m.completedLimit)
|
||
|
|
}
|
||
|
|
|
||
|
|
func trimFileTransferSnapshotsLocked(snapshots map[string]fileTransferSnapshot, limit int) {
|
||
|
|
if limit <= 0 || len(snapshots) <= limit {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
for len(snapshots) > limit {
|
||
|
|
oldestKey := ""
|
||
|
|
oldestSnapshot := fileTransferSnapshot{}
|
||
|
|
for key, snapshot := range snapshots {
|
||
|
|
if oldestKey == "" || fileTransferSnapshotOlder(snapshot, oldestSnapshot, key, oldestKey) {
|
||
|
|
oldestKey = key
|
||
|
|
oldestSnapshot = snapshot
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if oldestKey == "" {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
delete(snapshots, oldestKey)
|
||
|
|
}
|
||
|
|
}
|