Add multi-disk copy workflow

This commit is contained in:
2026-04-23 22:24:32 +03:00
parent 5b3cb9e393
commit 31bac2b5d8
10 changed files with 466 additions and 202 deletions
+88 -11
View File
@@ -2,6 +2,8 @@ package watcher
import (
"context"
"path/filepath"
"sort"
"sync"
"time"
@@ -10,7 +12,7 @@ import (
type DiskEvent struct {
Info disk.DiskInfo
Prev disk.DiskState
Prev disk.DiskInfo
}
type Handler func(event DiskEvent)
@@ -20,8 +22,8 @@ type Watcher struct {
interval time.Duration
handler Handler
mu sync.RWMutex
current disk.DiskInfo
mu sync.RWMutex
disks map[string]disk.DiskInfo
}
func New(mountPath string, interval time.Duration, handler Handler) *Watcher {
@@ -29,13 +31,42 @@ func New(mountPath string, interval time.Duration, handler Handler) *Watcher {
mountPath: mountPath,
interval: interval,
handler: handler,
disks: make(map[string]disk.DiskInfo),
}
}
func (w *Watcher) CurrentDisk() disk.DiskInfo {
func (w *Watcher) ListDisks() []disk.DiskInfo {
w.mu.RLock()
defer w.mu.RUnlock()
return w.current
items := make([]disk.DiskInfo, 0, len(w.disks))
for _, info := range w.disks {
items = append(items, info)
}
sort.Slice(items, func(i, j int) bool { return items[i].MountPath < items[j].MountPath })
return items
}
func (w *Watcher) DiskByMountPath(mountPath string) (disk.DiskInfo, bool) {
w.mu.RLock()
defer w.mu.RUnlock()
info, ok := w.disks[mountPath]
return info, ok
}
func (w *Watcher) DiskByID(diskID string) (disk.DiskInfo, bool) {
w.mu.RLock()
defer w.mu.RUnlock()
for _, info := range w.disks {
if info.DiskID == diskID {
return info, true
}
}
return disk.DiskInfo{}, false
}
func (w *Watcher) ProbeNow() {
w.probe()
}
func (w *Watcher) Run(ctx context.Context) {
@@ -56,15 +87,61 @@ func (w *Watcher) Run(ctx context.Context) {
}
func (w *Watcher) probe() {
info, _ := disk.Probe(w.mountPath)
next := discoverDisks(w.mountPath)
w.mu.Lock()
prev := w.current.State
changed := prev != info.State
w.current = info
prev := w.disks
w.disks = next
w.mu.Unlock()
if changed && w.handler != nil {
w.handler(DiskEvent{Info: info, Prev: prev})
if w.handler == nil {
return
}
seen := make(map[string]struct{}, len(prev)+len(next))
for mountPath, info := range next {
seen[mountPath] = struct{}{}
prevInfo := prev[mountPath]
if prevInfo.State != info.State || prevInfo.DiskID != info.DiskID {
w.handler(DiskEvent{Info: info, Prev: prevInfo})
}
}
for mountPath, prevInfo := range prev {
if _, ok := seen[mountPath]; ok {
continue
}
w.handler(DiskEvent{
Info: disk.DiskInfo{
State: disk.DiskAbsent,
MountPath: mountPath,
},
Prev: prevInfo,
})
}
}
func discoverDisks(root string) map[string]disk.DiskInfo {
candidates := []string{root}
if entries, err := filepath.Glob(filepath.Join(root, "*")); err == nil {
for _, path := range entries {
candidates = append(candidates, path)
}
}
disks := make(map[string]disk.DiskInfo)
seen := make(map[string]struct{}, len(candidates))
for _, mountPath := range candidates {
if _, ok := seen[mountPath]; ok {
continue
}
seen[mountPath] = struct{}{}
info, _ := disk.Probe(mountPath)
if info.State == disk.DiskAbsent {
continue
}
disks[mountPath] = info
}
return disks
}