notify/file_transfer_monitor.go

175 lines
4.8 KiB
Go
Raw Normal View History

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)
}
}