diff --git a/base/aaa/user.go b/base/aaa/user.go index 3f03b68d..25f617d4 100644 --- a/base/aaa/user.go +++ b/base/aaa/user.go @@ -3,13 +3,16 @@ package aaa import ( ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/cli" - "github.com/shylinux/icebergs/base/gdb" "github.com/shylinux/icebergs/base/mdb" kit "github.com/shylinux/toolkits" "strings" ) +const ( + USER_CREATE = "user.create" +) + func _user_list(m *ice.Message) { m.Richs(USER, nil, kit.MDB_FOREACH, func(key string, value map[string]interface{}) { m.Push(key, value, []string{kit.MDB_TIME, USERZONE, USERNICK, USERNAME}) @@ -50,7 +53,7 @@ func _user_create(m *ice.Message, name, word string) { USERNODE, cli.NodeName, )) m.Log_CREATE(USERNAME, name, "hash", h) - m.Event(gdb.USER_CREATE, name) + m.Event(USER_CREATE, name) } func _user_search(m *ice.Message, kind, name, text string, arg ...string) { m.Richs(USER, nil, kit.MDB_FOREACH, func(key string, val map[string]interface{}) { diff --git a/base/ctx/conf.go b/base/ctx/conf.go index 542ced8c..330aff8f 100644 --- a/base/ctx/conf.go +++ b/base/ctx/conf.go @@ -60,7 +60,7 @@ func _config_load(m *ice.Message, name string, arg ...string) { for k, v := range data { msg.Search(k, func(p *ice.Context, s *ice.Context, key string) { - m.Log_IMPORT(CONFIG, kit.Keys(s.Name, key), kit.MDB_FILE, name) + // m.Log_IMPORT(CONFIG, kit.Keys(s.Name, key), kit.MDB_FILE, name) s.Configs[key].Value = v }) } diff --git a/base/gdb/event.go b/base/gdb/event.go new file mode 100644 index 00000000..94e52996 --- /dev/null +++ b/base/gdb/event.go @@ -0,0 +1,56 @@ +package gdb + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" +) + +func _event_listen(m *ice.Message, event string, cmd string) { + h := m.Cmdx(mdb.INSERT, EVENT, "", mdb.HASH, EVENT, event) + m.Cmdy(mdb.INSERT, EVENT, kit.Keys(kit.MDB_HASH, h), mdb.LIST, kit.SSH_CMD, cmd) +} +func _event_action(m *ice.Message, event string, arg ...string) { + m.Option(mdb.FIELDS, "time,id,cmd") + m.Cmd(mdb.SELECT, EVENT, kit.Keys(kit.MDB_HASH, kit.Hashs(event)), mdb.LIST).Table(func(index int, value map[string]string, head []string) { + m.Cmd(kit.Split(value[kit.SSH_CMD]), event, arg).Cost("event %v %v", event, arg) + }) +} + +const EVENT = "event" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + EVENT: {Name: EVENT, Help: "事件流", Value: kit.Data( + kit.MDB_SHORT, EVENT, + )}, + }, + Commands: map[string]*ice.Command{ + EVENT: {Name: "event event id auto 监听", Help: "事件流", Action: map[string]*ice.Action{ + LISTEN: {Name: "listen event cmd", Help: "监听", Hand: func(m *ice.Message, arg ...string) { + _event_listen(m, m.Option(EVENT), m.Option(kit.SSH_CMD)) + }}, + ACTION: {Name: "action event arg", Help: "触发", Hand: func(m *ice.Message, arg ...string) { + _event_action(m, m.Option(EVENT), arg[2:]...) + }}, + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, EVENT, "", mdb.HASH, EVENT, m.Option(EVENT)) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 0 { + m.Option(mdb.FIELDS, "time,event,count") + m.Cmdy(mdb.SELECT, EVENT, "", mdb.HASH) + m.PushAction(ACTION, mdb.REMOVE) + return + } + + m.Option(mdb.FIELDS, kit.Select("time,id,cmd", mdb.DETAIL, len(arg) > 1)) + m.Cmdy(mdb.SELECT, EVENT, kit.Keys(kit.MDB_HASH, kit.Hashs(arg[0])), mdb.LIST, kit.MDB_ID, arg[1:]) + if len(arg) == 1 { + m.Sort(kit.MDB_ID) + } + }}, + }, + }, nil) +} diff --git a/base/gdb/gdb.go b/base/gdb/gdb.go index 173ad355..0d659a8b 100644 --- a/base/gdb/gdb.go +++ b/base/gdb/gdb.go @@ -3,67 +3,39 @@ package gdb import ( ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/cli" - "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" kit "github.com/shylinux/toolkits" "os" - "os/signal" - "syscall" "time" ) type Frame struct { - s chan os.Signal t <-chan time.Time - d chan []string + s chan os.Signal + e chan bool } func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server { return &Frame{} } func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server { + f.t = time.Tick(kit.Duration(m.Cap(ice.CTX_STREAM, ice.MOD_TICK))) + f.s = make(chan os.Signal, ice.MOD_CHAN) + f.e = make(chan bool, 1) return f } func (f *Frame) Start(m *ice.Message, arg ...string) bool { for { select { - case s, ok := <-f.s: - if !ok { - return true - } - // 信号事件 - m.Logs(EVENT, SIGNAL, s) - m.Cmd(m.Confv(SIGNAL, kit.Keys(kit.MDB_HASH, s)), kit.Keys(s)) + case <-f.e: + return true - case t, ok := <-f.t: - if !ok { - return true - } + case s := <-f.s: + m.Cmd(SIGNAL, ACTION, SIGNAL, s) - // 定时事件 - stamp := int(t.Unix()) - m.Confm(TIMER, kit.MDB_HASH, func(key string, value map[string]interface{}) { - if kit.Int(value["next"]) <= stamp { - m.Logs(EVENT, TIMER, key, kit.MDB_TIME, value["next"]) - value["next"] = stamp + int(kit.Duration(value["interval"]))/int(time.Second) - m.Cmd(value["cmd"]) - m.Grow(TIMER, nil, map[string]interface{}{ - "create_time": kit.Format(t), "interval": value["interval"], - "cmd": value["cmd"], "key": key, - }) - } - }) - - case d, ok := <-f.d: - if !ok { - return true - } - // 异步事件 - m.Logs(EVENT, d[0], d[1:]) - m.Grows(EVENT, d[0], "", "", func(index int, value map[string]interface{}) { - m.Cmd(value["cmd"], d).Cost("event %v", d) - }) + case <-f.t: + _timer_action(m.Spawn()) } } return true @@ -73,147 +45,37 @@ func (f *Frame) Close(m *ice.Message, arg ...string) bool { } const ( - SYSTEM_INIT = "system.init" - - SERVE_START = "serve.start" - SERVE_CLOSE = "serve.close" - SPACE_START = "space.start" - SPACE_CLOSE = "space.close" - DREAM_START = "dream.start" - DREAM_CLOSE = "dream.close" - - USER_CREATE = "user.create" - CHAT_CREATE = "chat.create" - MISS_CREATE = "miss.create" - MIND_CREATE = "mind.create" -) - -const ( - INIT = "init" - AUTO = "auto" - MAKE = "make" - BEGIN = "begin" END = "end" - OPEN = "open" - CLOSE = "close" + START = "start" STOP = "stop" RESTART = "restart" ) -const ( - LISTEN = "listen" - ACTION = "action" -) -const ( - ROUTINE = "routine" - SIGNAL = "signal" - TIMER = "timer" - EVENT = "event" - DEBUG = "debug" -) +const GDB = "gdb" -var Index = &ice.Context{Name: "gdb", Help: "事件模块", - Configs: map[string]*ice.Config{ - ROUTINE: {Name: "routine", Help: "协程", Value: kit.Data()}, - - SIGNAL: {Name: "signal", Help: "信号器", Value: kit.Dict( - kit.MDB_META, kit.Dict("pid", "var/run/ice.pid"), - kit.MDB_LIST, kit.List(), - kit.MDB_HASH, kit.Dict( - "2", []interface{}{"exit", "1"}, - "3", []interface{}{"exit", "0"}, - "15", []interface{}{"exit", "1"}, - // "20", []interface{}{"void"}, - "30", []interface{}{"exit"}, - "31", []interface{}{"exit", "1"}, - // "28", []interface{}{"void"}, - ), - )}, - TIMER: {Name: "timer", Help: "定时器", Value: kit.Data("tick", "100ms")}, - EVENT: {Name: "event", Help: "触发器", Value: kit.Data()}, - }, +var Index = &ice.Context{Name: GDB, Help: "事件模块", Commands: map[string]*ice.Command{ ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if os.Getenv("ctx_mod") != "" { - m.Cmd(nfs.SAVE, kit.Select(m.Conf(SIGNAL, "meta.pid"), - m.Conf(cli.RUNTIME, "conf.ctx_pid")), m.Conf(cli.RUNTIME, "host.pid")) - } - // 进程标识 - if f, ok := m.Target().Server().(*Frame); ok { - // 注册信号 - f.s = make(chan os.Signal, ice.MOD_CHAN) - m.Richs(SIGNAL, nil, kit.MDB_FOREACH, func(key string, value string) { - m.Logs(LISTEN, key, value) - signal.Notify(f.s, syscall.Signal(kit.Int(key))) - }) - // 启动心跳 - f.t = time.Tick(kit.Duration(m.Cap(ice.CTX_STREAM, m.Conf(TIMER, "meta.tick")))) - // 分发事件 - f.d = make(chan []string, ice.MOD_CHAN) - } + m.Cmd(nfs.SAVE, kit.Select(m.Conf(SIGNAL, kit.META_PATH), m.Conf(cli.RUNTIME, "conf.ctx_pid")), m.Conf(cli.RUNTIME, "host.pid")) + + m.Cmd(SIGNAL, LISTEN, SIGNAL, "3", kit.MDB_NAME, "退出", kit.SSH_CMD, "exit 0") + m.Cmd(SIGNAL, LISTEN, SIGNAL, "2", kit.MDB_NAME, "重启", kit.SSH_CMD, "exit 1") + m.Load() }}, ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if f, ok := m.Target().Server().(*Frame); ok { - // 停止心跳 - close(f.s) - // 停止事件 - close(f.d) + f.e <- true } + m.Save(TIMER) }}, - - ROUTINE: {Name: "routine hash auto", Help: "协程", Action: map[string]*ice.Action{ - mdb.CREATE: {Name: "create", Help: "创建", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.INSERT, ROUTINE, "", mdb.LIST, arg) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Option(mdb.FIELDS, "time,fileline") - m.Cmdy(mdb.SELECT, ROUTINE, "", mdb.LIST, arg) - }}, - - SIGNAL: {Name: "signal", Help: "信号器", Action: map[string]*ice.Action{ - LISTEN: {Name: "listen signal cmd...", Help: "监听事件", Hand: func(m *ice.Message, arg ...string) { - m.Rich(SIGNAL, arg[0], arg[1:]) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, - - TIMER: {Name: "timer", Help: "定时器", Action: map[string]*ice.Action{ - LISTEN: {Name: "listen delay interval cmd...", Help: "监听事件", Hand: func(m *ice.Message, arg ...string) { - m.Rich(TIMER, nil, kit.Dict( - "next", time.Now().Add(kit.Duration(arg[0])).Unix(), - "interval", arg[1], "cmd", arg[2:], - )) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, - - EVENT: {Name: "event", Help: "触发器", Action: map[string]*ice.Action{ - LISTEN: {Name: "listen event cmd...", Help: "监听事件", Hand: func(m *ice.Message, arg ...string) { - m.Grow(EVENT, arg[0], kit.Dict("cmd", arg[1:])) - m.Logs(LISTEN, arg[0], arg[1:]) - }}, - ACTION: {Name: "action event arg...", Help: "触发事件", Hand: func(m *ice.Message, arg ...string) { - if f, ok := m.Target().Server().(*Frame); ok { - m.Logs(ACTION, arg[0], arg[1:]) - f.d <- arg - } - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, - - DEBUG: {Name: "debug", Help: "调试器", Action: map[string]*ice.Action{ - LISTEN: {Name: "listen event cmd...", Help: "监听事件", Hand: func(m *ice.Message, arg ...string) { - m.Grow(EVENT, arg[0], kit.Dict("cmd", arg[1:])) - m.Logs(LISTEN, arg[0], "cmd", arg[1:]) - }}, - ACTION: {Name: "action event arg...", Help: "触发事件", Hand: func(m *ice.Message, arg ...string) { - if f, ok := m.Target().Server().(*Frame); ok { - m.Logs(ACTION, arg[0], "arg", arg[1:]) - f.d <- arg - } - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, }, } -func init() { ice.Index.Register(Index, &Frame{}, SIGNAL, TIMER, EVENT, DEBUG) } +func init() { + ice.Index.Register(Index, &Frame{}, + ROUTINE, SIGNAL, EVENT, TIMER, + ) +} diff --git a/base/gdb/gdb.shy b/base/gdb/gdb.shy new file mode 100644 index 00000000..93a014a8 --- /dev/null +++ b/base/gdb/gdb.shy @@ -0,0 +1,7 @@ +chapter "gdb" + +field "协程池" routine +field "信号量" signal +field "事件流" event + +field "定时器" timer diff --git a/base/gdb/routine.go b/base/gdb/routine.go new file mode 100644 index 00000000..6fe9de32 --- /dev/null +++ b/base/gdb/routine.go @@ -0,0 +1,61 @@ +package gdb + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "strings" +) + +const ( + INNER = "inner" +) +const ROUTINE = "routine" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + ROUTINE: {Name: ROUTINE, Help: "协程池", Value: kit.Data()}, + }, + Commands: map[string]*ice.Command{ + ROUTINE: {Name: "routine hash auto 清理", Help: "协程池", Action: map[string]*ice.Action{ + mdb.CREATE: {Name: "create fileline status", Help: "创建", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.INSERT, ROUTINE, "", mdb.HASH, arg) + }}, + mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.MODIFY, ROUTINE, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), arg) + }}, + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, ROUTINE, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) + }}, + mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Option(mdb.FIELDS, "time,hash,status,fileline") + m.Cmdy(mdb.PRUNES, ROUTINE, "", mdb.HASH, kit.MDB_STATUS, STOP) + }}, + + INNER: {Name: "inner", Help: "源码", Hand: func(m *ice.Message, arg ...string) { + switch kit.Select("", arg, 0) { + case kit.SSH_RUN: + m.Cmdy(INNER, arg[1:]) + default: + ls := kit.Split(m.Option("fileline"), ":") + switch kit.Split(ls[0], "/")[0] { + case "usr": + ls[0] = strings.TrimPrefix(ls[0], "usr/icebergs/") + case "icebergs": + ls[0] = strings.TrimPrefix(ls[0], "icebergs/") + } + + m.PushPlugin(INNER, INNER, kit.SSH_RUN) + m.Push("args", kit.Format([]string{"usr/icebergs/", ls[0], ls[1]})) + } + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Option(mdb.FIELDS, kit.Select("time,hash,status,fileline", mdb.DETAIL, len(arg) > 0)) + m.Cmdy(mdb.SELECT, ROUTINE, "", mdb.HASH, kit.MDB_HASH, arg) + m.PushAction(INNER, mdb.REMOVE) + }}, + }, + }, nil) +} diff --git a/base/gdb/signal.go b/base/gdb/signal.go new file mode 100644 index 00000000..09fed6fe --- /dev/null +++ b/base/gdb/signal.go @@ -0,0 +1,58 @@ +package gdb + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "os/signal" + "syscall" +) + +func _signal_listen(m *ice.Message, s int, arg ...string) { + if f, ok := m.Target().Server().(*Frame); ok { + m.Cmdy(mdb.INSERT, SIGNAL, "", mdb.HASH, arg) + signal.Notify(f.s, syscall.Signal(s)) + } +} +func _signal_action(m *ice.Message, s int) { + m.Option(mdb.FIELDS, "time,signal,name,cmd") + msg := m.Cmd(mdb.SELECT, SIGNAL, "", mdb.HASH, SIGNAL, s) + msg.Table(func(index int, value map[string]string, head []string) { + m.Cmdy(kit.Split(value[kit.SSH_CMD])) + }) +} + +const ( + LISTEN = "listen" + ACTION = "action" +) +const SIGNAL = "signal" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + SIGNAL: {Name: SIGNAL, Help: "信号器", Value: kit.Data( + kit.MDB_PATH, "var/run/ice.pid", kit.MDB_SHORT, SIGNAL, + )}, + }, + Commands: map[string]*ice.Command{ + SIGNAL: {Name: "signal auto 监听", Help: "信号器", Action: map[string]*ice.Action{ + LISTEN: {Name: "listen signal name cmd", Help: "监听", Hand: func(m *ice.Message, arg ...string) { + _signal_listen(m, kit.Int(m.Option(SIGNAL)), arg...) + }}, + ACTION: {Name: "action signal", Help: "触发", Hand: func(m *ice.Message, arg ...string) { + _signal_action(m, kit.Int(m.Option(SIGNAL))) + }}, + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, SIGNAL, "", mdb.HASH, SIGNAL, m.Option(SIGNAL)) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Option(mdb.FIELDS, "time,signal,name,cmd") + m.Cmdy(mdb.SELECT, SIGNAL, "", mdb.HASH, SIGNAL, arg) + m.PushAction(ACTION, mdb.REMOVE) + m.Sort(SIGNAL) + }}, + }, + }, nil) +} diff --git a/base/gdb/timer.go b/base/gdb/timer.go new file mode 100644 index 00000000..6099fd48 --- /dev/null +++ b/base/gdb/timer.go @@ -0,0 +1,76 @@ +package gdb + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "time" +) + +func _timer_create(m *ice.Message, arg ...string) { + m.Cmdy(mdb.INSERT, TIMER, "", mdb.HASH, "delay", "10ms", "interval", "10m", "order", 1, "next", m.Time(m.Option("delay")), arg) +} +func _timer_action(m *ice.Message, arg ...string) { + now := time.Now().UnixNano() + m.Option(mdb.FIELDS, "time,hash,delay,interval,order,next,cmd") + + m.Richs(TIMER, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + if value = kit.GetMeta(value); value[kit.MDB_STATUS] == STOP { + return + } + + order := kit.Int(value["order"]) + if n := kit.Time(kit.Format(value["next"])); now > n && order > 0 { + m.Logs(TIMER, "key", key, "order", order) + + msg := m.Cmd(value[kit.SSH_CMD]) + m.Grow(TIMER, kit.Keys(kit.MDB_HASH, key), kit.Dict("res", msg.Result())) + if value["order"] = kit.Format(order - 1); order > 1 { + value["next"] = msg.Time(value["interval"]) + } + } + }) +} + +const TIMER = "timer" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + TIMER: {Name: TIMER, Help: "定时器", Value: kit.Data("tick", "100ms")}, + }, + Commands: map[string]*ice.Command{ + TIMER: {Name: "timer hash id auto 添加 清理", Help: "定时器", Action: map[string]*ice.Action{ + mdb.CREATE: {Name: "create delay=10ms interval=10s order=3 cmd=runtime", Help: "添加", Hand: func(m *ice.Message, arg ...string) { + _timer_create(m, arg...) + }}, + mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.MODIFY, TIMER, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), arg) + }}, + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, TIMER, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) + }}, + mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Option(mdb.FIELDS, "time,hash,delay,interval,order,next,cmd") + m.Cmdy(mdb.PRUNES, TIMER, "", mdb.HASH, "order", 0) + }}, + + ACTION: {Name: "action", Help: "执行", Hand: func(m *ice.Message, arg ...string) { + _timer_action(m, arg...) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 0 { + m.Option(mdb.FIELDS, kit.Select("time,hash,delay,interval,order,next,cmd", mdb.DETAIL, len(arg) > 0)) + m.Cmdy(mdb.SELECT, TIMER, "", mdb.HASH, kit.MDB_HASH, arg) + m.PushAction(mdb.REMOVE) + return + } + + m.Option(mdb.FIELDS, kit.Select("time,id,res", mdb.DETAIL, len(arg) > 1)) + m.Cmdy(mdb.SELECT, TIMER, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:]) + return + }}, + }, + }, nil) +} diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 8760668a..7cb14121 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -9,8 +9,12 @@ import ( "os" "path" "sort" + "strings" ) +func _fields(m *ice.Message) []string { + return kit.Split(kit.Select("time,hash,type,name,text", strings.Join(kit.Simple(m.Optionv(FIELDS)), ","))) +} func _file_name(m *ice.Message, arg ...string) string { return kit.Select(path.Join("usr/export", path.Join(arg[:2]...)), arg, 3) } @@ -29,7 +33,7 @@ func _hash_select(m *ice.Message, prefix, chain, field, value string) { if field == kit.MDB_HASH && value == RANDOM { value = kit.MDB_RANDOMS } - fields := kit.Split(kit.Select("time,hash,type,name,text", m.Option(FIELDS))) + fields := _fields(m) m.Richs(prefix, chain, value, func(key string, val map[string]interface{}) { if val[kit.MDB_META] != nil { val = val[kit.MDB_META].(map[string]interface{}) diff --git a/base/ssh/scripts.go b/base/ssh/scripts.go index 7ef55b73..ba514dc0 100644 --- a/base/ssh/scripts.go +++ b/base/ssh/scripts.go @@ -17,60 +17,6 @@ import ( "time" ) -type item struct { - c chan []byte - last []byte -} - -func (i item) Read(buf []byte) (int, error) { - b := <-i.c - n := copy(buf, b) - return n, nil -} - -type tmux struct { - input io.Reader - waits []chan []byte -} - -func (t *tmux) get() *item { - c := make(chan []byte) - t.waits = append(t.waits, c) - return &item{c: c} -} -func (t *tmux) loop() { - buf := make([]byte, 1024) - for { - n, e := t.input.Read(buf) - if e != nil { - break - } - if len(t.waits) > 0 { - wait := t.waits[len(t.waits)-1] - wait <- buf[:n] - } - } -} -func (t *tmux) read(cb func(buf []byte)) { - c := make(chan []byte) - t.waits = append(t.waits, c) - go func() { - for { - cb(<-c) - } - }() - return -} -func (t *tmux) over() { - if len(t.waits) > 0 { - t.waits = t.waits[:len(t.waits)-1] - } -} - -var stdin = &tmux{input: os.Stdin} - -func init() { go stdin.loop() } - func Render(msg *ice.Message, cmd string, args ...interface{}) { defer func() { msg.Log_EXPORT(mdb.RENDER, cmd, kit.MDB_TEXT, args) }() @@ -287,7 +233,6 @@ func (f *Frame) scan(m *ice.Message, h, line string, r io.Reader) *Frame { f.ps2 = kit.Simple(m.Confv("prompt", "meta.PS2")) ps := f.ps1 - f.count = 1 m.I, m.O = r, f.stdout bio := bufio.NewScanner(r) for f.prompt(m, ps...); bio.Scan() && !f.exit; f.prompt(m, ps...) { @@ -295,6 +240,9 @@ func (f *Frame) scan(m *ice.Message, h, line string, r io.Reader) *Frame { f.count++ if len(bio.Text()) == 0 { + if h == STDIO { + f.count-- + } continue // 空行 } if strings.HasSuffix(bio.Text(), "\\") { @@ -332,8 +280,7 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { var r io.Reader switch m.Cap(ice.CTX_STREAM, f.source) { case STDIO: // 终端交互 - // r, f.stdout = os.Stdin, os.Stdout - r, f.stdout = stdin.get(), os.Stdout + r, f.stdout = os.Stdin, os.Stdout m.Option("_option", ice.MSG_USERNAME) m.Option(ice.MSG_USERNAME, cli.UserName) @@ -359,7 +306,8 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { return true } - if f.source == STDIO { + if f.count = 1; f.source == STDIO { + f.count = kit.Int(m.Conf(SOURCE, "hash.stdio.meta.count")) + 1 f.scan(m, STDIO, "", r) } else { h := m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, kit.MDB_NAME, f.source) diff --git a/base/ssh/service.go b/base/ssh/service.go index f166acb8..54550141 100644 --- a/base/ssh/service.go +++ b/base/ssh/service.go @@ -201,11 +201,22 @@ func init() { mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) }}, + mdb.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) { + u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) + m.Option("hostname", strings.Split(u.Host, ":")[0]) + + m.Option("_process", "_inner") + if buf, err := kit.Render(` +ssh {{.Option "user.name"}}@{{.Option "hostname"}} -p {{.Option "port"}} +`, m); err == nil { + m.Cmdy("web.wiki.spark", "shell", string(buf)) + } + }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { m.Option(mdb.FIELDS, "time,status,port,private,auth,count") m.Cmdy(mdb.SELECT, SERVICE, "", mdb.HASH) - m.PushAction("导入,添加,导出") + m.PushAction(mdb.IMPORT, mdb.INSERT, mdb.EXPORT, mdb.INVITE) return } diff --git a/base/ssh/session.go b/base/ssh/session.go index 4a6f3145..d0d6ef03 100644 --- a/base/ssh/session.go +++ b/base/ssh/session.go @@ -95,9 +95,8 @@ func init() { value = kit.GetMeta(value) input := value["input"].(io.Writer) - stdin.read(func(buf []byte) { + _watch(m, os.Stdin, input, func(buf []byte) { m.Debug("input %v", string(buf)) - input.Write(buf) }) output := value["output"].(io.Reader) diff --git a/base/web/serve.go b/base/web/serve.go index 0007e5c3..d2a2b012 100644 --- a/base/web/serve.go +++ b/base/web/serve.go @@ -17,6 +17,10 @@ import ( ) const LOGIN = "_login" +const ( + SERVE_START = "serve.start" + SERVE_CLOSE = "serve.close" +) func _serve_login(msg *ice.Message, cmds []string, w http.ResponseWriter, r *http.Request) ([]string, bool) { msg.Option(ice.MSG_USERNAME, "") diff --git a/base/web/web.go b/base/web/web.go index 9fbc5d2a..b897fde5 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -5,7 +5,6 @@ import ( "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/ctx" - "github.com/shylinux/icebergs/base/gdb" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/tcp" kit "github.com/shylinux/toolkits" @@ -78,9 +77,9 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool { web.m, web.Server = m, &http.Server{Handler: web} m.Option(tcp.LISTEN_CB, func(l net.Listener) { - m.Event(gdb.SERVE_START, arg[0]) + m.Event(SERVE_START, arg[0]) m.Warn(true, "listen %s", web.Server.Serve(l)) - m.Event(gdb.SERVE_CLOSE, arg[0]) + m.Event(SERVE_CLOSE, arg[0]) }) ls := strings.Split(m.Cap(ice.CTX_STREAM, client["hostname"]), ":") diff --git a/conf.go b/conf.go index 0307df4e..c4b1027d 100644 --- a/conf.go +++ b/conf.go @@ -5,6 +5,7 @@ const ( //MOD MOD_FILE = 0640 MOD_CHAN = 16 + MOD_TICK = "1s" MOD_BUF = 1024 MOD_DATE = "2006-01-02" diff --git a/exec.go b/exec.go index ef91ddbc..eda66af4 100644 --- a/exec.go +++ b/exec.go @@ -109,11 +109,11 @@ func (m *Message) Back(res *Message) *Message { } return m } -func (m *Message) Gos(msg *Message, cb interface{}) *Message { - m.Cmd("gdb.routine", "create", "fileline", kit.FileLine(cb, 3)) - - task.Put(nil, func(task *task.Task) error { +func (m *Message) Gos(msg *Message, cb interface{}, args ...interface{}) *Message { + task.Put(m.Cmdx("gdb.routine", "create", "fileline", kit.FileLine(cb, 3), "status", "start"), func(task *task.Task) error { + msg.Optionv("task.hash", task.Arg) msg.Optionv("_task", task) + msg.TryCatch(msg, true, func(msg *Message) { switch cb := cb.(type) { case func(*Message): @@ -122,16 +122,17 @@ func (m *Message) Gos(msg *Message, cb interface{}) *Message { cb() } }) + + msg.Option(kit.MDB_HASH, task.Arg) + msg.Cmdx("gdb.routine", "modify", "status", "stop") return nil }) return m } -func (m *Message) Go(cb interface{}) *Message { +func (m *Message) Go(cb interface{}, args ...interface{}) *Message { switch cb := cb.(type) { case func(*Message): - return m.Gos(m.Spawn(), cb) - case func(): - return m.Gos(m, cb) + return m.Gos(m.Spawn(), cb, args...) } - return m.Gos(m, cb) + return m.Gos(m, cb, args...) } diff --git a/go.sum b/go.sum index e69de29b..7fb84c40 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,19 @@ +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4/go.mod h1:kcRFpEzolcEklV6rD7W95mG49/sbdX/PlFmd7ni3RvA= +github.com/nareix/joy4 v0.0.0-20200507095837-05a4ffbb5369/go.mod h1:aFJ1ZwLjvHN4yEzE5Bkz8rD8/d8Vlj3UIuvz2yfET7I= +github.com/shylinux/toolkits v0.1.8 h1:Lh5HkR1aRzhOOVu9eHwZ5y7dfW7hcFy29IR5tQ5qUeM= +github.com/shylinux/toolkits v0.1.8/go.mod h1:Y68Ot6xOmo1bun67YvqC3chDGeU2gDxtsUnvVDGJm4g= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= +github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2/go.mod h1:lPnW9HVS0vJdeYyQtOvIvlXgZPNhUAhwz+z5r8AJk0Y= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/misc.go b/misc.go index 75e974d0..73ca9080 100644 --- a/misc.go +++ b/misc.go @@ -37,11 +37,11 @@ func (m *Message) Watch(key string, arg ...string) *Message { if len(arg) == 0 { arg = append(arg, m.Prefix("auto")) } - m.Cmd("gdb.event", "listen", key, arg) + m.Cmd("gdb.event", "listen", "event", key, "cmd", strings.Join(arg, " ")) return m } func (m *Message) Event(key string, arg ...string) *Message { - m.Cmd("gdb.event", "action", key, arg) + m.Cmd("gdb.event", "action", "event", key, strings.Join(arg, " ")) return m } func (m *Message) Right(arg ...interface{}) bool { @@ -75,10 +75,8 @@ func (m *Message) PushRender(key, view, name string, arg ...string) *Message { case "button": list := []string{} for _, k := range kit.Split(name) { - list = append(list, fmt.Sprintf(``, k)) - } - for _, k := range arg { - list = append(list, fmt.Sprintf(``, k)) + list = append(list, fmt.Sprintf(``, + k, kit.Select(k, kit.Value(m.cmd.Meta, kit.Keys("trans", k))))) } m.Push(key, strings.Join(list, "")) case "video": @@ -105,6 +103,12 @@ func (m *Message) PushAction(list ...interface{}) { func (m *Message) PushButton(key string, arg ...string) { m.PushRender("action", "button", key, arg...) } +func (m *Message) PushPlugin(key string, arg ...string) *Message { + m.Option("_process", "_field") + m.Option("_prefix", arg) + m.Cmdy("command", key) + return m +} func (m *Message) PushDetail(value interface{}, arg ...interface{}) *Message { return m.Push("detail", value, arg...) } diff --git a/misc/git/repos.go b/misc/git/repos.go index f87a9dfe..af4d2029 100644 --- a/misc/git/repos.go +++ b/misc/git/repos.go @@ -5,7 +5,6 @@ import ( "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" - "github.com/shylinux/icebergs/base/web" kit "github.com/shylinux/toolkits" "os" @@ -148,35 +147,37 @@ func init() { }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Richs(REPOS, nil, kit.Select(kit.MDB_FOREACH, arg, 0), func(key string, value map[string]interface{}) { - if m.Option(cli.CMD_DIR, kit.Value(value, "meta.path")); len(arg) > 0 { - // 更改详情 + value = kit.GetMeta(value) + + if m.Option(cli.CMD_DIR, value[kit.MDB_PATH]); len(arg) > 0 { m.Echo(m.Cmdx(cli.SYSTEM, GIT, "diff")) - return + return // 更改详情 } // 更改列表 for _, v := range strings.Split(strings.TrimSpace(m.Cmdx(cli.SYSTEM, GIT, "status", "-sb")), "\n") { vs := strings.SplitN(strings.TrimSpace(v), " ", 2) - m.Push("name", kit.Value(value, "meta.name")) + m.Push("name", value[kit.MDB_NAME]) m.Push("tags", vs[0]) m.Push("file", vs[1]) + list := []string{} switch vs[0] { case "##": if strings.Contains(vs[1], "ahead") { - list = append(list, m.Cmdx(mdb.RENDER, web.RENDER.Button, "上传")) + list = append(list, "上传") } default: if strings.Contains(vs[0], "??") { - list = append(list, m.Cmdx(mdb.RENDER, web.RENDER.Button, "添加")) + list = append(list, "添加") } else { - list = append(list, m.Cmdx(mdb.RENDER, web.RENDER.Button, "提交")) + list = append(list, "提交") } } - m.Push("action", strings.Join(list, "")) + m.PushButton(strings.Join(list, ",")) } }) - m.Sort("name") + m.Sort(kit.MDB_NAME) }}, }, }, nil) diff --git a/misc/tmux/tmux.go b/misc/tmux/tmux.go index 0872984f..4f2135d0 100644 --- a/misc/tmux/tmux.go +++ b/misc/tmux/tmux.go @@ -86,22 +86,22 @@ var Index = &ice.Context{Name: TMUX, Help: "工作台", } }}, mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - m.Conf(BUFFER, mdb.LIST, "") - m.Conf(BUFFER, kit.Keys(mdb.META, "count"), "0") + m.Conf(m.Prefix(BUFFER), mdb.LIST, "") + m.Conf(m.Prefix(BUFFER), kit.Keys(mdb.META, "count"), "0") - m.Cmd(BUFFER).Table(func(index int, value map[string]string, head []string) { - m.Grow(BUFFER, "", kit.Dict( + m.Cmd(m.Prefix(BUFFER)).Table(func(index int, value map[string]string, head []string) { + m.Grow(m.Prefix(BUFFER), "", kit.Dict( "name", value[head[0]], "text", m.Cmdx(cli.SYSTEM, TMUX, "show-buffer", "-b", value[head[0]]), )) }) m.Cmdy(mdb.EXPORT, m.Prefix(BUFFER), "", mdb.LIST) }}, mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - m.Conf(BUFFER, mdb.LIST, "") - m.Conf(BUFFER, kit.Keys(mdb.META, "count"), "0") + m.Conf(m.Prefix(BUFFER), mdb.LIST, "") + m.Conf(m.Prefix(BUFFER), kit.Keys(mdb.META, "count"), "0") m.Cmdy(mdb.IMPORT, m.Prefix(BUFFER), "", mdb.LIST) - m.Grows(BUFFER, "", "", "", func(index int, value map[string]interface{}) { + m.Grows(m.Prefix(BUFFER), "", "", "", func(index int, value map[string]interface{}) { m.Cmd(cli.SYSTEM, TMUX, "set-buffer", "-b", value["name"], value["text"]) }) }}, @@ -145,7 +145,7 @@ var Index = &ice.Context{Name: TMUX, Help: "工作台", m.Cmdy(mdb.IMPORT, m.Prefix(SCRIPT), "", mdb.HASH) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if m.Option(mdb.FIELDS, m.Conf(SCRIPT, kit.META_FIELD)); len(arg) > 0 { + if m.Option(mdb.FIELDS, m.Conf(m.Prefix(SCRIPT), kit.META_FIELD)); len(arg) > 0 { m.Option(mdb.FIELDS, mdb.DETAIL) } m.Cmdy(mdb.SELECT, m.Prefix(SCRIPT), "", mdb.HASH, kit.MDB_NAME, arg) @@ -232,13 +232,13 @@ var Index = &ice.Context{Name: TMUX, Help: "工作台", if len(arg) == 0 { // 会话列表 - m.Split(m.Cmdx(cli.SYSTEM, TMUX, "list-session", "-F", m.Conf(cmd, "meta.format")), m.Conf(cmd, "meta.fields"), ",", "\n") + m.Split(m.Cmdx(cli.SYSTEM, TMUX, "list-session", "-F", m.Conf(m.Prefix(cmd), "meta.format")), m.Conf(m.Prefix(cmd), "meta.fields"), ",", "\n") m.Table(func(index int, value map[string]string, head []string) { switch value["tag"] { case "1": - m.PushRender("action", "button", "") + m.PushButton("") default: - m.PushRender("action", "button", "进入", "删除") + m.PushButton("进入", "删除") } }) return @@ -260,11 +260,11 @@ var Index = &ice.Context{Name: TMUX, Help: "工作台", }}, WINDOW: {Name: "windows", Help: "窗口", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Split(m.Cmdx(cli.SYSTEM, TMUX, "list-windows", "-t", kit.Select("", arg, 0), - "-F", m.Conf(cmd, "meta.format")), m.Conf(cmd, "meta.fields"), ",", "\n") + "-F", m.Conf(m.Prefix(cmd), "meta.format")), m.Conf(m.Prefix(cmd), "meta.fields"), ",", "\n") }}, PANE: {Name: "panes", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Split(m.Cmdx(cli.SYSTEM, TMUX, "list-panes", "-t", kit.Select("", arg, 0), - "-F", m.Conf(cmd, "meta.format")), m.Conf(cmd, "meta.fields"), ",", "\n") + "-F", m.Conf(m.Prefix(cmd), "meta.format")), m.Conf(m.Prefix(cmd), "meta.fields"), ",", "\n") }}, VIEW: {Name: "view", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmdy(cli.SYSTEM, TMUX, "capture-pane", "-pt", kit.Select("", arg, 0)).Set(ice.MSG_APPEND) diff --git a/type.go b/type.go index dc4150f1..720d5603 100644 --- a/type.go +++ b/type.go @@ -87,7 +87,7 @@ func (c *Context) _hand(m *Message, cmd *Command, key string, k string, h *Actio for _, v := range h.List { name := kit.Format(kit.Value(v, "name")) value := kit.Format(kit.Value(v, "value")) - m.Option(name, value) + m.Option(name, kit.Select("", value, !strings.HasPrefix(value, "@"))) } for i := 0; i < len(arg)-1; i += 2 { m.Option(arg[i], arg[i+1]) @@ -101,6 +101,7 @@ func (c *Context) cmd(m *Message, cmd *Command, key string, arg ...string) *Mess return m } + m.cmd = cmd if m.Hand = true; len(arg) > 1 && arg[0] == "action" && cmd.Action != nil { if h, ok := cmd.Action[arg[1]]; ok { return c._hand(m, cmd, key, arg[1], h, arg[2:]...) @@ -176,6 +177,7 @@ func (c *Context) Merge(s *Context, x Server) *Context { } for k, a := range v.Action { + kit.Value(v.Meta, kit.Keys("trans", k), a.Help) if a.List == nil { a.List = c._split(a.Name) } @@ -287,7 +289,13 @@ func (c *Context) Start(m *Message, arg ...string) bool { m.Hold(1) wait := make(chan bool) - m.Gos(m, func(m *Message) { + + var p interface{} + if c.server != nil { + p = c.server.Start + } + + m.Go(func() { m.Log(LOG_START, c.Cap(CTX_FOLLOW)) c.Cap(CTX_STATUS, CTX_START) @@ -298,7 +306,7 @@ func (c *Context) Start(m *Message, arg ...string) bool { if m.Done(); m.wait != nil { m.wait <- true } - }) + }, p) <-wait return true } @@ -327,6 +335,7 @@ type Message struct { source *Context target *Context + cmd *Command cb func(*Message) *Message W http.ResponseWriter