diff --git a/etc/init.sh b/etc/init.sh index abd3d815..89a7fb3b 100644 --- a/etc/init.sh +++ b/etc/init.sh @@ -1,8 +1,18 @@ ~cli @lex lex -~aaa login root root + ~aaa login root root + ~cli var a = 10 +if $username == root + echo welcome root user: $username +end ~web serve -~ssh dial chat.shylinux.com:9090 true + +function nice + echo who +end + +return hello hello + sleep 1 ~host1 remote context mpa register terminal shhylinux term term term 1 @@ -11,6 +21,7 @@ sleep 1 ~nfs save usr/sess.txt "terminal: " $sessid ~nfs genqr usr/sess.png "terminal: " $sessid return +# ~ssh dial chat.shylinux.com:9090 true # ~cli # remote slaver listen ":9393" tcp # ~ssh diff --git a/src/context/cli/cli.go b/src/context/cli/cli.go index fd828b01..2c3a8f48 100644 --- a/src/context/cli/cli.go +++ b/src/context/cli/cli.go @@ -1,6 +1,6 @@ -package cli // {{{ -// }}} -import ( // {{{ +package cli + +import ( "context" "bufio" @@ -14,21 +14,22 @@ import ( // {{{ "unicode" ) -// }}} - type CLI struct { bio *bufio.Reader out io.WriteCloser - alias map[string]string - back string - exit bool + which int + lines []string + + alias map[string]string + lex *ctx.Message - lex *ctx.Message target *ctx.Context wait *ctx.Context + exit bool + test bool + save bool - *ctx.Message *ctx.Context } @@ -43,15 +44,29 @@ func (cli *CLI) echo(str string, arg ...interface{}) bool { func (cli *CLI) parse(m *ctx.Message) bool { line := m.Cap("next") if line == "" { - cli.echo(m.Conf("PS1")) - l, e := cli.bio.ReadString('\n') - m.Assert(e) - line = l + if m.Cap("level") == "0" { + cli.echo(m.Conf("PS1")) + } + if cli.bio == nil { + if cli.which == len(cli.lines) { + cli.exit = true + cli.which = 0 + m.Spawn(cli.target).Set("detail", "end").Post(cli.Context) + return false + } + line = cli.lines[cli.which] + cli.which++ + } else { + l, e := cli.bio.ReadString('\n') + m.Assert(e) + line = l + } } m.Cap("next", "") - if line = strings.TrimSpace(line); len(line) == 0 { - line, cli.back = cli.back, "" + if line = strings.TrimSpace(line); len(line) == 0 && m.Cap("stream") == "stdout" { + line = m.Cap("back") + m.Cap("back", "") } if len(line) == 0 || line[0] == '#' { return true @@ -95,21 +110,20 @@ func (cli *CLI) parse(m *ctx.Message) bool { } msg.Wait = make(chan bool) - msg.Post(cli.Context.Master()) + msg.Post(cli.Context) - if result := strings.TrimRight(strings.Join(msg.Meta["result"], ""), "\n"); len(result) > 0 { - cli.echo(m.Cap("result", result) + "\n") + if msg.Target().Context() != nil || msg.Target() == ctx.Index { + cli.target = msg.Target() + } + result := strings.TrimRight(strings.Join(msg.Meta["result"], ""), "\n") + m.Cap("result", result) + if len(result) > 0 { + cli.echo(result + "\n") } m.Cap("target", cli.target.Name) m.Cap("back", line) - m.Log("fuck", nil, "over") - if cli.wait != nil { - msg.Log("fuck", nil, "wait 1") - <-cli.wait.Exit - cli.wait = nil - msg.Log("fuck", nil, "wait 2") - } else { - cli.target = msg.Target() + if cli.bio != nil { + cli.lines = append(cli.lines, line) } return !cli.exit } @@ -120,6 +134,8 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server s := new(CLI) s.Context = c + s.lex = cli.lex + s.alias = cli.alias return s } @@ -213,12 +229,16 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { } func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { + cli.Context.Exit = make(chan bool) + cli.bio = nil + cli.exit = false + cli.test = false if stream, ok := m.Data["io"]; ok { + cli.Context.Master(cli.Context) io := stream.(io.ReadWriteCloser) cli.bio = bufio.NewReader(io) cli.out = io - cli.Context.Master(cli.Context) if msg := m.Find("aaa", true); msg != nil { cli.echo("username>") @@ -244,49 +264,45 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { } cli.Sessions["aaa"] = msg } - } else if stream, ok := m.Data["bio"]; ok { - cli.Context.Exit = make(chan bool) - cli.bio = stream.(*bufio.Reader) - m.AssertOne(m, true, func(m *ctx.Message) { - for cli.parse(m) { - } - }) - m.Log("fuck", nil, "done 1") - cli.Context.Exit <- true - m.Log("fuck", nil, "done 2") - return true - - } else if stream, ok := m.Data["file"]; ok { - cli.Context.Exit = make(chan bool) - io := stream.(io.ReadWriteCloser) - cli.bio = bufio.NewReader(io) - m.AssertOne(m, true, func(m *ctx.Message) { - for cli.parse(m) { - } - }) - m.Log("fuck", nil, "done 1") - cli.Context.Exit <- true - m.Log("fuck", nil, "done 2") - return true } else if len(arg) > 0 { + m.Cap("stream", "stdout") + m.Cap("next", "source "+m.Conf("init.sh")) cli.Context.Master(cli.Context) cli.bio = bufio.NewReader(os.Stdin) cli.out = os.Stdout - m.Cap("stream", "stdout") + cli.Caches["level"] = &ctx.Cache{Name: "操作目标", Value: "0", Help: "操作目标"} + } else if stream, ok := m.Data["file"]; ok { + if bio, ok := stream.(*bufio.Reader); ok { + m.Cap("stream", "file") + cli.bio = bio + } else { + m.Cap("stream", "file") + cli.bio = bufio.NewReader(stream.(io.ReadWriteCloser)) + } + m.Capi("level", 1) + defer m.Capi("level", -1) + + cli.test = m.Has("test") + cli.save = m.Has("save") } - if cli.bio != nil { - go m.AssertOne(m, true, func(m *ctx.Message) { - m.Cap("next", "source "+m.Conf("init.sh")) - for cli.parse(m) { - } - }) - } + go m.AssertOne(m, true, func(m *ctx.Message) { + for cli.parse(m) { + } + }) m.Capi("nterm", 1) defer m.Capi("nterm", -1) - m.Deal(nil, func(msg *ctx.Message, arg ...string) bool { + m.Deal(func(msg *ctx.Message, arg ...string) bool { + if cli.test { + if _, ok := Index.Commands[msg.Get("detail")]; ok { + msg.Exec(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) + } + return false + } + return true + }, func(msg *ctx.Message, arg ...string) bool { if msg.Get("result") == "error: " { if msg.Get("detail") != "login" { msg.Log("system", nil, "%v", msg.Meta["detail"]) @@ -310,17 +326,20 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { } } - cli.target = msg.Target() + if msg.Target().Context() != nil || msg.Target() == ctx.Index { + cli.target = msg.Target() + } return cli.exit == false }) - return true + m.Cap("status", "close") + return !cli.save } -func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ +func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { switch cli.Context { case m.Target(): - if cli.Context == Index { + if m.Target() == Index && m.Capi("nserver") > 1 { return false } case m.Source(): @@ -336,8 +355,6 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ return true } -// }}} - var Pulse *ctx.Message var Index = &ctx.Context{Name: "cli", Help: "管理中心", Caches: map[string]*ctx.Cache{ @@ -345,18 +362,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", }, Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ - "source": &ctx.Command{Name: "source file", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli := m.Master().Master().Server.(*CLI) - f, e := os.Open(arg[0]) - m.Assert(e) - m.Put("option", "file", f).Start(arg[0], "脚本文件", key) - m.Log("fuck", nil, "source") - cli.wait = m.Target() - }}, - "return": &ctx.Command{Name: "return", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli := m.Master().Master().Server.(*CLI) - cli.exit = true - }}, "sleep": &ctx.Command{Name: "sleep time", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { t, e := strconv.Atoi(arg[0]) m.Assert(e) @@ -364,14 +369,70 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", time.Sleep(time.Second * time.Duration(t)) m.Log("info", nil, "sleep %ds done", t) }}, - "if": &ctx.Command{Name: "if a [ = | != ] b", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli := m.Master().Master().Server.(*CLI) - m.Put("option", "bio", cli.bio).Start(strings.Join(arg, " "), "条件语句", key) - cli.wait = m.Target() + "source": &ctx.Command{Name: "source file", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + f, e := os.Open(arg[0]) + m.Assert(e) + m.Put("option", "file", f).Start(key, "脚本文件") + <-m.Target().Exit + }}, + "return": &ctx.Command{Name: "return result...", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + m.Assert(ok) + cli.exit = true + for _, v := range arg { + cli.Pulse.Echo(v) + } + }}, + "if": &ctx.Command{Name: "if a [ == | != ] b", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + m.Assert(ok) + + if arg[1] == "==" && arg[0] != arg[2] { + m.Add("option", "test") + } + if arg[1] == "!=" && arg[0] == arg[2] { + m.Add("option", "test") + } + m.Put("option", "file", cli.bio).Start(key, "条件语句") + <-m.Target().Exit + }}, + "for": &ctx.Command{Name: "for var in list", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + m.Assert(ok) + + if arg[1] == "==" && arg[0] != arg[2] { + m.Add("option", "test") + } + if arg[1] == "!=" && arg[0] == arg[2] { + m.Add("option", "test") + } + m.Put("option", "file", cli.bio).Start(key, "条件语句") + <-m.Target().Exit }}, "end": &ctx.Command{Name: "end", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli := m.Master().Master().Server.(*CLI) + cli, ok := m.Source().Server.(*CLI) + m.Assert(ok) cli.exit = true + m.Log("fuck", nil, "%v", cli.lines) + m.Echo(strings.Join(arg, "")) + }}, + "var": &ctx.Command{Name: "var a [= b]", Help: "定义变量", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + m.Assert(ok) + val := "" + if len(arg) > 2 { + val = arg[2] + } + cli.Pulse.Cap(arg[0], arg[0], val, "临时变量") + }}, + "function": &ctx.Command{Name: "function name", Help: "运行脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + cli, ok := m.Source().Server.(*CLI) + m.Target(m.Source().Context()) + m.Assert(ok) + m.Add("option", "test") + m.Add("option", "save") + m.Put("option", "file", cli.bio).Start(arg[0], "定义函数") + m.Log("fuck", nil, "end function") }}, "alias": &ctx.Command{Name: "alias [short [long]]", Help: "查看日志", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { cli := c.Server.(*CLI) // {{{ @@ -419,12 +480,12 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "master": &ctx.Command{Name: "open [master|slaver] [script [log]]", Help: "建立远程连接", Options: map[string]string{"master": "主控终端", "slaver": "被控终端", "args": "启动参数", "io": "读写流"}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - cli, ok := c.Server.(*CLI) // {{{ + _, ok := c.Server.(*CLI) // {{{ m.Assert(ok, "模块类型错误") m.Assert(m.Target() != c, "模块是主控模块") msg := m.Spawn(c) - msg.Start(fmt.Sprintf("PTS%d", cli.Capi("nterm")), arg[0], arg[1:]...) + msg.Start(fmt.Sprintf("PTS%d", Pulse.Capi("nterm")), arg[0], arg[1:]...) // }}} }}, }, diff --git a/src/context/ctx.go b/src/context/ctx.go index f91280c3..40f896e6 100644 --- a/src/context/ctx.go +++ b/src/context/ctx.go @@ -133,7 +133,7 @@ func (c *Context) Begin(m *Message) *Context { // {{{ c.Owner = m.master.Owner c.Group = m.master.Group - m.Log("begin", nil, "%d context %v", m.root.Capi("ncontext", 1), m.Meta["detail"]) + m.Log("begin", nil, "%d context %v %v", m.root.Capi("ncontext", 1), m.Meta["detail"], m.Meta["option"]) for k, x := range c.Configs { if x.Hand != nil { m.Conf(k, x.Value) @@ -156,7 +156,7 @@ func (c *Context) Start(m *Message) bool { // {{{ if m.Cap("status") != "start" { running := make(chan bool) go m.AssertOne(m, true, func(m *Message) { - m.Log(m.Cap("status", "start"), nil, "%d server %v", m.root.Capi("nserver", 1), m.Meta["detail"]) + m.Log(m.Cap("status", "start"), nil, "%d server %v %v", m.root.Capi("nserver", 1), m.Meta["detail"], m.Meta["option"]) if running <- true; c.Server != nil && c.Server.Start(m, m.Meta["detail"]...) { c.Close(m, m.Meta["detail"]...) @@ -217,6 +217,10 @@ func (c *Context) Close(m *Message, arg ...string) bool { // {{{ if c.context != nil { m.Log("close", nil, "%d context %v", m.root.Capi("ncontext", -1)+1, arg) delete(c.context.contexts, c.Name) + c.context = nil + if c.Exit != nil { + c.Exit <- true + } } return true } @@ -969,13 +973,10 @@ func (m *Message) Deal(pre func(msg *Message, arg ...string) bool, post func(msg return } - if pre != nil && !pre(msg, msg.Meta["detail"]...) { - run = false - return + if pre == nil || pre(msg, msg.Meta["detail"]...) { + msg.Exec(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) } - msg.Exec(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) - if post != nil && !post(msg, msg.Meta["result"]...) { run = false return @@ -1029,33 +1030,33 @@ func (m *Message) Confi(key string, arg ...int) int { // {{{ // }}} func (m *Message) Conf(key string, arg ...string) string { // {{{ var hand func(m *Message, x *Config, arg ...string) string - for s := m.target; s != nil; s = s.context { - if x, ok := s.Configs[key]; ok { - if !m.Check(s, "configs", key) { - continue - } + for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { + for s := c; s != nil; s = s.context { + if x, ok := s.Configs[key]; ok { + if !m.Check(s, "configs", key) { + continue + } - switch len(arg) { - case 3: - if hand == nil { - hand = x.Hand - } - case 1: - m.Log("conf", s, "%s %v", key, arg) + switch len(arg) { + case 3: + if hand == nil { + hand = x.Hand + } + case 1: + m.Log("conf", s, "%s %v", key, arg) - if x.Hand != nil { - x.Value = x.Hand(m, x, arg[0]) - } else { - x.Value = arg[0] + if x.Hand != nil { + x.Value = x.Hand(m, x, arg[0]) + } else { + x.Value = arg[0] + } + return x.Value + case 0: + if x.Hand != nil { + return x.Hand(m, x) + } + return x.Value } - return x.Value - case 0: - if x.Hand != nil { - return x.Hand(m, x) - } - return x.Value - default: - panic(errors.New(key + "配置项参数错误")) } } } @@ -1070,7 +1071,7 @@ func (m *Message) Conf(key string, arg ...string) string { // {{{ return m.Conf(key, arg[1]) } - m.Assert(false, key+"配置项操作错误") + m.Log("error", nil, "配置项不存在") return "" } @@ -1090,31 +1091,31 @@ func (m *Message) Capi(key string, arg ...int) int { // {{{ // }}} func (m *Message) Cap(key string, arg ...string) string { // {{{ var hand func(m *Message, x *Cache, arg ...string) string - for s := m.target; s != nil; s = s.context { - if x, ok := s.Caches[key]; ok { - if !m.Check(s, "caches", key) { - continue - } + for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { + for s := c; s != nil; s = s.context { + if x, ok := s.Caches[key]; ok { + if !m.Check(s, "caches", key) { + continue + } - switch len(arg) { - case 3: - if hand == nil { - hand = x.Hand + switch len(arg) { + case 3: + if hand == nil { + hand = x.Hand + } + case 1: + if x.Hand != nil { + x.Value = x.Hand(m, x, arg[0]) + } else { + x.Value = arg[0] + } + return x.Value + case 0: + if x.Hand != nil { + return x.Hand(m, x) + } + return x.Value } - case 1: - if x.Hand != nil { - x.Value = x.Hand(m, x, arg[0]) - } else { - x.Value = arg[0] - } - return x.Value - case 0: - if x.Hand != nil { - return x.Hand(m, x) - } - return x.Value - default: - panic(errors.New(key + "缓存项参数错误")) } } } @@ -1129,9 +1130,8 @@ func (m *Message) Cap(key string, arg ...string) string { // {{{ return m.Cap(key, arg[1]) } - m.Assert(false, key+"缓存项操作错误") + m.Log("error", nil, "缓存项不存在") return "" - } // }}} @@ -1558,6 +1558,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心", case 2: m.Conf(arg[0], arg[1]) + case 3: + m.Conf(arg[0], arg[2]) case 4: m.Conf(arg[0], arg[1:]...) } @@ -1597,30 +1599,22 @@ var Index = &Context{Name: "ctx", Help: "模块中心", m.Cap(arg[0], "") } - m.BackTrace(func(m *Message) bool { - // if all { - // m.Echo("%s config:\n", m.target.Name) - // } - if x, ok := m.target.Caches[arg[0]]; ok { - if m.Check(m.target, "caches", arg[0]) { - // if all { - // m.Echo(" ") - // } - // m.Echo("%s: %s\n", x.Name, x.Help) - m.Echo("%s", x.Value) - return false - } - } - return true - // return all - }) + m.Echo("%s", m.Cap(arg[0])) case 2: m.Cap(arg[0], arg[1]) + case 3: + m.Cap(arg[0], arg[2]) case 4: m.Cap(arg[0], arg[1:]...) } // }}} }}, + "pulse": &Command{Name: "arg name", Help: "查看日志", Hand: func(m *Message, c *Context, key string, arg ...string) { + p := m.Target().Pulse + m.Echo("%d\n", p.code) + m.Echo("%v\n", p.Meta["detail"]) + m.Echo("%v\n", p.Meta["option"]) + }}, }, Index: map[string]*Context{ "void": &Context{Name: "void",