From 52089121a8a507da583dd8210c9b0a202430a74b Mon Sep 17 00:00:00 2001 From: shaoying Date: Tue, 28 Nov 2017 21:32:27 +0800 Subject: [PATCH 1/3] =?UTF-8?q?mac=20add=20lex=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E8=AF=8D=E6=B3=95=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/init.sh | 16 +++++++++---- src/context/cli/cli.go | 52 ++++++++++++++++++++++++++++++++++++++---- src/context/ctx.go | 22 +++++++++++++----- src/example/bench.go | 3 +++ 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/etc/init.sh b/etc/init.sh index 39b23fa6..136d752b 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -1,8 +1,14 @@ -# @debug on -~aaa -# login root 94ca7394d007fa189cc4be0a2625d716 root +@debug on +~root aaa login root root +~root lex +server start +~root cli +@lex lex + +# login root 94ca7394d007fa189cc4be0a2625d716 root + # ~cli # remote slaver listen :9393 tcp @@ -10,8 +16,8 @@ login root root # login shy shy # userinfo add context hi hello nice # userinfo add command hi context -~web -listen +# ~web +# listen # ~demo # listen # ~home spawn test diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index b1fdf45b..5cb4167a 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -27,6 +27,7 @@ type CLI struct { next string exit bool login *ctx.Context + lex *ctx.Message target *ctx.Context *ctx.Context @@ -113,11 +114,24 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{ } back: + line = strings.TrimSpace(line) if line[0] == '#' { return true } ls := strings.Split(line, " ") + if cli.lex != nil { + cli.lex.Cmd("split", line) + ls = cli.lex.Meta["result"] + for i := 0; i < len(ls); i++ { + if ls[i][0] == '"' { + ls[i] = ls[i][1 : len(ls[i])-1] + } + } + if len(ls) == 0 { + return true + } + } msg := m.Spawn(cli.target) msg.Wait = make(chan bool) @@ -139,7 +153,9 @@ back: } for i := 0; i < len(ls); i++ { - ls[i] = strings.TrimSpace(ls[i]) + if cli.lex == nil { + ls[i] = strings.TrimSpace(ls[i]) + } if ls[i][0] == '#' { break @@ -181,6 +197,32 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ return x.Value }} + cli.Configs["lex"] = &ctx.Config{Name: "屏蔽脚本输出(yes/no)", Value: "", Help: "屏蔽脚本输出的信息,yes:屏蔽,no:不屏蔽", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { + if len(arg) > 0 { + cli, ok := m.Target.Server.(*CLI) + if !ok { + return "" + } + cli.lex = m.Find(arg[0], m.Target.Root) + if cli.lex == nil { + return "" + } + + cli.lex.Target.Start(cli.lex) + cli.lex.Cmd("train", "[ \n\t]+", "1") + + cli.lex.Cmd("train", "[a-zA-Z][a-zA-Z0-9]*", "2", "2") + + cli.lex.Cmd("train", "0x[0-9]+", "3", "2") + cli.lex.Cmd("train", "[0-9]+", "3", "2") + + cli.lex.Cmd("train", "\"[^\"]*\"", "4", "2") + cli.lex.Cmd("train", "'[^']*'", "4", "2") + + cli.lex.Cmd("train", "[~!@#$&*:]", "4", "2") + } + return "" + }} 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 { @@ -353,7 +395,9 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", if s := m.Search(target, m.Get("args")); len(s) > 0 { ms = append(ms, s...) arg = arg[1:] + break } + fallthrough default: ms = append(ms, m.Spawn(target)) } @@ -361,11 +405,9 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", for _, v := range ms { switch { case m.Has("start"): - args := m.Meta["start"] - v.Start(arg[0], args[1:]...) + v.Start(arg[0], arg[1:]...) case m.Has("spawn"): - args := m.Meta["spawn"] - v.Target.Spawn(v, args[0]).Begin(v) + v.Target.Spawn(v, arg[0]).Begin(v) cli.target = v.Target case m.Has("switch"): cli.target = v.Target diff --git a/src/context/ctx.go b/src/context/ctx.go index 82818fed..5d605669 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -9,6 +9,7 @@ import ( // {{{ "os/exec" "path" "regexp" + "runtime" "runtime/debug" "strconv" "strings" @@ -689,10 +690,14 @@ func (m *Message) Search(c *Context, name string) []*Message { // {{{ } // }}} -func (m *Message) Find(name string) *Message { // {{{ +func (m *Message) Find(name string, begin ...*Context) *Message { // {{{ ns := strings.Split(name, ".") - cs := m.Target.contexts - old := m.Target.Name + target := m.Target + if len(begin) > 0 { + target = begin[0] + } + cs := target.contexts + old := target.Name for _, v := range ns { if x, ok := cs[v]; ok { @@ -788,8 +793,8 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ } m.AssertOne(m, true, func(m *Message) { - m.Log("system", ":%v", arg) - cmd := exec.Command(key, arg[1:]...) + m.Log("system", ": %s %v", key, arg) + cmd := exec.Command(key, arg...) v, e := cmd.CombinedOutput() if e != nil { m.Echo("%s\n", e) @@ -1137,6 +1142,7 @@ var Index = &Context{Name: "ctx", Help: "根模块", switch arg[0] { case "start": go m.Set("detail", arg[1:]...).Target.Start(m) + runtime.Gosched() case "stop": m.Set("detail", arg[1:]...).Target.Exit(m) case "switch": @@ -1305,11 +1311,15 @@ var Index = &Context{Name: "ctx", Help: "根模块", m.Target.BackTrace(func(s *Context) bool { switch len(arg) { case 0: + target := m.Target + m.Target = s for k, v := range s.Caches { if m.Check(m.Target, "caches", k) { - m.Echo("%s(%s): %s\n", k, v.Value, v.Name) + m.Echo("%s(%s): %s\n", k, m.Cap(k), v.Name) } } + m.Target = target + case 1: if v, ok := s.Caches[arg[0]]; ok { if m.Check(m.Target, "caches", arg[0]) { diff --git a/src/example/bench.go b/src/example/bench.go index 3c5889f5..757c011c 100644 --- a/src/example/bench.go +++ b/src/example/bench.go @@ -11,6 +11,9 @@ import ( _ "context/ssh" _ "context/web" + + _ "context/lex" + "os" ) From 0288417c241568d4c02e6c30c96568a2189e5036 Mon Sep 17 00:00:00 2001 From: shaoying Date: Fri, 1 Dec 2017 04:56:45 +0800 Subject: [PATCH 2/3] =?UTF-8?q?mac=20mod=20Server=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BA=86=E5=BE=88=E5=A4=9A=E7=BB=86=E8=8A=82=EF=BC=8C=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++ etc/init.sh | 25 ++- etc/lex.sh | 12 ++ src/context/cli/cli.go | 90 +++++----- src/context/ctx.go | 394 +++++++++++++++++++++-------------------- 5 files changed, 283 insertions(+), 250 deletions(-) create mode 100644 etc/lex.sh diff --git a/README.md b/README.md index 6a168aaf..6807b212 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,15 @@ context: 通过提供自由的模块,简洁的接口,动态的结构,让 * 权限树 * 消息树 +## 分支管理 +* 0.1 ctx cli +* 0.2 mdb tcp +* 0.3 aaa ssh +* 0.4 web nfs +* 0.5 lex yac + +## 终端管理 +* 寻址 指令 事件 函数 资源 +* 文件 进程 配置 框架 模块 +* 表示 会话 认证 搜索 交互 + diff --git a/etc/init.sh b/etc/init.sh index 136d752b..fed74915 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -1,16 +1,27 @@ -@debug on +# @debug on +# ~root aaa +# login root root +# + +source etc/lex.sh + +~root mdb +open chat chat "chat:chat@/chat" mysql + ~root aaa login root root -~root lex -server start -~root cli -@lex lex +# ~root +# $nserver +# # login root 94ca7394d007fa189cc4be0a2625d716 root -# ~cli -# remote slaver listen :9393 tcp +# ~root tcp +# listen ":9393" +# listen ":9394" +~root cli +remote slaver listen ":9393" tcp # ~aaa # login shy shy diff --git a/etc/lex.sh b/etc/lex.sh new file mode 100644 index 00000000..4e927176 --- /dev/null +++ b/etc/lex.sh @@ -0,0 +1,12 @@ +~root lex +server start +train [a-zA-Z][a-zA-Z0-9]* 2 2 +train 0x[0-9]+ 3 2 +train [0-9]+ 3 2 +train "[^"]*" 4 2 +train '[^']*' 4 2 +train [~!@#$&*:] 4 2 + +~root cli +@lex lex + diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index 5cb4167a..683d0149 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -47,7 +47,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 { if msg := m.Spawn(cli.Root).Find("aaa"); msg != nil { username := "" @@ -121,8 +121,9 @@ back: } ls := strings.Split(line, " ") if cli.lex != nil { - cli.lex.Cmd("split", line) - ls = cli.lex.Meta["result"] + msg := m.Spawn(cli.lex.Target) + msg.Cmd("split", line) + ls = msg.Meta["result"] for i := 0; i < len(ls); i++ { if ls[i][0] == '"' { ls[i] = ls[i][1 : len(ls[i])-1] @@ -190,6 +191,17 @@ func (cli *CLI) echo(str string, arg ...interface{}) { // {{{ // }}} +func (cli *CLI) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{ + c.Caches = map[string]*ctx.Cache{} + c.Configs = map[string]*ctx.Config{} + + c.Owner = nil + s := new(CLI) + s.Context = c + return s +} + +// }}} 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 { @@ -203,23 +215,13 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ if !ok { return "" } + cli.lex = m.Find(arg[0], m.Target.Root) if cli.lex == nil { return "" } - cli.lex.Target.Start(cli.lex) cli.lex.Cmd("train", "[ \n\t]+", "1") - - cli.lex.Cmd("train", "[a-zA-Z][a-zA-Z0-9]*", "2", "2") - - cli.lex.Cmd("train", "0x[0-9]+", "3", "2") - cli.lex.Cmd("train", "[0-9]+", "3", "2") - - cli.lex.Cmd("train", "\"[^\"]*\"", "4", "2") - cli.lex.Cmd("train", "'[^']*'", "4", "2") - - cli.lex.Cmd("train", "[~!@#$&*:]", "4", "2") } return "" }} @@ -328,18 +330,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ } // }}} -func (cli *CLI) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{ - c.Caches = map[string]*ctx.Cache{} - c.Configs = map[string]*ctx.Config{} - - c.Owner = nil - s := new(CLI) - s.Context = c - return s -} - -// }}} -func (cli *CLI) Exit(m *ctx.Message, arg ...string) bool { // {{{ +func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ switch cli.Context { case m.Source: return false @@ -359,8 +350,8 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", }, Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ - "context": &ctx.Command{Name: "context [root|back|home] [[find|search] name] [list|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, "list": 0, "show": 0, "switch": 0, "start": 0, "spawn": 0}, + "context": &ctx.Command{Name: "context [root|back|home] [[find|search] name] [list|show|spawn|start|switch|close][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, "list": 0, "show": 0, "close": 0, "switch": 0, "start": 0, "spawn": 0}, Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { cli, ok := m.Source.Server.(*CLI) // {{{ if !ok { @@ -384,15 +375,15 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", ms := []*ctx.Message{} switch { case m.Has("search"): - if s := m.Search(target, m.Get("search")); len(s) > 0 { + if s := m.Search(m.Get("search"), target); len(s) > 0 { ms = append(ms, s...) } case m.Has("find"): - if msg := m.Spawn(target).Find(m.Get("find")); msg != nil { + if msg := m.Find(m.Get("find"), target); msg != nil { ms = append(ms, msg) } case m.Has("args"): - if s := m.Search(target, m.Get("args")); len(s) > 0 { + if s := m.Search(m.Get("args"), target); len(s) > 0 { ms = append(ms, s...) arg = arg[1:] break @@ -404,13 +395,15 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", for _, v := range ms { switch { - case m.Has("start"): - v.Start(arg[0], arg[1:]...) case m.Has("spawn"): - v.Target.Spawn(v, arg[0]).Begin(v) + v.Target.Spawn(v, arg[0], arg[1]).Begin(v) cli.target = v.Target + case m.Has("start"): + v.Set("detail", arg...).Target.Start(v) case m.Has("switch"): cli.target = v.Target + case m.Has("close"): + v.Target.Close(v) case m.Has("show"): m.Echo("%s(%s): %s\n", v.Target.Name, v.Target.Owner.Name, v.Target.Help) if len(v.Target.Requests) > 0 { @@ -429,16 +422,18 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", } } case m.Has("list") || cli.target == v.Target: - m.Travel(v.Target, func(m *ctx.Message) bool { - if m.Target.Context != nil && m.Target != v.Target { - target := m.Target - m.Target = m.Target.Owner - if m.Target != nil && m.Check(m.Target, "caches", "username") && m.Check(m.Target, "caches", "group") { - m.Echo("%s: %s(%s) %s %s\n", target.Context.Name, target.Name, target.Help, m.Cap("username"), m.Cap("group")) - } else { - m.Echo("%s: %s(%s)\n", target.Context.Name, target.Name, target.Help) + m.Travel(v.Target, func(msg *ctx.Message) bool { + if msg.Target.Context != nil { + target := msg.Target + m.Echo("%s: %s(%s)", target.Context.Name, target.Name, target.Help) + + msg.Target = msg.Target.Owner + if msg.Target != nil && msg.Check(msg.Target, "caches", "username") && msg.Check(msg.Target, "caches", "group") { + m.Echo(" %s %s", msg.Cap("username"), msg.Cap("group")) } - m.Target = target + + m.Echo("\n") + msg.Target = target } return true }) @@ -527,12 +522,12 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", if m.Has("listen") { action = "listen" } - msg := m.Spawn(c.Root).Find(m.Get("args")) + msg := m.Find(m.Get("args"), m.Target.Root) if m.Has("master") { msg.Template = msg.Spawn(msg.Source).Add("option", "master") } - msg.Cmd(action, m.Get(action)) + msg.Cmd(action, m.Get(action), m.Get(action), action, m.Get(action)) return "" }}, @@ -540,7 +535,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", "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"]...) // {{{ + m.Start(fmt.Sprintf("PTS%d", m.Capi("nterm")), "管理终端", arg...) // {{{ return "" // }}} }}, @@ -550,7 +545,8 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端", Index: map[string]*ctx.Context{ "void": &ctx.Context{Name: "void", Commands: map[string]*ctx.Command{ - "open": &ctx.Command{}, + "context": &ctx.Command{}, + "open": &ctx.Command{}, }, }, }, diff --git a/src/context/ctx.go b/src/context/ctx.go index 5d605669..d7bae479 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -9,7 +9,6 @@ import ( // {{{ "os/exec" "path" "regexp" - "runtime" "runtime/debug" "strconv" "strings" @@ -18,23 +17,21 @@ 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 @@ -43,16 +40,13 @@ type Command struct { // {{{ Hand func(c *Context, m *Message, key string, arg ...string) string } -// }}} -type Server interface { // {{{ +type Server interface { + Spawn(c *Context, m *Message, arg ...string) Server 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 + Close(m *Message, arg ...string) bool } -// }}} - type Context struct { Name string Help string @@ -81,72 +75,28 @@ type Context struct { } func (c *Context) Register(s *Context, x Server) *Context { // {{{ - Index.Root = Index - if c.contexts == nil { c.contexts = make(map[string]*Context) } if x, ok := c.contexts[s.Name]; ok { - panic(errors.New(c.Name + " 上下文已存在" + x.Name)) + panic(errors.New(c.Name + "上下文中已存在模块:" + x.Name)) } - s.Server = x - s.Context = c c.contexts[s.Name] = s + s.Context = c + s.Server = x + + s.Root = Index 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 } // }}} -func (c *Context) Begin(m *Message) *Context { // {{{ - for k, x := range c.Configs { - if x.Hand != nil { - m.Conf(k, x.Value) - } - } - - if c.Server != nil { - c.Server.Begin(m, m.Meta["detail"]...) - } - - return c -} - -// }}} -func (c *Context) Start(m *Message) bool { // {{{ - - if _, ok := c.Caches["status"]; !ok { - c.Caches["status"] = &Cache{Name: "服务状态", Value: "stop", Help: "服务状态,start:正在运行,stop:未在运行"} - } - - if m.Cap("status") != "start" && c.Server != nil { - m.AssertOne(m, true, func(m *Message) { - m.Cap("status", "start") - defer m.Cap("status", "stop") - - m.Log("start", "%s: %d %v", c.Name, m.Root.Capi("nserver", 1), m.Meta["detail"]) - defer m.Root.Capi("nserver", -1) - defer m.Log("stop", "%s: %d %v", c.Name, m.Root.Capi("nserver"), m.Meta["detail"]) - - c.Requests = []*Message{m} - c.Server.Start(m, m.Meta["detail"]...) - }) - } - m.Root.Wait <- true - - return true -} - -// }}} -func (c *Context) Spawn(m *Message, key string) *Context { // {{{ - s := &Context{Name: key, Help: c.Help, Owner: m.Source.Owner} - m.Log("begin", "%s: %s", key, c.Help) +func (c *Context) Spawn(m *Message, name string, help string) *Context { // {{{ + s := &Context{Name: name, Help: help, Context: c, Owner: m.Source.Owner} + m.Log("spawn", "%s: %s", name, help) m.Target = s if m.Template != nil { m.Template.Source = s @@ -161,17 +111,62 @@ func (c *Context) Spawn(m *Message, key string) *Context { // {{{ } // }}} -func (c *Context) Exit(m *Message, arg ...string) { // {{{ - m.Log("exit", "%s: %v", c.Name, arg) +func (c *Context) Begin(m *Message) *Context { // {{{ + m.Log("begin", "%s: %d %v", c.Name, Pulse.Capi("ncontext", 1), m.Meta["detail"]) + for k, x := range c.Configs { + if x.Hand != nil { + m.Conf(k, x.Value) + } + } + + c.Requests = []*Message{m} + + if c.Server != nil { + c.Server.Begin(m, m.Meta["detail"]...) + } + + return c +} + +// }}} +func (c *Context) Start(m *Message) bool { // {{{ + if _, ok := c.Caches["status"]; !ok { + c.Caches["status"] = &Cache{Name: "服务状态(start/stop)", Value: "stop", Help: "服务状态,start:正在运行,stop:未在运行"} + } + + if m.Cap("status") != "start" && c.Server != nil { + running := make(chan bool) + go m.AssertOne(m, true, func(m *Message) { + m.Log(m.Cap("status", "start"), "%s: %d %v", c.Name, m.Root.Capi("nserver", 1), m.Meta["detail"]) + + running <- true + c.Requests = append(c.Requests, m) + if c.Server.Start(m, m.Meta["detail"]...) { + c.Close(m, m.Meta["detail"]...) + } + }) + <-running + } + + return true +} + +// }}} +func (c *Context) Close(m *Message, arg ...string) { // {{{ + if c.Server != nil && c.Server.Close(m, arg...) { + m.Log("close", "%s: %d %v", c.Name, m.Root.Capi("ncontext", -1)+1, arg) + delete(c.Context.contexts, c.Name) + } + return if m.Target == c { for _, v := range c.Sessions { if v.Target != c { - v.Target.Exit(v, arg...) + v.Target.Close(v, arg...) } } - if c.Server != nil && c.Server.Exit(m, arg...) { + if c.Server != nil && c.Server.Close(m, arg...) { if len(c.Sessions) == 0 && c.Context != nil { delete(c.Context.contexts, c.Name) } @@ -179,18 +174,22 @@ func (c *Context) Exit(m *Message, arg ...string) { // {{{ for _, v := range c.Requests { if v.Source != c { - v.Source.Exit(v, arg...) + v.Source.Close(v, arg...) } } } else if m.Source == c { delete(c.Sessions, m.Name) - if c.Server != nil && c.Server.Exit(m, arg...) { + if c.Server != nil && c.Server.Close(m, arg...) { if len(c.Sessions) == 0 && c.Context != nil { delete(c.Context.contexts, c.Name) } } } + + if len(c.Requests) == 0 { + m.Log(m.Cap("status", "stop"), "%s: %d %v", c.Name, m.Root.Capi("nserver", -1), m.Meta["detail"]) + } } // }}} @@ -369,16 +368,6 @@ func (c *Context) Del(arg ...string) { // {{{ // }}} -func (c *Context) BackTrace(hand func(s *Context) bool) { // {{{ - for cs := c; cs != nil; cs = cs.Context { - if !hand(cs) { - return - } - } -} - -// }}} - type Message struct { Code int Time time.Time @@ -403,24 +392,20 @@ type Message struct { func (m *Message) Log(action, str string, arg ...interface{}) { // {{{ color := 0 switch action { - case "check": + case "error", "check": color = 31 case "cmd": color = 32 case "conf": color = 33 - case "find": + case "search", "find", "spawn": color = 35 - case "search": - color = 35 - case "spawn": - color = 35 - case "begin": - color = 36 - case "start": - color = 36 - case "stop": + case "begin", "start", "close": color = 36 + case "debug": + if m.Conf("debug") != "on" { + return + } } if m.Name != "" { @@ -432,28 +417,31 @@ func (m *Message) Log(action, str string, arg ...interface{}) { // {{{ // }}} func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{ - switch e := e.(type) { - case error: - case string: - if e == "error:" { - if len(msg) > 0 { - panic(errors.New(msg[0])) - } - panic(errors.New("error")) + case bool: + if e { + return true + } + case string: + if e != "error:" { + return true + } + case error: + if e == nil { + return true } - return true default: return true } - m.Log("error", "error: %v", e) - m.Set("result", "error:", fmt.Sprintln(e)) - - if m.Conf("debug") == "on" { - fmt.Println(m.Code, "error:", e) + if len(msg) > 0 { + e = errors.New(msg[0]) + } + if _, ok := e.(error); !ok { + e = errors.New("error") } + m.Set("result", "error:", fmt.Sprintln(e)) panic(e) } @@ -461,27 +449,20 @@ func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{ func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message)) *Message { // {{{ defer func() { if e := recover(); e != nil { - if _, ok := e.(error); ok { - msg.Log("error", "error: %v", e) - if msg.Conf("debug") == "on" && e != io.EOF { - fmt.Println(msg.Target.Name, "error:", e) - debug.PrintStack() - } + msg.Log("error", "error: %v", 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 { + } else if len(hand) > 1 { m.AssertOne(msg, safe, hand[1:]...) - } else { - if !safe { - panic(e) - } + } else if !safe { + panic(e) } } - // Pulse.Wait <- true }() if len(hand) > 0 { @@ -493,7 +474,6 @@ func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message)) // }}} func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{ - msg := &Message{ Code: m.Capi("nmessage", 1), Time: time.Now(), @@ -659,16 +639,10 @@ func (m *Message) End(s bool) { // {{{ // }}} -func (m *Message) Travel(c *Context, hand func(m *Message) bool) { // {{{ +func (m *Message) BackTrace(hand func(m *Message) bool) { // {{{ target := m.Target - - cs := []*Context{c} - for i := 0; i < len(cs); i++ { - for _, v := range cs[i].contexts { - cs = append(cs, v) - } - m.Target = cs[i] - if m.Check(m.Target) && !hand(m) { + for cs := target; cs != nil; cs = cs.Context { + if m.Check(cs) && !hand(m) { break } } @@ -676,49 +650,74 @@ func (m *Message) Travel(c *Context, hand func(m *Message) bool) { // {{{ } // }}} -func (m *Message) Search(c *Context, name string) []*Message { // {{{ - ms := make([]*Message, 0, 3) +func (m *Message) Travel(c *Context, hand func(m *Message) bool) { // {{{ + target := m.Target - m.Travel(c, func(m *Message) bool { - if strings.Contains(m.Target.Name, name) || strings.Contains(m.Target.Help, name) { + cs := []*Context{c} + for i := 0; i < len(cs); i++ { + if m.Target = cs[i]; m.Check(cs[i]) && !hand(m) { + break + } + + for _, v := range cs[i].contexts { + cs = append(cs, v) + } + } + + m.Target = target +} + +// }}} +func (m *Message) Search(key string, begin ...*Context) []*Message { // {{{ + target := m.Target + if len(begin) > 0 { + target = begin[0] + } + + reg, e := regexp.Compile(key) + m.Assert(e) + + ms := make([]*Message, 0, 3) + m.Travel(target, func(m *Message) bool { + if reg.MatchString(m.Target.Name) || reg.FindString(m.Target.Help) != "" { + m.Log("search", "%s: %d match [%s]", m.Target.Name, len(ms)+1, key) ms = append(ms, m.Spawn(m.Target)) - m.Log("search", "%s: match [%s]", m.Target.Name, name) } return true }) + + for _, v := range ms { + v.Source = m.Target + } + return ms } // }}} func (m *Message) Find(name string, begin ...*Context) *Message { // {{{ - ns := strings.Split(name, ".") target := m.Target if len(begin) > 0 { target = begin[0] } - cs := target.contexts - old := target.Name - for _, v := range ns { + cs := target.contexts + for _, v := range strings.Split(name, ".") { if x, ok := cs[v]; ok { cs = x.contexts - m.Target = x + target = x } else { - m.Log("find", "%s: not find %s", m.Target.Name, v) + m.Log("find", "%s: not find %s", target.Name, v) return nil - panic(errors.New(m.Target.Name + " not find: " + v)) } } - m.Log("find", "%s: find %s", old, name) - return m + m.Log("find", "%s: find %s", m.Target.Name, name) + return m.Spawn(target) } // }}} -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) Start(name string, help string, arg ...string) bool { // {{{ + return m.Set("detail", arg...).Target.Spawn(m, name, help).Begin(m).Start(m) } // }}} @@ -730,7 +729,6 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{ } for s := c; s != nil; s = s.Context { if x, ok := s.Commands[key]; ok { - m.Master = s if !m.Check(s, "commands", key) { break } @@ -905,7 +903,16 @@ 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) + if s.Messages == nil { + panic(s.Name + " 没有开启消息处理") + } + + s.Messages <- m + if m.Wait != nil { + <-m.Wait + } + + return m.Get("result") } return m.Exec(m.Meta["detail"][0], m.Meta["detail"][1:]...) @@ -1036,8 +1043,6 @@ func (m *Message) Capi(key string, arg ...int) int { // {{{ // }}} -var Pulse = &Message{Code: 0, Time: time.Now(), Source: Index, Master: Index, Target: Index} - var Index = &Context{Name: "ctx", Help: "根模块", Caches: map[string]*Cache{ "nserver": &Cache{Name: "服务数量", Value: "0", Help: "显示已经启动运行模块的数量"}, @@ -1141,10 +1146,9 @@ var Index = &Context{Name: "ctx", Help: "根模块", default: switch arg[0] { case "start": - go m.Set("detail", arg[1:]...).Target.Start(m) - runtime.Gosched() + m.Set("detail", arg[1:]...).Target.Start(m) case "stop": - m.Set("detail", arg[1:]...).Target.Exit(m) + m.Set("detail", arg[1:]...).Target.Close(m) case "switch": } } @@ -1226,22 +1230,22 @@ var Index = &Context{Name: "ctx", Help: "根模块", all = true } - m.Target.BackTrace(func(s *Context) bool { + m.BackTrace(func(m *Message) bool { switch len(arg) { case 0: - for k, v := range s.Commands { + for k, v := range m.Target.Commands { if m.Check(m.Target, "commands", k) { m.Echo("%s: %s\n", k, v.Name) } } case 1: - if v, ok := s.Commands[arg[0]]; ok { + if v, ok := m.Target.Commands[arg[0]]; ok { if m.Check(m.Target, "commands", arg[0]) { m.Echo("%s\n%s\n", v.Name, v.Help) } } case 3: - if v, ok := s.Commands[arg[0]]; ok { + if v, ok := m.Target.Commands[arg[0]]; ok { if m.Check(m.Target, "commands", arg[0]) { v.Name = arg[1] v.Help = arg[2] @@ -1262,21 +1266,31 @@ var Index = &Context{Name: "ctx", Help: "根模块", switch len(arg) { case 0: - m.Target.BackTrace(func(s *Context) bool { - m.Echo("%s configs:\n", s.Name) - for k, v := range s.Configs { + m.BackTrace(func(m *Message) bool { + if all { + m.Echo("%s configs:\n", m.Target.Name) + } + for k, v := range m.Target.Configs { if m.Check(m.Target, "configs", k) { - m.Echo(" %s(%s): %s\n", k, v.Value, v.Name) + if all { + m.Echo(" ") + } + m.Echo("%s(%s): %s\n", k, v.Value, v.Name) } } return all }) case 1: - m.Target.BackTrace(func(s *Context) bool { - m.Echo("%s config:\n", s.Name) - if v, ok := s.Configs[arg[0]]; ok { + m.BackTrace(func(m *Message) bool { + if all { + m.Echo("%s config:\n", m.Target.Name) + } + if v, ok := m.Target.Configs[arg[0]]; ok { if m.Check(m.Target, "configs", arg[0]) { - m.Echo(" %s: %s\n", v.Name, v.Help) + if all { + m.Echo(" ") + } + m.Echo("%s: %s\n", v.Name, v.Help) } } return all @@ -1308,39 +1322,31 @@ var Index = &Context{Name: "ctx", Help: "根模块", all = true } - m.Target.BackTrace(func(s *Context) bool { + m.BackTrace(func(m *Message) bool { switch len(arg) { case 0: - target := m.Target - m.Target = s - for k, v := range s.Caches { + for k, v := range m.Target.Caches { if m.Check(m.Target, "caches", k) { m.Echo("%s(%s): %s\n", k, m.Cap(k), v.Name) } } - m.Target = target case 1: - if v, ok := s.Caches[arg[0]]; ok { + if v, ok := m.Target.Caches[arg[0]]; ok { if m.Check(m.Target, "caches", arg[0]) { 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 m.Check(m.Target, "caches", arg[1]) { - if _, ok := s.Caches[arg[1]]; ok { - delete(s.Caches, arg[1]) + if _, ok := m.Target.Caches[arg[1]]; ok { + delete(m.Target.Caches, arg[1]) } } default: - if _, ok := s.Caches[arg[0]]; ok { + if _, ok := m.Target.Caches[arg[0]]; ok { if m.Check(m.Target, "caches", arg[0]) { m.Echo("%s: %s\n", arg[0], m.Cap(arg[0], arg[1])) } @@ -1376,9 +1382,12 @@ var Index = &Context{Name: "ctx", Help: "根模块", }, } +var Pulse = &Message{Code: 0, Time: time.Now(), Source: Index, Master: Index, Target: Index} + func init() { - Pulse.Root = Pulse Pulse.Wait = make(chan bool, 10) + Pulse.Root = Pulse + Index.Root = Index } func Start(args ...string) { @@ -1397,23 +1406,16 @@ func Start(args ...string) { Pulse.Conf("root", args[3]) } - Pulse.Travel(Index, func(m *Message) bool { + for _, m := range Pulse.Search("") { m.Target.Begin(m) - return true - }) - Pulse.Target = Index + } - 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 _, m := range Pulse.Search(Pulse.Conf("start")) { + m.Put("option", "io", os.Stdout).Target.Start(m) + } - for n > 0 || Pulse.Capi("nserver") > 0 { - <-Pulse.Wait - n-- - } + <-Pulse.Wait + for Pulse.Capi("nserver") > 0 { + <-Pulse.Wait } } From 69d0e3d63aefa064ec02a28dae698eb29c7eecc8 Mon Sep 17 00:00:00 2001 From: shaoying Date: Fri, 1 Dec 2017 04:59:21 +0800 Subject: [PATCH 3/3] =?UTF-8?q?mac=20syn=200.1.0=20=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context/mdb/mdb.go | 137 ++++++++++++++++++--------------- src/context/tcp/tcp.go | 169 +++++++++++++++++++++-------------------- 2 files changed, 159 insertions(+), 147 deletions(-) diff --git a/src/context/mdb/mdb.go b/src/context/mdb/mdb.go index 7954369e..642469d2 100644 --- a/src/context/mdb/mdb.go +++ b/src/context/mdb/mdb.go @@ -6,50 +6,30 @@ import ( // {{{ "database/sql" _ "github.com/go-sql-driver/mysql" - "errors" "fmt" ) // }}} type MDB struct { - db *sql.DB + *sql.DB *ctx.Context } -func (mdb *MDB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ - return mdb -} - -// }}} -func (mdb *MDB) Start(m *ctx.Message, arg ...string) bool { // {{{ - if m.Conf("source") == "" || m.Conf("driver") == "" { - return true - } - - db, e := sql.Open(m.Conf("driver"), m.Conf("source")) - m.Assert(e) - mdb.db = db - - m.Log("info", "%s: open %s %s", mdb.Name, m.Conf("driver"), m.Conf("source")) - m.Capi("nsource", 1) - - return true -} - -// }}} func (mdb *MDB) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{ - c.Caches = map[string]*ctx.Cache{} - c.Configs = map[string]*ctx.Config{ - "source": &ctx.Config{Name: "source", Value: "", Help: "数据库参数"}, - "driver": &ctx.Config{Name: "driver", Value: "", Help: "数据库驱动"}, + c.Caches = map[string]*ctx.Cache{ + "source": &ctx.Cache{Name: "数据库参数", Value: "", Help: "数据库参数"}, + "driver": &ctx.Cache{Name: "数据库驱动", Value: "", Help: "数据库驱动"}, } + c.Configs = map[string]*ctx.Config{} if len(arg) > 0 { - m.Conf("source", arg[0]) - if len(arg) > 1 { - m.Conf("driver", arg[1]) - } + m.Cap("source", arg[0]) + } + if len(arg) > 1 { + m.Cap("driver", arg[1]) + } else { + m.Cap("driver", m.Conf("driver")) } s := new(MDB) @@ -58,52 +38,76 @@ func (mdb *MDB) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server } // }}} -func (mdb *MDB) Exit(m *ctx.Message, arg ...string) bool { // {{{ - if mdb.db != nil && m.Target == mdb.Context { - m.Log("info", "%s: close %s %s", mdb.Name, m.Conf("driver"), m.Conf("source")) - m.Capi("nsource", -1) - mdb.db.Close() - mdb.db = nil +func (mdb *MDB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ + return mdb +} + +// }}} +func (mdb *MDB) Start(m *ctx.Message, arg ...string) bool { // {{{ + if len(arg) > 0 { + m.Cap("source", arg[0]) + } + if len(arg) > 1 { + m.Cap("driver", arg[1]) + } else { + m.Cap("driver", m.Conf("driver")) } - return true + if m.Cap("source") == "" || m.Cap("driver") == "" { + return false + } + + db, e := sql.Open(m.Cap("driver"), m.Cap("source")) + m.Assert(e) + mdb.DB = db + + m.Log("info", "%s: %d open %s %s", mdb.Name, m.Capi("nsource", 1), m.Cap("driver"), m.Cap("source")) + return false +} + +// }}} +func (mdb *MDB) Close(m *ctx.Message, arg ...string) bool { // {{{ + if mdb.DB != nil && m.Target == mdb.Context { + m.Log("info", "%s: %d close %s %s", mdb.Name, m.Capi("nsource", -1)+1, m.Cap("driver"), m.Cap("source")) + mdb.DB.Close() + mdb.DB = nil + return true + } + + return false } // }}} var Index = &ctx.Context{Name: "mdb", Help: "内存数据库", Caches: map[string]*ctx.Cache{ - "nsource": &ctx.Cache{Name: "数据源数量", Value: "0", Help: "数据库连接的数量"}, + "nsource": &ctx.Cache{Name: "数据源数量", Value: "0", Help: "已打开数据库的数量"}, + }, + Configs: map[string]*ctx.Config{ + "driver": &ctx.Config{Name: "数据库驱动(mysql)", Value: "mysql", Help: "数据库驱动"}, }, - Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ - "open": &ctx.Command{Name: "open name [source [driver]]", Help: "打开数据库", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - m.Start(arg[0], arg[1:]...) // {{{ + "open": &ctx.Command{Name: "open name help [source [driver]]", Help: "打开数据库", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + m.Target = m.Master // {{{ + m.Start(arg[0], arg[1], arg[2:]...) return "" // }}} }}, - "exec": &ctx.Command{Name: "exec sql [arg]", Help: "执行SQL语句", - Appends: map[string]string{ - "LastInsertId": "最后插入元组的标识", - "RowsAffected": "修改元组的数量", - }, + "exec": &ctx.Command{Name: "exec sql [arg]", Help: "执行操作语句", + Appends: map[string]string{"LastInsertId": "最后插入元组的标识", "RowsAffected": "修改元组的数量"}, Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { mdb, ok := m.Target.Server.(*MDB) // {{{ - if !ok { - m.Assert(errors.New("目标模块类型错误")) - } - if len(arg) == 0 { - m.Assert(errors.New("缺少参数")) - } + m.Assert(ok, "目标模块类型错误") + m.Assert(len(arg) > 0, "缺少参数") + m.Assert(mdb.DB != nil, "数据库未打开") which := make([]interface{}, 0, len(arg)) for _, v := range arg[1:] { which = append(which, v) } - ret, e := mdb.db.Exec(arg[0], which...) + ret, e := mdb.Exec(arg[0], which...) m.Assert(e) - id, e := ret.LastInsertId() m.Assert(e) n, e := ret.RowsAffected() @@ -111,24 +115,22 @@ var Index = &ctx.Context{Name: "mdb", Help: "内存数据库", m.Add("append", "LastInsertId", fmt.Sprintf("%d", id)) m.Add("append", "RowsAffected", fmt.Sprintf("%d", n)) + m.Log("info", "%s: last(%d) rows(%d)", m.Target.Name, id, n) return "" // }}} }}, - "query": &ctx.Command{Name: "query sql [arg]", Help: "执行SQL语句", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + "query": &ctx.Command{Name: "query sql [arg]", Help: "执行查询语句", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { mdb, ok := m.Target.Server.(*MDB) // {{{ - if !ok { - m.Assert(errors.New("目标模块类型错误")) - } - if len(arg) == 0 { - m.Assert(errors.New("缺少参数")) - } + m.Assert(ok, "目标模块类型错误") + m.Assert(len(arg) > 0, "缺少参数") + m.Assert(mdb.DB != nil, "数据库未打开") which := make([]interface{}, 0, len(arg)) for _, v := range arg[1:] { which = append(which, v) } - rows, e := mdb.db.Query(arg[0], which...) + rows, e := mdb.Query(arg[0], which...) m.Assert(e) defer rows.Close() @@ -150,10 +152,19 @@ var Index = &ctx.Context{Name: "mdb", Help: "内存数据库", m.Add("append", k, string(b)) case int64: m.Add("append", k, fmt.Sprintf("%d", b)) + default: + m.Add("append", k, "") } } } + m.Log("info", "%s: cols(%d) rows(%d)", m.Target.Name, len(m.Meta["append"]), len(m.Meta[m.Meta["append"][0]])) + return "" + // }}} + }}, + "close": &ctx.Command{Name: "close name", Help: "关闭数据库", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + msg := m.Find(arg[0], m.Master) // {{{ + msg.Target.Close(msg) return "" // }}} }}, diff --git a/src/context/tcp/tcp.go b/src/context/tcp/tcp.go index 313be38a..2b9b2187 100644 --- a/src/context/tcp/tcp.go +++ b/src/context/tcp/tcp.go @@ -2,69 +2,30 @@ package tcp // {{{ // }}} import ( // {{{ "context" - "log" + + "fmt" "net" + "strconv" ) // }}} type TCP struct { - l net.Listener - c net.Conn - close bool + net.Conn + net.Listener *ctx.Context } -func (tcp *TCP) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ - return tcp -} - -// }}} -func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool { // {{{ - if arg[0] == "dial" { - c, e := net.Dial(m.Conf("protocol"), m.Conf("address")) - m.Assert(e) - tcp.c = c - - log.Printf("%s dial(%d): %v->%v", tcp.Name, m.Capi("nclient", 1), c.LocalAddr(), c.RemoteAddr()) - m.Reply(c.LocalAddr().String()).Put("option", "io", c).Cmd("open") - return true - } - - l, e := net.Listen(m.Conf("protocol"), m.Conf("address")) - m.Assert(e) - tcp.l = l - - log.Printf("%s listen(%d): %v", tcp.Name, m.Capi("nlisten", 1), l.Addr()) - defer m.Capi("nlisten", -1) - defer log.Println("%s close(%d): %v", tcp.Name, m.Capi("nlisten"), l.Addr()) - - for { - c, e := l.Accept() - m.Assert(e) - log.Printf("%s accept(%d): %v<-%v", tcp.Name, m.Capi("nclient", 1), c.LocalAddr(), c.RemoteAddr()) - m.Reply(c.RemoteAddr().String()).Put("option", "io", c).Cmd("open") - } - - return true -} - -// }}} func (tcp *TCP) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{ - c.Caches = map[string]*ctx.Cache{} + c.Caches = map[string]*ctx.Cache{ + "protocol": &ctx.Cache{Name: "protocol(tcp/tcp4/tcp6)", Value: m.Conf("protocol"), Help: "监听地址"}, + "security": &ctx.Cache{Name: "security(true/false)", Value: m.Conf("security"), Help: "加密通信"}, + "address": &ctx.Cache{Name: "address", Value: arg[1], Help: "监听地址"}, + } c.Configs = map[string]*ctx.Config{} - if len(arg) > 1 { - switch arg[0] { - case "listen": - c.Caches["nclient"] = &ctx.Cache{Name: "nclient", Value: "0", Help: "连接数量"} - c.Configs["address"] = &ctx.Config{Name: "address", Value: arg[1], Help: "监听地址"} - case "dial": - c.Configs["address"] = &ctx.Config{Name: "address", Value: arg[1], Help: "连接地址"} - } - } if len(arg) > 2 { - c.Configs["security"] = &ctx.Config{Name: "security(true/false)", Value: "true", Help: "加密通信"} + m.Cap("security", arg[2]) } s := new(TCP) @@ -74,32 +35,65 @@ func (tcp *TCP) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server } // }}} -func (tcp *TCP) Exit(m *ctx.Message, arg ...string) bool { // {{{ - switch tcp.Context { - case m.Source: - c, ok := m.Data["io"].(net.Conn) - if !ok { - c = tcp.c - } - if c != nil { - log.Println(tcp.Name, "close:", c.LocalAddr(), "--", c.RemoteAddr()) - c.Close() - } +func (tcp *TCP) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ + return tcp +} - case m.Target: - if tcp.l != nil { - log.Println(tcp.Name, "close:", tcp.l.Addr()) - tcp.l.Close() - } - if tcp.c != nil { - log.Println(tcp.Name, "close:", tcp.c.LocalAddr(), "->", tcp.c.RemoteAddr()) - tcp.c.Close() +// }}} +func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool { // {{{ + switch arg[0] { + case "dial": + c, e := net.Dial(m.Cap("protocol"), m.Cap("address")) + m.Assert(e) + tcp.Conn = c + + m.Log("info", "%s: dial(%d) %v->%v", tcp.Name, m.Capi("nclient"), c.LocalAddr(), c.RemoteAddr()) + // m.Reply(c.LocalAddr().String()).Put("option", "io", c).Cmd("open") + return false + case "accept": + return false + } + + l, e := net.Listen(m.Cap("protocol"), m.Cap("address")) + m.Assert(e) + tcp.Listener = l + + m.Log("info", "%s: listen(%d) %v", tcp.Name, m.Capi("nlisten"), l.Addr()) + + for { + c, e := l.Accept() + m.Assert(e) + + msg := m.Spawn(tcp.Context.Context) + msg.Start(fmt.Sprintf("com%d", m.Capi("nclient", 1)), c.RemoteAddr().String(), "accept", c.RemoteAddr().String()) + msg.Log("info", "%s: accept(%d) %v<-%v", tcp.Name, m.Capi("nclient"), c.LocalAddr(), c.RemoteAddr()) + + if tcp, ok := msg.Target.Server.(*TCP); ok { + tcp.Conn = c } + rep := m.Reply(c.RemoteAddr().String()) + rep.Source = msg.Target + rep.Put("option", "io", c).Cmd("open") } return true } +// }}} +func (tcp *TCP) Close(m *ctx.Message, arg ...string) bool { // {{{ + if tcp.Listener != nil { + m.Log("info", "%s: close(%d) %v", tcp.Name, m.Capi("nlisten", -1)+1, tcp.Listener.Addr()) + tcp.Listener.Close() + return true + } + if tcp.Conn != nil { + tcp.Conn.Close() + return true + } + + return false +} + // }}} var Index = &ctx.Context{Name: "tcp", Help: "网络连接", @@ -116,13 +110,13 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络连接", switch len(arg) { // {{{ case 0: m.Travel(m.Target, func(m *ctx.Message) bool { - if tcp, ok := m.Target.Server.(*TCP); ok && tcp.l != nil { - m.Echo("%s %v\n", m.Target.Name, tcp.l.Addr()) + if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Listener != nil { + m.Echo("%s %v\n", m.Target.Name, tcp.Addr()) } return true }) - case 1: - go m.Start(arg[0], m.Meta["detail"]...) + default: + m.Start(fmt.Sprintf("pub%d", m.Capi("nlisten", 1)), arg[0], m.Meta["detail"]...) } return "" // }}} @@ -131,26 +125,32 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络连接", switch len(arg) { // {{{ case 0: m.Travel(m.Target, func(m *ctx.Message) bool { - if tcp, ok := m.Target.Server.(*TCP); ok && tcp.c != nil { - m.Echo("%s %v->%v\n", m.Target.Name, tcp.c.LocalAddr(), tcp.c.RemoteAddr()) + if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Conn != nil { + m.Echo("%s %v<->%v\n", m.Target.Name, tcp.LocalAddr(), tcp.RemoteAddr()) } return true }) - case 1: - m.Start(arg[0], m.Meta["detail"]...) + default: + m.Start(fmt.Sprintf("com%d", m.Capi("nclient", 1)), arg[0], m.Meta["detail"]...) } return "" // }}} }}, - "exit": &ctx.Command{Name: "exit", Help: "退出", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { - tcp, ok := m.Target.Server.(*TCP) // {{{ - if !ok { - tcp, ok = m.Source.Server.(*TCP) + "send": &ctx.Command{Name: "send message", Help: "发送消息", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Conn != nil { // {{{ + tcp.Conn.Write([]byte(arg[0])) } - if ok { - tcp.Context.Exit(m) + return "" + // }}} + }}, + "recv": &ctx.Command{Name: "recv size", Help: "接收消息", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { + if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Conn != nil { // {{{ + size, e := strconv.Atoi(arg[0]) + m.Assert(e) + buf := make([]byte, size) + tcp.Conn.Read(buf) + return string(buf) } - return "" // }}} }}, @@ -159,6 +159,7 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络连接", "void": &ctx.Context{ Commands: map[string]*ctx.Command{ "listen": &ctx.Command{}, + "dial": &ctx.Command{}, }, }, },