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-- }