Fix EventStream.match randomness behaviour

This commit is contained in:
gizak 2015-09-18 21:07:57 -04:00
parent e89b10ff4f
commit 1cb28b0a3c
3 changed files with 63 additions and 105 deletions

View File

@ -1,19 +0,0 @@
// +build ignore
package main
import "github.com/gizak/termui"
func main() {
termui.Init()
termui.UseTheme("helloworld")
b := termui.NewBlock()
b.Width = 20
b.Height = 30
b.BorderLabel = "[HELLO](fg-red,bg-white) [WORLD](fg-blue,bg-green)"
termui.Render(b)
<-termui.EventCh()
termui.Close()
}

125
events.go
View File

@ -9,8 +9,8 @@
package termui package termui
import ( import (
"path"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@ -145,32 +145,12 @@ func NewSysEvtCh() chan Event {
var DefaultEvtStream = NewEvtStream() var DefaultEvtStream = NewEvtStream()
/*
type evtCtl struct {
in chan Event
out chan Event
suspend chan int
recover chan int
close chan int
}
func newEvtCtl() evtCtl {
ec := evtCtl{}
ec.in = make(chan Event)
ec.suspend = make(chan int)
ec.recover = make(chan int)
ec.close = make(chan int)
ec.out = make(chan Event)
return ec
}
*/
//
type EvtStream struct { type EvtStream struct {
sync.RWMutex
srcMap map[string]chan Event srcMap map[string]chan Event
stream chan Event stream chan Event
wg sync.WaitGroup wg sync.WaitGroup
sigStopLoop chan int sigStopLoop chan Event
Handlers map[string]func(Event) Handlers map[string]func(Event)
} }
@ -179,69 +159,40 @@ func NewEvtStream() *EvtStream {
srcMap: make(map[string]chan Event), srcMap: make(map[string]chan Event),
stream: make(chan Event), stream: make(chan Event),
Handlers: make(map[string]func(Event)), Handlers: make(map[string]func(Event)),
sigStopLoop: make(chan int), sigStopLoop: make(chan Event),
} }
} }
func (es *EvtStream) Init() { func (es *EvtStream) Init() {
es.Merge("internal", es.sigStopLoop)
go func() { go func() {
es.wg.Wait() es.wg.Wait()
close(es.stream) close(es.stream)
}() }()
} }
// a: /sys/bell func cleanPath(p string) string {
// b: /sys if p == "" {
// score: 1 return "/"
//
// a: /sys
// b: /usr
// score: -1
//
// a: /sys
// b: /
// score: 0
func MatchScore(a, b string) int {
// divide by "" and rm heading ""
sliced := func(s string) []string {
ss := strings.Split(s, "/")
i := 0
for j := range ss {
if ss[j] == "" {
i++
} else {
break
}
}
return ss[i:]
} }
if p[0] != '/' {
sa := sliced(a) p = "/" + p
sb := sliced(b)
score := 0
if len(sb) > len(sa) {
return -1 // sb couldnt be more deeper than sa
} }
return path.Clean(p)
}
for i, s := range sa { func isPathMatch(pattern, path string) bool {
if i >= len(sb) { if len(pattern) == 0 {
break // exhaust b return false
}
if s != sb[i] {
return -1 // mismatch
}
score++
} }
n := len(pattern)
return score return len(path) >= n && path[0:n] == pattern
} }
func (es *EvtStream) Merge(name string, ec chan Event) { func (es *EvtStream) Merge(name string, ec chan Event) {
es.Lock()
defer es.Unlock()
es.wg.Add(1) es.wg.Add(1)
es.srcMap[name] = ec es.srcMap[name] = ec
@ -255,38 +206,47 @@ func (es *EvtStream) Merge(name string, ec chan Event) {
} }
func (es *EvtStream) Handle(path string, handler func(Event)) { func (es *EvtStream) Handle(path string, handler func(Event)) {
es.Handlers[path] = handler es.Handlers[cleanPath(path)] = handler
} }
func (es *EvtStream) match(path string) string { func (es *EvtStream) match(path string) string {
n := 0 n := -1
pattern := "" pattern := ""
for m := range es.Handlers { for m := range es.Handlers {
if MatchScore(path, m) < 0 { if !isPathMatch(m, path) {
continue continue
} }
if pattern == "" || len(m) > n { if len(m) > n {
pattern = m pattern = m
n = len(m)
} }
} }
return pattern return pattern
} }
func (es *EvtStream) Loop() { func (es *EvtStream) Loop() {
for { for e := range es.stream {
select { if e.Path == "/sig/stoploop" {
case e := <-es.stream:
if pattern := es.match(e.Path); pattern != "" {
es.Handlers[pattern](e)
}
case <-es.sigStopLoop:
return return
} }
go func(a Event) {
es.RLock()
defer es.RUnlock()
if pattern := es.match(a.Path); pattern != "" {
h := es.Handlers[pattern]
h(a)
}
}(e)
} }
} }
func (es *EvtStream) StopLoop() { func (es *EvtStream) StopLoop() {
go func() { es.sigStopLoop <- 1 }() go func() {
e := Event{
Path: "/sig/stoploop",
}
es.sigStopLoop <- e
}()
} }
func Merge(name string, ec chan Event) { func Merge(name string, ec chan Event) {
@ -319,7 +279,6 @@ func NewTimerCh(du time.Duration) chan Event {
n++ n++
time.Sleep(du) time.Sleep(du)
e := Event{} e := Event{}
e.From = "timer"
e.Type = "timer" e.Type = "timer"
e.Path = "/timer/" + du.String() e.Path = "/timer/" + du.String()
e.Time = time.Now().Unix() e.Time = time.Now().Unix()
@ -328,11 +287,11 @@ func NewTimerCh(du time.Duration) chan Event {
Count: n, Count: n,
} }
t <- e t <- e
} }
}(t) }(t)
return t return t
} }
var DefualtHandler = func(e Event) { var DefualtHandler = func(e Event) {
} }

View File

@ -23,16 +23,34 @@ func main() {
} }
defer termui.Close() defer termui.Close()
termui.UseTheme("helloworld")
b := termui.NewBlock()
b.Width = 20
b.Height = 30
b.BorderLabel = "[HELLO](fg-red,bg-white) [WORLD](fg-blue,bg-green)"
termui.SendBufferToRender(b)
termui.Handle("/sys", func(e termui.Event) { termui.Handle("/sys", func(e termui.Event) {
k, ok := e.Data.(termui.EvtKbd) k, ok := e.Data.(termui.EvtKbd)
debug.Logf("-->%v\n", e) debug.Logf("->%v\n", e)
if ok && k.KeyStr == "q" { if ok && k.KeyStr == "q" {
termui.StopLoop() termui.StopLoop()
} }
}) })
termui.Handle("/timer", func(e termui.Event) { termui.Handle("/timer/1s", func(e termui.Event) {
//debug.Logf("-->%v\n", e) //debug.Logf("<-%v\n", e)
t := e.Data.(termui.EvtTimer)
if t.Count%2 == 0 {
b.BorderLabel = "[HELLO](fg-red,bg-green) [WORLD](fg-blue,bg-white)"
} else {
b.BorderLabel = "[HELLO](fg-blue,bg-white) [WORLD](fg-red,bg-green)"
}
termui.SendBufferToRender(b)
}) })
termui.Loop() termui.Loop()
} }