1
0
forked from x/ContextOS
2017-11-09 22:51:50 +08:00

608 lines
15 KiB
Go

package cli // {{{
// }}}
import ( // {{{
"bufio"
"context"
_ "context/tcp"
_ "context/web"
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
"time"
"unicode"
)
// }}}
type CLI struct {
out io.WriteCloser
in io.ReadCloser
ins []io.ReadCloser
bio *bufio.Reader
bios []*bufio.Reader
history []map[string]string
alias map[string]string
next string
exit bool
target *ctx.Context
*ctx.Context
}
func (cli *CLI) push(f io.ReadCloser) { // {{{
if cli.ins == nil || cli.bios == nil {
cli.ins = make([]io.ReadCloser, 0, 3)
cli.bios = make([]*bufio.Reader, 0, 3)
}
cli.in = f
cli.ins = append(cli.ins, cli.in)
cli.bio = bufio.NewReader(f)
cli.bios = append(cli.bios, cli.bio)
}
// }}}
func (cli *CLI) parse() bool { // {{{
if len(cli.ins) == 1 || cli.Conf("slient") != "yes" {
cli.echo(cli.Conf("PS1"))
}
line := ""
if cli.next == "" {
ls, e := cli.bio.ReadString('\n')
if e == io.EOF {
l := len(cli.ins)
if l == 1 {
cli.echo("\n%s\n", cli.Conf("结束语"))
return false
ls = "exit"
e = nil
} else {
cli.ins = cli.ins[:l-1]
cli.bios = cli.bios[:l-1]
cli.in = cli.ins[l-2]
cli.bio = cli.bios[l-2]
return true
}
}
cli.Assert(e)
line = ls
if len(cli.ins) > 1 || cli.Conf("slient") != "yes" {
cli.echo(line)
}
if len(line) == 1 {
if len(cli.ins) == 1 {
line = cli.history[len(cli.history)-1]["cli"]
} else {
return true
}
}
} else {
line = cli.next
cli.next = ""
if cli.Conf("slient") != "yes" {
cli.echo(line)
cli.echo("\n")
}
}
back:
line = strings.TrimSpace(line)
if line[0] == '#' {
return true
}
ls := strings.Split(line, " ")
msg := &ctx.Message{Wait: make(chan bool)}
msg.Message = cli.Resource[0]
msg.Context = cli.Context
msg.Target = cli.target
r := rune(ls[0][0])
if !unicode.IsNumber(r) || !unicode.IsLetter(r) || r == '$' || r == '_' {
if _, ok := cli.alias[string(r)]; ok {
msg.Add("detail", ls[0][:1])
if len(ls[0]) > 1 {
ls[0] = ls[0][1:]
} else {
if len(ls) > 1 {
ls = ls[1:]
} else {
ls = nil
}
}
}
}
for i := 0; i < len(ls); i++ {
ls[i] = strings.TrimSpace(ls[i])
if ls[i][0] == '#' {
break
}
if ls[i] != "" {
msg.Add("detail", ls[i])
}
}
ls = msg.Meta["detail"]
if n, e := strconv.Atoi(ls[0]); e == nil && 0 <= n && n < len(cli.history) && ls[0] != cli.history[n]["cli"] {
line = cli.history[n]["cli"]
msg.Meta["detail"] = nil
goto back
}
msg.Post(cli.Context)
for _, v := range msg.Meta["result"] {
cli.echo(v)
}
return true
}
// }}}
func (cli *CLI) echo(str string, arg ...interface{}) { // {{{
if len(cli.ins) == 1 || cli.Conf("slient") != "yes" {
fmt.Fprintf(cli.out, str, arg...)
}
}
// }}}
func (cli *CLI) Begin(m *ctx.Message) ctx.Server { // {{{
cli.history = make([]map[string]string, 0, 100)
cli.target = cli.Context
return cli.Server
}
// }}}
func (cli *CLI) Start(m *ctx.Message) bool { // {{{
cli.Capi("nterm", 1)
defer cli.Capi("nterm", -1)
if stream, ok := m.Data["io"]; ok {
io := stream.(io.ReadWriteCloser)
cli.out = io
cli.push(io)
cli.echo("%s\n", cli.Conf("开场白"))
if f, e := os.Open(cli.Conf("init.sh")); e == nil {
cli.push(f)
}
defer recover()
go cli.AssertOne(m, func(c *ctx.Context, m *ctx.Message) {
for cli.parse() {
}
})
}
for cli.Deal(func(msg *ctx.Message) bool {
arg := msg.Meta["detail"]
if a, ok := cli.alias[arg[0]]; ok {
arg[0] = a
}
return true
}, func(msg *ctx.Message) bool {
arg := msg.Meta["detail"]
cli.history = append(cli.history, map[string]string{
"time": time.Now().Format("15:04:05"),
"index": fmt.Sprintf("%d", len(cli.history)),
"cli": strings.Join(arg, " "),
})
if cli.exit == true {
return false
}
return true
}) {
}
return true
}
// }}}
func (cli *CLI) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{
c.Caches = map[string]*ctx.Cache{
"status": &ctx.Cache{Name: "status", Value: "stop", Help: "服务状态"},
}
c.Configs = map[string]*ctx.Config{
"address": &ctx.Config{Name: "address", Value: arg[0], Help: "监听地址"},
"protocol": &ctx.Config{Name: "protocol", Value: arg[1], Help: "监听协议"},
"init.sh": &ctx.Config{Name: "init.sh", Value: "", Help: "默认启动脚本"},
}
c.Commands = cli.Commands
c.Messages = make(chan *ctx.Message, 10)
s := new(CLI)
s.Context = c
s.alias = map[string]string{
"~": "context",
"!": "history",
"@": "config",
"$": "cache",
"&": "server",
"*": "message",
}
return s
}
// }}}
func (cli *CLI) Exit(m *ctx.Message, arg ...string) bool { // {{{
if cli.Context != Index {
delete(cli.Context.Context.Contexts, cli.Name)
}
return true
}
// }}}
var Index = &ctx.Context{Name: "cli", Help: "管理终端",
Caches: map[string]*ctx.Cache{
"nterm": &ctx.Cache{Name: "nterm", Value: "0", Help: "终端数量"},
"status": &ctx.Cache{Name: "status", Value: "stop", Help: "服务状态"},
"nhistory": &ctx.Cache{Name: "nhistory", Value: "0", Help: "终端数量", Hand: func(c *ctx.Context, x *ctx.Cache, arg ...string) string {
if cli, ok := c.Server.(*CLI); ok { // {{{
return fmt.Sprintf("%d", len(cli.history))
}
return x.Value
// }}}
}},
},
Configs: map[string]*ctx.Config{
"开场白": &ctx.Config{Name: "开场白", Value: "\n~~~ Hello Context & Message World ~~~\n", Help: "开场白"},
"结束语": &ctx.Config{Name: "结束语", Value: "\n~~~ Byebye Context & Message World ~~~\n", Help: "结束语"},
"slient": &ctx.Config{Name: "slient", Value: "yes", Help: "屏蔽脚本输出"},
"PS1": &ctx.Config{Name: "PS1", Value: "target", Help: "命令行提示符", Hand: func(c *ctx.Context, x *ctx.Config, arg ...string) string {
cli, ok := c.Server.(*CLI) // {{{
if ok && cli.target != nil {
// c = cli.target
switch x.Value {
case "target":
return fmt.Sprintf("%s[%s]\033[32m%s\033[0m> ", c.Cap("nhistory"), time.Now().Format("15:04:05"), cli.target.Name)
case "detail":
return fmt.Sprintf("%s[%s](%s,%s,%s)\033[32m%s\033[0m> ", c.Cap("nhistory"), time.Now().Format("15:04:05"), c.Cap("ncontext"), c.Cap("nmessage"), c.Cap("nserver"), c.Name)
}
}
return fmt.Sprintf("[%s]\033[32m%s\033[0m ", time.Now().Format("15:04:05"), x.Value)
// }}}
}},
},
Commands: map[string]*ctx.Command{
"context": &ctx.Command{Name: "context [spawn|find|search name [which]]|root|back|home", Help: "查看上下文", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
cli, ok := c.Server.(*CLI) // {{{
switch len(arg) {
case 0:
// cs := []*ctx.Context{m.Target}
cs := []*ctx.Context{m.Target.Root}
for i := 0; i < len(cs); i++ {
if len(cs[i].Contexts) > 0 {
m.Echo("%s: ", cs[i].Name)
for k, v := range cs[i].Contexts {
cs = append(cs, v)
m.Echo("%s, ", k)
}
m.Echo("\n")
}
}
case 1:
switch arg[0] {
case "root":
if ok {
cli.target = cli.Context.Root
} else {
m.Target = m.Target.Root
}
case "back":
if ok {
if cli.Context.Context != nil {
cli.target = cli.Context.Context
}
} else {
if m.Target.Context != nil {
m.Target = m.Target.Context
}
}
case "home":
if ok {
cli.target = cli.Context
} else {
m.Target = m.Context
}
default:
// if cs := m.Target.Find(strings.Split(arg[1], ".")); cs != nil {
if cs := c.Root.Search(arg[0]); cs != nil && len(cs) > 0 {
if ok {
cli.target = cs[0]
} else {
m.Target = cs[0]
}
}
}
case 2, 3:
switch arg[0] {
case "spawn":
m.Target.Spawn(m, arg[1])
case "find":
cs := m.Target.Find(arg[1])
if cs != nil {
m.Echo("%s: %s\n", cs.Name, cs.Help)
if len(arg) == 4 {
if ok {
cli.target = cs
} else {
m.Target = cs
}
}
}
case "search":
cs := m.Target.Search(arg[1])
for i, v := range cs {
m.Echo("[%d] %s: %s\n", i, v.Name, v.Help)
}
if len(arg) == 3 {
n, e := strconv.Atoi(arg[2])
if 0 <= n && n < len(cs) && e == nil {
if ok {
cli.target = cs[n]
} else {
m.Target = cs[n]
}
} else {
m.Echo("参数错误(0<=n<%s)", len(cs))
}
}
}
}
return ""
// }}}
}},
"message": &ctx.Command{Name: "message detail...", Help: "查看上下文", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
// {{{
ms := []*ctx.Message{ctx.Pulse}
for i := 0; i < len(ms); i++ {
m.Echo("%d %s.%s -> %s.%d\n", ms[i].Code, ms[i].Context.Name, ms[i].Name, ms[i].Target.Name, ms[i].Index)
// m.Echo("%d %s %s.%s -> %s.%d\n", ms[i].Code, ms[i].Time.Format("2006/01/02 15:03:04"), ms[i].Context.Name, ms[i].Name, ms[i].Target.Name, ms[i].Index)
ms = append(ms, ms[i].Messages...)
}
return ""
// }}}
}},
"server": &ctx.Command{Name: "server start|stop|switch", Help: "服务启动停止切换", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
s := m.Target // {{{
switch len(arg) {
case 0:
cs := []*ctx.Context{m.Target.Root}
for i := 0; i < len(cs); i++ {
if x, ok := cs[i].Caches["status"]; ok {
m.Echo("%s(%s): %s\n", cs[i].Name, x.Value, cs[i].Help)
}
for _, v := range cs[i].Contexts {
cs = append(cs, v)
}
}
return "server start"
case 1:
switch arg[0] {
case "start":
if s != nil {
go s.Start(m)
}
case "stop":
case "switch":
}
}
return ""
// }}}
}},
"source": &ctx.Command{Name: "source file", Help: "运行脚本", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
f, e := os.Open(arg[0])
c.Assert(e)
cli.push(f)
}
return ""
// }}}
}},
"alias": &ctx.Command{Name: "alias [short [long]]", Help: "查看日志", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 0:
for k, v := range cli.alias {
m.Echo("%s: %s\n", k, v)
}
case 2:
switch arg[0] {
case "delete":
delete(cli.alias, arg[1])
default:
cli.alias[arg[0]] = arg[1]
m.Echo("%s: %s\n", arg[0], cli.alias[arg[0]])
}
default:
cli.alias[arg[0]] = strings.Join(arg[1:], " ")
m.Echo("%s: %s\n", arg[0], cli.alias[arg[0]])
}
return ""
// }}}
}},
"history": &ctx.Command{Name: "history number", Help: "查看日志", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 0:
for i, v := range cli.history {
m.Echo("%d %s %s\n", i, v["time"], v["cli"])
}
case 1:
n, e := strconv.Atoi(arg[0])
if e == nil && 0 <= n && n < len(cli.history) {
log.Println("shy log why:", cli.history[n]["cli"])
cli.next = cli.history[n]["cli"]
}
default:
n, e := strconv.Atoi(arg[0])
if e == nil && 0 <= n && n < len(cli.history) {
cli.history[n]["cli"] = strings.Join(arg[1:], " ")
}
}
return ""
// }}}
}},
"command": &ctx.Command{Name: "command [name [value [help]]]", Help: "查看修改添加配置", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
switch len(arg) { // {{{
case 0:
for k, v := range m.Target.Commands {
m.Echo("%s: %s\n", k, v.Help)
}
case 2:
if v, ok := m.Target.Commands[arg[0]]; ok {
m.Echo("%s: %s\n", v.Name, v.Help)
}
case 3:
switch arg[0] {
case "delete":
if _, ok := m.Target.Commands[arg[1]]; ok {
delete(m.Target.Commands, arg[1])
}
}
}
m.Echo("\n")
return ""
// }}}
}},
"config": &ctx.Command{Name: "config [name [value [help]]]", Help: "查看修改添加配置", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
switch len(arg) { // {{{
case 0:
for k, v := range m.Target.Configs {
m.Echo("%s(%s): %s\n", k, v.Value, v.Help)
}
case 1:
if v, ok := m.Target.Configs[arg[0]]; ok {
m.Echo("%s: %s\n", v.Name, v.Help)
}
case 2:
switch arg[0] {
case "void":
m.Target.Conf(arg[1], "")
case "delete":
if _, ok := m.Target.Configs[arg[1]]; ok {
delete(m.Target.Configs, arg[1])
}
default:
m.Target.Conf(arg[0], arg[1])
}
case 4:
m.Target.Conf(arg[0], arg[1:]...)
}
return ""
// }}}
}},
"cache": &ctx.Command{Name: "cache [name [value [help]]]", Help: "查看修改添加配置", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
switch len(arg) { // {{{
case 0:
for k, v := range m.Target.Caches {
m.Echo("%s(%s): %s\n", k, v.Value, v.Help)
}
case 1:
if v, ok := m.Target.Caches[arg[0]]; ok {
m.Echo("%s: %s\n", v.Name, v.Help)
}
case 2:
switch arg[0] {
case "delete":
if _, ok := m.Target.Caches[arg[1]]; ok {
delete(m.Target.Caches, arg[1])
}
default:
if _, ok := m.Target.Caches[arg[0]]; ok {
m.Echo("%s: %s\n", arg[0], m.Target.Cap(arg[0], arg[1:]...))
}
}
case 4:
m.Target.Cap(arg[0], arg[1:]...)
}
return ""
// }}}
}},
"exit": &ctx.Command{Name: "exit", Help: "退出", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
cli, ok := m.Target.Server.(*CLI) // {{{
if !ok {
cli, ok = m.Context.Server.(*CLI)
}
if ok {
if !cli.exit {
m.Echo(c.Conf("结束语"))
cli.Context.Exit(m)
}
cli.exit = true
}
return ""
// }}}
}},
"remote": &ctx.Command{Name: "remote master|slave listen|dial address protocol", Help: "建立远程连接", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
switch len(arg) { // {{{
case 0:
case 4:
if arg[0] == "master" {
if arg[1] == "dial" {
} else {
}
} else {
if arg[1] == "listen" {
s := c.Root.Find(arg[3])
m.Message.Spawn(s, arg[2]).Cmd("listen", arg[2])
} else {
}
}
}
return ""
// }}}
}},
"accept": &ctx.Command{Name: "accept address protocl", Help: "建立远程连接",
Options: map[string]string{"io": "读写流"},
Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string {
m.Start(fmt.Sprintf("PTS%d", c.Capi("nterm")), arg[1]) // {{{
return ""
// }}}
}},
"void": &ctx.Command{Name: "", Help: "", Hand: nil},
},
Messages: make(chan *ctx.Message, 10),
}
func init() {
cli := &CLI{alias: map[string]string{
"~": "context",
"!": "history",
"@": "config",
"$": "cache",
"&": "server",
"*": "message",
}}
cli.Context = Index
ctx.Index.Register(Index, cli)
}