forked from x/ContextOS
Merge branch '0.3.0' into 0.4.0
This commit is contained in:
commit
dd2568959b
12
README.md
12
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
|
||||||
|
|
||||||
|
## 终端管理
|
||||||
|
* 寻址 指令 事件 函数 资源
|
||||||
|
* 文件 进程 配置 框架 模块
|
||||||
|
* 表示 会话 认证 搜索 交互
|
||||||
|
|
||||||
|
29
etc/init.sh
29
etc/init.sh
@ -1,17 +1,34 @@
|
|||||||
# @debug on
|
# @debug on
|
||||||
~aaa
|
# ~root aaa
|
||||||
# login root 94ca7394d007fa189cc4be0a2625d716 root
|
# login root root
|
||||||
|
#
|
||||||
|
|
||||||
|
source etc/lex.sh
|
||||||
|
|
||||||
|
~root mdb
|
||||||
|
open chat chat "chat:chat@/chat" mysql
|
||||||
|
|
||||||
|
~root aaa
|
||||||
login root root
|
login root root
|
||||||
|
|
||||||
# ~cli
|
# ~root
|
||||||
# remote slaver listen :9393 tcp
|
# $nserver
|
||||||
|
|
||||||
|
#
|
||||||
|
# login root 94ca7394d007fa189cc4be0a2625d716 root
|
||||||
|
|
||||||
|
# ~root tcp
|
||||||
|
# listen ":9393"
|
||||||
|
# listen ":9394"
|
||||||
|
~root cli
|
||||||
|
remote slaver listen ":9393" tcp
|
||||||
|
|
||||||
# ~aaa
|
# ~aaa
|
||||||
# login shy shy
|
# login shy shy
|
||||||
# userinfo add context hi hello nice
|
# userinfo add context hi hello nice
|
||||||
# userinfo add command hi context
|
# userinfo add command hi context
|
||||||
~web
|
# ~web
|
||||||
listen
|
# listen
|
||||||
# ~demo
|
# ~demo
|
||||||
# listen
|
# listen
|
||||||
# ~home spawn test
|
# ~home spawn test
|
||||||
|
12
etc/lex.sh
Normal file
12
etc/lex.sh
Normal file
@ -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
|
||||||
|
|
@ -27,79 +27,74 @@ func (aaa *AAA) session(meta string) string { // {{{
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
func (aaa *AAA) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
func (aaa *AAA) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server {
|
||||||
return aaa
|
c.Caches = map[string]*ctx.Cache{}
|
||||||
}
|
c.Configs = map[string]*ctx.Config{}
|
||||||
|
|
||||||
// }}}
|
|
||||||
func (aaa *AAA) Start(m *ctx.Message, arg ...string) bool { // {{{
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
func (aaa *AAA) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{
|
|
||||||
c.Caches = map[string]*ctx.Cache{
|
|
||||||
"username": &ctx.Cache{Name: "用户名", Value: arg[0], Help: "用户名"},
|
|
||||||
"password": &ctx.Cache{Name: "密码", Value: "", Help: "用户密码,加密存储", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string {
|
|
||||||
if len(arg) > 0 { // {{{
|
|
||||||
if arg[0] == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if x.Value == "" {
|
|
||||||
bs := md5.Sum([]byte(fmt.Sprintln("用户密码:%s", arg[0])))
|
|
||||||
return hex.EncodeToString(bs[:])
|
|
||||||
} else {
|
|
||||||
bs := md5.Sum([]byte(fmt.Sprintln("用户密码:%s", arg[0])))
|
|
||||||
if x.Value != hex.EncodeToString(bs[:]) {
|
|
||||||
m.Log("info", "%s: login error", m.Target.Name)
|
|
||||||
panic("密码错误")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x.Value
|
|
||||||
// }}}
|
|
||||||
}},
|
|
||||||
"group": &ctx.Cache{Name: "群组", Value: arg[0], Help: "用户所属群组"},
|
|
||||||
"sessid": &ctx.Cache{Name: "会话标识", Value: aaa.session(arg[0]), Help: "用户的会话标识"},
|
|
||||||
"time": &ctx.Cache{Name: "登录时间", Value: fmt.Sprintf("%d", time.Now().Unix()), Help: "用户登录时间"},
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(arg) > 2 {
|
|
||||||
c.Caches["password"].Value = arg[1]
|
|
||||||
c.Caches["group"].Value = arg[2]
|
|
||||||
} else if len(arg) > 1 {
|
|
||||||
m.Cap("password", arg[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
s := new(AAA)
|
s := new(AAA)
|
||||||
s.Context = c
|
s.Context = c
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (aaa *AAA) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
||||||
|
aaa.Caches["group"] = &ctx.Cache{Name: "用户组", Value: m.Conf("rootname"), Help: "用户组"}
|
||||||
|
aaa.Caches["username"] = &ctx.Cache{Name: "用户名", Value: m.Conf("rootname"), Help: "用户名"}
|
||||||
|
aaa.Caches["password"] = &ctx.Cache{Name: "密码", Value: "", Help: "用户密码,加密存储", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string {
|
||||||
|
if len(arg) > 0 { // {{{
|
||||||
|
if x.Value == "" {
|
||||||
|
bs := md5.Sum([]byte(fmt.Sprintln("用户密码:%s", arg[0])))
|
||||||
|
return hex.EncodeToString(bs[:])
|
||||||
|
} else {
|
||||||
|
bs := md5.Sum([]byte(fmt.Sprintln("用户密码:%s", arg[0])))
|
||||||
|
if x.Value != hex.EncodeToString(bs[:]) {
|
||||||
|
m.Assert("error:", "密码错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x.Value
|
||||||
// }}}
|
// }}}
|
||||||
func (aaa *AAA) Exit(m *ctx.Message, arg ...string) bool { // {{{
|
}}
|
||||||
return true
|
aaa.Caches["sessid"] = &ctx.Cache{Name: "会话标识", Value: "", Help: "用户的会话标识"}
|
||||||
|
aaa.Caches["time"] = &ctx.Cache{Name: "登录时间", Value: "", Help: "用户登录时间"}
|
||||||
|
|
||||||
|
if len(arg) > 0 {
|
||||||
|
m.Cap("username", arg[0])
|
||||||
|
m.Cap("group", arg[0])
|
||||||
|
}
|
||||||
|
if len(arg) > 1 {
|
||||||
|
m.Cap("group", arg[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
return aaa
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aaa *AAA) Start(m *ctx.Message, arg ...string) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aaa *AAA) Close(m *ctx.Message, arg ...string) bool {
|
||||||
|
if m.Cap("username") != m.Conf("rootname") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
|
var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
|
||||||
Caches: map[string]*ctx.Cache{},
|
Caches: map[string]*ctx.Cache{
|
||||||
|
"nuser": &ctx.Cache{Name: "用户数量", Value: "0", Help: "用户数量"},
|
||||||
|
},
|
||||||
Configs: map[string]*ctx.Config{
|
Configs: map[string]*ctx.Config{
|
||||||
"rootname": &ctx.Config{Name: "根用户的名称", Value: "root", Help: "系统根据此名确定是否超级用户"},
|
"rootname": &ctx.Config{Name: "根用户名", Value: "root", Help: "根用户名"},
|
||||||
},
|
},
|
||||||
Commands: map[string]*ctx.Command{
|
Commands: map[string]*ctx.Command{
|
||||||
"login": &ctx.Command{Name: "login [sessid]|[username password [group]]]", Help: "", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
"login": &ctx.Command{Name: "login [sessid]|[[group] username password]]", Help: "", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
||||||
m.Target = m.Master
|
m.Master = m.Target
|
||||||
aaa := m.Target.Server.(*AAA) // {{{
|
aaa := m.Target.Server.(*AAA) // {{{
|
||||||
|
|
||||||
switch len(arg) {
|
switch len(arg) {
|
||||||
case 0:
|
case 0:
|
||||||
m.Travel(m.Target, func(m *ctx.Message) bool {
|
m.Travel(m.Target, func(m *ctx.Message) bool {
|
||||||
if m.Target.Name == "aaa" {
|
m.Echo("%s(%s): %s\n", m.Target.Name, m.Cap("group"), m.Cap("sessid"))
|
||||||
return true
|
|
||||||
}
|
|
||||||
m.Echo("%s %s %s\n", m.Target.Name, m.Cap("group"), m.Cap("sessid"))
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
case 1:
|
case 1:
|
||||||
@ -112,33 +107,40 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
|
|||||||
}
|
}
|
||||||
m.Target = target
|
m.Target = target
|
||||||
case 2:
|
case 2:
|
||||||
m.Master = aaa.Context
|
|
||||||
if m.Find(arg[0]) != nil {
|
|
||||||
m.Cap("password", arg[1])
|
|
||||||
m.Log("info", "%s: login", aaa.Name)
|
|
||||||
} else {
|
|
||||||
m.Start(arg[0], arg...)
|
|
||||||
aaa.sessions[m.Cap("sessid")] = m.Target
|
|
||||||
m.Log("info", "%s: logup %s", aaa.Name, m.Target.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
target := m.Target
|
|
||||||
if arg[0] == m.Conf("rootname") {
|
if arg[0] == m.Conf("rootname") {
|
||||||
|
m.Cap("password", arg[1])
|
||||||
|
m.Source.Owner = aaa.Context
|
||||||
m.Travel(m.Target.Root, func(m *ctx.Message) bool {
|
m.Travel(m.Target.Root, func(m *ctx.Message) bool {
|
||||||
if m.Target.Owner == nil {
|
if m.Target.Owner == nil {
|
||||||
m.Target.Owner = target
|
m.Target.Owner = aaa.Context
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Target.Owner = target
|
source := m.Source
|
||||||
m.Source.Owner = target
|
if msg := m.Find(arg[0]); msg == nil {
|
||||||
m.Source.Group = m.Cap("group")
|
m.Start(arg[0], arg[0], arg[0])
|
||||||
|
m.Cap("sessid", aaa.session(arg[0]))
|
||||||
|
m.Cap("time", fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
|
} else {
|
||||||
|
m = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Cap("password", arg[1])
|
||||||
|
m.Log("info", "%s: login", m.Target.Name)
|
||||||
|
aaa.sessions[m.Cap("sessid")] = m.Target
|
||||||
|
|
||||||
|
m.Target.Owner = m.Target
|
||||||
|
source.Owner = m.Target
|
||||||
|
source.Group = m.Cap("group")
|
||||||
|
|
||||||
|
m.Log("info", "%s: login", source.Name)
|
||||||
return m.Cap("sessid")
|
return m.Cap("sessid")
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
m.Start(arg[0], arg...)
|
m.Start(arg[0], arg[0], arg[0])
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
|
@ -27,6 +27,7 @@ type CLI struct {
|
|||||||
next string
|
next string
|
||||||
exit bool
|
exit bool
|
||||||
login *ctx.Context
|
login *ctx.Context
|
||||||
|
lex *ctx.Message
|
||||||
|
|
||||||
target *ctx.Context
|
target *ctx.Context
|
||||||
*ctx.Context
|
*ctx.Context
|
||||||
@ -46,7 +47,7 @@ func (cli *CLI) push(f io.ReadCloser) { // {{{
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (cli *CLI) parse(m *ctx.Message) bool { // {{{
|
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 {
|
if msg := m.Spawn(cli.Root).Find("aaa"); msg != nil {
|
||||||
|
|
||||||
username := ""
|
username := ""
|
||||||
@ -113,11 +114,25 @@ func (cli *CLI) parse(m *ctx.Message) bool { // {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
back:
|
back:
|
||||||
|
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
if line[0] == '#' {
|
if line[0] == '#' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
ls := strings.Split(line, " ")
|
ls := strings.Split(line, " ")
|
||||||
|
if cli.lex != nil {
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(ls) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
msg := m.Spawn(cli.target)
|
msg := m.Spawn(cli.target)
|
||||||
msg.Wait = make(chan bool)
|
msg.Wait = make(chan bool)
|
||||||
@ -139,7 +154,9 @@ back:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(ls); i++ {
|
for i := 0; i < len(ls); i++ {
|
||||||
|
if cli.lex == nil {
|
||||||
ls[i] = strings.TrimSpace(ls[i])
|
ls[i] = strings.TrimSpace(ls[i])
|
||||||
|
}
|
||||||
|
|
||||||
if ls[i][0] == '#' {
|
if ls[i][0] == '#' {
|
||||||
break
|
break
|
||||||
@ -174,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 { // {{{
|
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
cli.Caches["username"] = &ctx.Cache{Name: "登录用户", Value: "", Help: "登录用户名"}
|
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 {
|
cli.Caches["nhistory"] = &ctx.Cache{Name: "历史命令数量", Value: "0", Help: "当前终端已经执行命令的数量", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string {
|
||||||
@ -181,6 +209,22 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
|||||||
return x.Value
|
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.Cmd("train", "[ \n\t]+", "1")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}}
|
||||||
cli.Configs["slient"] = &ctx.Config{Name: "屏蔽脚本输出(yes/no)", Value: "yes", Help: "屏蔽脚本输出的信息,yes:屏蔽,no:不屏蔽"}
|
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["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.Configs["PS1"] = &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
|
||||||
@ -286,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 { // {{{
|
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
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 { // {{{
|
|
||||||
switch cli.Context {
|
switch cli.Context {
|
||||||
case m.Source:
|
case m.Source:
|
||||||
return false
|
return false
|
||||||
@ -317,8 +350,8 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端",
|
|||||||
},
|
},
|
||||||
Configs: map[string]*ctx.Config{},
|
Configs: map[string]*ctx.Config{},
|
||||||
Commands: map[string]*ctx.Command{
|
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:启动参数",
|
"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, "switch": 0, "start": 0, "spawn": 0},
|
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 {
|
Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
||||||
cli, ok := m.Source.Server.(*CLI) // {{{
|
cli, ok := m.Source.Server.(*CLI) // {{{
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -342,33 +375,35 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端",
|
|||||||
ms := []*ctx.Message{}
|
ms := []*ctx.Message{}
|
||||||
switch {
|
switch {
|
||||||
case m.Has("search"):
|
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...)
|
ms = append(ms, s...)
|
||||||
}
|
}
|
||||||
case m.Has("find"):
|
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)
|
ms = append(ms, msg)
|
||||||
}
|
}
|
||||||
case m.Has("args"):
|
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...)
|
ms = append(ms, s...)
|
||||||
arg = arg[1:]
|
arg = arg[1:]
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
fallthrough
|
||||||
default:
|
default:
|
||||||
ms = append(ms, m.Spawn(target))
|
ms = append(ms, m.Spawn(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range ms {
|
for _, v := range ms {
|
||||||
switch {
|
switch {
|
||||||
case m.Has("start"):
|
|
||||||
args := m.Meta["start"]
|
|
||||||
v.Start(arg[0], args[1:]...)
|
|
||||||
case m.Has("spawn"):
|
case m.Has("spawn"):
|
||||||
args := m.Meta["spawn"]
|
v.Target.Spawn(v, arg[0], arg[1]).Begin(v)
|
||||||
v.Target.Spawn(v, args[0]).Begin(v)
|
|
||||||
cli.target = v.Target
|
cli.target = v.Target
|
||||||
|
case m.Has("start"):
|
||||||
|
v.Set("detail", arg...).Target.Start(v)
|
||||||
case m.Has("switch"):
|
case m.Has("switch"):
|
||||||
cli.target = v.Target
|
cli.target = v.Target
|
||||||
|
case m.Has("close"):
|
||||||
|
v.Target.Close(v)
|
||||||
case m.Has("show"):
|
case m.Has("show"):
|
||||||
m.Echo("%s(%s): %s\n", v.Target.Name, v.Target.Owner.Name, v.Target.Help)
|
m.Echo("%s(%s): %s\n", v.Target.Name, v.Target.Owner.Name, v.Target.Help)
|
||||||
if len(v.Target.Requests) > 0 {
|
if len(v.Target.Requests) > 0 {
|
||||||
@ -387,16 +422,18 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端",
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case m.Has("list") || cli.target == v.Target:
|
case m.Has("list") || cli.target == v.Target:
|
||||||
m.Travel(v.Target, func(m *ctx.Message) bool {
|
m.Travel(v.Target, func(msg *ctx.Message) bool {
|
||||||
if m.Target.Context != nil && m.Target != v.Target {
|
if msg.Target.Context != nil {
|
||||||
target := m.Target
|
target := msg.Target
|
||||||
m.Target = m.Target.Owner
|
m.Echo("%s: %s(%s)", target.Context.Name, target.Name, target.Help)
|
||||||
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"))
|
msg.Target = msg.Target.Owner
|
||||||
} else {
|
if msg.Target != nil && msg.Check(msg.Target, "caches", "username") && msg.Check(msg.Target, "caches", "group") {
|
||||||
m.Echo("%s: %s(%s)\n", target.Context.Name, target.Name, target.Help)
|
m.Echo(" %s %s", msg.Cap("username"), msg.Cap("group"))
|
||||||
}
|
}
|
||||||
m.Target = target
|
|
||||||
|
m.Echo("\n")
|
||||||
|
msg.Target = target
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -485,12 +522,12 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端",
|
|||||||
if m.Has("listen") {
|
if m.Has("listen") {
|
||||||
action = "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") {
|
if m.Has("master") {
|
||||||
msg.Template = msg.Spawn(msg.Source).Add("option", "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 ""
|
return ""
|
||||||
}},
|
}},
|
||||||
@ -498,7 +535,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端",
|
|||||||
"open": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接",
|
"open": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接",
|
||||||
Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"},
|
Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"},
|
||||||
Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
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 ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
}},
|
}},
|
||||||
@ -508,6 +545,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理终端",
|
|||||||
Index: map[string]*ctx.Context{
|
Index: map[string]*ctx.Context{
|
||||||
"void": &ctx.Context{Name: "void",
|
"void": &ctx.Context{Name: "void",
|
||||||
Commands: map[string]*ctx.Command{
|
Commands: map[string]*ctx.Command{
|
||||||
|
"context": &ctx.Command{},
|
||||||
"open": &ctx.Command{},
|
"open": &ctx.Command{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -17,23 +17,21 @@ import ( // {{{
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
type Cache struct { // {{{
|
type Cache struct {
|
||||||
Name string
|
Name string
|
||||||
Value string
|
Value string
|
||||||
Help string
|
Help string
|
||||||
Hand func(m *Message, x *Cache, arg ...string) string
|
Hand func(m *Message, x *Cache, arg ...string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
type Config struct {
|
||||||
type Config struct { // {{{
|
|
||||||
Name string
|
Name string
|
||||||
Value string
|
Value string
|
||||||
Help string
|
Help string
|
||||||
Hand func(m *Message, x *Config, arg ...string) string
|
Hand func(m *Message, x *Config, arg ...string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
type Command struct {
|
||||||
type Command struct { // {{{
|
|
||||||
Name string
|
Name string
|
||||||
Help string
|
Help string
|
||||||
Formats map[string]int
|
Formats map[string]int
|
||||||
@ -42,16 +40,13 @@ type Command struct { // {{{
|
|||||||
Hand func(c *Context, m *Message, key string, arg ...string) string
|
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
|
Begin(m *Message, arg ...string) Server
|
||||||
Start(m *Message, arg ...string) bool
|
Start(m *Message, arg ...string) bool
|
||||||
Spawn(c *Context, m *Message, arg ...string) Server
|
Close(m *Message, arg ...string) bool
|
||||||
Exit(m *Message, arg ...string) bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Name string
|
Name string
|
||||||
Help string
|
Help string
|
||||||
@ -80,72 +75,28 @@ type Context struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) Register(s *Context, x Server) *Context { // {{{
|
func (c *Context) Register(s *Context, x Server) *Context { // {{{
|
||||||
Index.Root = Index
|
|
||||||
|
|
||||||
if c.contexts == nil {
|
if c.contexts == nil {
|
||||||
c.contexts = make(map[string]*Context)
|
c.contexts = make(map[string]*Context)
|
||||||
}
|
}
|
||||||
if x, ok := c.contexts[s.Name]; ok {
|
if x, ok := c.contexts[s.Name]; ok {
|
||||||
panic(errors.New(c.Name + " 上下文已存在" + x.Name))
|
panic(errors.New(c.Name + "上下文中已存在模块:" + x.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Server = x
|
|
||||||
s.Context = c
|
|
||||||
c.contexts[s.Name] = s
|
c.contexts[s.Name] = s
|
||||||
|
s.Context = c
|
||||||
|
s.Server = x
|
||||||
|
|
||||||
|
s.Root = Index
|
||||||
if c.Root != nil {
|
if c.Root != nil {
|
||||||
s.Root = c.Root
|
s.Root = c.Root
|
||||||
} else {
|
|
||||||
s.Root = Index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Printf("%s sub(%d): %s", c.Name, Pulse.Capi("ncontext", 1), s.Name)
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (c *Context) Begin(m *Message) *Context { // {{{
|
func (c *Context) Spawn(m *Message, name string, help string) *Context { // {{{
|
||||||
for k, x := range c.Configs {
|
s := &Context{Name: name, Help: help, Context: c, Owner: m.Source.Owner}
|
||||||
if x.Hand != nil {
|
m.Log("spawn", "%s: %s", name, help)
|
||||||
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)
|
|
||||||
m.Target = s
|
m.Target = s
|
||||||
if m.Template != nil {
|
if m.Template != nil {
|
||||||
m.Template.Source = s
|
m.Template.Source = s
|
||||||
@ -160,17 +111,62 @@ func (c *Context) Spawn(m *Message, key string) *Context { // {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (c *Context) Exit(m *Message, arg ...string) { // {{{
|
func (c *Context) Begin(m *Message) *Context { // {{{
|
||||||
m.Log("exit", "%s: %v", c.Name, arg)
|
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 {
|
if m.Target == c {
|
||||||
for _, v := range c.Sessions {
|
for _, v := range c.Sessions {
|
||||||
if v.Target != c {
|
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 {
|
if len(c.Sessions) == 0 && c.Context != nil {
|
||||||
delete(c.Context.contexts, c.Name)
|
delete(c.Context.contexts, c.Name)
|
||||||
}
|
}
|
||||||
@ -178,18 +174,22 @@ func (c *Context) Exit(m *Message, arg ...string) { // {{{
|
|||||||
|
|
||||||
for _, v := range c.Requests {
|
for _, v := range c.Requests {
|
||||||
if v.Source != c {
|
if v.Source != c {
|
||||||
v.Source.Exit(v, arg...)
|
v.Source.Close(v, arg...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if m.Source == c {
|
} else if m.Source == c {
|
||||||
delete(c.Sessions, m.Name)
|
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 {
|
if len(c.Sessions) == 0 && c.Context != nil {
|
||||||
delete(c.Context.contexts, c.Name)
|
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"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
@ -368,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 {
|
type Message struct {
|
||||||
Code int
|
Code int
|
||||||
Time time.Time
|
Time time.Time
|
||||||
@ -402,24 +392,20 @@ type Message struct {
|
|||||||
func (m *Message) Log(action, str string, arg ...interface{}) { // {{{
|
func (m *Message) Log(action, str string, arg ...interface{}) { // {{{
|
||||||
color := 0
|
color := 0
|
||||||
switch action {
|
switch action {
|
||||||
case "check":
|
case "error", "check":
|
||||||
color = 31
|
color = 31
|
||||||
case "cmd":
|
case "cmd":
|
||||||
color = 32
|
color = 32
|
||||||
case "conf":
|
case "conf":
|
||||||
color = 33
|
color = 33
|
||||||
case "find":
|
case "search", "find", "spawn":
|
||||||
color = 35
|
color = 35
|
||||||
case "search":
|
case "begin", "start", "close":
|
||||||
color = 35
|
|
||||||
case "spawn":
|
|
||||||
color = 35
|
|
||||||
case "begin":
|
|
||||||
color = 36
|
|
||||||
case "start":
|
|
||||||
color = 36
|
|
||||||
case "stop":
|
|
||||||
color = 36
|
color = 36
|
||||||
|
case "debug":
|
||||||
|
if m.Conf("debug") != "on" {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Name != "" {
|
if m.Name != "" {
|
||||||
@ -431,28 +417,31 @@ func (m *Message) Log(action, str string, arg ...interface{}) { // {{{
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{
|
func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{
|
||||||
|
|
||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
case error:
|
case bool:
|
||||||
case string:
|
if e {
|
||||||
if e == "error:" {
|
|
||||||
if len(msg) > 0 {
|
|
||||||
panic(errors.New(msg[0]))
|
|
||||||
}
|
|
||||||
panic(errors.New("error"))
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if e != "error:" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case error:
|
||||||
|
if e == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Log("error", "error: %v", e)
|
if len(msg) > 0 {
|
||||||
m.Set("result", "error:", fmt.Sprintln(e))
|
e = errors.New(msg[0])
|
||||||
|
}
|
||||||
if m.Conf("debug") == "on" {
|
if _, ok := e.(error); !ok {
|
||||||
fmt.Println(m.Code, "error:", e)
|
e = errors.New("error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.Set("result", "error:", fmt.Sprintln(e))
|
||||||
panic(e)
|
panic(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,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 { // {{{
|
func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message)) *Message { // {{{
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
if _, ok := e.(error); ok {
|
|
||||||
msg.Log("error", "error: %v", e)
|
msg.Log("error", "error: %v", e)
|
||||||
if msg.Conf("debug") == "on" && e != io.EOF {
|
if msg.Conf("debug") == "on" && e != io.EOF {
|
||||||
fmt.Println(msg.Target.Name, "error:", e)
|
fmt.Println(msg.Target.Name, "error:", e)
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if e == io.EOF {
|
if e == io.EOF {
|
||||||
return
|
return
|
||||||
}
|
} else if len(hand) > 1 {
|
||||||
|
|
||||||
if len(hand) > 1 {
|
|
||||||
m.AssertOne(msg, safe, hand[1:]...)
|
m.AssertOne(msg, safe, hand[1:]...)
|
||||||
} else {
|
} else if !safe {
|
||||||
if !safe {
|
|
||||||
panic(e)
|
panic(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Pulse.Wait <- true
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if len(hand) > 0 {
|
if len(hand) > 0 {
|
||||||
@ -492,7 +474,6 @@ func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message))
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{
|
func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{
|
||||||
|
|
||||||
msg := &Message{
|
msg := &Message{
|
||||||
Code: m.Capi("nmessage", 1),
|
Code: m.Capi("nmessage", 1),
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
@ -658,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
|
target := m.Target
|
||||||
|
for cs := target; cs != nil; cs = cs.Context {
|
||||||
cs := []*Context{c}
|
if m.Check(cs) && !hand(m) {
|
||||||
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) {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,45 +650,74 @@ func (m *Message) Travel(c *Context, hand func(m *Message) bool) { // {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (m *Message) Search(c *Context, name string) []*Message { // {{{
|
func (m *Message) Travel(c *Context, hand func(m *Message) bool) { // {{{
|
||||||
ms := make([]*Message, 0, 3)
|
target := m.Target
|
||||||
|
|
||||||
m.Travel(c, func(m *Message) bool {
|
cs := []*Context{c}
|
||||||
if strings.Contains(m.Target.Name, name) || strings.Contains(m.Target.Help, name) {
|
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))
|
ms = append(ms, m.Spawn(m.Target))
|
||||||
m.Log("search", "%s: match [%s]", m.Target.Name, name)
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for _, v := range ms {
|
||||||
|
v.Source = m.Target
|
||||||
|
}
|
||||||
|
|
||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
func (m *Message) Find(name string) *Message { // {{{
|
func (m *Message) Find(name string, begin ...*Context) *Message { // {{{
|
||||||
ns := strings.Split(name, ".")
|
target := m.Target
|
||||||
cs := m.Target.contexts
|
if len(begin) > 0 {
|
||||||
old := m.Target.Name
|
target = begin[0]
|
||||||
|
}
|
||||||
|
|
||||||
for _, v := range ns {
|
cs := target.contexts
|
||||||
|
for _, v := range strings.Split(name, ".") {
|
||||||
if x, ok := cs[v]; ok {
|
if x, ok := cs[v]; ok {
|
||||||
cs = x.contexts
|
cs = x.contexts
|
||||||
m.Target = x
|
target = x
|
||||||
} else {
|
} else {
|
||||||
m.Log("find", "%s: not find %s", m.Target.Name, v)
|
m.Log("find", "%s: not find %s", target.Name, v)
|
||||||
return nil
|
return nil
|
||||||
panic(errors.New(m.Target.Name + " not find: " + v))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.Log("find", "%s: find %s", old, name)
|
m.Log("find", "%s: find %s", m.Target.Name, name)
|
||||||
return m
|
return m.Spawn(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
func (m *Message) Start(key string, arg ...string) bool { // {{{
|
func (m *Message) Start(name string, help string, arg ...string) bool { // {{{
|
||||||
m.Set("detail", arg...)
|
return m.Set("detail", arg...).Target.Spawn(m, name, help).Begin(m).Start(m)
|
||||||
m.Target.Spawn(m, key).Begin(m).Start(m)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
@ -725,7 +729,6 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{
|
|||||||
}
|
}
|
||||||
for s := c; s != nil; s = s.Context {
|
for s := c; s != nil; s = s.Context {
|
||||||
if x, ok := s.Commands[key]; ok {
|
if x, ok := s.Commands[key]; ok {
|
||||||
m.Master = s
|
|
||||||
if !m.Check(s, "commands", key) {
|
if !m.Check(s, "commands", key) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -788,8 +791,8 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.AssertOne(m, true, func(m *Message) {
|
m.AssertOne(m, true, func(m *Message) {
|
||||||
m.Log("system", ":%v", arg)
|
m.Log("system", ": %s %v", key, arg)
|
||||||
cmd := exec.Command(key, arg[1:]...)
|
cmd := exec.Command(key, arg...)
|
||||||
v, e := cmd.CombinedOutput()
|
v, e := cmd.CombinedOutput()
|
||||||
if e != nil {
|
if e != nil {
|
||||||
m.Echo("%s\n", e)
|
m.Echo("%s\n", e)
|
||||||
@ -900,7 +903,16 @@ func (m *Message) Cmd(arg ...string) string { // {{{
|
|||||||
m.Set("detail", arg...)
|
m.Set("detail", arg...)
|
||||||
|
|
||||||
if s := m.Target.Master; s != nil && s != m.Source.Master {
|
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:]...)
|
return m.Exec(m.Meta["detail"][0], m.Meta["detail"][1:]...)
|
||||||
@ -1031,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: "根模块",
|
var Index = &Context{Name: "ctx", Help: "根模块",
|
||||||
Caches: map[string]*Cache{
|
Caches: map[string]*Cache{
|
||||||
"nserver": &Cache{Name: "服务数量", Value: "0", Help: "显示已经启动运行模块的数量"},
|
"nserver": &Cache{Name: "服务数量", Value: "0", Help: "显示已经启动运行模块的数量"},
|
||||||
@ -1136,9 +1146,9 @@ var Index = &Context{Name: "ctx", Help: "根模块",
|
|||||||
default:
|
default:
|
||||||
switch arg[0] {
|
switch arg[0] {
|
||||||
case "start":
|
case "start":
|
||||||
go m.Set("detail", arg[1:]...).Target.Start(m)
|
m.Set("detail", arg[1:]...).Target.Start(m)
|
||||||
case "stop":
|
case "stop":
|
||||||
m.Set("detail", arg[1:]...).Target.Exit(m)
|
m.Set("detail", arg[1:]...).Target.Close(m)
|
||||||
case "switch":
|
case "switch":
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1220,22 +1230,22 @@ var Index = &Context{Name: "ctx", Help: "根模块",
|
|||||||
all = true
|
all = true
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Target.BackTrace(func(s *Context) bool {
|
m.BackTrace(func(m *Message) bool {
|
||||||
switch len(arg) {
|
switch len(arg) {
|
||||||
case 0:
|
case 0:
|
||||||
for k, v := range s.Commands {
|
for k, v := range m.Target.Commands {
|
||||||
if m.Check(m.Target, "commands", k) {
|
if m.Check(m.Target, "commands", k) {
|
||||||
m.Echo("%s: %s\n", k, v.Name)
|
m.Echo("%s: %s\n", k, v.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
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]) {
|
if m.Check(m.Target, "commands", arg[0]) {
|
||||||
m.Echo("%s\n%s\n", v.Name, v.Help)
|
m.Echo("%s\n%s\n", v.Name, v.Help)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 3:
|
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]) {
|
if m.Check(m.Target, "commands", arg[0]) {
|
||||||
v.Name = arg[1]
|
v.Name = arg[1]
|
||||||
v.Help = arg[2]
|
v.Help = arg[2]
|
||||||
@ -1256,20 +1266,30 @@ var Index = &Context{Name: "ctx", Help: "根模块",
|
|||||||
|
|
||||||
switch len(arg) {
|
switch len(arg) {
|
||||||
case 0:
|
case 0:
|
||||||
m.Target.BackTrace(func(s *Context) bool {
|
m.BackTrace(func(m *Message) bool {
|
||||||
m.Echo("%s configs:\n", s.Name)
|
if all {
|
||||||
for k, v := range s.Configs {
|
m.Echo("%s configs:\n", m.Target.Name)
|
||||||
|
}
|
||||||
|
for k, v := range m.Target.Configs {
|
||||||
if m.Check(m.Target, "configs", k) {
|
if m.Check(m.Target, "configs", k) {
|
||||||
|
if all {
|
||||||
|
m.Echo(" ")
|
||||||
|
}
|
||||||
m.Echo("%s(%s): %s\n", k, v.Value, v.Name)
|
m.Echo("%s(%s): %s\n", k, v.Value, v.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return all
|
return all
|
||||||
})
|
})
|
||||||
case 1:
|
case 1:
|
||||||
m.Target.BackTrace(func(s *Context) bool {
|
m.BackTrace(func(m *Message) bool {
|
||||||
m.Echo("%s config:\n", s.Name)
|
if all {
|
||||||
if v, ok := s.Configs[arg[0]]; ok {
|
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]) {
|
if m.Check(m.Target, "configs", arg[0]) {
|
||||||
|
if all {
|
||||||
|
m.Echo(" ")
|
||||||
|
}
|
||||||
m.Echo("%s: %s\n", v.Name, v.Help)
|
m.Echo("%s: %s\n", v.Name, v.Help)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1302,35 +1322,31 @@ var Index = &Context{Name: "ctx", Help: "根模块",
|
|||||||
all = true
|
all = true
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Target.BackTrace(func(s *Context) bool {
|
m.BackTrace(func(m *Message) bool {
|
||||||
switch len(arg) {
|
switch len(arg) {
|
||||||
case 0:
|
case 0:
|
||||||
for k, v := range s.Caches {
|
for k, v := range m.Target.Caches {
|
||||||
if m.Check(m.Target, "caches", k) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1:
|
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]) {
|
if m.Check(m.Target, "caches", arg[0]) {
|
||||||
m.Echo("%s: %s\n", v.Name, v.Help)
|
m.Echo("%s: %s\n", v.Name, v.Help)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
if s != m.Target {
|
|
||||||
m.Echo("请到%s模块上下文中操作缓存%v", s.Name, arg)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch arg[0] {
|
switch arg[0] {
|
||||||
case "delete":
|
case "delete":
|
||||||
if m.Check(m.Target, "caches", arg[1]) {
|
if m.Check(m.Target, "caches", arg[1]) {
|
||||||
if _, ok := s.Caches[arg[1]]; ok {
|
if _, ok := m.Target.Caches[arg[1]]; ok {
|
||||||
delete(s.Caches, arg[1])
|
delete(m.Target.Caches, arg[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if _, ok := s.Caches[arg[0]]; ok {
|
if _, ok := m.Target.Caches[arg[0]]; ok {
|
||||||
if m.Check(m.Target, "caches", arg[0]) {
|
if m.Check(m.Target, "caches", arg[0]) {
|
||||||
m.Echo("%s: %s\n", arg[0], m.Cap(arg[0], arg[1]))
|
m.Echo("%s: %s\n", arg[0], m.Cap(arg[0], arg[1]))
|
||||||
}
|
}
|
||||||
@ -1366,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() {
|
func init() {
|
||||||
Pulse.Root = Pulse
|
|
||||||
Pulse.Wait = make(chan bool, 10)
|
Pulse.Wait = make(chan bool, 10)
|
||||||
|
Pulse.Root = Pulse
|
||||||
|
Index.Root = Index
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(args ...string) {
|
func Start(args ...string) {
|
||||||
@ -1387,23 +1406,16 @@ func Start(args ...string) {
|
|||||||
Pulse.Conf("root", args[3])
|
Pulse.Conf("root", args[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
Pulse.Travel(Index, func(m *Message) bool {
|
for _, m := range Pulse.Search("") {
|
||||||
m.Target.Begin(m)
|
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 n > 0 || Pulse.Capi("nserver") > 0 {
|
for _, m := range Pulse.Search(Pulse.Conf("start")) {
|
||||||
|
m.Put("option", "io", os.Stdout).Target.Start(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
<-Pulse.Wait
|
||||||
|
for Pulse.Capi("nserver") > 0 {
|
||||||
<-Pulse.Wait
|
<-Pulse.Wait
|
||||||
n--
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,50 +6,30 @@ import ( // {{{
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
type MDB struct {
|
type MDB struct {
|
||||||
db *sql.DB
|
*sql.DB
|
||||||
*ctx.Context
|
*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 { // {{{
|
func (mdb *MDB) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
c.Caches = map[string]*ctx.Cache{}
|
c.Caches = map[string]*ctx.Cache{
|
||||||
c.Configs = map[string]*ctx.Config{
|
"source": &ctx.Cache{Name: "数据库参数", Value: "", Help: "数据库参数"},
|
||||||
"source": &ctx.Config{Name: "source", Value: "", Help: "数据库参数"},
|
"driver": &ctx.Cache{Name: "数据库驱动", Value: "", Help: "数据库驱动"},
|
||||||
"driver": &ctx.Config{Name: "driver", Value: "", Help: "数据库驱动"},
|
|
||||||
}
|
}
|
||||||
|
c.Configs = map[string]*ctx.Config{}
|
||||||
|
|
||||||
if len(arg) > 0 {
|
if len(arg) > 0 {
|
||||||
m.Conf("source", arg[0])
|
m.Cap("source", arg[0])
|
||||||
if len(arg) > 1 {
|
|
||||||
m.Conf("driver", arg[1])
|
|
||||||
}
|
}
|
||||||
|
if len(arg) > 1 {
|
||||||
|
m.Cap("driver", arg[1])
|
||||||
|
} else {
|
||||||
|
m.Cap("driver", m.Conf("driver"))
|
||||||
}
|
}
|
||||||
|
|
||||||
s := new(MDB)
|
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 { // {{{
|
func (mdb *MDB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
if mdb.db != nil && m.Target == mdb.Context {
|
return mdb
|
||||||
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) 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"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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 true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
var Index = &ctx.Context{Name: "mdb", Help: "内存数据库",
|
var Index = &ctx.Context{Name: "mdb", Help: "内存数据库",
|
||||||
Caches: map[string]*ctx.Cache{
|
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{
|
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 {
|
"open": &ctx.Command{Name: "open name help [source [driver]]", Help: "打开数据库", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
||||||
m.Start(arg[0], arg[1:]...) // {{{
|
m.Target = m.Master // {{{
|
||||||
|
m.Start(arg[0], arg[1], arg[2:]...)
|
||||||
return ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
}},
|
}},
|
||||||
"exec": &ctx.Command{Name: "exec sql [arg]", Help: "执行SQL语句",
|
"exec": &ctx.Command{Name: "exec sql [arg]", Help: "执行操作语句",
|
||||||
Appends: map[string]string{
|
Appends: map[string]string{"LastInsertId": "最后插入元组的标识", "RowsAffected": "修改元组的数量"},
|
||||||
"LastInsertId": "最后插入元组的标识",
|
|
||||||
"RowsAffected": "修改元组的数量",
|
|
||||||
},
|
|
||||||
Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
||||||
mdb, ok := m.Target.Server.(*MDB) // {{{
|
mdb, ok := m.Target.Server.(*MDB) // {{{
|
||||||
if !ok {
|
m.Assert(ok, "目标模块类型错误")
|
||||||
m.Assert(errors.New("目标模块类型错误"))
|
m.Assert(len(arg) > 0, "缺少参数")
|
||||||
}
|
m.Assert(mdb.DB != nil, "数据库未打开")
|
||||||
if len(arg) == 0 {
|
|
||||||
m.Assert(errors.New("缺少参数"))
|
|
||||||
}
|
|
||||||
|
|
||||||
which := make([]interface{}, 0, len(arg))
|
which := make([]interface{}, 0, len(arg))
|
||||||
for _, v := range arg[1:] {
|
for _, v := range arg[1:] {
|
||||||
which = append(which, v)
|
which = append(which, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, e := mdb.db.Exec(arg[0], which...)
|
ret, e := mdb.Exec(arg[0], which...)
|
||||||
m.Assert(e)
|
m.Assert(e)
|
||||||
|
|
||||||
id, e := ret.LastInsertId()
|
id, e := ret.LastInsertId()
|
||||||
m.Assert(e)
|
m.Assert(e)
|
||||||
n, e := ret.RowsAffected()
|
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", "LastInsertId", fmt.Sprintf("%d", id))
|
||||||
m.Add("append", "RowsAffected", fmt.Sprintf("%d", n))
|
m.Add("append", "RowsAffected", fmt.Sprintf("%d", n))
|
||||||
|
m.Log("info", "%s: last(%d) rows(%d)", m.Target.Name, id, n)
|
||||||
return ""
|
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) // {{{
|
mdb, ok := m.Target.Server.(*MDB) // {{{
|
||||||
if !ok {
|
m.Assert(ok, "目标模块类型错误")
|
||||||
m.Assert(errors.New("目标模块类型错误"))
|
m.Assert(len(arg) > 0, "缺少参数")
|
||||||
}
|
m.Assert(mdb.DB != nil, "数据库未打开")
|
||||||
if len(arg) == 0 {
|
|
||||||
m.Assert(errors.New("缺少参数"))
|
|
||||||
}
|
|
||||||
|
|
||||||
which := make([]interface{}, 0, len(arg))
|
which := make([]interface{}, 0, len(arg))
|
||||||
for _, v := range arg[1:] {
|
for _, v := range arg[1:] {
|
||||||
which = append(which, v)
|
which = append(which, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, e := mdb.db.Query(arg[0], which...)
|
rows, e := mdb.Query(arg[0], which...)
|
||||||
m.Assert(e)
|
m.Assert(e)
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
@ -150,10 +152,19 @@ var Index = &ctx.Context{Name: "mdb", Help: "内存数据库",
|
|||||||
m.Add("append", k, string(b))
|
m.Add("append", k, string(b))
|
||||||
case int64:
|
case int64:
|
||||||
m.Add("append", k, fmt.Sprintf("%d", b))
|
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 ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
}},
|
}},
|
||||||
|
@ -27,7 +27,7 @@ func (ssh *SSH) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ssh *SSH) Exit(m *ctx.Message, arg ...string) bool {
|
func (ssh *SSH) Close(m *ctx.Message, arg ...string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,69 +2,30 @@ package tcp // {{{
|
|||||||
// }}}
|
// }}}
|
||||||
import ( // {{{
|
import ( // {{{
|
||||||
"context"
|
"context"
|
||||||
"log"
|
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
type TCP struct {
|
type TCP struct {
|
||||||
l net.Listener
|
net.Conn
|
||||||
c net.Conn
|
net.Listener
|
||||||
close bool
|
|
||||||
*ctx.Context
|
*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 { // {{{
|
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{}
|
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 {
|
if len(arg) > 2 {
|
||||||
c.Configs["security"] = &ctx.Config{Name: "security(true/false)", Value: "true", Help: "加密通信"}
|
m.Cap("security", arg[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
s := new(TCP)
|
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 { // {{{
|
func (tcp *TCP) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
switch tcp.Context {
|
return tcp
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case m.Target:
|
// }}}
|
||||||
if tcp.l != nil {
|
func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
log.Println(tcp.Name, "close:", tcp.l.Addr())
|
switch arg[0] {
|
||||||
tcp.l.Close()
|
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
|
||||||
}
|
}
|
||||||
if tcp.c != nil {
|
|
||||||
log.Println(tcp.Name, "close:", tcp.c.LocalAddr(), "->", tcp.c.RemoteAddr())
|
l, e := net.Listen(m.Cap("protocol"), m.Cap("address"))
|
||||||
tcp.c.Close()
|
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
|
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: "网络连接",
|
var Index = &ctx.Context{Name: "tcp", Help: "网络连接",
|
||||||
@ -116,13 +110,13 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络连接",
|
|||||||
switch len(arg) { // {{{
|
switch len(arg) { // {{{
|
||||||
case 0:
|
case 0:
|
||||||
m.Travel(m.Target, func(m *ctx.Message) bool {
|
m.Travel(m.Target, func(m *ctx.Message) bool {
|
||||||
if tcp, ok := m.Target.Server.(*TCP); ok && tcp.l != nil {
|
if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Listener != nil {
|
||||||
m.Echo("%s %v\n", m.Target.Name, tcp.l.Addr())
|
m.Echo("%s %v\n", m.Target.Name, tcp.Addr())
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
case 1:
|
default:
|
||||||
go m.Start(arg[0], m.Meta["detail"]...)
|
m.Start(fmt.Sprintf("pub%d", m.Capi("nlisten", 1)), arg[0], m.Meta["detail"]...)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
@ -131,26 +125,32 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络连接",
|
|||||||
switch len(arg) { // {{{
|
switch len(arg) { // {{{
|
||||||
case 0:
|
case 0:
|
||||||
m.Travel(m.Target, func(m *ctx.Message) bool {
|
m.Travel(m.Target, func(m *ctx.Message) bool {
|
||||||
if tcp, ok := m.Target.Server.(*TCP); ok && tcp.c != nil {
|
if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Conn != nil {
|
||||||
m.Echo("%s %v->%v\n", m.Target.Name, tcp.c.LocalAddr(), tcp.c.RemoteAddr())
|
m.Echo("%s %v<->%v\n", m.Target.Name, tcp.LocalAddr(), tcp.RemoteAddr())
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
case 1:
|
default:
|
||||||
m.Start(arg[0], m.Meta["detail"]...)
|
m.Start(fmt.Sprintf("com%d", m.Capi("nclient", 1)), arg[0], m.Meta["detail"]...)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
}},
|
}},
|
||||||
"exit": &ctx.Command{Name: "exit", Help: "退出", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
"send": &ctx.Command{Name: "send message", Help: "发送消息", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
|
||||||
tcp, ok := m.Target.Server.(*TCP) // {{{
|
if tcp, ok := m.Target.Server.(*TCP); ok && tcp.Conn != nil { // {{{
|
||||||
if !ok {
|
tcp.Conn.Write([]byte(arg[0]))
|
||||||
tcp, ok = m.Source.Server.(*TCP)
|
|
||||||
}
|
}
|
||||||
if ok {
|
return ""
|
||||||
tcp.Context.Exit(m)
|
// }}}
|
||||||
|
}},
|
||||||
|
"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 ""
|
return ""
|
||||||
// }}}
|
// }}}
|
||||||
}},
|
}},
|
||||||
@ -159,6 +159,7 @@ var Index = &ctx.Context{Name: "tcp", Help: "网络连接",
|
|||||||
"void": &ctx.Context{
|
"void": &ctx.Context{
|
||||||
Commands: map[string]*ctx.Command{
|
Commands: map[string]*ctx.Command{
|
||||||
"listen": &ctx.Command{},
|
"listen": &ctx.Command{},
|
||||||
|
"dial": &ctx.Command{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,9 @@ import (
|
|||||||
_ "context/ssh"
|
_ "context/ssh"
|
||||||
|
|
||||||
_ "context/web"
|
_ "context/web"
|
||||||
|
|
||||||
|
_ "context/lex"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user