Skip to content

Instantly share code, notes, and snippets.

@ppknap
Created September 28, 2014 09:52
Show Gist options
  • Save ppknap/bf8d9ab54b9dc131db45 to your computer and use it in GitHub Desktop.
Save ppknap/bf8d9ab54b9dc131db45 to your computer and use it in GitHub Desktop.
Why not?:<
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