From c293a1bd95615c763ee319cc2bf481c68305d140 Mon Sep 17 00:00:00 2001 From: shaoying Date: Sun, 12 Nov 2017 20:33:48 +0800 Subject: [PATCH 1/3] =?UTF-8?q?mac=20add=20userinfo=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=9A=84=E7=94=A8=E6=88=B7=E6=9D=83=E9=99=90=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/init.sh | 6 ++++ src/context/cli/cli.go | 69 +++++++++++++++++++++++++++++++++++++++--- src/context/ctx.go | 49 ++++++++++++++++++++++-------- 3 files changed, 107 insertions(+), 17 deletions(-) diff --git a/etc/init.sh b/etc/init.sh index e69de29b..73f620ce 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -0,0 +1,6 @@ +~aaa +login root 94ca7394d007fa189cc4be0a2625d716 root +login root root + +~cli +remote slave listen :9393 tcp diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index 5396d2af..a5e37532 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -5,6 +5,7 @@ import ( // {{{ "context" "fmt" "io" + // "log" "os" "strconv" "strings" @@ -25,6 +26,7 @@ type CLI struct { alias map[string]string next string exit bool + login *ctx.Context target *ctx.Context *ctx.Context @@ -44,6 +46,33 @@ func (cli *CLI) push(f io.ReadCloser) { // {{{ // }}} func (cli *CLI) parse(m *ctx.Message) bool { // {{{ + if len(cli.ins) == 1 && cli.Owner == nil { + + username := "" + fmt.Fprintf(cli.out, "username>") + fmt.Fscanln(cli.in, &username) + + password := "" + fmt.Fprintf(cli.out, "password>") + fmt.Fscanln(cli.in, &password) + + if aaa := cli.Root.Find("aaa"); aaa != nil { + cli.Owner = Index.Owner + msg := m.Spawn(aaa, "user") + + if msg.Cmd("login", username, password) == "" { + fmt.Fprintln(cli.out, "登录失败") + m.Post(cli.Context, "exit") + cli.out.Close() + cli.in.Close() + return false + } + + cli.Owner = msg.Target + cli.Cap("user", msg.Target.Cap("username")) + } + } + if len(cli.ins) == 1 || cli.Conf("slient") != "yes" { cli.echo(cli.Conf("PS1")) } @@ -175,6 +204,7 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ // }}} func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ + cli.Owner = nil cli.Capi("nterm", 1) defer cli.Capi("nterm", -1) @@ -253,9 +283,11 @@ func (cli *CLI) Exit(m *ctx.Message, arg ...string) bool { // {{{ var Index = &ctx.Context{Name: "cli", Help: "管理终端", Caches: map[string]*ctx.Cache{ "nterm": &ctx.Cache{Name: "终端数量", Value: "0", Help: "已经运行的终端数量"}, + "user": &ctx.Cache{Name: "登录用户", Value: "", Help: "登录用户名"}, }, Configs: map[string]*ctx.Config{ - "slient": &ctx.Config{Name: "屏蔽脚本输出(yes/no)", Value: "yes", Help: "屏蔽脚本输出的信息,yes:屏蔽,no:不屏蔽"}, + "slient": &ctx.Config{Name: "屏蔽脚本输出(yes/no)", Value: "yes", Help: "屏蔽脚本输出的信息,yes:屏蔽,no:不屏蔽"}, + "default": &ctx.Config{Name: "默认的搜索起点(root/back/home)", Value: "root", Help: "模块搜索的默认起点,root:从根模块,back:从父模块,home:从当前模块"}, // "hello": &ctx.Config{Name: "开场白", Value: "\n~~~ Hello Context & Message World ~~~\n", Help: "模块启动时输出的信息"}, // "byebye": &ctx.Config{Name: "结束语", Value: "\n~~~ Byebye Context & Message World ~~~\n", Help: "模块停止时输出的信息"}, @@ -278,15 +310,18 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", }, Commands: map[string]*ctx.Command{ "context": &ctx.Command{Name: "context [root|back|home] [[find|search] name] [show|spawn|start|switch][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - cli, ok := c.Server.(*CLI) // {{{ + cli, ok := m.Context.Server.(*CLI) // {{{ if !ok { - return "" + cli, ok = c.Server.(*CLI) + if !ok { + return "" + } } switch len(arg) { case 0: m.Target.Root.Travel(func(c *ctx.Context) bool { - if c.Context != nil { + if c.Context != nil && m.Context.Check(c) { m.Echo("%s: %s(%s)\n", c.Context.Name, c.Name, c.Help) } return true @@ -295,6 +330,16 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } target := m.Target + switch c.Conf("default") { + case "root": + target = target.Root + case "back": + if target.Context != nil { + target = target.Context + } + case "home": + } + method := "search" action := "switch" which := "" @@ -343,6 +388,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } for _, v := range cs { + if !m.Context.Check(v) { + continue + } + switch action { case "switch": cli.target = v @@ -565,6 +614,14 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", return "" // }}} }}, + "userinfo": &ctx.Command{Name: "userinfo", Help: "查看模块的用户信息", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + o := m.Target.Owner // {{{ + if o != nil { + m.Echo("%s\n", o.Name) + } + return "" + // }}} + }}, "exit": &ctx.Command{Name: "exit", Help: "退出", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { cli, ok := m.Target.Server.(*CLI) // {{{ if !ok { @@ -572,9 +629,11 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } if ok { if !cli.exit { - m.Echo(c.Conf("结束语")) + // m.Echo(c.Conf("结束语")) cli.Context.Exit(m) } + cli.in.Close() + cli.out.Close() cli.exit = true } diff --git a/src/context/ctx.go b/src/context/ctx.go index bde786dc..fed8eccb 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -204,7 +204,7 @@ func (m *Message) End(s bool) { // {{{ // }}} -func (m *Message) Cmd(arg ...string) string { // {{{ +func (m *Message) Start(key string, arg ...string) bool { // {{{ if len(arg) > 0 { if m.Meta == nil { m.Meta = make(map[string][]string) @@ -212,7 +212,9 @@ func (m *Message) Cmd(arg ...string) string { // {{{ m.Meta["detail"] = arg } - return m.Target.Cmd(m, m.Meta["detail"][0], m.Meta["detail"][1:]...) + m.Target.Spawn(m, key).Start(m) + + return true } // }}} @@ -225,7 +227,7 @@ func (m *Message) Post(c *Context, arg ...string) bool { // {{{ } if c.Messages == nil { - panic(m.Target.Name + " 没有开启消息处理") + panic(c.Name + " 没有开启消息处理") } c.Messages <- m @@ -237,7 +239,7 @@ func (m *Message) Post(c *Context, arg ...string) bool { // {{{ } // }}} -func (m *Message) Start(key string, arg ...string) bool { // {{{ +func (m *Message) Cmd(arg ...string) string { // {{{ if len(arg) > 0 { if m.Meta == nil { m.Meta = make(map[string][]string) @@ -245,9 +247,7 @@ func (m *Message) Start(key string, arg ...string) bool { // {{{ m.Meta["detail"] = arg } - m.Target.Spawn(m, key).Start(m) - - return true + return m.Target.Cmd(m, m.Meta["detail"][0], m.Meta["detail"][1:]...) } // }}} @@ -276,6 +276,7 @@ type Context struct { Requests []*Message Sessions map[string]*Message + Owner *Context Index map[string]*Context Groups map[string]*Context @@ -299,6 +300,7 @@ func (c *Context) Assert(e error) bool { // {{{ func (c *Context) AssertOne(m *Message, safe bool, hand ...func(c *Context, m *Message)) *Context { // {{{ defer func() { if e := recover(); e != nil { + log.Println(c.Name, e) if c.Conf("debug") == "on" && e != io.EOF { fmt.Println(c.Name, "error:", e) debug.PrintStack() @@ -381,10 +383,12 @@ func (c *Context) Start(m *Message) bool { // {{{ defer Index.Capi("nserver", -1) defer log.Printf("%d stop(%s): %s %s", m.Code, Index.Cap("nserver"), c.Name, c.Help) + c.Owner = m.Owner c.Requests = []*Message{m} c.Server.Start(m, m.Meta["detail"]...) }) } + Pulse.Wait <- true return true } @@ -657,6 +661,22 @@ func (c *Context) Del(arg ...string) { // {{{ // }}} +func (c *Context) Check(s *Context) bool { // {{{ + // if c.Owner != nil { + // log.Println("source:", c.Owner.Name) + // } + // if s.Owner != nil { + // log.Println("target:", s.Owner.Name) + // } + if c.Owner == s.Owner || c.Owner == Index.Owner { + // log.Println("match:") + return true + } + // log.Println("not match:") + return false +} + +// }}} func (c *Context) Travel(hand func(s *Context) bool) { // {{{ cs := []*Context{c} for i := 0; i < len(cs); i++ { @@ -687,8 +707,6 @@ func (c *Context) Search(name string) []*Context { // {{{ if strings.Contains(s.Name, name) || strings.Contains(s.Help, name) { cs = append(cs, s) log.Println(c.Name, "search:", s.Name, "[match]", name) - } else { - log.Println(c.Name, "search:", s.Name) } return true }) @@ -723,6 +741,11 @@ func (c *Context) Cmd(m *Message, key string, arg ...string) string { // {{{ if x, ok := s.Commands[key]; ok { log.Printf("%s cmd(%s->%s): %v", c.Name, m.Context.Name, m.Target.Name, m.Meta["detail"]) + if !m.Context.Check(m.Target) { + log.Printf("没有权限:") + return "" + } + for _, v := range m.Meta["option"] { if _, ok := x.Options[v]; !ok { panic(errors.New(fmt.Sprintf("未知参数:" + v))) @@ -731,8 +754,10 @@ func (c *Context) Cmd(m *Message, key string, arg ...string) string { // {{{ m.Meta["result"] = nil c.AssertOne(m, true, func(c *Context, m *Message) { - x.Hand(c, m, key, arg...) - + ret := x.Hand(c, m, key, arg...) + if ret != "" { + m.Echo(ret) + } }) if x.Appends != nil { @@ -753,6 +778,7 @@ func (c *Context) Cmd(m *Message, key string, arg ...string) string { // {{{ // }}} func (c *Context) Conf(key string, arg ...string) string { // {{{ for s := c; s != nil; s = s.Context { + if x, ok := s.Configs[key]; ok { switch len(arg) { case 0: @@ -935,7 +961,6 @@ func init() { Pulse.Target = Index Pulse.Context = Index Pulse.Wait = make(chan bool, 10) - } func Start(args ...string) { From 954dd13717f3c290b3b17ebb82de8a3fe553b5b1 Mon Sep 17 00:00:00 2001 From: shaoying Date: Mon, 13 Nov 2017 08:45:10 +0800 Subject: [PATCH 2/3] =?UTF-8?q?mac=20mod=20message.ccc=20=E5=B0=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E6=93=8D=E4=BD=9C=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E6=B6=88=E6=81=AF=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/init.sh | 13 +- src/context/cli/cli.go | 72 +++--- src/context/ctx.go | 524 ++++++++++++++++++++++------------------- 3 files changed, 323 insertions(+), 286 deletions(-) diff --git a/etc/init.sh b/etc/init.sh index 73f620ce..8838af3b 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -1,6 +1,7 @@ -~aaa -login root 94ca7394d007fa189cc4be0a2625d716 root -login root root - -~cli -remote slave listen :9393 tcp +# @debug on +# ~aaa +# login root 94ca7394d007fa189cc4be0a2625d716 root +# login root root +# +# ~cli +# remote slave listen :9393 tcp diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index a5e37532..0c24a16c 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -46,7 +46,7 @@ func (cli *CLI) push(f io.ReadCloser) { // {{{ // }}} func (cli *CLI) parse(m *ctx.Message) bool { // {{{ - if len(cli.ins) == 1 && cli.Owner == nil { + if false && len(cli.ins) == 1 && cli.Owner == nil { username := "" fmt.Fprintf(cli.out, "username>") @@ -69,12 +69,12 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{ } cli.Owner = msg.Target - cli.Cap("user", msg.Target.Cap("username")) + m.Cap("user", msg.Cap("username")) } } - if len(cli.ins) == 1 || cli.Conf("slient") != "yes" { - cli.echo(cli.Conf("PS1")) + if len(cli.ins) == 1 || m.Conf("slient") != "yes" { + cli.echo(m.Conf("PS1")) } line := "" @@ -95,10 +95,10 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{ return true } } - cli.Assert(e) + m.Assert(e) line = ls - if len(cli.ins) > 1 || cli.Conf("slient") != "yes" { + if len(cli.ins) > 1 || m.Conf("slient") != "yes" { cli.echo(line) } @@ -113,7 +113,7 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{ line = cli.next cli.next = "" - if cli.Conf("slient") != "yes" { + if m.Conf("slient") != "yes" { cli.echo(line) cli.echo("\n") } @@ -174,9 +174,9 @@ back: // }}} func (cli *CLI) echo(str string, arg ...interface{}) { // {{{ - if len(cli.ins) == 1 || cli.Conf("slient") != "yes" { - fmt.Fprintf(cli.out, str, arg...) - } + // if len(cli.ins) == 1 || m.Conf("slient") != "yes" { + fmt.Fprintf(cli.out, str, arg...) + // } } // }}} @@ -194,7 +194,7 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ cli.target = cli.Context - cli.Caches["nhistory"] = &ctx.Cache{Name: "历史命令数量", Value: "0", Help: "当前终端已经执行命令的数量", Hand: func(c *ctx.Context, x *ctx.Cache, arg ...string) string { + cli.Caches["nhistory"] = &ctx.Cache{Name: "历史命令数量", Value: "0", Help: "当前终端已经执行命令的数量", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string { x.Value = fmt.Sprintf("%d", len(cli.history)) return x.Value }} @@ -205,14 +205,14 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ // }}} func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ cli.Owner = nil - cli.Capi("nterm", 1) - defer cli.Capi("nterm", -1) + m.Capi("nterm", 1) + defer m.Capi("nterm", -1) if cli.Messages == nil { - cli.Messages = make(chan *ctx.Message, cli.Confi("MessageQueueSize")) + cli.Messages = make(chan *ctx.Message, m.Confi("MessageQueueSize")) } if len(arg) > 0 { - cli.Conf("init.sh", "启动脚本", arg[0], "模块启动时自动运行的脚本") + m.Conf("init.sh", "启动脚本", arg[0], "模块启动时自动运行的脚本") } if stream, ok := m.Data["io"]; ok { @@ -220,7 +220,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ cli.out = io cli.push(io) - if f, e := os.Open(cli.Conf("init.sh")); e == nil { + if f, e := os.Open(m.Conf("init.sh")); e == nil { cli.push(f) } @@ -232,7 +232,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ }) } - for cli.Deal(func(msg *ctx.Message, arg ...string) bool { + for m.Deal(func(msg *ctx.Message, arg ...string) bool { if a, ok := cli.alias[arg[0]]; ok { arg[0] = a } @@ -273,7 +273,7 @@ func (cli *CLI) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server // }}} func (cli *CLI) Exit(m *ctx.Message, arg ...string) bool { // {{{ if cli.Context != Index { - delete(cli.Context.Context.Contexts, cli.Name) + // delete(cli.Context.Context.Contexts, cli.Name) } return true } @@ -291,15 +291,15 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", // "hello": &ctx.Config{Name: "开场白", Value: "\n~~~ Hello Context & Message World ~~~\n", Help: "模块启动时输出的信息"}, // "byebye": &ctx.Config{Name: "结束语", Value: "\n~~~ Byebye Context & Message World ~~~\n", Help: "模块停止时输出的信息"}, - "PS1": &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(c *ctx.Context, x *ctx.Config, arg ...string) string { - cli, ok := c.Server.(*CLI) // {{{ + "PS1": &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { + cli, ok := m.Target.Server.(*CLI) // {{{ if ok && cli.target != nil { // c = cli.target switch x.Value { case "target": - return fmt.Sprintf("%s[%s]\033[32m%s\033[0m> ", c.Cap("nhistory"), time.Now().Format("15:04:05"), cli.target.Name) + return fmt.Sprintf("%s[%s]\033[32m%s\033[0m> ", m.Cap("nhistory"), time.Now().Format("15:04:05"), cli.target.Name) case "detail": - return fmt.Sprintf("%s[%s](%s,%s,%s)\033[32m%s\033[0m> ", c.Cap("nhistory"), time.Now().Format("15:04:05"), c.Cap("ncontext"), c.Cap("nmessage"), c.Cap("nserver"), c.Name) + return fmt.Sprintf("%s[%s](%s,%s,%s)\033[32m%s\033[0m> ", m.Cap("nhistory"), time.Now().Format("15:04:05"), m.Cap("ncontext"), m.Cap("nmessage"), m.Cap("nserver"), m.Target.Name) } } @@ -310,7 +310,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", }, Commands: map[string]*ctx.Command{ "context": &ctx.Command{Name: "context [root|back|home] [[find|search] name] [show|spawn|start|switch][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - cli, ok := m.Context.Server.(*CLI) // {{{ + cli, ok := m.Source.Server.(*CLI) // {{{ if !ok { cli, ok = c.Server.(*CLI) if !ok { @@ -321,7 +321,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", switch len(arg) { case 0: m.Target.Root.Travel(func(c *ctx.Context) bool { - if c.Context != nil && m.Context.Check(c) { + if c.Context != nil && m.Source.Check(c) { m.Echo("%s: %s(%s)\n", c.Context.Name, c.Name, c.Help) } return true @@ -330,7 +330,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } target := m.Target - switch c.Conf("default") { + switch m.Conf("default") { case "root": target = target.Root case "back": @@ -388,7 +388,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } for _, v := range cs { - if !m.Context.Check(v) { + if !m.Source.Check(v) { continue } @@ -409,7 +409,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } m.Echo("索引模块:\n") for i, v := range v.Requests { - m.Echo("\t%d(%d): %s %s\n", i, v.Code, v.Context.Name, v.Context.Help) + m.Echo("\t%d(%d): %s %s\n", i, v.Code, v.Source.Name, v.Source.Help) } } } @@ -420,7 +420,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", "message": &ctx.Command{Name: "message", Help: "查看上下文", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { ms := []*ctx.Message{ctx.Pulse} // {{{ for i := 0; i < len(ms); i++ { - m.Echo("%d %s.%s -> %s.%d: %s %v\n", ms[i].Code, ms[i].Context.Name, ms[i].Name, ms[i].Target.Name, ms[i].Index, ms[i].Time.Format("15:04:05"), ms[i].Meta["detail"]) + m.Echo("%d %s.%s -> %s.%d: %s %v\n", ms[i].Code, ms[i].Source.Name, ms[i].Name, ms[i].Target.Name, ms[i].Index, ms[i].Time.Format("15:04:05"), ms[i].Meta["detail"]) ms = append(ms, ms[i].Messages...) } return "" @@ -455,7 +455,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", switch len(arg) { case 1: f, e := os.Open(arg[0]) - c.Assert(e) + m.Assert(e) cli.push(f) } @@ -555,16 +555,16 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", switch arg[0] { case "void": - s.Conf(arg[1], "") + m.Conf(arg[1], "") case "delete": if _, ok := s.Configs[arg[1]]; ok { delete(s.Configs, arg[1]) } default: - s.Conf(arg[0], arg[1]) + m.Conf(arg[0], arg[1]) } case 4: - s.Conf(arg[0], arg[1:]...) + m.Conf(arg[0], arg[1:]...) return false } return all @@ -601,11 +601,11 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } default: if _, ok := s.Caches[arg[0]]; ok { - m.Echo("%s: %s\n", arg[0], s.Cap(arg[0], arg[1:]...)) + m.Echo("%s: %s\n", arg[0], m.Cap(arg[0], arg[1:]...)) } } case 4: - s.Cap(arg[0], arg[1:]...) + m.Cap(arg[0], arg[1:]...) return false } @@ -625,7 +625,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", "exit": &ctx.Command{Name: "exit", Help: "退出", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { cli, ok := m.Target.Server.(*CLI) // {{{ if !ok { - cli, ok = m.Context.Server.(*CLI) + cli, ok = m.Source.Server.(*CLI) } if ok { if !cli.exit { @@ -663,7 +663,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", Options: map[string]string{"io": "读写流"}, Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { // {{{ if m.Has("io") { - m.Start(fmt.Sprintf("PTS%d", c.Capi("nterm")), arg[1]) + m.Start(fmt.Sprintf("PTS%d", m.Capi("nterm")), arg[1]) } else { switch arg[1] { case "tcp": diff --git a/src/context/ctx.go b/src/context/ctx.go index fed8eccb..c31546bb 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -17,23 +17,21 @@ import ( // {{{ // }}} -type Cache struct { // {{{ +type Cache struct { Name string Value string Help string - Hand func(c *Context, x *Cache, arg ...string) string + Hand func(m *Message, x *Cache, arg ...string) string } -// }}} -type Config struct { // {{{ +type Config struct { Name string Value string Help string - Hand func(c *Context, x *Config, arg ...string) string + Hand func(m *Message, x *Config, arg ...string) string } -// }}} -type Command struct { // {{{ +type Command struct { Name string Help string Options map[string]string @@ -41,8 +39,6 @@ type Command struct { // {{{ Hand func(c *Context, m *Message, key string, arg ...string) string } -// }}} - type Message struct { Code int Time time.Time @@ -51,10 +47,11 @@ type Message struct { Data map[string]interface{} Wait chan bool - Name string - *Context Index int Target *Context + Master *Context + Source *Context + Name string Messages []*Message Message *Message @@ -82,10 +79,11 @@ func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{ msg := &Message{ Time: time.Now(), Target: c, + Master: c, Message: m, Root: m.Root, } - msg.Context = m.Target + msg.Source = m.Target if len(key) == 0 { return msg @@ -97,13 +95,13 @@ func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{ m.Messages = append(m.Messages, msg) msg.Code = m.Capi("nmessage", 1) - if msg.Sessions == nil { - msg.Sessions = make(map[string]*Message) + if msg.Source.Sessions == nil { + msg.Source.Sessions = make(map[string]*Message) } - msg.Sessions[key[0]] = msg + msg.Source.Sessions[key[0]] = msg msg.Name = key[0] - log.Printf("%d spawn %d: %s.%s->%s.%d", m.Code, msg.Code, msg.Context.Name, msg.Name, msg.Target.Name, msg.Index) + log.Printf("%d spawn %d: %s.%s->%s.%d", m.Code, msg.Code, msg.Source.Name, msg.Name, msg.Target.Name, msg.Index) return msg } @@ -204,6 +202,38 @@ func (m *Message) End(s bool) { // {{{ // }}} +func (m *Message) Check(s *Context, arg ...string) bool { // {{{ + if m.Source.Owner != s.Owner && m.Source.Owner != s.Root.Owner { + if len(arg) != 2 { + return false + } + + g, ok := s.Index[m.Source.Group] + if !ok { + if g, ok = s.Index["void"]; !ok { + return false + } + } + + switch arg[0] { + case "commands": + _, ok = g.Commands[arg[0]] + case "configs": + _, ok = g.Configs[arg[0]] + case "caches": + _, ok = g.Caches[arg[0]] + } + + if !ok { + return false + } + } + + return true +} + +// }}} + func (m *Message) Start(key string, arg ...string) bool { // {{{ if len(arg) > 0 { if m.Meta == nil { @@ -246,21 +276,197 @@ func (m *Message) Cmd(arg ...string) string { // {{{ } m.Meta["detail"] = arg } + arg = m.Meta["detail"] - return m.Target.Cmd(m, m.Meta["detail"][0], m.Meta["detail"][1:]...) + if m.Code != 0 { + log.Printf("%d cmd(%s:%s->%s.%d): %v", m.Code, m.Source.Name, m.Name, m.Master.Name, m.Index, arg) + } else { + log.Printf("%d cmd(%s->%s): %v", m.Code, m.Source.Name, m.Master.Name, arg) + } + + for s := m.Master; s != nil; s = s.Context { + + if !m.Check(s, "commands", arg[0]) { + panic(errors.New(fmt.Sprintf("没有权限:" + arg[0]))) + } + + if x, ok := s.Commands[arg[0]]; ok { + if x.Options != nil { + for _, v := range m.Meta["option"] { + if _, ok := x.Options[v]; !ok { + panic(errors.New(fmt.Sprintf("未知参数:" + v))) + } + } + } + + m.Meta["result"] = nil + m.Master.AssertOne(m, true, func(c *Context, m *Message) { + ret := x.Hand(c, m, arg[0], arg[1:]...) + if ret != "" { + m.Echo(ret) + } + }) + + if x.Appends != nil { + for _, v := range m.Meta["append"] { + if _, ok := x.Appends[v]; !ok { + panic(errors.New(fmt.Sprintf("未知参数:" + v))) + } + } + } + return m.Get("result") + } + } + + panic(errors.New(fmt.Sprintf("未知命令:" + arg[0]))) +} + +// }}} +func (m *Message) Conf(key string, arg ...string) string { // {{{ + for s := m.Target; s != nil; s = s.Context { + if !m.Check(s, "configs", key) { + panic(errors.New(fmt.Sprintf("没有权限:" + key))) + } + + if x, ok := s.Configs[key]; ok { + switch len(arg) { + case 0: + if x.Hand != nil { + return x.Hand(m, x) + } + return x.Value + case 1: + if m.Code != 0 { + log.Printf("%d conf(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Master.Name, m.Index, key, arg) + } else { + log.Printf("%d conf(%s->%s): %s %v", m.Code, m.Source.Name, m.Master.Name, key, arg) + } + + x.Value = arg[0] + if x.Hand != nil { + x.Hand(m, x, x.Value) + } + return x.Value + case 3: + if m.Code != 0 { + log.Printf("%d conf(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Master.Name, m.Index, key, arg) + } else { + log.Printf("%d conf(%s->%s): %s %v", m.Code, m.Source.Name, m.Master.Name, key, arg) + } + + if s == m.Target { + panic(errors.New(key + "配置项已存在")) + } + if m.Target.Configs == nil { + m.Target.Configs = make(map[string]*Config) + } + m.Target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2], Hand: x.Hand} + return arg[1] + default: + panic(errors.New(key + "配置项参数错误")) + } + } + } + + if len(arg) == 3 { + log.Println(m.Target.Name, "conf:", key, arg) + if m.Target.Configs == nil { + m.Target.Configs = make(map[string]*Config) + } + m.Target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2]} + return arg[1] + } + + panic(errors.New(key + "配置项不存在")) +} + +// }}} +func (m *Message) Confi(key string, arg ...int) int { // {{{ + if len(arg) > 0 { + n, e := strconv.Atoi(m.Conf(key, fmt.Sprintf("%d", arg[0]))) + m.Assert(e) + return n + } + + n, e := strconv.Atoi(m.Conf(key)) + m.Assert(e) + return n +} + +// }}} +func (m *Message) Cap(key string, arg ...string) string { // {{{ + // if m.Code != 0 { + // log.Printf("%d cap(%s:%s->%s.%d): %s %v", m.Code, m.Context.Name, m.Name, m.Master.Name, m.Index, key, arg) + // } else { + // log.Printf("%d cap(%s->%s): %s %v", m.Code, m.Context.Name, m.Master.Name, key, arg) + // } + // + for s := m.Target; s != nil; s = s.Context { + if !m.Check(s, "caches", key) { + panic(errors.New(fmt.Sprintf("没有权限:" + key))) + } + + if x, ok := s.Caches[key]; ok { + switch len(arg) { + case 0: + if x.Hand != nil { + x.Value = x.Hand(m, x) + } + return x.Value + case 1: + if x.Hand != nil { + x.Value = x.Hand(m, x, arg[0]) + } else { + x.Value = arg[0] + } + return x.Value + case 3: + log.Println(m.Target.Name, "cap:", key, arg) + if s == m.Target { + panic(errors.New(key + "缓存项已存在")) + } + if m.Target.Caches == nil { + m.Target.Caches = make(map[string]*Cache) + } + m.Target.Caches[key] = &Cache{arg[0], arg[1], arg[2], x.Hand} + return arg[1] + default: + panic(errors.New(key + "缓存项参数错误")) + } + } + } + if len(arg) == 3 { + log.Println(m.Target.Name, "cap:", key, arg) + if m.Target.Caches == nil { + m.Target.Caches = make(map[string]*Cache) + } + m.Target.Caches[key] = &Cache{arg[0], arg[1], arg[2], nil} + return arg[1] + } + + panic(errors.New(key + "缓存项不存在")) +} + +// }}} +func (m *Message) Capi(key string, arg ...int) int { // {{{ + n, e := strconv.Atoi(m.Cap(key)) + m.Assert(e) + if len(arg) > 0 { + n += arg[0] + m.Cap(key, strconv.Itoa(n)) + } + return n } // }}} -type Server interface { // {{{ +type Server interface { Begin(m *Message, arg ...string) Server Start(m *Message, arg ...string) bool Spawn(c *Context, m *Message, arg ...string) Server Exit(m *Message, arg ...string) bool } -// }}} - type Context struct { Name string Help string @@ -277,31 +483,20 @@ type Context struct { Sessions map[string]*Message Owner *Context + Group string Index map[string]*Context Groups map[string]*Context - Contexts map[string]*Context + contexts map[string]*Context Context *Context Root *Context } -func (c *Context) Assert(e error) bool { // {{{ - if e != nil { - log.Println(c.Name, "error:", e) - if c.Conf("debug") == "on" { - fmt.Println(c.Name, "error:", e) - } - panic(e) - } - return true -} - -// }}} func (c *Context) AssertOne(m *Message, safe bool, hand ...func(c *Context, m *Message)) *Context { // {{{ defer func() { if e := recover(); e != nil { log.Println(c.Name, e) - if c.Conf("debug") == "on" && e != io.EOF { + if m.Conf("debug") == "on" && e != io.EOF { fmt.Println(c.Name, "error:", e) debug.PrintStack() } @@ -332,27 +527,28 @@ func (c *Context) AssertOne(m *Message, safe bool, hand ...func(c *Context, m *M // }}} func (c *Context) Register(s *Context, x Server) *Context { // {{{ - if c.Contexts == nil { - c.Contexts = make(map[string]*Context) + + if c.contexts == nil { + c.contexts = make(map[string]*Context) } - if x, ok := c.Contexts[s.Name]; ok { + if x, ok := c.contexts[s.Name]; ok { panic(errors.New(c.Name + " 上下文已存在" + x.Name)) } - c.Contexts[s.Name] = s + c.contexts[s.Name] = s s.Root = c.Root s.Context = c s.Server = x - log.Printf("%s sub(%d): %s", c.Name, Index.Capi("ncontext", 1), s.Name) + log.Printf("%s sub(%d): %s", c.Name, Pulse.Capi("ncontext", 1), s.Name) return s } // }}} func (c *Context) Begin(m *Message) *Context { // {{{ - for k, x := range c.Configs { + for k, x := range m.Target.Configs { if x.Hand != nil { - c.Conf(k, x.Value) + m.Conf(k, x.Value) } } @@ -374,16 +570,16 @@ func (c *Context) Start(m *Message) bool { // {{{ c.Caches["status"] = &Cache{Name: "服务状态", Value: "stop", Help: "服务状态,start:正在运行,stop:未在运行"} } - if c.Cap("status") != "start" && c.Server != nil { + if m.Cap("status") != "start" && c.Server != nil { c.AssertOne(m, true, func(c *Context, m *Message) { - c.Cap("status", "start") - defer c.Cap("status", "stop") + m.Cap("status", "start") + defer m.Cap("status", "stop") - log.Printf("%d start(%d): %s %s", m.Code, Index.Capi("nserver", 1), c.Name, c.Help) - defer Index.Capi("nserver", -1) - defer log.Printf("%d stop(%s): %s %s", m.Code, Index.Cap("nserver"), c.Name, c.Help) + log.Printf("%d start(%d): %s %s", m.Code, Pulse.Capi("nserver", 1), c.Name, c.Help) + defer Pulse.Capi("nserver", -1) + defer log.Printf("%d stop(%s): %s %s", m.Code, Pulse.Cap("nserver"), c.Name, c.Help) - c.Owner = m.Owner + c.Owner = m.Source.Owner c.Requests = []*Message{m} c.Server.Start(m, m.Meta["detail"]...) }) @@ -407,12 +603,12 @@ func (c *Context) Spawn(m *Message, key string) *Context { // {{{ // }}} -func (c *Context) Deal(pre func(m *Message, arg ...string) bool, post func(m *Message, arg ...string) bool) (live bool) { // {{{ +func (msg *Message) Deal(pre func(m *Message, arg ...string) bool, post func(m *Message, arg ...string) bool) (live bool) { // {{{ - if c.Messages == nil { - c.Messages = make(chan *Message, c.Confi("MessageQueueSize")) + if msg.Target.Messages == nil { + msg.Target.Messages = make(chan *Message, msg.Confi("MessageQueueSize")) } - m := <-c.Messages + m := <-msg.Target.Messages defer m.End(true) if len(m.Meta["detail"]) == 0 { @@ -424,14 +620,15 @@ func (c *Context) Deal(pre func(m *Message, arg ...string) bool, post func(m *Me } arg := m.Meta["detail"] - c.AssertOne(m, true, func(c *Context, m *Message) { + msg.Target.AssertOne(m, true, func(c *Context, m *Message) { m.Cmd() }, func(c *Context, m *Message) { - c.Cmd(m, arg[0], arg[1:]...) + m.Master = c + m.Cmd() }, func(c *Context, m *Message) { - log.Printf("system command(%s->%s): %v", m.Context.Name, m.Target.Name, arg) + log.Printf("system command(%s->%s): %v", m.Source.Name, m.Target.Name, arg) cmd := exec.Command(arg[0], arg[1:]...) v, e := cmd.CombinedOutput() if e != nil { @@ -455,7 +652,7 @@ func (c *Context) Exit(m *Message, arg ...string) { // {{{ if m.Target == c { if m.Index == -1 { - log.Println(c.Name, c.Help, "exit: resource", m.Code, m.Context.Name, m.Context.Help) + log.Println(c.Name, c.Help, "exit: resource", m.Code, m.Source.Name, m.Source.Help) if c.Server != nil { c.Server.Exit(m, arg...) log.Println(c.Name, c.Help, "exit: self", m.Code) @@ -480,11 +677,11 @@ func (c *Context) Exit(m *Message, arg ...string) { // {{{ for _, v := range c.Requests { if v.Index != -1 { v.Index = -1 - v.Context.Exit(v, arg...) - log.Println(c.Name, c.Help, "exit: resource", v.Code, v.Context.Name, v.Context.Help) + v.Source.Exit(v, arg...) + log.Println(c.Name, c.Help, "exit: resource", v.Code, v.Source.Name, v.Source.Help) } } - } else if m.Context == c { + } else if m.Source == c { m.Name = "" log.Println(c.Name, c.Help, "exit: session", m.Code, m.Target.Name, m.Target.Help) if c.Server != nil { @@ -680,7 +877,7 @@ func (c *Context) Check(s *Context) bool { // {{{ func (c *Context) Travel(hand func(s *Context) bool) { // {{{ cs := []*Context{c} for i := 0; i < len(cs); i++ { - for _, v := range cs[i].Contexts { + for _, v := range cs[i].contexts { cs = append(cs, v) } @@ -716,10 +913,10 @@ func (c *Context) Search(name string) []*Context { // {{{ // }}} func (c *Context) Find(name string) (s *Context) { // {{{ ns := strings.Split(name, ".") - cs := c.Contexts + cs := c.contexts for _, v := range ns { if x, ok := cs[v]; ok { - cs = x.Contexts + cs = x.contexts s = x } else { panic(errors.New(c.Name + " not find: " + name)) @@ -730,168 +927,7 @@ func (c *Context) Find(name string) (s *Context) { // {{{ // }}} -func (c *Context) Cmd(m *Message, key string, arg ...string) string { // {{{ - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - m.Meta["detail"] = nil - m.Add("detail", key, arg...) - - for s := c; s != nil; s = s.Context { - if x, ok := s.Commands[key]; ok { - log.Printf("%s cmd(%s->%s): %v", c.Name, m.Context.Name, m.Target.Name, m.Meta["detail"]) - - if !m.Context.Check(m.Target) { - log.Printf("没有权限:") - return "" - } - - for _, v := range m.Meta["option"] { - if _, ok := x.Options[v]; !ok { - panic(errors.New(fmt.Sprintf("未知参数:" + v))) - } - } - - m.Meta["result"] = nil - c.AssertOne(m, true, func(c *Context, m *Message) { - ret := x.Hand(c, m, key, arg...) - if ret != "" { - m.Echo(ret) - } - }) - - if x.Appends != nil { - for _, v := range m.Meta["append"] { - if _, ok := x.Appends[v]; !ok { - panic(errors.New(fmt.Sprintf("未知参数:" + v))) - } - } - } - - return m.Get("result") - } - } - - panic(errors.New(fmt.Sprintf("未知命令:" + key))) -} - -// }}} -func (c *Context) Conf(key string, arg ...string) string { // {{{ - for s := c; s != nil; s = s.Context { - - if x, ok := s.Configs[key]; ok { - switch len(arg) { - case 0: - if x.Hand != nil { - return x.Hand(c, x) - } - return x.Value - case 1: - log.Println(c.Name, "conf:", key, arg[0]) - x.Value = arg[0] - if x.Hand != nil { - x.Hand(c, x, x.Value) - } - return x.Value - case 3: - log.Println(c.Name, "conf:", key, arg) - if s == c { - panic(errors.New(key + "配置项已存在")) - } - if c.Configs == nil { - c.Configs = make(map[string]*Config) - } - c.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2], Hand: x.Hand} - return arg[1] - default: - panic(errors.New(key + "配置项参数错误")) - } - } - } - - if len(arg) == 3 { - log.Println(c.Name, "conf:", key, arg) - if c.Configs == nil { - c.Configs = make(map[string]*Config) - } - c.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2]} - return arg[1] - } - - panic(errors.New(key + "配置项不存在")) -} - -// }}} -func (c *Context) Confi(key string, arg ...int) int { // {{{ - if len(arg) > 0 { - n, e := strconv.Atoi(c.Conf(key, fmt.Sprintf("%d", arg[0]))) - c.Assert(e) - return n - } - - n, e := strconv.Atoi(c.Conf(key)) - c.Assert(e) - return n -} - -// }}} -func (c *Context) Cap(key string, arg ...string) string { // {{{ - for s := c; s != nil; s = s.Context { - if x, ok := s.Caches[key]; ok { - switch len(arg) { - case 0: - if x.Hand != nil { - x.Value = x.Hand(c, x) - } - return x.Value - case 1: - if x.Hand != nil { - x.Value = x.Hand(c, x, arg[0]) - } else { - x.Value = arg[0] - } - return x.Value - case 3: - log.Println(c.Name, "cap:", key, arg) - if s == c { - panic(errors.New(key + "缓存项已存在")) - } - if c.Caches == nil { - c.Caches = make(map[string]*Cache) - } - c.Caches[key] = &Cache{arg[0], arg[1], arg[2], x.Hand} - return arg[1] - default: - panic(errors.New(key + "缓存项参数错误")) - } - } - } - if len(arg) == 3 { - log.Println(c.Name, "cap:", key, arg) - if c.Caches == nil { - c.Caches = make(map[string]*Cache) - } - c.Caches[key] = &Cache{arg[0], arg[1], arg[2], nil} - return arg[1] - } - - panic(errors.New(key + "缓存项不存在")) -} - -// }}} -func (c *Context) Capi(key string, arg ...int) int { // {{{ - n, e := strconv.Atoi(c.Cap(key)) - c.Assert(e) - if len(arg) > 0 { - n += arg[0] - c.Cap(key, strconv.Itoa(n)) - } - return n -} - -// }}} - -var Pulse = &Message{Code: 1, Time: time.Now(), Name: "ctx", Index: 0} +var Pulse = &Message{Code: 1, Time: time.Now(), Index: 0, Target: Index, Master: Index, Source: Index, Name: "ctx"} var Index = &Context{Name: "ctx", Help: "根模块", Caches: map[string]*Cache{ @@ -902,7 +938,7 @@ var Index = &Context{Name: "ctx", Help: "根模块", Configs: map[string]*Config{ "start": &Config{Name: "启动模块", Value: "cli", Help: "启动时自动运行的模块"}, "init.sh": &Config{Name: "启动脚本", Value: "etc/init.sh", Help: "模块启动时自动运行的脚本"}, - "bench.log": &Config{Name: "日志文件", Value: "var/bench.log", Help: "模块日志输出的文件", Hand: func(c *Context, x *Config, arg ...string) string { + "bench.log": &Config{Name: "日志文件", Value: "var/bench.log", Help: "模块日志输出的文件", Hand: func(m *Message, x *Config, arg ...string) string { if len(arg) > 0 { // {{{ if e := os.MkdirAll(path.Dir(arg[0]), os.ModePerm); e == nil { if l, e := os.Create(x.Value); e == nil { @@ -913,11 +949,11 @@ var Index = &Context{Name: "ctx", Help: "根模块", return x.Value // }}} }}, - "root": &Config{Name: "工作目录", Value: ".", Help: "所有模块的当前目录", Hand: func(c *Context, x *Config, arg ...string) string { + "root": &Config{Name: "工作目录", Value: ".", Help: "所有模块的当前目录", Hand: func(m *Message, x *Config, arg ...string) string { if len(arg) > 0 { // {{{ if !path.IsAbs(x.Value) { wd, e := os.Getwd() - c.Assert(e) + m.Assert(e) x.Value = path.Join(wd, x.Value) } @@ -945,56 +981,56 @@ var Index = &Context{Name: "ctx", Help: "根模块", }, Commands: map[string]*Command{ "show": &Command{Name: "输出简单的信息", Help: "建立远程连接", Hand: func(c *Context, m *Message, key string, arg ...string) string { - m.Echo("nserver: %s\n", c.Cap("nserver")) // {{{ - m.Echo("ncontext: %s\n", c.Cap("ncontext")) - m.Echo("nmessage: %s\n", c.Cap("nmessage")) + m.Echo("nserver: %s\n", m.Cap("nserver")) // {{{ + m.Echo("ncontext: %s\n", m.Cap("ncontext")) + m.Echo("nmessage: %s\n", m.Cap("nmessage")) return "" // }}} }}, }, - Requests: []*Message{Pulse}, - Sessions: map[string]*Message{"root": Pulse}, } func init() { Pulse.Root = Pulse - Pulse.Target = Index - Pulse.Context = Index Pulse.Wait = make(chan bool, 10) + Index.Requests = []*Message{Pulse} + Index.Sessions = map[string]*Message{"root": Pulse} } func Start(args ...string) { if len(args) > 0 { - Index.Conf("start", args[0]) + Pulse.Conf("start", args[0]) } if len(args) > 1 { - Index.Conf("init.sh", args[1]) + Pulse.Conf("init.sh", args[1]) } if len(args) > 2 { - Index.Conf("bench.log", args[2]) + Pulse.Conf("bench.log", args[2]) } else { - Index.Conf("bench.log", Index.Conf("bench.log")) + Pulse.Conf("bench.log", Pulse.Conf("bench.log")) } if len(args) > 3 { - Index.Conf("root", args[3]) + Pulse.Conf("root", args[3]) } log.Println("\n\n\n") Index.Travel(func(s *Context) bool { + Pulse.Target = s s.Root = Index - s.Begin(nil) + s.Begin(Pulse) return true }) + Pulse.Target = Index - if n := 0; Index.Conf("start") != "" { - for _, s := range Index.Contexts { - if ok, _ := regexp.MatchString(Index.Conf("start"), s.Name); ok { + if n := 0; Pulse.Conf("start") != "" { + for _, s := range Index.contexts { + if ok, _ := regexp.MatchString(Pulse.Conf("start"), s.Name); ok { go s.Start(Pulse.Spawn(s, s.Name).Put("option", "io", os.Stdout)) n++ } } - for n > 0 || Index.Capi("nserver", 0) > 0 { + for n > 0 || Pulse.Capi("nserver", 0) > 0 { <-Pulse.Wait n-- } From 30b713c05a865434d7315bae600f3eb57c9137e8 Mon Sep 17 00:00:00 2001 From: shaoying Date: Sun, 19 Nov 2017 15:23:08 +0800 Subject: [PATCH 3/3] =?UTF-8?q?mac=20mod=20ctx&cli=20=E5=8A=A0=E5=BC=BA?= =?UTF-8?q?=E4=BA=86=E6=B6=88=E6=81=AF=E9=A9=B1=E5=8A=A8=E7=9A=84=E4=BD=9C?= =?UTF-8?q?=E7=94=A8=EF=BC=8C=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E8=A7=A3=E6=9E=90=E4=B8=8E=E5=9B=9E=E5=A4=8D=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E9=80=80=E5=87=BA=E8=BF=87=E7=A8=8B?= =?UTF-8?q?=EF=BC=8Ccli=E6=B7=BB=E5=8A=A0=E4=B8=BB=E6=8E=A7=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/init.sh | 8 +- src/context/cli/cli.go | 506 +++++---------- src/context/ctx.go | 1341 +++++++++++++++++++++++----------------- 3 files changed, 946 insertions(+), 909 deletions(-) diff --git a/etc/init.sh b/etc/init.sh index 8838af3b..96c50e8f 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -2,6 +2,8 @@ # ~aaa # login root 94ca7394d007fa189cc4be0a2625d716 root # login root root -# -# ~cli -# remote slave listen :9393 tcp + +~cli +remote slaver listen :9393 tcp +# ~aaa +# login shy shy diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index 0c24a16c..4c38b6bc 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -5,7 +5,7 @@ import ( // {{{ "context" "fmt" "io" - // "log" + "log" "os" "strconv" "strings" @@ -21,6 +21,7 @@ type CLI struct { ins []io.ReadCloser bio *bufio.Reader bios []*bufio.Reader + bufs [][]byte history []map[string]string alias map[string]string @@ -62,7 +63,7 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{ if msg.Cmd("login", username, password) == "" { fmt.Fprintln(cli.out, "登录失败") - m.Post(cli.Context, "exit") + m.Cmd("exit") cli.out.Close() cli.in.Close() return false @@ -82,23 +83,20 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{ ls, e := cli.bio.ReadString('\n') if e == io.EOF { l := len(cli.ins) - if l == 1 { - // cli.echo("\n%s\n", cli.Conf("结束语")) - return false - ls = "exit" - e = nil - } else { + if l > 1 { cli.ins = cli.ins[:l-1] cli.bios = cli.bios[:l-1] cli.in = cli.ins[l-2] cli.bio = cli.bios[l-2] return true } + // cli.echo("\n%s\n", cli.Conf("结束语")) + return false } m.Assert(e) line = ls - if len(cli.ins) > 1 || m.Conf("slient") != "yes" { + if len(cli.ins) > 1 && m.Conf("slient") != "yes" { cli.echo(line) } @@ -182,6 +180,36 @@ func (cli *CLI) echo(str string, arg ...interface{}) { // {{{ // }}} func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ + cli.Caches["username"] = &ctx.Cache{Name: "登录用户", Value: "", Help: "登录用户名"} + cli.Caches["nhistory"] = &ctx.Cache{Name: "历史命令数量", Value: "0", Help: "当前终端已经执行命令的数量", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string { + x.Value = fmt.Sprintf("%d", len(cli.history)) + return x.Value + }} + + cli.Configs["slient"] = &ctx.Config{Name: "屏蔽脚本输出(yes/no)", Value: "yes", Help: "屏蔽脚本输出的信息,yes:屏蔽,no:不屏蔽"} + cli.Configs["default"] = &ctx.Config{Name: "默认的搜索起点(root/back/home)", Value: "root", Help: "模块搜索的默认起点,root:从根模块,back:从父模块,home:从当前模块"} + cli.Configs["PS1"] = &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { + cli, ok := m.Target.Server.(*CLI) // {{{ + if ok && cli.target != nil { + // c = cli.target + switch x.Value { + case "target": + return fmt.Sprintf("%s[%s]\033[32m%s\033[0m> ", m.Cap("nhistory"), time.Now().Format("15:04:05"), cli.target.Name) + case "detail": + return fmt.Sprintf("%s[%s](%s,%s,%s)\033[32m%s\033[0m> ", m.Cap("nhistory"), time.Now().Format("15:04:05"), m.Cap("ncontext"), m.Cap("nmessage"), m.Cap("nserver"), m.Target.Name) + } + + } + + return fmt.Sprintf("[%s]\033[32m%s\033[0m ", time.Now().Format("15:04:05"), x.Value) + // }}} + }} + + if len(arg) > 0 { + cli.Configs["init.sh"] = &ctx.Config{Name: "启动脚本", Value: arg[0], Help: "模块启动时自动运行的脚本"} + } + + cli.target = cli.Context cli.history = make([]map[string]string, 0, 100) cli.alias = map[string]string{ "~": "context", @@ -192,44 +220,44 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ "*": "message", } - cli.target = cli.Context - - cli.Caches["nhistory"] = &ctx.Cache{Name: "历史命令数量", Value: "0", Help: "当前终端已经执行命令的数量", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string { - x.Value = fmt.Sprintf("%d", len(cli.history)) - return x.Value - }} - return cli } // }}} func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ - cli.Owner = nil m.Capi("nterm", 1) defer m.Capi("nterm", -1) - if cli.Messages == nil { - cli.Messages = make(chan *ctx.Message, m.Confi("MessageQueueSize")) - } - if len(arg) > 0 { - m.Conf("init.sh", "启动脚本", arg[0], "模块启动时自动运行的脚本") - } - if stream, ok := m.Data["io"]; ok { io := stream.(io.ReadWriteCloser) cli.out = io cli.push(io) - if f, e := os.Open(m.Conf("init.sh")); e == nil { - cli.push(f) - } - - // cli.echo("%s\n", cli.Conf("hello")) - - go cli.AssertOne(m, true, func(c *ctx.Context, m *ctx.Message) { - for cli.parse(m) { + if m.Has("master") { + log.Println(cli.Name, "master terminal:") + if cli.bufs == nil { + cli.bufs = make([][]byte, 0, 10) } - }) + for { + b := make([]byte, 128) + n, e := cli.bio.Read(b) + log.Println(cli.Name, "read:", n) + m.Assert(e) + cli.bufs = append(cli.bufs, b) + } + return true + } else { + log.Println(cli.Name, "slaver terminal:") + + if f, e := os.Open(m.Conf("init.sh")); e == nil { + cli.push(f) + } + + go m.AssertOne(m, true, func(m *ctx.Message) { + for cli.parse(m) { + } + }) + } } for m.Deal(func(msg *ctx.Message, arg ...string) bool { @@ -272,9 +300,14 @@ func (cli *CLI) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server // }}} func (cli *CLI) Exit(m *ctx.Message, arg ...string) bool { // {{{ - if cli.Context != Index { - // delete(cli.Context.Context.Contexts, cli.Name) + switch cli.Context { + case m.Source: + return false + + case m.Target: + log.Println(cli.Name, "release:") } + return true } @@ -283,173 +316,93 @@ func (cli *CLI) Exit(m *ctx.Message, arg ...string) bool { // {{{ var Index = &ctx.Context{Name: "cli", Help: "管理终端", Caches: map[string]*ctx.Cache{ "nterm": &ctx.Cache{Name: "终端数量", Value: "0", Help: "已经运行的终端数量"}, - "user": &ctx.Cache{Name: "登录用户", Value: "", Help: "登录用户名"}, }, - Configs: map[string]*ctx.Config{ - "slient": &ctx.Config{Name: "屏蔽脚本输出(yes/no)", Value: "yes", Help: "屏蔽脚本输出的信息,yes:屏蔽,no:不屏蔽"}, - "default": &ctx.Config{Name: "默认的搜索起点(root/back/home)", Value: "root", Help: "模块搜索的默认起点,root:从根模块,back:从父模块,home:从当前模块"}, - // "hello": &ctx.Config{Name: "开场白", Value: "\n~~~ Hello Context & Message World ~~~\n", Help: "模块启动时输出的信息"}, - // "byebye": &ctx.Config{Name: "结束语", Value: "\n~~~ Byebye Context & Message World ~~~\n", Help: "模块停止时输出的信息"}, - - "PS1": &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { - cli, ok := m.Target.Server.(*CLI) // {{{ - if ok && cli.target != nil { - // c = cli.target - switch x.Value { - case "target": - return fmt.Sprintf("%s[%s]\033[32m%s\033[0m> ", m.Cap("nhistory"), time.Now().Format("15:04:05"), cli.target.Name) - case "detail": - return fmt.Sprintf("%s[%s](%s,%s,%s)\033[32m%s\033[0m> ", m.Cap("nhistory"), time.Now().Format("15:04:05"), m.Cap("ncontext"), m.Cap("nmessage"), m.Cap("nserver"), m.Target.Name) + Configs: map[string]*ctx.Config{}, + Commands: map[string]*ctx.Command{ + "context": &ctx.Command{Name: "context [root|back|home] [[find|search] name] [show|spawn|start|switch][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", + Formats: map[string]int{"root": 0, "back": 0, "home": 0, "find": 1, "search": 1, "show": 0, "switch": 0, "start": -1, "spawn": -1}, + Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + cli, ok := m.Source.Server.(*CLI) // {{{ + if !ok { + cli, ok = c.Server.(*CLI) + if !ok { + return "" + } } - } - - return fmt.Sprintf("[%s]\033[32m%s\033[0m ", time.Now().Format("15:04:05"), x.Value) - // }}} - }}, - }, - Commands: map[string]*ctx.Command{ - "context": &ctx.Command{Name: "context [root|back|home] [[find|search] name] [show|spawn|start|switch][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - cli, ok := m.Source.Server.(*CLI) // {{{ - if !ok { - cli, ok = c.Server.(*CLI) - if !ok { + switch len(arg) { + case 0: + m.Target.Root.Travel(func(c *ctx.Context) bool { + if c.Context != nil && m.Source.Check(c) { + m.Echo("%s: %s(%s)\n", c.Context.Name, c.Name, c.Help) + } + return true + }) return "" } - } - switch len(arg) { - case 0: - m.Target.Root.Travel(func(c *ctx.Context) bool { - if c.Context != nil && m.Source.Check(c) { - m.Echo("%s: %s(%s)\n", c.Context.Name, c.Name, c.Help) - } - return true - }) - return "" - } - - target := m.Target - switch m.Conf("default") { - case "root": - target = target.Root - case "back": - if target.Context != nil { - target = target.Context - } - case "home": - } - - method := "search" - action := "switch" - which := "" - args := []string{} - - for len(arg) > 0 { - switch arg[0] { - case "root": - target = m.Target.Root - case "back": - if m.Target.Context != nil { - target = m.Target.Context - } - case "home": + target := m.Target.Root + if m.Has("home") { target = m.Target - case "find", "search": - method = arg[0] - which = arg[1] - arg = arg[1:] - case "switch", "spawn", "start", "show": - action = arg[0] - args = arg[1:] - arg = arg[:1] - default: - which = arg[0] + } + if m.Has("root") { + target = m.Target.Root + } + if m.Has("back") && target.Context != nil { + target = m.Target.Context } - arg = arg[1:] - } - - cs := []*ctx.Context{} - - if which == "" { - cs = append(cs, target) - } else { - switch method { - case "search": - if s := target.Search(which); len(s) > 0 { + cs := []*ctx.Context{} + switch { + case m.Has("search"): + if s := target.Search(m.Get("search")); len(s) > 0 { cs = append(cs, s...) } - case "find": - if s := target.Find(which); s != nil { + case m.Has("find"): + if s := target.Find(m.Get("find")); s != nil { cs = append(cs, s) } - } - } - - for _, v := range cs { - if !m.Source.Check(v) { - continue + case m.Has("args"): + if s := target.Search(m.Get("args")); len(s) > 0 { + cs = append(cs, s...) + } + default: + cs = append(cs, target) } - switch action { - case "switch": - cli.target = v - case "spawn": - msg := m.Spawn(v) - // msg.Add("detail", args[1:]...) - v.Spawn(msg, args[0]).Begin(msg) - case "start": - m.Message.Spawn(v, args[0]).Start(arg[0], args[1:]...) - case "show": - m.Echo("%s: %s\n", v.Name, v.Help) - m.Echo("引用模块:\n") - for k, v := range v.Sessions { - m.Echo("\t%s(%d): %s %s\n", k, v.Code, v.Target.Name, v.Target.Help) - } - m.Echo("索引模块:\n") - for i, v := range v.Requests { - m.Echo("\t%d(%d): %s %s\n", i, v.Code, v.Source.Name, v.Source.Help) + for _, v := range cs { + // if !m.Source.Check(v) { + // continue + // } + // + switch { + case m.Has("start"): + args := m.Meta["start"] + m.Message.Spawn(v, args[0]).Start(arg[0], args[1:]...) + case m.Has("spawn"): + args := m.Meta["spawn"] + msg := m.Spawn(v) + v.Spawn(msg, args[0]).Begin(msg) + case m.Has("switch"): + cli.target = v + case m.Has("show"): + m.Echo("%s: %s\n", v.Name, v.Help) + m.Echo("模块资源:\n") + for i, v := range v.Requests { + m.Echo("\t%d(%d): <- %s %s\n", i, v.Code, v.Source.Name, v.Source.Help) + } + m.Echo("模块引用:\n") + for k, v := range v.Sessions { + m.Echo("\t%s(%d): -> %s %s\n", k, v.Code, v.Target.Name, v.Target.Help) + } + default: + cli.target = v } } - } - return "" - // }}} - }}, - "message": &ctx.Command{Name: "message", Help: "查看上下文", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - ms := []*ctx.Message{ctx.Pulse} // {{{ - for i := 0; i < len(ms); i++ { - m.Echo("%d %s.%s -> %s.%d: %s %v\n", ms[i].Code, ms[i].Source.Name, ms[i].Name, ms[i].Target.Name, ms[i].Index, ms[i].Time.Format("15:04:05"), ms[i].Meta["detail"]) - ms = append(ms, ms[i].Messages...) - } - return "" - // }}} - }}, - "server": &ctx.Command{Name: "server start|stop|switch", Help: "服务启动停止切换", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - s := m.Target // {{{ - switch len(arg) { - case 0: - m.Target.Root.Travel(func(c *ctx.Context) bool { - if x, ok := c.Caches["status"]; ok { - m.Echo("%s(%s): %s\n", c.Name, x.Value, c.Help) - } - return true - }) - - case 1: - switch arg[0] { - case "start": - if s != nil { - go s.Start(m) - } - case "stop": - case "switch": - } - } - return "" - // }}} - }}, + return "" + // }}} + }}, "source": &ctx.Command{Name: "source file", Help: "运行脚本", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { cli := c.Server.(*CLI) // {{{ switch len(arg) { @@ -505,170 +458,43 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", return "" // }}} }}, - "command": &ctx.Command{Name: "command [all] [name args]", Help: "查看修改添加配置", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - all := false // {{{ - if len(arg) > 0 && arg[0] == "all" { - arg = arg[1:] - all = true - } + "remote": &ctx.Command{Name: "remote [send args...]|[[master|slaver] listen|dial address protocol]", Help: "建立远程连接", + Formats: map[string]int{"send": -1, "master": 0, "slaver": 0, "listen": 1, "dial": 1}, + Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + if m.Has("send") { // {{{ + cli := m.Target.Server.(*CLI) - m.Target.BackTrace(func(s *ctx.Context) bool { - switch len(arg) { - case 0: - for k, v := range s.Commands { - m.Echo("%s: %s\n", k, v.Name) + cli.out.Write([]byte(strings.Join(m.Meta["args"], " ") + "\n")) + m.Echo("~~~remote~~~\n") + time.Sleep(100 * time.Millisecond) + for _, b := range cli.bufs { + m.Echo("%s", string(b)) } - case 1: - if v, ok := s.Commands[arg[0]]; ok { - m.Echo("%s\n%s\n", v.Name, v.Help) - } - default: - m.Spawn(s).Cmd(arg...) - return false - } - return all - }) - return "" - // }}} - }}, - "config": &ctx.Command{Name: "config [all] [key value|[name value help]]", Help: "查看修改添加配置", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - all := false // {{{ - if len(arg) > 0 && arg[0] == "all" { - arg = arg[1:] - all = true - } + cli.bufs = cli.bufs[0:0] + m.Echo("\n~~~remote~~~\n") - m.Target.BackTrace(func(s *ctx.Context) bool { - switch len(arg) { - case 0: - for k, v := range s.Configs { - m.Echo("%s(%s): %s\n", k, v.Value, v.Name) - } - case 1: - if v, ok := s.Configs[arg[0]]; ok { - m.Echo("%s: %s\n", v.Name, v.Help) - } - case 2: - if s != m.Target { - return false - } - - switch arg[0] { - case "void": - m.Conf(arg[1], "") - case "delete": - if _, ok := s.Configs[arg[1]]; ok { - delete(s.Configs, arg[1]) - } - default: - m.Conf(arg[0], arg[1]) - } - case 4: - m.Conf(arg[0], arg[1:]...) - return false - } - return all - }) - return "" - // }}} - }}, - "cache": &ctx.Command{Name: "cache [all] [key value|[name value help]]", Help: "查看修改添加配置", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - all := false // {{{ - if len(arg) > 0 && arg[0] == "all" { - arg = arg[1:] - all = true - } - - m.Target.BackTrace(func(s *ctx.Context) bool { - switch len(arg) { - case 0: - for k, v := range s.Caches { - m.Echo("%s(%s): %s\n", k, v.Value, v.Name) - } - case 1: - if v, ok := s.Caches[arg[0]]; ok { - m.Echo("%s: %s\n", v.Name, v.Help) - } - case 2: - if s != m.Target { - return false - } - - switch arg[0] { - case "delete": - if _, ok := s.Caches[arg[1]]; ok { - delete(s.Caches, arg[1]) - } - default: - if _, ok := s.Caches[arg[0]]; ok { - m.Echo("%s: %s\n", arg[0], m.Cap(arg[0], arg[1:]...)) - } - } - case 4: - m.Cap(arg[0], arg[1:]...) - return false + return "" } - return all - }) - return "" - // }}} - }}, - "userinfo": &ctx.Command{Name: "userinfo", Help: "查看模块的用户信息", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - o := m.Target.Owner // {{{ - if o != nil { - m.Echo("%s\n", o.Name) - } - return "" - // }}} - }}, - "exit": &ctx.Command{Name: "exit", Help: "退出", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - cli, ok := m.Target.Server.(*CLI) // {{{ - if !ok { - cli, ok = m.Source.Server.(*CLI) - } - if ok { - if !cli.exit { - // m.Echo(c.Conf("结束语")) - cli.Context.Exit(m) + s := c.Root.Find(m.Get("args")) + action := "dial" + if m.Has("listen") { + action = "listen" } - cli.in.Close() - cli.out.Close() - cli.exit = true - } - return "" - // }}} - }}, - "remote": &ctx.Command{Name: "remote master|slave listen|dial address protocol", Help: "建立远程连接", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - switch len(arg) { // {{{ - case 0: - case 4: - if arg[0] == "master" { - if arg[1] == "dial" { - } else { - } - } else { - if arg[1] == "listen" { - s := c.Root.Find(arg[3]) - m.Message.Spawn(s, arg[2]).Cmd("listen", arg[2]) - } else { - } - } - } - return "" - // }}} - }}, - "open": &ctx.Command{Name: "open address protocl", Help: "建立远程连接", - Options: map[string]string{"io": "读写流"}, - Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { // {{{ - if m.Has("io") { - m.Start(fmt.Sprintf("PTS%d", m.Capi("nterm")), arg[1]) - } else { - switch arg[1] { - case "tcp": - } + msg := m.Spawn(s) + if m.Has("master") { + msg.Template = msg.Spawn(msg.Source).Add("option", "master") } + msg.Cmd(action, m.Get(action)) + + return "" + }}, + // }}} + "open": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接", + Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"}, + Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + go m.Start(fmt.Sprintf("PTS%d", m.Capi("nterm")), m.Meta["args"]...) // {{{ return "" // }}} }}, diff --git a/src/context/ctx.go b/src/context/ctx.go index c31546bb..62ea6455 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -17,456 +17,41 @@ import ( // {{{ // }}} -type Cache struct { +type Cache struct { // {{{ Name string Value string Help string Hand func(m *Message, x *Cache, arg ...string) string } -type Config struct { +// }}} +type Config struct { // {{{ Name string Value string Help string Hand func(m *Message, x *Config, arg ...string) string } -type Command struct { +// }}} +type Command struct { // {{{ Name string Help string + Formats map[string]int Options map[string]string Appends map[string]string Hand func(c *Context, m *Message, key string, arg ...string) string } -type Message struct { - Code int - Time time.Time - - Meta map[string][]string - Data map[string]interface{} - Wait chan bool - - Index int - Target *Context - Master *Context - Source *Context - Name string - - Messages []*Message - Message *Message - Root *Message -} - -func (m *Message) Assert(e error) bool { // {{{ - if e != nil { - m.Add("result", "error:", fmt.Sprintln(e)) - - log.Println(m.Code, "error:", e) - if m.Conf("debug") == "on" { - fmt.Println(m.Code, "error:", e) - } - - panic(e) - } - return true -} - // }}} - -func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{ - - msg := &Message{ - Time: time.Now(), - Target: c, - Master: c, - Message: m, - Root: m.Root, - } - msg.Source = m.Target - - if len(key) == 0 { - return msg - } - - if m.Messages == nil { - m.Messages = make([]*Message, 0, 10) - } - m.Messages = append(m.Messages, msg) - msg.Code = m.Capi("nmessage", 1) - - if msg.Source.Sessions == nil { - msg.Source.Sessions = make(map[string]*Message) - } - msg.Source.Sessions[key[0]] = msg - msg.Name = key[0] - - log.Printf("%d spawn %d: %s.%s->%s.%d", m.Code, msg.Code, msg.Source.Name, msg.Name, msg.Target.Name, msg.Index) - return msg - -} - -// }}} - -func (m *Message) Add(meta string, key string, value ...string) *Message { // {{{ - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - if _, ok := m.Meta[meta]; !ok { - m.Meta[meta] = make([]string, 0, 3) - } - - switch meta { - case "detail", "result": - m.Meta[meta] = append(m.Meta[meta], key) - m.Meta[meta] = append(m.Meta[meta], value...) - case "option", "append": - if _, ok := m.Meta[key]; !ok { - m.Meta[meta] = append(m.Meta[meta], key) - m.Meta[key] = make([]string, 0, 3) - } - m.Meta[key] = append(m.Meta[key], value...) - default: - panic(errors.New("消息参数错误")) - } - - return m -} - -// }}} -func (m *Message) Put(meta string, key string, value interface{}) *Message { // {{{ - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - if m.Data == nil { - m.Data = make(map[string]interface{}) - } - - switch meta { - case "option", "append": - if _, ok := m.Meta[meta]; !ok { - m.Meta[meta] = make([]string, 0, 3) - } - if _, ok := m.Data[key]; !ok { - m.Meta[meta] = append(m.Meta[meta], key) - } - m.Data[key] = value - default: - panic(errors.New("消息参数错误")) - } - - return m -} - -// }}} -func (m *Message) Has(key string) bool { // {{{ - if _, ok := m.Meta[key]; ok { - return true - } - if _, ok := m.Data[key]; ok { - return true - } - return false -} - -// }}} -func (m *Message) Get(key string) string { // {{{ - if meta, ok := m.Meta[key]; ok { - if len(meta) > 0 { - return meta[0] - } - } - return "" -} - -// }}} -func (m *Message) Echo(str string, arg ...interface{}) *Message { // {{{ - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - if _, ok := m.Meta["result"]; !ok { - m.Meta["result"] = make([]string, 0, 3) - } - - m.Meta["result"] = append(m.Meta["result"], fmt.Sprintf(str, arg...)) - return m -} - -// }}} -func (m *Message) End(s bool) { // {{{ - if m.Wait != nil { - m.Wait <- s - } - m.Wait = nil -} - -// }}} - -func (m *Message) Check(s *Context, arg ...string) bool { // {{{ - if m.Source.Owner != s.Owner && m.Source.Owner != s.Root.Owner { - if len(arg) != 2 { - return false - } - - g, ok := s.Index[m.Source.Group] - if !ok { - if g, ok = s.Index["void"]; !ok { - return false - } - } - - switch arg[0] { - case "commands": - _, ok = g.Commands[arg[0]] - case "configs": - _, ok = g.Configs[arg[0]] - case "caches": - _, ok = g.Caches[arg[0]] - } - - if !ok { - return false - } - } - - return true -} - -// }}} - -func (m *Message) Start(key string, arg ...string) bool { // {{{ - if len(arg) > 0 { - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - m.Meta["detail"] = arg - } - - m.Target.Spawn(m, key).Start(m) - - return true -} - -// }}} -func (m *Message) Post(c *Context, arg ...string) bool { // {{{ - if len(arg) > 0 { - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - m.Meta["detail"] = arg - } - - if c.Messages == nil { - panic(c.Name + " 没有开启消息处理") - } - - c.Messages <- m - if m.Wait != nil { - return <-m.Wait - } - return true - -} - -// }}} -func (m *Message) Cmd(arg ...string) string { // {{{ - if len(arg) > 0 { - if m.Meta == nil { - m.Meta = make(map[string][]string) - } - m.Meta["detail"] = arg - } - arg = m.Meta["detail"] - - if m.Code != 0 { - log.Printf("%d cmd(%s:%s->%s.%d): %v", m.Code, m.Source.Name, m.Name, m.Master.Name, m.Index, arg) - } else { - log.Printf("%d cmd(%s->%s): %v", m.Code, m.Source.Name, m.Master.Name, arg) - } - - for s := m.Master; s != nil; s = s.Context { - - if !m.Check(s, "commands", arg[0]) { - panic(errors.New(fmt.Sprintf("没有权限:" + arg[0]))) - } - - if x, ok := s.Commands[arg[0]]; ok { - if x.Options != nil { - for _, v := range m.Meta["option"] { - if _, ok := x.Options[v]; !ok { - panic(errors.New(fmt.Sprintf("未知参数:" + v))) - } - } - } - - m.Meta["result"] = nil - m.Master.AssertOne(m, true, func(c *Context, m *Message) { - ret := x.Hand(c, m, arg[0], arg[1:]...) - if ret != "" { - m.Echo(ret) - } - }) - - if x.Appends != nil { - for _, v := range m.Meta["append"] { - if _, ok := x.Appends[v]; !ok { - panic(errors.New(fmt.Sprintf("未知参数:" + v))) - } - } - } - return m.Get("result") - } - } - - panic(errors.New(fmt.Sprintf("未知命令:" + arg[0]))) -} - -// }}} -func (m *Message) Conf(key string, arg ...string) string { // {{{ - for s := m.Target; s != nil; s = s.Context { - if !m.Check(s, "configs", key) { - panic(errors.New(fmt.Sprintf("没有权限:" + key))) - } - - if x, ok := s.Configs[key]; ok { - switch len(arg) { - case 0: - if x.Hand != nil { - return x.Hand(m, x) - } - return x.Value - case 1: - if m.Code != 0 { - log.Printf("%d conf(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Master.Name, m.Index, key, arg) - } else { - log.Printf("%d conf(%s->%s): %s %v", m.Code, m.Source.Name, m.Master.Name, key, arg) - } - - x.Value = arg[0] - if x.Hand != nil { - x.Hand(m, x, x.Value) - } - return x.Value - case 3: - if m.Code != 0 { - log.Printf("%d conf(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Master.Name, m.Index, key, arg) - } else { - log.Printf("%d conf(%s->%s): %s %v", m.Code, m.Source.Name, m.Master.Name, key, arg) - } - - if s == m.Target { - panic(errors.New(key + "配置项已存在")) - } - if m.Target.Configs == nil { - m.Target.Configs = make(map[string]*Config) - } - m.Target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2], Hand: x.Hand} - return arg[1] - default: - panic(errors.New(key + "配置项参数错误")) - } - } - } - - if len(arg) == 3 { - log.Println(m.Target.Name, "conf:", key, arg) - if m.Target.Configs == nil { - m.Target.Configs = make(map[string]*Config) - } - m.Target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2]} - return arg[1] - } - - panic(errors.New(key + "配置项不存在")) -} - -// }}} -func (m *Message) Confi(key string, arg ...int) int { // {{{ - if len(arg) > 0 { - n, e := strconv.Atoi(m.Conf(key, fmt.Sprintf("%d", arg[0]))) - m.Assert(e) - return n - } - - n, e := strconv.Atoi(m.Conf(key)) - m.Assert(e) - return n -} - -// }}} -func (m *Message) Cap(key string, arg ...string) string { // {{{ - // if m.Code != 0 { - // log.Printf("%d cap(%s:%s->%s.%d): %s %v", m.Code, m.Context.Name, m.Name, m.Master.Name, m.Index, key, arg) - // } else { - // log.Printf("%d cap(%s->%s): %s %v", m.Code, m.Context.Name, m.Master.Name, key, arg) - // } - // - for s := m.Target; s != nil; s = s.Context { - if !m.Check(s, "caches", key) { - panic(errors.New(fmt.Sprintf("没有权限:" + key))) - } - - if x, ok := s.Caches[key]; ok { - switch len(arg) { - case 0: - if x.Hand != nil { - x.Value = x.Hand(m, x) - } - return x.Value - case 1: - if x.Hand != nil { - x.Value = x.Hand(m, x, arg[0]) - } else { - x.Value = arg[0] - } - return x.Value - case 3: - log.Println(m.Target.Name, "cap:", key, arg) - if s == m.Target { - panic(errors.New(key + "缓存项已存在")) - } - if m.Target.Caches == nil { - m.Target.Caches = make(map[string]*Cache) - } - m.Target.Caches[key] = &Cache{arg[0], arg[1], arg[2], x.Hand} - return arg[1] - default: - panic(errors.New(key + "缓存项参数错误")) - } - } - } - if len(arg) == 3 { - log.Println(m.Target.Name, "cap:", key, arg) - if m.Target.Caches == nil { - m.Target.Caches = make(map[string]*Cache) - } - m.Target.Caches[key] = &Cache{arg[0], arg[1], arg[2], nil} - return arg[1] - } - - panic(errors.New(key + "缓存项不存在")) -} - -// }}} -func (m *Message) Capi(key string, arg ...int) int { // {{{ - n, e := strconv.Atoi(m.Cap(key)) - m.Assert(e) - if len(arg) > 0 { - n += arg[0] - m.Cap(key, strconv.Itoa(n)) - } - return n -} - -// }}} - -type Server interface { +type Server interface { // {{{ Begin(m *Message, arg ...string) Server Start(m *Message, arg ...string) bool Spawn(c *Context, m *Message, arg ...string) Server Exit(m *Message, arg ...string) bool } +// }}} + type Context struct { Name string Help string @@ -475,58 +60,27 @@ type Context struct { Configs map[string]*Config Commands map[string]*Command - Messages chan *Message - Message *Message + contexts map[string]*Context + Context *Context + Root *Context + Server - Requests []*Message + Message *Message + Messages chan *Message + Sessions map[string]*Message + Requests []*Message + Master *Context Owner *Context Group string Index map[string]*Context Groups map[string]*Context - - contexts map[string]*Context - Context *Context - Root *Context } -func (c *Context) AssertOne(m *Message, safe bool, hand ...func(c *Context, m *Message)) *Context { // {{{ - defer func() { - if e := recover(); e != nil { - log.Println(c.Name, e) - if m.Conf("debug") == "on" && e != io.EOF { - fmt.Println(c.Name, "error:", e) - debug.PrintStack() - } - - if e == io.EOF { - return - } - - if len(hand) > 1 { - c.AssertOne(m, safe, hand[1:]...) - } else { - if !safe { - log.Println(c.Name, "error:", e) - panic(e) - } - } - } - // Pulse.Wait <- true - }() - - if len(hand) > 0 { - hand[0](c, m) - } - - return c -} - -// }}} - func (c *Context) Register(s *Context, x Server) *Context { // {{{ + Index.Root = Index if c.contexts == nil { c.contexts = make(map[string]*Context) @@ -535,10 +89,14 @@ func (c *Context) Register(s *Context, x Server) *Context { // {{{ panic(errors.New(c.Name + " 上下文已存在" + x.Name)) } - c.contexts[s.Name] = s - s.Root = c.Root - s.Context = c s.Server = x + s.Context = c + c.contexts[s.Name] = s + if c.Root != nil { + s.Root = c.Root + } else { + s.Root = Index + } log.Printf("%s sub(%d): %s", c.Name, Pulse.Capi("ncontext", 1), s.Name) return s @@ -546,18 +104,14 @@ func (c *Context) Register(s *Context, x Server) *Context { // {{{ // }}} func (c *Context) Begin(m *Message) *Context { // {{{ - for k, x := range m.Target.Configs { + for k, x := range c.Configs { if x.Hand != nil { m.Conf(k, x.Value) } } if c.Server != nil { - if m != nil { - c.Server.Begin(m, m.Meta["detail"]...) - } else { - c.Server.Begin(m) - } + c.Server.Begin(m, m.Meta["detail"]...) } return c @@ -571,20 +125,19 @@ func (c *Context) Start(m *Message) bool { // {{{ } if m.Cap("status") != "start" && c.Server != nil { - c.AssertOne(m, true, func(c *Context, m *Message) { + m.AssertOne(m, true, func(m *Message) { m.Cap("status", "start") defer m.Cap("status", "stop") - log.Printf("%d start(%d): %s %s", m.Code, Pulse.Capi("nserver", 1), c.Name, c.Help) - defer Pulse.Capi("nserver", -1) - defer log.Printf("%d stop(%s): %s %s", m.Code, Pulse.Cap("nserver"), c.Name, c.Help) + log.Printf("%d start(%d): %s %s %v", m.Code, m.Root.Capi("nserver", 1), c.Name, c.Help, m.Meta["detail"]) + defer m.Root.Capi("nserver", -1) + defer log.Printf("%d stop(%s): %s %s", m.Code, m.Root.Cap("nserver"), c.Name, c.Help) - c.Owner = m.Source.Owner c.Requests = []*Message{m} c.Server.Start(m, m.Meta["detail"]...) }) } - Pulse.Wait <- true + m.Root.Wait <- true return true } @@ -593,103 +146,53 @@ func (c *Context) Start(m *Message) bool { // {{{ func (c *Context) Spawn(m *Message, key string) *Context { // {{{ s := &Context{Name: key, Help: c.Help} m.Target = s + if m.Template != nil { + m.Template.Source = s + } + if c.Server != nil { - c.Register(s, c.Server.Spawn(s, m, m.Meta["detail"]...)).Begin(m) + c.Register(s, c.Server.Spawn(s, m, m.Meta["detail"]...)) } else { - c.Register(s, nil).Begin(m) + c.Register(s, nil) } return s } -// }}} - -func (msg *Message) Deal(pre func(m *Message, arg ...string) bool, post func(m *Message, arg ...string) bool) (live bool) { // {{{ - - if msg.Target.Messages == nil { - msg.Target.Messages = make(chan *Message, msg.Confi("MessageQueueSize")) - } - m := <-msg.Target.Messages - defer m.End(true) - - if len(m.Meta["detail"]) == 0 { - return true - } - - if pre != nil && !pre(m, m.Meta["detail"]...) { - return false - } - - arg := m.Meta["detail"] - msg.Target.AssertOne(m, true, func(c *Context, m *Message) { - m.Cmd() - - }, func(c *Context, m *Message) { - m.Master = c - m.Cmd() - - }, func(c *Context, m *Message) { - log.Printf("system command(%s->%s): %v", m.Source.Name, m.Target.Name, arg) - cmd := exec.Command(arg[0], arg[1:]...) - v, e := cmd.CombinedOutput() - if e != nil { - m.Echo("%s\n", e) - } else { - m.Echo(string(v)) - } - }) - - if post != nil && !post(m, m.Meta["result"]...) { - return false - } - - return true -} - // }}} func (c *Context) Exit(m *Message, arg ...string) { // {{{ - log.Println(c.Sessions) - log.Println(c.Requests) + if m.Code != 0 { + log.Printf("%d exit(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Target.Name, m.Index, c.Name, arg) + } else { + log.Printf("%d exit(%s->%s): %s %v", m.Code, m.Source.Name, m.Target.Name, c.Name, arg) + } if m.Target == c { - if m.Index == -1 { - log.Println(c.Name, c.Help, "exit: resource", m.Code, m.Source.Name, m.Source.Help) - if c.Server != nil { - c.Server.Exit(m, arg...) - log.Println(c.Name, c.Help, "exit: self", m.Code) - } - return - } - m.Index = -1 - for _, v := range c.Sessions { - if v.Name != "" { - v.Name = "" + if v.Target != c { v.Target.Exit(v, arg...) - log.Println(c.Name, c.Help, "exit: session", v.Code, v.Target.Name, v.Target.Help) } } - if c.Server != nil { - c.Server.Exit(m, arg...) - log.Println(c.Name, c.Help, "exit: self", m.Code) + if c.Server != nil && c.Server.Exit(m, arg...) { + if len(c.Sessions) == 0 && c.Context != nil { + delete(c.Context.contexts, c.Name) + } } for _, v := range c.Requests { - if v.Index != -1 { - v.Index = -1 + if v.Source != c { v.Source.Exit(v, arg...) - log.Println(c.Name, c.Help, "exit: resource", v.Code, v.Source.Name, v.Source.Help) } } } else if m.Source == c { - m.Name = "" - log.Println(c.Name, c.Help, "exit: session", m.Code, m.Target.Name, m.Target.Help) - if c.Server != nil { - c.Server.Exit(m, arg...) - log.Println(c.Name, c.Help, "exit: self", m.Code) + delete(c.Sessions, m.Name) + + if c.Server != nil && c.Server.Exit(m, arg...) { + if len(c.Sessions) == 0 && c.Context != nil { + delete(c.Context.contexts, c.Name) + } } } - } // }}} @@ -919,21 +422,577 @@ func (c *Context) Find(name string) (s *Context) { // {{{ cs = x.contexts s = x } else { + log.Println(c.Name, "not find:", name) + return nil panic(errors.New(c.Name + " not find: " + name)) } } - return + log.Println(c.Name, "find:", name) + return s } // }}} -var Pulse = &Message{Code: 1, Time: time.Now(), Index: 0, Target: Index, Master: Index, Source: Index, Name: "ctx"} +type Message struct { + Code int + Time time.Time + + Meta map[string][]string + Data map[string]interface{} + Wait chan bool + + Messages []*Message + Message *Message + Root *Message + + Name string + Source *Context + Target *Context + Index int + + Template *Message +} + +func (m *Message) Assert(e error) bool { // {{{ + if e != nil { + m.Set("result", "error:", fmt.Sprintln(e)) + + log.Println(m.Code, "error:", e) + if m.Conf("debug") == "on" { + fmt.Println(m.Code, "error:", e) + } + + panic(e) + } + return true +} + +// }}} +func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message)) *Message { // {{{ + defer func() { + if e := recover(); e != nil { + log.Println(msg.Target.Name, e) + if msg.Conf("debug") == "on" && e != io.EOF { + fmt.Println(msg.Target.Name, "error:", e) + debug.PrintStack() + } + + if e == io.EOF { + return + } + + if len(hand) > 1 { + m.AssertOne(msg, safe, hand[1:]...) + } else { + if !safe { + log.Println(msg.Target.Name, "error:", e) + panic(e) + } + } + } + // Pulse.Wait <- true + }() + + if len(hand) > 0 { + hand[0](msg) + } + + return m +} + +// }}} +func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{ + + msg := &Message{ + Time: time.Now(), + Message: m, + Root: m.Root, + Source: m.Target, + Target: c, + } + + if len(key) == 0 { + return msg + } + + msg.Code = m.Capi("nmessage", 1) + + if m.Messages == nil { + m.Messages = make([]*Message, 0, 10) + } + m.Messages = append(m.Messages, msg) + + if msg.Source.Sessions == nil { + msg.Source.Sessions = make(map[string]*Message) + } + msg.Source.Sessions[key[0]] = msg + msg.Name = key[0] + + log.Printf("%d spawn %d: %s.%s->%s.%d", m.Code, msg.Code, msg.Source.Name, msg.Name, msg.Target.Name, msg.Index) + return msg +} + +// }}} +func (m *Message) Reply(key ...string) *Message { // {{{ + if m.Template == nil { + return m.Spawn(m.Source, key...) + } + + msg := m.Template + msg.Time = time.Now() + if len(key) == 0 { + return msg + } + + msg.Code = m.Capi("nmessage", 1) + + if m.Messages == nil { + m.Messages = make([]*Message, 0, 10) + } + m.Messages = append(m.Messages, msg) + + if msg.Source.Sessions == nil { + msg.Source.Sessions = make(map[string]*Message) + } + msg.Source.Sessions[key[0]] = msg + msg.Name = key[0] + + log.Printf("%d spawn %d: %s.%s->%s.%d", m.Code, msg.Code, msg.Source.Name, msg.Name, msg.Target.Name, msg.Index) + return msg +} + +// }}} + +func (m *Message) Add(meta string, key string, value ...string) *Message { // {{{ + if m.Meta == nil { + m.Meta = make(map[string][]string) + } + if _, ok := m.Meta[meta]; !ok { + m.Meta[meta] = make([]string, 0, 3) + } + + switch meta { + case "detail", "result": + m.Meta[meta] = append(m.Meta[meta], key) + m.Meta[meta] = append(m.Meta[meta], value...) + case "option", "append": + if _, ok := m.Meta[key]; !ok { + m.Meta[meta] = append(m.Meta[meta], key) + m.Meta[key] = make([]string, 0, 3) + } + m.Meta[key] = append(m.Meta[key], value...) + default: + panic(errors.New("消息参数错误")) + } + + return m +} + +// }}} +func (m *Message) Set(meta string, arg ...string) *Message { // {{{ + if m.Meta == nil { + m.Meta = make(map[string][]string) + } + if len(arg) > 0 { + m.Meta[meta] = arg + } + return m +} + +// }}} +func (m *Message) Put(meta string, key string, value interface{}) *Message { // {{{ + if m.Meta == nil { + m.Meta = make(map[string][]string) + } + if m.Data == nil { + m.Data = make(map[string]interface{}) + } + + switch meta { + case "option", "append": + if _, ok := m.Meta[meta]; !ok { + m.Meta[meta] = make([]string, 0, 3) + } + if _, ok := m.Data[key]; !ok { + m.Meta[meta] = append(m.Meta[meta], key) + } + m.Data[key] = value + default: + panic(errors.New("消息参数错误")) + } + + return m +} + +// }}} +func (m *Message) Has(key string) bool { // {{{ + if _, ok := m.Meta[key]; ok { + return true + } + if _, ok := m.Data[key]; ok { + return true + } + return false +} + +// }}} +func (m *Message) Get(key string) string { // {{{ + if meta, ok := m.Meta[key]; ok { + if len(meta) > 0 { + return meta[0] + } + } + return "" +} + +// }}} +func (m *Message) Echo(str string, arg ...interface{}) *Message { // {{{ + if m.Meta == nil { + m.Meta = make(map[string][]string) + } + if _, ok := m.Meta["result"]; !ok { + m.Meta["result"] = make([]string, 0, 3) + } + + m.Meta["result"] = append(m.Meta["result"], fmt.Sprintf(str, arg...)) + return m +} + +// }}} +func (m *Message) End(s bool) { // {{{ + if m.Wait != nil { + m.Wait <- s + } + m.Wait = nil +} + +// }}} + +func (m *Message) Start(key string, arg ...string) bool { // {{{ + m.Set("detail", arg...) + m.Target.Spawn(m, key).Begin(m).Start(m) + return true +} + +// }}} +func (m *Message) Exec(arg ...string) string { // {{{ + + cs := []*Context{m.Target, m.Target.Master, m.Source, m.Source.Master} + for _, c := range cs { + if c == nil { + continue + } + for s := c; s != nil; s = s.Context { + if x, ok := s.Commands[arg[0]]; ok { + success := false + m.AssertOne(m, true, func(m *Message) { + if m.Code != 0 { + log.Printf("%d cmd(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Target.Name, m.Index, c.Name, arg) + } else { + log.Printf("%d cmd(%s->%s): %s %v", m.Code, m.Source.Name, m.Target.Name, c.Name, arg) + } + + if x.Options != nil { + for _, v := range m.Meta["option"] { + if _, ok := x.Options[v]; !ok { + panic(errors.New(fmt.Sprintf("未知参数:" + v))) + } + } + } + + if x.Formats != nil { + for i, args := 1, m.Meta["detail"]; i < len(args); i++ { + n, ok := x.Formats[args[i]] + if !ok { + m.Add("option", "args", arg[i]) + continue + } + + if n < 0 { + n += len(args) - i - 1 + } + + m.Add("option", args[i], arg[i+1:i+1+n]...) + i += n + } + } + + m.Meta["result"] = nil + ret := x.Hand(c, m, arg[0], arg[1:]...) + if ret != "" { + m.Echo(ret) + } + + if x.Appends != nil { + for _, v := range m.Meta["append"] { + if _, ok := x.Appends[v]; !ok { + panic(errors.New(fmt.Sprintf("未知参数:" + v))) + } + } + } + + success = true + }) + + return m.Get("result") + } + } + } + + m.AssertOne(m, true, func(m *Message) { + log.Printf("system command(%s->%s): %v", m.Source.Name, m.Target.Name, arg) + cmd := exec.Command(arg[0], arg[1:]...) + v, e := cmd.CombinedOutput() + if e != nil { + m.Echo("%s\n", e) + } else { + m.Echo(string(v)) + } + }) + return "" +} + +// }}} +func (m *Message) Check(s *Context, arg ...string) bool { // {{{ + return true + if s.Root.Owner == nil { + return true + } + if m.Source.Owner != nil { + log.Println("source:", m.Source.Name, m.Source.Owner.Name) + } + if s.Owner != nil { + log.Println("target:", s.Name, s.Owner.Name) + } + + if m.Source.Owner != s.Owner && m.Source.Owner != s.Root.Owner { + if len(arg) != 2 { + return false + } + + g, ok := s.Index[m.Source.Group] + if !ok { + if g, ok = s.Index["void"]; !ok { + return false + } + } + + switch arg[0] { + case "commands": + _, ok = g.Commands[arg[0]] + case "configs": + _, ok = g.Configs[arg[0]] + case "caches": + _, ok = g.Caches[arg[0]] + } + + if !ok { + return false + } + } + + return true +} + +// }}} +func (m *Message) Deal(pre func(msg *Message, arg ...string) bool, post func(msg *Message, arg ...string) bool) (live bool) { // {{{ + if m.Target.Messages == nil { + m.Target.Messages = make(chan *Message, m.Confi("MessageQueueSize")) + } + + msg := <-m.Target.Messages + defer msg.End(true) + + if len(msg.Meta["detail"]) == 0 { + return true + } + + if pre != nil && !pre(msg, msg.Meta["detail"]...) { + return false + } + + msg.Exec(msg.Meta["detail"]...) + + if post != nil && !post(msg, msg.Meta["result"]...) { + return false + } + + return true +} + +// }}} +func (m *Message) Post(s *Context) string { // {{{ + if s.Messages == nil { + panic(s.Name + " 没有开启消息处理") + } + + s.Messages <- m + if m.Wait != nil { + <-m.Wait + } + + return m.Get("result") +} + +// }}} + +func (m *Message) Cmd(arg ...string) string { // {{{ + m.Set("detail", arg...) + + if s := m.Target.Master; s != nil && s != m.Source.Master { + m.Post(s) + } + + return m.Exec(m.Meta["detail"]...) +} + +// }}} +func (m *Message) Conf(key string, arg ...string) string { // {{{ + for s := m.Target; s != nil; s = s.Context { + if !m.Check(s, "configs", key) { + panic(errors.New(fmt.Sprintf("没有权限:" + key))) + os.Exit(1) + } + + if x, ok := s.Configs[key]; ok { + switch len(arg) { + case 0: + if x.Hand != nil { + return x.Hand(m, x) + } + return x.Value + case 1: + if m.Code != 0 { + log.Printf("%d conf(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Target.Name, m.Index, key, arg) + } else { + log.Printf("%d conf(%s->%s): %s %v", m.Code, m.Source.Name, m.Target.Name, key, arg) + } + + x.Value = arg[0] + if x.Hand != nil { + x.Hand(m, x, x.Value) + } + return x.Value + case 3: + if m.Code != 0 { + log.Printf("%d conf(%s:%s->%s.%d): %s %v", m.Code, m.Source.Name, m.Name, m.Target.Name, m.Index, key, arg) + } else { + log.Printf("%d conf(%s->%s): %s %v", m.Code, m.Source.Name, m.Target.Name, key, arg) + } + + if s == m.Target { + panic(errors.New(key + "配置项已存在")) + } + if m.Target.Configs == nil { + m.Target.Configs = make(map[string]*Config) + } + m.Target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2], Hand: x.Hand} + return arg[1] + default: + panic(errors.New(key + "配置项参数错误")) + } + } + } + + if len(arg) == 3 { + log.Println(m.Target.Name, "conf:", key, arg) + if m.Target.Configs == nil { + m.Target.Configs = make(map[string]*Config) + } + m.Target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2]} + return arg[1] + } + + panic(errors.New(key + "配置项不存在")) +} + +// }}} +func (m *Message) Confi(key string, arg ...int) int { // {{{ + if len(arg) > 0 { + n, e := strconv.Atoi(m.Conf(key, fmt.Sprintf("%d", arg[0]))) + m.Assert(e) + return n + } + + n, e := strconv.Atoi(m.Conf(key)) + m.Assert(e) + return n +} + +// }}} +func (m *Message) Cap(key string, arg ...string) string { // {{{ + // if m.Code != 0 { + // log.Printf("%d cap(%s:%s->%s.%d): %s %v", m.Code, m.Context.Name, m.Name, m.Master.Name, m.Index, key, arg) + // } else { + // log.Printf("%d cap(%s->%s): %s %v", m.Code, m.Context.Name, m.Master.Name, key, arg) + // } + // + for s := m.Target; s != nil; s = s.Context { + if !m.Check(s, "caches", key) { + panic(errors.New(fmt.Sprintf("没有权限:" + key))) + } + + if x, ok := s.Caches[key]; ok { + switch len(arg) { + case 0: + if x.Hand != nil { + x.Value = x.Hand(m, x) + } + return x.Value + case 1: + if x.Hand != nil { + x.Value = x.Hand(m, x, arg[0]) + } else { + x.Value = arg[0] + } + return x.Value + case 3: + log.Println(m.Target.Name, "cap:", key, arg) + if s == m.Target { + panic(errors.New(key + "缓存项已存在")) + } + if m.Target.Caches == nil { + m.Target.Caches = make(map[string]*Cache) + } + m.Target.Caches[key] = &Cache{arg[0], arg[1], arg[2], x.Hand} + return arg[1] + default: + panic(errors.New(key + "缓存项参数错误")) + } + } + } + if len(arg) == 3 { + log.Println(m.Target.Name, "cap:", key, arg) + if m.Target.Caches == nil { + m.Target.Caches = make(map[string]*Cache) + } + m.Target.Caches[key] = &Cache{arg[0], arg[1], arg[2], nil} + return arg[1] + } + + panic(errors.New(key + "缓存项不存在")) +} + +// }}} +func (m *Message) Capi(key string, arg ...int) int { // {{{ + n, e := strconv.Atoi(m.Cap(key)) + m.Assert(e) + if len(arg) > 0 { + n += arg[0] + m.Cap(key, strconv.Itoa(n)) + } + return n +} + +// }}} + +var Pulse = &Message{Code: 0, Time: time.Now(), Source: Index, Target: Index} var Index = &Context{Name: "ctx", Help: "根模块", Caches: map[string]*Cache{ "nserver": &Cache{Name: "服务数量", Value: "0", Help: "显示已经启动运行模块的数量"}, - "ncontext": &Cache{Name: "模块数量", Value: "1", Help: "显示功能树已经注册模块的数量"}, - "nmessage": &Cache{Name: "消息数量", Value: "1", Help: "显示模块启动时所创建消息的数量"}, + "ncontext": &Cache{Name: "模块数量", Value: "0", Help: "显示功能树已经注册模块的数量"}, + "nmessage": &Cache{Name: "消息数量", Value: "0", Help: "显示模块启动时所创建消息的数量"}, }, Configs: map[string]*Config{ "start": &Config{Name: "启动模块", Value: "cli", Help: "启动时自动运行的模块"}, @@ -943,6 +1002,7 @@ var Index = &Context{Name: "ctx", Help: "根模块", if e := os.MkdirAll(path.Dir(arg[0]), os.ModePerm); e == nil { if l, e := os.Create(x.Value); e == nil { log.SetOutput(l) + log.Println("\n\n") } } } @@ -975,15 +1035,167 @@ var Index = &Context{Name: "ctx", Help: "根模块", "ContextSessionSize": &Config{Name: "会话队列长度", Value: "10", Help: "每个模块可以启动其它模块的数量"}, "MessageQueueSize": &Config{Name: "消息队列长度", Value: "10", Help: "每个模块接收消息的队列长度"}, - "debug": &Config{Name: "调试模式(off/on)", Value: "off", Help: "是否打印错误信息,off:不打印,on:打印)"}, + "debug": &Config{Name: "调试模式(off/on)", Value: "on", Help: "是否打印错误信息,off:不打印,on:打印)"}, "cert": &Config{Name: "证书文件", Value: "etc/cert.pem", Help: "证书文件"}, "key": &Config{Name: "私钥文件", Value: "etc/key.pem", Help: "私钥文件"}, }, Commands: map[string]*Command{ - "show": &Command{Name: "输出简单的信息", Help: "建立远程连接", Hand: func(c *Context, m *Message, key string, arg ...string) string { - m.Echo("nserver: %s\n", m.Cap("nserver")) // {{{ - m.Echo("ncontext: %s\n", m.Cap("ncontext")) - m.Echo("nmessage: %s\n", m.Cap("nmessage")) + "userinfo": &Command{Name: "userinfo", Help: "查看模块的用户信息", Hand: func(c *Context, m *Message, key string, arg ...string) string { + target := m.Target // {{{ + defer func() { m.Target = target }() + + m.Target = target.Owner + if m.Target != nil { + m.Echo("%s %s\n", m.Cap("username"), m.Cap("group")) + } + return "" + // }}} + }}, + "server": &Command{Name: "server [start|exit|switch][args]", Help: "服务启动停止切换", Hand: func(c *Context, m *Message, key string, arg ...string) string { + switch len(arg) { // {{{ + case 0: + m.Target.Root.Travel(func(c *Context) bool { + if x, ok := c.Caches["status"]; ok { + m.Echo("%s(%s): %s\n", c.Name, x.Value, c.Help) + } + return true + }) + + default: + switch arg[0] { + case "start": + go m.Set("detail", arg[1:]...).Target.Start(m) + case "stop": + m.Set("detail", arg[1:]...).Target.Exit(m) + case "switch": + } + } + return "" + // }}} + }}, + "message": &Command{Name: "message", Help: "查看消息", Hand: func(c *Context, m *Message, key string, arg ...string) string { + ms := []*Message{m.Root} // {{{ + for i := 0; i < len(ms); i++ { + if ms[i].Code != 0 { + m.Echo("%d %s.%s -> %s.%d: %s %v\n", ms[i].Code, ms[i].Source.Name, ms[i].Name, ms[i].Target.Name, ms[i].Index, ms[i].Time.Format("15:04:05"), ms[i].Meta["detail"]) + } + ms = append(ms, ms[i].Messages...) + } + return "" + // }}} + }}, + "command": &Command{Name: "command [all] [key [name help]]", Help: "查看或修改命令", Hand: func(c *Context, m *Message, key string, arg ...string) string { + all := false // {{{ + if len(arg) > 0 && arg[0] == "all" { + arg = arg[1:] + all = true + } + + m.Target.BackTrace(func(s *Context) bool { + switch len(arg) { + case 0: + for k, v := range s.Commands { + m.Echo("%s: %s\n", k, v.Name) + } + case 1: + if v, ok := s.Commands[arg[0]]; ok { + m.Echo("%s\n%s\n", v.Name, v.Help) + } + case 3: + if v, ok := s.Commands[arg[0]]; ok { + v.Name = arg[1] + v.Help = arg[2] + m.Echo("%s\n%s\n", v.Name, v.Help) + } + return false + } + return all + }) + return "" + // }}} + }}, + "config": &Command{Name: "config [all] [[delete|void] key [value]|[name value help]]", Help: "删除、空值、查看、修改或添加配置", Hand: func(c *Context, m *Message, key string, arg ...string) string { + all := false // {{{ + if len(arg) > 0 && arg[0] == "all" { + arg = arg[1:] + all = true + } + + m.Target.BackTrace(func(s *Context) bool { + switch len(arg) { + case 0: + for k, v := range s.Configs { + m.Echo("%s(%s): %s\n", k, v.Value, v.Name) + } + case 1: + if v, ok := s.Configs[arg[0]]; ok { + m.Echo("%s: %s\n", v.Name, v.Help) + } + case 2: + if s != m.Target { + m.Echo("请到%s模块上下文中操作配置%v", s.Name, arg) + return false + } + + switch arg[0] { + case "void": + m.Conf(arg[1], "") + case "delete": + if _, ok := s.Configs[arg[1]]; ok { + delete(s.Configs, arg[1]) + } + default: + m.Conf(arg[0], arg[1]) + } + case 4: + m.Conf(arg[0], arg[1:]...) + return false + } + return all + }) + return "" + // }}} + }}, + "cache": &Command{Name: "cache [all] [[delete] key [value]|[name value help]]", Help: "删除、查看、修改或添加配置", Hand: func(c *Context, m *Message, key string, arg ...string) string { + all := false // {{{ + if len(arg) > 0 && arg[0] == "all" { + arg = arg[1:] + all = true + } + + m.Target.BackTrace(func(s *Context) bool { + switch len(arg) { + case 0: + for k, v := range s.Caches { + m.Echo("%s(%s): %s\n", k, v.Value, v.Name) + } + case 1: + if v, ok := s.Caches[arg[0]]; ok { + m.Echo("%s: %s\n", v.Name, v.Help) + } + case 2: + if s != m.Target { + m.Echo("请到%s模块上下文中操作缓存%v", s.Name, arg) + return false + } + + switch arg[0] { + case "delete": + if _, ok := s.Caches[arg[1]]; ok { + delete(s.Caches, arg[1]) + } + default: + if _, ok := s.Caches[arg[0]]; ok { + m.Echo("%s: %s\n", arg[0], m.Cap(arg[0], arg[1])) + } + } + case 4: + m.Cap(arg[0], arg[1:]...) + return false + } + + return all + }) return "" // }}} }}, @@ -993,8 +1205,6 @@ var Index = &Context{Name: "ctx", Help: "根模块", func init() { Pulse.Root = Pulse Pulse.Wait = make(chan bool, 10) - Index.Requests = []*Message{Pulse} - Index.Sessions = map[string]*Message{"root": Pulse} } func Start(args ...string) { @@ -1016,7 +1226,6 @@ func Start(args ...string) { Index.Travel(func(s *Context) bool { Pulse.Target = s - s.Root = Index s.Begin(Pulse) return true }) @@ -1030,7 +1239,7 @@ func Start(args ...string) { } } - for n > 0 || Pulse.Capi("nserver", 0) > 0 { + for n > 0 || Pulse.Capi("nserver") > 0 { <-Pulse.Wait n-- }