From 7a2f552db57a117a9f111d615e0ed1057bd0243a Mon Sep 17 00:00:00 2001 From: shaoying Date: Wed, 18 Dec 2019 23:38:01 +0800 Subject: [PATCH] add log&gdb --- base.go | 89 +++++++++++++++++--------- base/cli/cli.go | 5 ++ base/ctx/ctx.go | 28 +++++++-- base/gdb/gdb.go | 75 ++++++++++++---------- base/log/log.go | 84 +++++++++++++++++++++++-- base/shy.go | 6 +- base/ssh/ssh.go | 63 ++++++++++++++++++- base/tcp/tcp.go | 30 ++++++++- base/web/web.go | 6 +- core/chat/chat.go | 2 - demo/build.sh | 6 +- demo/miss.md | 11 ++++ type.go | 155 ++++++++++++++++++++++++++++++++++++++++------ 13 files changed, 462 insertions(+), 98 deletions(-) diff --git a/base.go b/base.go index 23e1d51c..5cf37ba9 100644 --- a/base.go +++ b/base.go @@ -2,11 +2,15 @@ package ice import ( "github.com/shylinux/toolkits" + "os" + "strings" + "sync" "time" ) type Frame struct { + code int } func (f *Frame) Spawn(m *Message, c *Context, arg ...string) Server { @@ -21,28 +25,15 @@ func (f *Frame) Begin(m *Message, arg ...string) Server { list[s] = sub } }) + m.target.wg = &sync.WaitGroup{} return f } func (f *Frame) Start(m *Message, arg ...string) bool { - // 加载配置 - m.Travel(func(p *Context, s *Context) { - if _, ok := s.Commands["_init"]; ok { - m.Spawns(s).Runs("_init", "_init", arg...) - } - }) - - // 启动服务 - Index.begin.Cmd(arg) + m.Cmd("_init").Cmd("init", arg) return true } func (f *Frame) Close(m *Message, arg ...string) bool { - // 保存配置 - m.Travel(func(p *Context, s *Context) { - if _, ok := s.Commands["_exit"]; ok { - m.Spawns(s).Runs("_exit", "_exit", arg...) - } - }) - + m.target.wg.Wait() list := map[*Context]*Message{m.target: m} m.Travel(func(p *Context, s *Context) { if msg, ok := list[p]; ok && msg != nil { @@ -55,29 +46,63 @@ func (f *Frame) Close(m *Message, arg ...string) bool { } var Index = &Context{Name: "ice", Help: "冰山模块", - Caches: map[string]*Cache{}, + Caches: map[string]*Cache{ + "status": {Value: "begin"}, + "stream": {Value: "shy"}, + }, Configs: map[string]*Config{ + "table": {Name: "数据缓存", Value: map[string]interface{}{ + "space": " ", + "col_sep": " ", + "row_sep": "\n", + "compact": "false", + }}, "cache": {Name: "数据缓存", Value: map[string]interface{}{ "store": "var/data", "limit": "30", "least": "10", }}, + "help": {Value: map[string]interface{}{ + "index": []interface{}{ + "^_^ 欢迎使用冰山框架 ^_^", + "^_^ Welcome to Icebergs world ^_^", + "", + "Meet: shylinuxc@gmail.com", + "More: https://shylinux.com", + "More: https://github.com/shylinux/icebergs", + "", + }, + }}, }, Commands: map[string]*Command{ "_init": {Name: "_init", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) { + m.Travel(func(p *Context, s *Context) { + if _, ok := s.Commands["_init"]; ok && p != nil { + m.Spawns(s).Runs("_init", "_init", arg...) + } + }) + }}, + "init": {Name: "init", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) { + m.Start("log", arg...) + m.Start("gdb", arg...) + m.Start("ssh", arg...) + m.Cmd(arg) + }}, + "help": {Name: "help", Help: "帮助", Hand: func(m *Message, c *Context, cmd string, arg ...string) { + m.Echo(strings.Join(kit.Simple(m.Confv("help", "index")), "\n")) }}, "exit": {Name: "exit", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) { - c.Close(m.Spawn(c), arg...) - os.Exit(kit.Int(kit.Select("0", arg, 0))) - }}, - "restart": {Name: "restart", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) { - switch kit.Select("0", arg, 0) { - case "0": - c.Close(m.Spawn(c), arg...) - os.Exit(kit.Int(kit.Select("0", arg, 0))) - } + Code = kit.Int(kit.Select("0", arg, 0)) + m.root.Cmd("_exit") }}, "_exit": {Name: "_init", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) { + m.root.Travel(func(p *Context, s *Context) { + if _, ok := s.Commands["_exit"]; ok && p != nil { + m.TryCatch(m.Spawns(s), true, func(msg *Message) { + msg.Runs("_exit", "_exit", arg...) + }) + } + }) }}, }, } @@ -94,9 +119,10 @@ var Pulse = &Message{ func init() { Index.root = Index Pulse.root = Pulse - Index.server = &Frame{} } +var Code = 0 + func Run(arg ...string) string { if len(arg) == 0 { arg = os.Args[1:] @@ -105,8 +131,13 @@ func Run(arg ...string) string { arg = append(arg, os.Getenv("ice_serve")) } - if Index.Begin(Pulse.Spawns(), arg...).Start(Index.begin.Spawns(), arg...) { - Index.Close(Index.start.Spawns(), arg...) + frame := &Frame{} + Index.server = frame + + if frame.Begin(Pulse.Spawns(), arg...).Start(Pulse.Spawns(), arg...) { + frame.Close(Pulse.Spawns(), arg...) } + time.Sleep(time.Second) + os.Exit(Code) return Pulse.Result() } diff --git a/base/cli/cli.go b/base/cli/cli.go index c7eab0a9..6d8d6524 100644 --- a/base/cli/cli.go +++ b/base/cli/cli.go @@ -24,6 +24,8 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块", }, Commands: map[string]*ice.Command{ "_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd("ctx.config", "load", "var/conf/cli.json") + m.Conf("runtime", "host.GOARCH", runtime.GOARCH) m.Conf("runtime", "host.GOOS", runtime.GOOS) m.Conf("runtime", "host.pid", os.Getpid()) @@ -42,6 +44,9 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块", m.Conf("runtime", "node.name", m.Conf("runtime", "boot.pathname")) m.Log("info", "runtime %v", kit.Formats(m.Confv("runtime"))) }}, + "_exit": {Name: "_exit", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd("ctx.config", "save", "var/conf/cli.json", "cli.runtime") + }}, "runtime": {Name: "runtime", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, "system": {Name: "system", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) { diff --git a/base/ctx/ctx.go b/base/ctx/ctx.go index ca146840..07fe4085 100644 --- a/base/ctx/ctx.go +++ b/base/ctx/ctx.go @@ -5,19 +5,40 @@ import ( "github.com/shylinux/icebergs" "github.com/shylinux/toolkits" "os" + "sort" ) var Index = &ice.Context{Name: "ctx", Help: "元始模块", Caches: map[string]*ice.Cache{}, Configs: map[string]*ice.Config{}, Commands: map[string]*ice.Command{ + "context": {Name: "context", Help: "模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + ice.Pulse.Travel(func(p *ice.Context, s *ice.Context) { + if p != nil { + m.Push("ups", p.Name) + } else { + m.Push("ups", "shy") + } + m.Push("name", s.Name) + m.Push("status", s.Cap("status")) + m.Push("stream", s.Cap("stream")) + m.Push("help", s.Help) + }) + }}, "command": {Name: "command", Help: "命令", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { ice.Pulse.Travel(func(p *ice.Context, s *ice.Context) { - for k, v := range s.Commands { + list := []string{} + for k := range s.Commands { if k[0] == '/' || k[0] == '_' { continue } + list = append(list, k) + } + sort.Strings(list) + + for _, k := range list { + v := s.Commands[k] if p != nil && p != ice.Index { m.Push("key", p.Name+"."+s.Name) } else { @@ -39,10 +60,7 @@ var Index = &ice.Context{Name: "ctx", Help: "元始模块", m.Push("meta", kit.Format(i.Meta)) m.Push("list", kit.Format(i.List)) } else { - switch arg[2] { - case "run": - m.Copy(m.Spawns(s).Runs(key, key, arg[3:]...)) - } + m.Copy(m.Spawns(s).Runs(key, key, arg[3:]...)) } } }) diff --git a/base/gdb/gdb.go b/base/gdb/gdb.go index eb164d16..c87feacd 100644 --- a/base/gdb/gdb.go +++ b/base/gdb/gdb.go @@ -10,7 +10,7 @@ import ( ) type Frame struct { - signal chan os.Signal + p chan os.Signal } func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server { @@ -22,35 +22,37 @@ func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server { f.WriteString(kit.Format(os.Getpid())) m.Log("info", "pid %d %s", os.Getpid(), p) } - - f.signal = make(chan os.Signal, 10) - m.Confm("signal", nil, func(sig string, action string) { - m.Log("signal", "add %s: %s", sig, action) - signal.Notify(f.signal, syscall.Signal(kit.Int(sig))) - }) - - m.Gos(m, func(m *ice.Message) { - if s, ok := <-f.signal; ok { - m.Log("info", "signal %v", s) - m.Cmd(m.Confv("signal", kit.Format(s))) - } - }) - m.Gos(m, func(m *ice.Message) { - for { - time.Sleep(100 * time.Millisecond) - now := int(time.Now().Unix()) - m.Confm("timer", "hash", func(key string, value map[string]interface{}) { - if kit.Int(value["next"]) <= now { - m.Log("info", "timer %v %v", key, value["next"]) - m.Cmd(value["cmd"]) - value["next"] = now + int(kit.Duration(value["interval"]))/int(time.Second) - } - }) - } - }) return f } func (f *Frame) Start(m *ice.Message, arg ...string) bool { + f.p = make(chan os.Signal, 10) + m.Confm("signal", nil, func(sig string, action string) { + m.Log("signal", "add %s: %s", sig, action) + signal.Notify(f.p, syscall.Signal(kit.Int(sig))) + }) + + m.Cap("stream", m.Conf("timer", "meta.tick")) + tick := time.Tick(kit.Duration(m.Conf("timer", "meta.tick"))) + for { + select { + case sig, ok := <-f.p: + if !ok { + return true + } + m.Log("info", "signal %v", sig) + m.Cmd(m.Confv("signal", kit.Format(sig))) + case now, _ := <-tick: + // m.Log("info", "ticker %v", kit.Format(now)) + stamp := int(now.Unix()) + m.Confm("timer", "hash", func(key string, value map[string]interface{}) { + if kit.Int(value["next"]) <= stamp { + m.Log("info", "timer %v %v", key, value["next"]) + m.Cmd(value["cmd"]) + value["next"] = stamp + int(kit.Duration(value["interval"]))/int(time.Second) + } + }) + } + } return true } func (f *Frame) Close(m *ice.Message, arg ...string) bool { @@ -62,18 +64,29 @@ var Index = &ice.Context{Name: "gdb", Help: "调试模块", Configs: map[string]*ice.Config{ "logpid": &ice.Config{Name: "logpid", Value: "var/run/shy.pid", Help: ""}, "signal": &ice.Config{Name: "signal", Value: map[string]interface{}{ - "2": []interface{}{"exit"}, "3": "QUIT", "15": "TERM", + "2": []interface{}{"exit"}, + "3": []interface{}{"exit", "1"}, + "15": []interface{}{"exit", "1"}, + "30": []interface{}{"exit"}, + "31": []interface{}{"exit", "1"}, "28": "WINCH", - "30": "restart", - "31": "upgrade", }, Help: "信号"}, "timer": {Name: "定时器", Value: map[string]interface{}{ - "meta": map[string]interface{}{}, + "meta": map[string]interface{}{ + "tick": "100ms", + }, "hash": map[string]interface{}{}, "list": map[string]interface{}{}, }}, }, Commands: map[string]*ice.Command{ + "_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Echo("hello %s world", c.Name) + }}, + "_exit": {Name: "_exit", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + f := m.Target().Server().(*Frame) + close(f.p) + }}, "timer": {Name: "timer", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch arg[0] { case "start": diff --git a/base/log/log.go b/base/log/log.go index 4c0ccaa8..0e8f6313 100644 --- a/base/log/log.go +++ b/base/log/log.go @@ -1,17 +1,93 @@ package log import ( + "fmt" "github.com/shylinux/icebergs" + "github.com/shylinux/toolkits" + "os" + "path" ) +type Log struct { + m *ice.Message + level string + str string +} + +type Frame struct { + p chan *Log +} + +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.p = make(chan *Log, 100) + ice.Log = func(msg *ice.Message, level string, str string) { + f.p <- &Log{m: msg, level: level, str: str} + } + return f +} +func (f *Frame) Start(m *ice.Message, arg ...string) bool { + m.Confm("file", nil, func(key string, value map[string]interface{}) { + if f, p, e := kit.Create(kit.Format(value["path"])); m.Assert(e) { + m.Cap("stream", path.Base(p)) + m.Log("info", "log %s %s", key, p) + value["file"] = f + } + }) + + for { + if l, ok := <-f.p; !ok { + break + } else { + file := kit.Select("bench", m.Conf("show", l.level+".file")) + f := m.Confv("file", file+".file").(*os.File) + + ls := []string{l.m.Format("prefix"), " "} + ls = append(ls, m.Conf("show", l.level+".prefix"), + l.level, " ", l.str, m.Conf("show", l.level+".suffix"), "\n") + + for _, v := range ls { + fmt.Fprintf(f, v) + } + } + } + return true +} +func (f *Frame) Close(m *ice.Message, arg ...string) bool { + return true +} + var Index = &ice.Context{Name: "log", Help: "日志模块", - Caches: map[string]*ice.Cache{}, - Configs: map[string]*ice.Config{}, + Caches: map[string]*ice.Cache{}, + Configs: map[string]*ice.Config{ + "file": &ice.Config{Name: "file", Value: map[string]interface{}{ + "bench": map[string]interface{}{"path": "var/log/bench.log"}, + }, Help: "信号"}, + "show": &ice.Config{Name: "file", Value: map[string]interface{}{ + "bench": map[string]interface{}{"file": "bench"}, + + "cmd": map[string]interface{}{"file": "bench", "prefix": "\033[32m", "suffix": "\033[0m"}, + "start": map[string]interface{}{"file": "bench", "prefix": "\033[32m", "suffix": "\033[0m"}, + "serve": map[string]interface{}{"file": "bench", "prefix": "\033[32m", "suffix": "\033[0m"}, + + "cost": map[string]interface{}{"file": "bench", "prefix": "\033[33m", "suffix": "\033[0m"}, + + "warn": map[string]interface{}{"file": "bench", "prefix": "\033[31m", "suffix": "\033[0m"}, + "close": map[string]interface{}{"file": "bench", "prefix": "\033[31m", "suffix": "\033[0m"}, + }, Help: "信号"}, + }, Commands: map[string]*ice.Command{ - "hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + "_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Echo("hello %s world", c.Name) }}, + "_exit": {Name: "_exit", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + f := m.Target().Server().(*Frame) + ice.Log = nil + close(f.p) + }}, }, } -func init() { ice.Index.Register(Index, nil) } +func init() { ice.Index.Register(Index, &Frame{}) } diff --git a/base/shy.go b/base/shy.go index 0b7b459f..bf067483 100644 --- a/base/shy.go +++ b/base/shy.go @@ -4,9 +4,13 @@ import ( _ "github.com/shylinux/icebergs/base/aaa" _ "github.com/shylinux/icebergs/base/cli" _ "github.com/shylinux/icebergs/base/ctx" + _ "github.com/shylinux/icebergs/base/web" + _ "github.com/shylinux/icebergs/base/gdb" _ "github.com/shylinux/icebergs/base/log" + _ "github.com/shylinux/icebergs/base/mdb" _ "github.com/shylinux/icebergs/base/nfs" - _ "github.com/shylinux/icebergs/base/web" + _ "github.com/shylinux/icebergs/base/ssh" + _ "github.com/shylinux/icebergs/base/tcp" ) diff --git a/base/ssh/ssh.go b/base/ssh/ssh.go index 407ab5cf..fd4fb4b8 100644 --- a/base/ssh/ssh.go +++ b/base/ssh/ssh.go @@ -2,16 +2,73 @@ package ssh import ( "github.com/shylinux/icebergs" + "github.com/shylinux/toolkits" + + "bufio" + "fmt" + "io" + "os" ) -var Index = &ice.Context{Name: "ssh", Help: "远程模块", +type Frame struct { + in io.ReadCloser + out io.WriteCloser +} + +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 { + return f +} +func (f *Frame) Start(m *ice.Message, arg ...string) bool { + f.in = os.Stdin + f.out = os.Stdout + m.Cap("stream", "stdio") + + prompt := "%d[15:04:05]%s> " + target := m.Target() + count := 0 + + bio := bufio.NewScanner(f.in) + fmt.Fprintf(f.out, m.Time(prompt, count, target.Name)) + for bio.Scan() { + ls := kit.Split(bio.Text()) + m.Log("info", "input %v", ls) + + msg := m.Spawn(target) + if msg.Cmdy(ls); !msg.Hand { + msg = msg.Cmdy("cli.system", ls) + } + res := msg.Result() + if res == "" { + msg.Table() + res = msg.Result() + } + + fmt.Fprintf(f.out, res) + fmt.Fprintf(f.out, m.Time(prompt, count, target.Name)) + count++ + } + return true +} +func (f *Frame) Close(m *ice.Message, arg ...string) bool { + return true +} + +var Index = &ice.Context{Name: "ssh", Help: "终端模块", Caches: map[string]*ice.Cache{}, Configs: map[string]*ice.Config{}, Commands: map[string]*ice.Command{ - "hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + "_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Echo("hello %s world", c.Name) }}, + "_exit": {Name: "_exit", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + f := m.Target().Server().(*Frame) + f.in.Close() + m.Target().Done() + }}, }, } -func init() { ice.Index.Register(Index, nil) } +func init() { ice.Index.Register(Index, &Frame{}) } diff --git a/base/tcp/tcp.go b/base/tcp/tcp.go index dbcb5349..c0325e57 100644 --- a/base/tcp/tcp.go +++ b/base/tcp/tcp.go @@ -2,14 +2,40 @@ package tcp import ( "github.com/shylinux/icebergs" + "net" + "strings" ) var Index = &ice.Context{Name: "tcp", Help: "网络模块", Caches: map[string]*ice.Cache{}, Configs: map[string]*ice.Config{}, Commands: map[string]*ice.Command{ - "hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Echo("hello %s world", c.Name) + "ifconfig": {Name: "ifconfig [name]", Help: "网络配置", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if ifs, e := net.Interfaces(); m.Assert(e) { + for _, v := range ifs { + if len(arg) > 0 && !strings.Contains(v.Name, arg[0]) { + continue + } + if ips, e := v.Addrs(); m.Assert(e) { + for _, x := range ips { + ip := strings.Split(x.String(), "/") + if strings.Contains(ip[0], ":") || len(ip) == 0 { + continue + } + if len(v.HardwareAddr.String()) == 0 { + continue + } + + m.Push("index", v.Index) + m.Push("name", v.Name) + m.Push("ip", ip[0]) + m.Push("mask", ip[1]) + m.Push("hard", v.HardwareAddr.String()) + } + } + } + m.Table() + } }}, }, } diff --git a/base/web/web.go b/base/web/web.go index e28da58f..07f7d63c 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -269,6 +269,7 @@ func (web *WEB) Start(m *ice.Message, arg ...string) bool { }) port := kit.Select(m.Conf("spide", "self.port"), arg, 0) + m.Cap("stream", port) web.m = m web.Server = &http.Server{Addr: port, Handler: web} m.Log("serve", "node %v", m.Conf("cli.runtime", "node")) @@ -311,10 +312,13 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", "_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Echo("hello %s world", c.Name) }}, + "_exit": {Name: "_exit", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Target().Done() + }}, "serve": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Conf("cli.runtime", "node.type", "server") m.Conf("cli.runtime", "node.name", m.Conf("cli.runtime", "boot.hostname")) - m.Run(arg...) + m.Target().Start(m, arg...) }}, "/space": &ice.Command{Name: "/space", Help: "", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { r := m.Optionv("request").(*http.Request) diff --git a/core/chat/chat.go b/core/chat/chat.go index 3fd9510b..f8ab1f5f 100644 --- a/core/chat/chat.go +++ b/core/chat/chat.go @@ -18,7 +18,6 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", }, Commands: map[string]*ice.Command{ "_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Cmd("ctx.config", "load", "var/conf/cli.json") m.Cmd("ctx.config", "load", "var/conf/aaa.json") m.Cmd("ctx.config", "load", "var/conf/chat.json") }}, @@ -42,7 +41,6 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", "_exit": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmd("ctx.config", "save", "var/conf/chat.json", "web.chat.group") m.Cmd("ctx.config", "save", "var/conf/aaa.json", "aaa.role", "aaa.user", "aaa.sess") - m.Cmd("ctx.config", "save", "var/conf/cli.json", "cli.runtime") }}, "/login": {Name: "/login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/demo/build.sh b/demo/build.sh index f578ef6e..815bc1c1 100755 --- a/demo/build.sh +++ b/demo/build.sh @@ -2,6 +2,7 @@ export ice_app=${ice_app:="ice.app"} export ice_err=${ice_err:="boot.log"} +export ice_conf=${ice_app:="var/conf"} export ice_serve=${ice_serve:="web.serve"} prepare() { @@ -38,13 +39,16 @@ build() { start() { [ -d usr/volcanos ] || git clone https://github.com/shylinux/volcanos usr/volcanos while true; do - date && $ice_app $* 2>$ice_err && log "\n\nrestarting..." && sleep 1 || break + date && $ice_app $* 2>$ice_err && log "\n\nrestarting..." || break done } log() { echo -e $*; } restart() { kill -2 `cat var/run/shy.pid` } +shutdown() { + kill -3 `cat var/run/shy.pid` +} help() { echo "usage: $0 cmd arg" } diff --git a/demo/miss.md b/demo/miss.md index fd439132..9189bd51 100644 --- a/demo/miss.md +++ b/demo/miss.md @@ -1,5 +1,16 @@ # {{title "hello world"}} +init.register +ice.Begin +ice.Start +ice.Close + +{{chart "table" ` +ctx cli aaa web +lex yac gdb log +tcp nfs ssh mdb +`}} + {{chart "chain" ` context volcanos diff --git a/type.go b/type.go index 3bef8db1..c2df0ce9 100644 --- a/type.go +++ b/type.go @@ -13,6 +13,7 @@ import ( "runtime" "sort" "strings" + "sync" "time" ) @@ -44,12 +45,13 @@ type Context struct { contexts map[string]*Context context *Context root *Context - begin *Message - start *Message - exit chan bool + begin *Message + start *Message server Server - id int + + wg *sync.WaitGroup + id int } type Server interface { Spawn(m *Message, c *Context, arg ...string) Server @@ -62,6 +64,12 @@ func (c *Context) ID() int { c.id++ return c.id } +func (c *Context) Cap(key string, arg ...interface{}) string { + if len(arg) > 0 { + c.Caches[key].Value = kit.Format(arg[0]) + } + return c.Caches[key].Value +} func (c *Context) Server() Server { return c.server } @@ -77,18 +85,43 @@ func (c *Context) Register(s *Context, x Server) *Context { return s } +func (c *Context) Done() bool { + if c.context != nil && c.context.wg != nil { + c.context.wg.Done() + } else { + c.root.wg.Done() + } + return true +} func (c *Context) Begin(m *Message, arg ...string) *Context { - c.begin = m + c.Caches["status"] = &Cache{Name: "status", Value: ""} + c.Caches["stream"] = &Cache{Name: "stream", Value: ""} + m.Log("begin", "%s", c.Name) - if c.server != nil { - c.server.Begin(m, arg...) + if c.begin = m; c.server != nil { + m.TryCatch(m, true, func(m *Message) { + c.server.Begin(m, arg...) + }) } return c } func (c *Context) Start(m *Message, arg ...string) bool { c.start = m - m.Log("start", "%s", c.Name) - return c.server.Start(m, arg...) + if c.context != nil && c.context.wg != nil { + c.context.wg.Add(1) + } else { + c.root.wg.Add(1) + } + + m.Gos(m, func(m *Message) { + m.Log("start", "%s", c.Name) + + c.Cap("status", "start") + c.server.Start(m, arg...) + c.Cap("status", "close") + c.Done() + }) + return true } func (c *Context) Close(m *Message, arg ...string) bool { m.Log("close", "%s", c.Name) @@ -347,6 +380,67 @@ func (m *Message) Table(cbs ...interface{}) *Message { cb(i, line, m.meta["append"]) } } + return m + } + + //计算列宽 + space := kit.Select(m.Conf("table", "space"), m.Option("table.space")) + depth, width := 0, map[string]int{} + for _, k := range m.meta["append"] { + if len(m.meta[k]) > depth { + depth = len(m.meta[k]) + } + width[k] = kit.Width(k, len(space)) + for _, v := range m.meta[k] { + if kit.Width(v, len(space)) > width[k] { + width[k] = kit.Width(v, len(space)) + } + } + } + + // 回调函数 + rows := kit.Select(m.Conf("table", "row_sep"), m.Option("table.row_sep")) + cols := kit.Select(m.Conf("table", "col_sep"), m.Option("table.col_sep")) + compact := kit.Select(m.Conf("table", "compact"), m.Option("table.compact")) == "true" + cb := func(maps map[string]string, lists []string, line int) bool { + for i, v := range lists { + if k := m.meta["append"][i]; compact { + v = maps[k] + } + + if m.Echo(v); i < len(lists)-1 { + m.Echo(cols) + } + } + m.Echo(rows) + return true + } + + // 输出表头 + row := map[string]string{} + wor := []string{} + for _, k := range m.meta["append"] { + row[k], wor = k, append(wor, k+strings.Repeat(space, width[k]-kit.Width(k, len(space)))) + } + if !cb(row, wor, -1) { + return m + } + + // 输出数据 + for i := 0; i < depth; i++ { + row := map[string]string{} + wor := []string{} + for _, k := range m.meta["append"] { + data := "" + if i < len(m.meta[k]) { + data = m.meta[k][i] + } + + row[k], wor = data, append(wor, data+strings.Repeat(space, width[k]-kit.Width(data, len(space)))) + } + if !cb(row, wor, i) { + break + } } return m } @@ -392,14 +486,19 @@ func (m *Message) Result(arg ...interface{}) string { return strings.Join(m.Resultv(), "") } +var Log func(*Message, string, string) + func (m *Message) Log(level string, str string, arg ...interface{}) *Message { + if Log != nil { + Log(m, level, fmt.Sprintf(str, arg...)) + } prefix, suffix := "", "" switch level { - case "cmd": + case "cmd", "start", "serve": prefix, suffix = "\033[32m", "\033[0m" case "cost": prefix, suffix = "\033[33m", "\033[0m" - case "warn": + case "warn", "close": prefix, suffix = "\033[31m", "\033[0m" } fmt.Fprintf(os.Stderr, "%s %d %s->%s %s%s %s%s\n", @@ -446,8 +545,14 @@ func (m *Message) Travel(cb func(p *Context, s *Context)) *Message { list := []*Context{m.target} for i := 0; i < len(list); i++ { cb(list[i].context, list[i]) - for _, v := range list[i].contexts { - list = append(list, v) + + ls := []string{} + for k := range list[i].contexts { + ls = append(ls, k) + } + sort.Strings(ls) + for _, k := range ls { + list = append(list, list[i].contexts[k]) } } return m @@ -496,6 +601,14 @@ func (m *Message) Runs(key string, cmd string, arg ...string) *Message { } return m } +func (m *Message) Start(key string, arg ...string) *Message { + m.Travel(func(p *Context, s *Context) { + if s.Name == key { + s.Start(m.Spawns(s), arg...) + } + }) + return m +} func (m *Message) Call(sync bool, cb func(*Message) *Message) *Message { if sync { wait := make(chan bool) @@ -721,20 +834,23 @@ func (m *Message) Cmd(arg ...interface{}) *Message { return m } - msg := m m.Search(list[0], func(p *Context, s *Context, key string) { for c := s; c != nil; c = c.context { if cmd, ok := c.Commands[key]; ok { - msg = m.Spawns(s).Log("cmd", "%s.%s %v", c.Name, key, list[1:]) - msg.meta["detail"] = list - msg.TryCatch(msg, true, func(msg *Message) { + m.TryCatch(m.Spawns(s), true, func(msg *Message) { + + msg.Log("cmd", "%s.%s %v", c.Name, key, list[1:]) + msg.meta["detail"] = list cmd.Hand(msg, c, key, list[1:]...) + msg.Hand = true + m.Hand = true + m = msg }) break } } }) - return msg + return m } func (m *Message) Confv(arg ...interface{}) (val interface{}) { m.Search(arg[0], func(p *Context, s *Context, key string) { @@ -780,7 +896,8 @@ func (m *Message) Capv(arg ...interface{}) interface{} { for _, s := range []*Context{m.target} { for c := s; c != nil; c = c.context { if caps, ok := c.Caches[key]; ok { - return kit.Value(caps.Value, arg[0]) + caps.Value = kit.Format(arg[0]) + return caps.Value } } }