Add multi-disk copy workflow
This commit is contained in:
+88
-11
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user