Fix EventStream.match randomness behaviour
This commit is contained in:
parent
e89b10ff4f
commit
1cb28b0a3c
@ -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
125
events.go
@ -9,8 +9,8 @@
|
||||
package termui
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -145,32 +145,12 @@ func NewSysEvtCh() chan Event {
|
||||
|
||||
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 {
|
||||
sync.RWMutex
|
||||
srcMap map[string]chan Event
|
||||
stream chan Event
|
||||
wg sync.WaitGroup
|
||||
sigStopLoop chan int
|
||||
sigStopLoop chan Event
|
||||
Handlers map[string]func(Event)
|
||||
}
|
||||
|
||||
@ -179,69 +159,40 @@ func NewEvtStream() *EvtStream {
|
||||
srcMap: make(map[string]chan Event),
|
||||
stream: make(chan Event),
|
||||
Handlers: make(map[string]func(Event)),
|
||||
sigStopLoop: make(chan int),
|
||||
sigStopLoop: make(chan Event),
|
||||
}
|
||||
}
|
||||
|
||||
func (es *EvtStream) Init() {
|
||||
es.Merge("internal", es.sigStopLoop)
|
||||
go func() {
|
||||
es.wg.Wait()
|
||||
close(es.stream)
|
||||
}()
|
||||
}
|
||||
|
||||
// a: /sys/bell
|
||||
// b: /sys
|
||||
// score: 1
|
||||
//
|
||||
// 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:]
|
||||
func cleanPath(p string) string {
|
||||
if p == "" {
|
||||
return "/"
|
||||
}
|
||||
|
||||
sa := sliced(a)
|
||||
sb := sliced(b)
|
||||
|
||||
score := 0
|
||||
if len(sb) > len(sa) {
|
||||
return -1 // sb couldnt be more deeper than sa
|
||||
if p[0] != '/' {
|
||||
p = "/" + p
|
||||
}
|
||||
return path.Clean(p)
|
||||
}
|
||||
|
||||
for i, s := range sa {
|
||||
if i >= len(sb) {
|
||||
break // exhaust b
|
||||
}
|
||||
|
||||
if s != sb[i] {
|
||||
return -1 // mismatch
|
||||
}
|
||||
score++
|
||||
func isPathMatch(pattern, path string) bool {
|
||||
if len(pattern) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return score
|
||||
n := len(pattern)
|
||||
return len(path) >= n && path[0:n] == pattern
|
||||
}
|
||||
|
||||
func (es *EvtStream) Merge(name string, ec chan Event) {
|
||||
es.Lock()
|
||||
defer es.Unlock()
|
||||
|
||||
es.wg.Add(1)
|
||||
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)) {
|
||||
es.Handlers[path] = handler
|
||||
es.Handlers[cleanPath(path)] = handler
|
||||
}
|
||||
|
||||
func (es *EvtStream) match(path string) string {
|
||||
n := 0
|
||||
n := -1
|
||||
pattern := ""
|
||||
for m := range es.Handlers {
|
||||
if MatchScore(path, m) < 0 {
|
||||
if !isPathMatch(m, path) {
|
||||
continue
|
||||
}
|
||||
if pattern == "" || len(m) > n {
|
||||
if len(m) > n {
|
||||
pattern = m
|
||||
n = len(m)
|
||||
}
|
||||
}
|
||||
return pattern
|
||||
}
|
||||
|
||||
func (es *EvtStream) Loop() {
|
||||
for {
|
||||
select {
|
||||
case e := <-es.stream:
|
||||
if pattern := es.match(e.Path); pattern != "" {
|
||||
es.Handlers[pattern](e)
|
||||
}
|
||||
case <-es.sigStopLoop:
|
||||
for e := range es.stream {
|
||||
if e.Path == "/sig/stoploop" {
|
||||
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() {
|
||||
go func() { es.sigStopLoop <- 1 }()
|
||||
go func() {
|
||||
e := Event{
|
||||
Path: "/sig/stoploop",
|
||||
}
|
||||
es.sigStopLoop <- e
|
||||
}()
|
||||
}
|
||||
|
||||
func Merge(name string, ec chan Event) {
|
||||
@ -319,7 +279,6 @@ func NewTimerCh(du time.Duration) chan Event {
|
||||
n++
|
||||
time.Sleep(du)
|
||||
e := Event{}
|
||||
e.From = "timer"
|
||||
e.Type = "timer"
|
||||
e.Path = "/timer/" + du.String()
|
||||
e.Time = time.Now().Unix()
|
||||
@ -328,11 +287,11 @@ func NewTimerCh(du time.Duration) chan Event {
|
||||
Count: n,
|
||||
}
|
||||
t <- e
|
||||
|
||||
}
|
||||
}(t)
|
||||
return t
|
||||
}
|
||||
|
||||
var DefualtHandler = func(e Event) {
|
||||
|
||||
}
|
||||
|
@ -23,16 +23,34 @@ func main() {
|
||||
}
|
||||
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) {
|
||||
k, ok := e.Data.(termui.EvtKbd)
|
||||
debug.Logf("-->%v\n", e)
|
||||
debug.Logf("->%v\n", e)
|
||||
if ok && k.KeyStr == "q" {
|
||||
termui.StopLoop()
|
||||
}
|
||||
})
|
||||
|
||||
termui.Handle("/timer", func(e termui.Event) {
|
||||
//debug.Logf("-->%v\n", e)
|
||||
termui.Handle("/timer/1s", func(e termui.Event) {
|
||||
//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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user