-
-
Save ppknap/bf8d9ab54b9dc131db45 to your computer and use it in GitHub Desktop.
Why not?:<
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
// ---- Events | |
const ( | |
Create = Event(0x00000001) | |
Delete = Event(0x00000002) | |
Write = Event(0x00000004) | |
Move = Event(0x00000008) | |
) | |
type Event uint32 | |
func (e Event) String() (s string) { | |
str := [...]string{"Create", "Delete", "Write", "Move"} | |
for i, ev := range [...]Event{Create, Delete, Write, Move} { | |
if e&ev != 0 { | |
s += str[i] + ";" | |
} | |
} | |
return | |
} | |
// EventInfo | |
type EventInfo interface { | |
Event() Event | |
} | |
// Tree Logic | |
type DirTree map[string]*nodenfo | |
var tree DirTree = make(map[string]*nodenfo) | |
type nodenfo struct { | |
mask Event | |
eventch map[chan<- EventInfo]Event | |
counter map[Event]int | |
} | |
func newNodeInfo() *nodenfo { | |
return &nodenfo{ | |
eventch: make(map[chan<- EventInfo]Event), | |
counter: make(map[Event]int), | |
} | |
} | |
func mergeev(ev ...Event) (merged Event) { | |
for _, e := range ev { | |
merged |= e | |
} | |
return | |
} | |
func toevslice(merged Event) (ev []Event) { | |
for _, e := range [...]Event{Create, Delete, Write, Move} { | |
if merged&e != 0 { | |
ev = append(ev, e) | |
} | |
} | |
return | |
} | |
func Watch(path string, ch chan<- EventInfo, events ...Event) error { | |
ni := tree[path] | |
if ni == nil { | |
tree[path] = newNodeInfo() | |
} | |
lastev := tree[path].eventch[ch] | |
newev := mergeev(events...) | |
tree[path].eventch[ch] |= newev | |
diffs := toevslice(lastev ^ newev) | |
for _, e := range diffs { | |
tree[path].counter[e]++ | |
} | |
newmask := Event(0) | |
for e, count := range tree[path].counter { | |
if count > 0 { | |
newmask |= e | |
} | |
} | |
if newmask != tree[path].mask { | |
fmt.Printf("Watch dir: %s, events: %s, chan: %p --> Sending a new mask %s\n", | |
path, newev.String(), ch, newmask.String()) | |
tree[path].mask = newmask | |
} else { | |
fmt.Printf("Watch dir: %s, events: %s, chan: %p --> No need to update mask.\n", | |
path, newev.String(), ch) | |
} | |
return nil | |
} | |
func Stop(ch chan<- EventInfo) error { | |
nis := []*nodenfo{} | |
paths := []string{} | |
for p, ni := range tree { | |
if _, ok := ni.eventch[ch]; ok { | |
nis = append(nis, ni) | |
paths = append(paths, p) | |
} | |
} | |
for i, ni := range nis { | |
newmask := Event(0) | |
send := false | |
mask := ni.eventch[ch] | |
for _, e := range toevslice(mask) { | |
ni.counter[e]-- | |
if ni.counter[e] == 0 { | |
send = true | |
delete(ni.counter, e) | |
} else { | |
newmask |= e | |
} | |
} | |
if send { | |
fmt.Printf("Stop dir: %s, chan: %p --> Sending a new mask %s\n", | |
paths[i], ch, newmask.String()) | |
} else { | |
fmt.Printf("Stop dir: %s, chan: %p --> No need to update mask\n", paths[i], ch) | |
} | |
} | |
return nil | |
} | |
func main() { | |
ch1, ch2 := make(chan<- EventInfo, 1), make(chan<- EventInfo, 1) | |
Watch("p1", ch1, Create|Delete) | |
Watch("p1", ch2, Create) | |
Watch("p2", ch1, Move) | |
Watch("p2", ch2, Move) | |
Stop(ch1) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment