diff --git a/base/aaa/role.go b/base/aaa/role.go index 1893a464..fbada273 100644 --- a/base/aaa/role.go +++ b/base/aaa/role.go @@ -16,8 +16,6 @@ const ( // 角色操作 White = "white" Black = "black" Right = "right" - Prune = "prune" - Clear = "clear" ) const ( // 返回结果 OK = "ok" diff --git a/base/cli/cli.go b/base/cli/cli.go index eed468e7..d2bb0b46 100644 --- a/base/cli/cli.go +++ b/base/cli/cli.go @@ -147,7 +147,7 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块", } }) case "ifconfig": - m.Cmdy("tcp.ip") + m.Cmdy("tcp.host") case "userinfo": m.Split(m.Cmdx(SYSTEM, "who"), "user term time", " ", "\n") diff --git a/base/cli/daemon.go b/base/cli/daemon.go index 30313af3..4b32edcb 100644 --- a/base/cli/daemon.go +++ b/base/cli/daemon.go @@ -34,10 +34,10 @@ func _daemon_show(m *ice.Message, cmd *exec.Cmd, out, err string) { h := m.Rich(DAEMON, nil, kit.Dict( kit.MDB_TYPE, "shell", kit.MDB_NAME, strings.Join(cmd.Args, " "), - kit.MDB_DIR, cmd.Dir, kit.MDB_PID, cmd.Process.Pid, kit.MDB_STATUS, StatusStart, + kit.SSH_DIR, cmd.Dir, kit.SSH_PID, cmd.Process.Pid, kit.MDB_STATUS, StatusStart, kit.MDB_EXTRA, kit.Dict(CMD_STDOUT, out, CMD_STDERR, err), )) - m.Log_EXPORT(kit.MDB_META, DAEMON, kit.MDB_KEY, h, kit.MDB_PID, cmd.Process.Pid) + m.Log_EXPORT(kit.MDB_META, DAEMON, kit.MDB_KEY, h, kit.SSH_PID, cmd.Process.Pid) m.Echo("%d", cmd.Process.Pid) m.Gos(m, func(m *ice.Message) { @@ -73,7 +73,7 @@ func init() { }}, "prune": {Name: "prune", Help: "清理", Hand: func(m *ice.Message, arg ...string) { m.Richs(DAEMON, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - if value["status"] == "error" || strings.Count(m.Cmdx(SYSTEM, "ps", value[kit.MDB_PID]), "\n") == 1 { + if value["status"] == "error" || strings.Count(m.Cmdx(SYSTEM, "ps", value[kit.SSH_PID]), "\n") == 1 { m.Conf(DAEMON, kit.Keys(kit.MDB_HASH, key), "") m.Log_DELETE(DAEMON, kit.Format(value)) } @@ -81,8 +81,8 @@ func init() { }}, "stop": {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) { m.Richs(DAEMON, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) { - m.Cmdy(SYSTEM, "kill", "-9", value[kit.MDB_PID]) - if strings.Count(m.Cmdx(SYSTEM, "ps", value[kit.MDB_PID]), "\n") == 1 { + m.Cmdy(SYSTEM, "kill", "-9", value[kit.SSH_PID]) + if strings.Count(m.Cmdx(SYSTEM, "ps", value[kit.SSH_PID]), "\n") == 1 { value[kit.MDB_STATUS] = StatusClose } }) diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 647ab9a0..3705b618 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -248,17 +248,32 @@ func _list_inputs(m *ice.Message, prefix, chain string, field, value string) { } func _zone_select(m *ice.Message, prefix, chain, zone string, id string) { + cb := m.Optionv("cache.cb") fields := kit.Split(kit.Select("zone,id,time,type,name,text", m.Option(FIELDS))) m.Richs(prefix, chain, kit.Select(kit.MDB_FOREACH, zone), func(key string, val map[string]interface{}) { if val[kit.MDB_META] != nil { val = val[kit.MDB_META].(map[string]interface{}) } + if zone == "" { + m.Push(key, val, fields) + return + } + m.Grows(prefix, kit.Keys(chain, kit.MDB_HASH, key), kit.MDB_ID, id, func(index int, value map[string]interface{}) { if value[kit.MDB_META] != nil { value = value[kit.MDB_META].(map[string]interface{}) } - m.Push(zone, value, fields, val) + switch cb := cb.(type) { + case func(string, map[string]interface{}, map[string]interface{}): + cb(key, value, val) + default: + if len(fields) == 1 && fields[0] == DETAIL { + m.Push(DETAIL, value) + break + } + m.Push(key, value, fields, val) + } }) }) @@ -450,7 +465,7 @@ var Index = &ice.Context{Name: "mdb", Help: "数据模块", func init() { ice.Index.Register(Index, nil, - INSERT, DELETE, SELECT, MODIFY, + INSERT, DELETE, MODIFY, SELECT, EXPORT, IMPORT, PRUNES, INPUTS, PLUGIN, RENDER, SEARCH, ENGINE, ) diff --git a/base/nfs/search.go b/base/nfs/_trash.go similarity index 100% rename from base/nfs/search.go rename to base/nfs/_trash.go diff --git a/base/ssh/_trash.go b/base/ssh/_trash.go new file mode 100644 index 00000000..2f826dd7 --- /dev/null +++ b/base/ssh/_trash.go @@ -0,0 +1,71 @@ +package ssh + +func (f *Frame) history(m *ice.Message, line string) string { + favor := m.Conf(SOURCE, kit.Keys(kit.MDB_META, web.FAVOR)) + if strings.HasPrefix(strings.TrimSpace(line), "!!") { + if len(line) == 2 { + line = m.Cmd(web.FAVOR, favor).Append(kit.MDB_TEXT) + } + } else if strings.HasPrefix(strings.TrimSpace(line), "!") { + if len(line) == 1 { + // 历史记录 + msg := m.Cmd(web.FAVOR, favor) + msg.Sort(kit.MDB_ID) + msg.Appendv(ice.MSG_APPEND, kit.MDB_TIME, kit.MDB_ID, kit.MDB_TEXT) + f.printf(m, msg.Table().Result()) + return "" + } + if i, e := strconv.Atoi(line[1:]); e == nil { + // 历史命令 + line = kit.Format(kit.Value(m.Cmd(web.FAVOR, favor, i).Optionv("value"), kit.MDB_TEXT)) + } else { + f.printf(m, m.Cmd("history", "search", line[1:]).Table().Result()) + return "" + } + } else if strings.TrimSpace(line) != "" && f.source == STDIO { + // 记录历史 + m.Cmd(web.FAVOR, favor, "cmd", f.source, line) + } + return line +} + +const ( + REMOTE = "remote" + QRCODE = "qrcode" +) + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + REMOTE: {Name: "remote", Help: "远程连接", Value: kit.Data()}, + }, + Commands: map[string]*ice.Command{ + + QRCODE: {Name: "qrcode arg...", Help: "命令提示", Action: map[string]*ice.Action{ + "json": {Name: "json [key val]...", Help: "json", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(cli.PYTHON, QRCODE, kit.Format(kit.Parse(nil, "", arg...))) + m.Render(ice.RENDER_RESULT) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmdy(cli.PYTHON, QRCODE, strings.Join(arg, "")) + m.Render(ice.RENDER_RESULT) + }}, + REMOTE: {Name: "remote user remote port local", Help: "远程连接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + key := m.Rich(REMOTE, nil, kit.Dict( + "user", arg[0], "remote", arg[1], "port", arg[2], "local", arg[3], + )) + m.Echo(key) + m.Info(key) + + m.Gos(m, func(m *ice.Message) { + for { + m.Cmd(cli.SYSTEM, "ssh", "-CNR", kit.Format("%s:%s:22", arg[2], kit.Select("localhost", arg, 3)), + kit.Format("%s@%s", arg[0], arg[1])) + m.Info("reconnect after 10s") + time.Sleep(time.Second * 10) + } + }) + }}, + }, + }, nil) +} diff --git a/base/ssh/server.go b/base/ssh/server.go index 6c11c91f..08692185 100644 --- a/base/ssh/server.go +++ b/base/ssh/server.go @@ -184,17 +184,12 @@ func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh request.Reply(true, nil) } } -func _ssh_listen(m *ice.Message, hostport string) { +func _ssh_listen(m *ice.Message, l net.Listener, hostport string) { h := m.Cmdx(mdb.INSERT, m.Prefix(LISTEN), "", mdb.HASH, aaa.HOSTPORT, hostport, kit.MDB_STATUS, "listen") defer m.Cmd(mdb.MODIFY, m.Prefix(LISTEN), "", mdb.HASH, kit.MDB_HASH, h, kit.MDB_STATUS, "close") config := _ssh_config(m) - l, e := net.Listen("tcp", hostport) - m.Assert(e) - defer l.Close() - m.Logs(LISTEN, ADDRESS, l.Addr()) - for { c, e := l.Accept() if m.Warn(e != nil, e) { @@ -248,7 +243,7 @@ func _ssh_config(m *ice.Message) *ssh.ServerConfig { }, PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { meta, res := map[string]string{"username": conn.User()}, errors.New(ice.ErrNotAuth) - if tcp.IPIsLocal(m, strings.Split(conn.RemoteAddr().String(), ":")[0]) { + if tcp.IsLocalHost(m, strings.Split(conn.RemoteAddr().String(), ":")[0]) { m.Log_AUTH(aaa.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) res = nil } else { @@ -382,8 +377,13 @@ func init() { }}, LISTEN: {Name: "listen hash=auto auto", Help: "服务", Action: map[string]*ice.Action{ - mdb.CREATE: {Name: "create port=9030", Help: "启动", Hand: func(m *ice.Message, arg ...string) { - m.Gos(m, func(m *ice.Message) { _ssh_listen(m, ":"+m.Option("port")) }) + mdb.CREATE: {Name: "create name=tcp port=9030", Help: "启动", Hand: func(m *ice.Message, arg ...string) { + m.Option(tcp.LISTEN_CB, func(l net.Listener) { + _ssh_listen(m, l, ":"+m.Option("port")) + }) + m.Gos(m, func(m *ice.Message) { + m.Cmdy(tcp.SERVER, tcp.LISTEN, kit.MDB_NAME, "ssh", tcp.PORT, m.Option(tcp.PORT)) + }) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if m.Option(mdb.FIELDS, m.Conf(LISTEN, kit.META_FIELD)); len(arg) > 0 { diff --git a/base/ssh/script.go b/base/ssh/ssh.go similarity index 59% rename from base/ssh/script.go rename to base/ssh/ssh.go index 5df6ae81..6e2aee00 100644 --- a/base/ssh/script.go +++ b/base/ssh/ssh.go @@ -5,7 +5,6 @@ import ( "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" - "github.com/shylinux/icebergs/base/web" kit "github.com/shylinux/toolkits" "bufio" @@ -14,48 +13,33 @@ import ( "io" "os" "path" - "strconv" "strings" "time" ) -type Frame struct { - source string - target *ice.Context - stdout io.Writer - - count int - ps1 []string - ps2 []string - - exit bool -} - func Render(msg *ice.Message, cmd string, args ...interface{}) { defer func() { msg.Log_EXPORT(mdb.RENDER, cmd, kit.MDB_TEXT, args) }() switch arg := kit.Simple(args...); cmd { - case ice.RENDER_OUTPUT: - - case ice.RENDER_DOWNLOAD: - os.Link(kit.Select(path.Base(arg[0]), arg, 2), arg[0]) - + case ice.RENDER_VOID: case ice.RENDER_RESULT: fmt.Fprintf(msg.O, msg.Result()) case ice.RENDER_QRCODE: - if len(args) > 0 { - fmt.Println(msg.Cmdx("cli.python", "qrcode", kit.Format(args[0], args[1:]...))) - } else { - fmt.Println(msg.Cmdx("cli.python", "qrcode", kit.Format(kit.Dict( - kit.MDB_TYPE, "cmd", kit.MDB_NAME, msg.Option("_cmd"), kit.MDB_TEXT, strings.TrimSpace(msg.Result()), - )))) + fmt.Fprintf(msg.O, msg.Cmdx(cli.PYTHON, "qrcode", kit.Format(args[0], args[1:]...))) + + case ice.RENDER_DOWNLOAD: + if f, e := os.Open(arg[0]); e == nil { + defer f.Close() + + io.Copy(msg.O, f) } + default: // 转换结果 res := msg.Result() if res == "" { - res = msg.Table(nil).Result() + res = msg.Table().Result() } args = append(args, "length:", len(res)) @@ -64,9 +48,13 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) { fmt.Fprintf(msg.O, "\n") } } - msg.Append(ice.MSG_OUTPUT, ice.RENDER_OUTPUT) } -func _ssh_script(m *ice.Message, name string) io.Reader { +func Script(m *ice.Message, name string) io.Reader { + if b, ok := ice.BinPack[name]; ok { + m.Debug("binpack %v %v", len(b), name) + return bytes.NewReader(b) + } + if strings.Contains(m.Option("_script"), "/") { name = path.Join(path.Dir(m.Option("_script")), name) } @@ -95,42 +83,19 @@ func _ssh_script(m *ice.Message, name string) io.Reader { } return nil } -func (f *Frame) history(m *ice.Message, line string) string { - favor := m.Conf(SOURCE, kit.Keys(kit.MDB_META, web.FAVOR)) - if strings.HasPrefix(strings.TrimSpace(line), "!!") { - if len(line) == 2 { - line = m.Cmd(web.FAVOR, favor).Append(kit.MDB_TEXT) - } - } else if strings.HasPrefix(strings.TrimSpace(line), "!") { - if len(line) == 1 { - // 历史记录 - msg := m.Cmd(web.FAVOR, favor) - msg.Sort(kit.MDB_ID) - msg.Appendv(ice.MSG_APPEND, kit.MDB_TIME, kit.MDB_ID, kit.MDB_TEXT) - f.printf(m, msg.Table().Result()) - return "" - } - if i, e := strconv.Atoi(line[1:]); e == nil { - // 历史命令 - line = kit.Format(kit.Value(m.Cmd(web.FAVOR, favor, i).Optionv("value"), kit.MDB_TEXT)) - } else { - f.printf(m, m.Cmd("history", "search", line[1:]).Table().Result()) - return "" - } - } else if strings.TrimSpace(line) != "" && f.source == STDIO { - // 记录历史 - m.Cmd(web.FAVOR, favor, "cmd", f.source, line) - } - return line -} -func (f *Frame) printf(m *ice.Message, res string, arg ...interface{}) *Frame { - if len(arg) > 0 { - fmt.Fprintf(f.stdout, res, arg...) - } else { - fmt.Fprint(f.stdout, res) - } - return f + +type Frame struct { + source string + target *ice.Context + stdout io.Writer + + count int + ps1 []string + ps2 []string + + exit bool } + func (f *Frame) prompt(m *ice.Message, list ...string) *Frame { if f.source != STDIO { return f @@ -143,7 +108,7 @@ func (f *Frame) prompt(m *ice.Message, list ...string) *Frame { for _, v := range list { switch v { case "count": - fmt.Fprintf(f.stdout, "%d", kit.Int(m.Conf("history", "meta.count"))+1) + fmt.Fprintf(f.stdout, "%d", f.count+1) case "time": fmt.Fprintf(f.stdout, time.Now().Format("15:04:05")) case "target": @@ -154,21 +119,30 @@ func (f *Frame) prompt(m *ice.Message, list ...string) *Frame { } return f } +func (f *Frame) printf(m *ice.Message, res string, arg ...interface{}) *Frame { + if len(arg) > 0 { + fmt.Fprintf(f.stdout, res, arg...) + } else { + fmt.Fprint(f.stdout, res) + } + return f +} func (f *Frame) option(m *ice.Message, ls []string) []string { - // 解析选项 ln := []string{} m.Option("cache.limit", 10) for i := 0; i < len(ls); i++ { if ls[i] == "--" { ln = append(ln, ls[i+1:]...) break - } else if strings.HasPrefix(ls[i], "-") { + } + + if strings.HasPrefix(ls[i], "-") { for j := i; j < len(ls); j++ { if j == len(ls)-1 || strings.HasPrefix(ls[j+1], "-") { - if i == j { - m.Option(ls[i][1:], "true") - } else { + if i < j { m.Option(ls[i][1:], ls[i+1:j+1]) + } else { + m.Option(ls[i][1:], "true") } i = j break @@ -201,7 +175,6 @@ func (f *Frame) change(m *ice.Message, ls []string) []string { return ls } func (f *Frame) alias(m *ice.Message, ls []string) []string { - // 命令替换 if alias, ok := m.Optionv(ice.MSG_ALIAS).(map[string]interface{}); ok { if len(ls) > 0 { if a := kit.Simple(alias[ls[0]]); len(a) > 0 { @@ -212,26 +185,23 @@ func (f *Frame) alias(m *ice.Message, ls []string) []string { return ls } func (f *Frame) parse(m *ice.Message, line string) string { + if strings.HasPrefix(line, "<") { + fmt.Fprintf(m.O, line) + return "" + } + for _, one := range kit.Split(line, ";", ";", ";") { m.Log_IMPORT("stdin", one, "length", len(one)) + async, one := false, strings.TrimSpace(one) if strings.TrimSuffix(one, "&") != one { async, one = true, strings.TrimSuffix(one, "&") } - ls := kit.Split(one) - if m.Option("scan_mode") == "scan" { - f.printf(m, ls[0]) - f.printf(m, "`") - f.printf(m, strings.Join(ls[1:], "` `")) - f.printf(m, "`") - f.printf(m, "\n") - continue - } - - // 解析引擎 msg := m.Spawns(f.target) msg.Option("_cmd", one) + + ls := kit.Split(one) ls = f.alias(msg, ls) ls = f.change(msg, ls) ls = f.option(msg, ls) @@ -240,15 +210,15 @@ func (f *Frame) parse(m *ice.Message, line string) string { } if async { - m.Debug("async %v", ls) - go msg.Cmd(ls[0], ls[1:]) + msg.Gos(msg, func(msg *ice.Message) { msg.Cmd(ls[0], ls[1:]) }) continue + } else { + msg.Cmdy(ls[0], ls[1:]) } - if strings.HasPrefix(line, "<") { - msg.Resultv(line) - } else if msg.Cmdy(ls[0], ls[1:]); strings.HasPrefix(msg.Result(), "warn: ") && m.Option("render") == "raw" { - msg.Resultv(line) + if strings.HasPrefix(msg.Result(), ice.ErrWarn) && m.Option("render") == "raw" { + fmt.Fprintf(msg.O, line) + continue } // 渲染引擎 @@ -257,7 +227,7 @@ func (f *Frame) parse(m *ice.Message, line string) string { } return "" } -func (f *Frame) scan(m *ice.Message, file, line string, r io.Reader) *Frame { +func (f *Frame) scan(m *ice.Message, line string, r io.Reader) *Frame { m.Option("ssh.return", func() { f.exit = true }) f.ps1 = kit.Simple(m.Confv("prompt", "meta.PS1")) f.ps2 = kit.Simple(m.Confv("prompt", "meta.PS2")) @@ -267,30 +237,26 @@ func (f *Frame) scan(m *ice.Message, file, line string, r io.Reader) *Frame { bio := bufio.NewScanner(r) for f.prompt(m, ps...); bio.Scan() && !f.exit; f.prompt(m, ps...) { if len(bio.Text()) == 0 { - // 空行 - continue + continue // 空行 } if strings.HasSuffix(bio.Text(), "\\") { - // 续行 line += bio.Text()[:len(bio.Text())-1] ps = f.ps2 - continue + continue // 续行 } if line += bio.Text(); strings.Count(line, "`")%2 == 1 { - // 多行 line += "\n" ps = f.ps2 - continue + continue // 多行 } if strings.HasPrefix(strings.TrimSpace(line), "#") { - // 注释 line = "" - continue - } - if line = f.history(m, line); line == "" { - // 历史命令 - continue + continue // 注释 } + // if line = f.history(m, line); line == "" { + // // 历史命令 + // continue + // } if ps = f.ps1; f.stdout == os.Stdout { // 清空格式 f.printf(m, "\033[0m") @@ -307,82 +273,62 @@ func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server return &Frame{} } func (f *Frame) Start(m *ice.Message, arg ...string) bool { + f.source, f.target = kit.Select(STDIO, arg, 0), m.Target() + var r io.Reader - switch kit.Select(STDIO, arg, 0) { - case STDIO: - // 终端交互 - f.source = STDIO + switch m.Cap(ice.CTX_STREAM, f.source) { + case STDIO: // 终端交互 r, f.stdout = os.Stdin, os.Stdout - m.Cap(ice.CTX_STREAM, STDIO) - f.target = m.Target() + m.Option("_option", ice.MSG_USERNAME) m.Option(ice.MSG_USERNAME, cli.UserName) m.Option(ice.MSG_USERROLE, aaa.ROOT) m.Option(ice.MSG_USERZONE, "boot") aaa.UserRoot(m) default: - if strings.HasPrefix(arg[0], "/dev") { - // 脚本解析 + f.target = m.Source() + + if strings.HasPrefix(f.source, "/dev") { r, f.stdout = m.I, m.O - f.source, f.target = STDIO, m.Source() - m.Cap(ice.CTX_STREAM, STDIO) - break - } - if b, ok := ice.BinPack[arg[0]]; ok { - m.Debug("binpack %v %v", arg[0], len(b)) - buf := bytes.NewBuffer(make([]byte, 0, 4096)) - defer func() { m.Echo(buf.String()) }() - - // 脚本解析 - f.source = arg[0] - r, f.stdout = bytes.NewReader(b), buf - m.Cap(ice.CTX_STREAM, arg[0]) - f.target = m.Source() break } - s := _ssh_script(m, arg[0]) - if s == nil { - return true - } buf := bytes.NewBuffer(make([]byte, 0, 4096)) defer func() { m.Echo(buf.String()) }() - // 脚本解析 - r, f.stdout = s, buf - f.source, f.target = arg[0], m.Source() - m.Cap(ice.CTX_STREAM, arg[0]) + if s := Script(m, f.source); s != nil { + r, f.stdout = s, buf + break + } + + return true } - f.scan(m, kit.Select(STDIO, arg, 0), "", r) + f.scan(m, "", r) return true } func (f *Frame) Close(m *ice.Message, arg ...string) bool { return true } +const ( + STDIO = "stdio" +) const ( SOURCE = "source" TARGET = "target" PROMPT = "prompt" - QRCODE = "qrcode" RETURN = "return" - REMOTE = "remote" -) -const ( - STDIO = "stdio" ) +const SSH = "ssh" -var Index = &ice.Context{Name: "ssh", Help: "终端模块", +var Index = &ice.Context{Name: SSH, Help: "终端模块", Configs: map[string]*ice.Config{ - SOURCE: {Name: "prompt", Help: "命令提示", Value: kit.Data( - web.FAVOR, "cmd.history", - )}, - PROMPT: {Name: "prompt", Help: "命令提示", Value: kit.Data( + SOURCE: {Name: SOURCE, Help: "加载脚本", Value: kit.Data()}, + PROMPT: {Name: PROMPT, Help: "命令提示", Value: kit.Data( "PS1", []interface{}{"\033[33;44m", "count", "[", "time", "]", "\033[5m", "target", "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"}, "PS2", []interface{}{"count", " ", "target", "> "}, )}, - REMOTE: {Name: "remote", Help: "远程连接", Value: kit.Data()}, }, Commands: map[string]*ice.Command{ ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() }}, @@ -410,46 +356,13 @@ var Index = &ice.Context{Name: "ssh", Help: "终端模块", f.ps1 = arg f.prompt(m) }}, - QRCODE: {Name: "qrcode arg...", Help: "命令提示", Action: map[string]*ice.Action{ - "json": {Name: "json [key val]...", Help: "json", Hand: func(m *ice.Message, arg ...string) { - val := map[string]interface{}{} - for i := 0; i < len(arg)-1; i += 2 { - kit.Value(val, arg[i], arg[i+1]) - } - f := m.Target().Server().(*Frame) - f.printf(m, m.Cmdx(cli.PYTHON, "qrcode", kit.Format(val))) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - f := m.Target().Server().(*Frame) - f.printf(m, m.Cmdx(cli.PYTHON, "qrcode", strings.Join(arg, ""))) - }}, - "what": {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Echo(kit.MergeURL2(m.Conf(web.SHARE, "meta.domain"), "/chat/lark/sso")) - }}, RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch cb := m.Optionv("ssh.return").(type) { case func(): cb() } }}, - - REMOTE: {Name: "remote user remote port local", Help: "远程连接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - key := m.Rich(REMOTE, nil, kit.Dict( - "user", arg[0], "remote", arg[1], "port", arg[2], "local", arg[3], - )) - m.Echo(key) - m.Info(key) - - m.Gos(m, func(m *ice.Message) { - for { - m.Cmd(cli.SYSTEM, "ssh", "-CNR", kit.Format("%s:%s:22", arg[2], kit.Select("localhost", arg, 3)), - kit.Format("%s@%s", arg[0], arg[1])) - m.Info("reconnect after 10s") - time.Sleep(time.Second * 10) - } - }) - }}, }, } -func init() { ice.Index.Register(Index, &Frame{}, SOURCE, QRCODE) } +func init() { ice.Index.Register(Index, &Frame{}, SOURCE, TARGET, RETURN) } diff --git a/base/tcp/_trash.go b/base/tcp/_trash.go new file mode 100644 index 00000000..07fee9ef --- /dev/null +++ b/base/tcp/_trash.go @@ -0,0 +1,94 @@ +package tcp + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" + "github.com/shylinux/icebergs/base/cli" + + "bufio" + "net" + "net/url" + "strings" +) + +func init() { + Index.Merge(&ice.Context{ + Commands: map[string]*ice.Command{ + "server": {Name: "server [tcp4|tcp6|udp4|udp6] addr", Help: "server", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + proto := "tcp4" + switch arg[0] { + case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6": + proto, arg = arg[0], arg[1:] + } + + if l, e := net.Listen(proto, arg[0]); m.Assert(e) { + m.Gos(m, func(m *ice.Message) { + // 启动服务 + m.Logs(ice.LOG_LISTEN, "addr", l.Addr()) + for { + if c, e := l.Accept(); m.Assert(e) { + m.Gos(m.Spawns(), func(msg *ice.Message) { + // 建立连接 + msg.Logs(ice.LOG_ACCEPT, "addr", c.RemoteAddr()) + msg.Option(ice.MSG_USERADDR, c.RemoteAddr()) + msg.Option(ice.MSG_USERNAME, "") + msg.Option(ice.MSG_USERROLE, "") + + switch msg.Cmdx("check", c.RemoteAddr().String()) { + case "local": + // 本机用户 + msg.Option(ice.MSG_USERNAME, msg.Conf(cli.RUNTIME, "boot.username")) + msg.Option(ice.MSG_USERROLE, msg.Cmdx(aaa.ROLE, "check", msg.Option(ice.MSG_USERNAME))) + msg.Logs(ice.LOG_AUTH, "name", msg.Option(ice.MSG_USERNAME), "role", msg.Option(ice.MSG_USERROLE)) + } + + cmds := []string{} + buf := bufio.NewWriter(c) + for bio := bufio.NewScanner(c); bio.Scan(); { + text := bio.Text() + msg.Logs("scan", "len", len(text), "text", text) + + if len(text) == 0 { + if len(cmds) > 0 { + msg.Cmd(aaa.ROLE, "right") + // 执行命令 + res := msg.Cmd(cmds) + + // 返回结果 + for _, str := range res.Resultv() { + buf.WriteString("result:") + buf.WriteString(url.QueryEscape(str)) + buf.WriteString("\n") + } + buf.WriteString("\n") + buf.Flush() + + cmds = cmds[:0] + } + continue + } + + // 解析请求 + line := strings.SplitN(bio.Text(), ":", 2) + line[0], e = url.QueryUnescape(line[0]) + m.Assert(e) + line[1], e = url.QueryUnescape(line[1]) + m.Assert(e) + switch line[0] { + case "cmds", ice.MSG_DETAIL: + cmds = append(cmds, line[1]) + default: + msg.Option(line[0], line[1]) + } + } + msg.Logs(ice.LOG_FINISH, "addr", c.RemoteAddr()) + }) + } + } + m.Logs(ice.LOG_FINISH, "addr", l.Addr()) + }) + } + }}, + }, + }, nil) +} diff --git a/base/tcp/client.go b/base/tcp/client.go new file mode 100644 index 00000000..0a07ce58 --- /dev/null +++ b/base/tcp/client.go @@ -0,0 +1,66 @@ +package tcp + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "net" +) + +const ( + DIAL_CB = "dial.cb" + DIAL = "dial" +) + +const CLIENT = "client" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + CLIENT: {Name: CLIENT, Help: "客户端", Value: kit.Data()}, + }, + Commands: map[string]*ice.Command{ + CLIENT: {Name: "client hash auto 连接 清理", Help: "客户端", Action: map[string]*ice.Action{ + DIAL: {Name: "dial host=localhost port=9010", Help: "连接", Hand: func(m *ice.Message, arg ...string) { + c, e := net.Dial(TCP, m.Option(HOST)+":"+m.Option(PORT)) + h := m.Cmdx(mdb.INSERT, CLIENT, "", mdb.HASH, HOST, m.Option(HOST), PORT, m.Option(PORT), kit.MDB_STATUS, kit.Select(ERROR, OPEN, e == nil), kit.MDB_ERROR, kit.Format(e)) + + c = &Conn{h: h, m: m, s: &Stat{}, Conn: c} + if e == nil { + defer c.Close() + } + + switch cb := m.Optionv(DIAL_CB).(type) { + case func(net.Conn, error): + cb(c, e) + case func(net.Conn): + m.Assert(e) + cb(c) + case func(net.Conn, []byte, error): + b := make([]byte, 4096) + for { + n, e := c.Read(b) + if cb(c, b[:n], e); e != nil { + break + } + } + default: + c.Write([]byte("hello world\n")) + } + }}, + mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, CLIENT, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) + }}, + mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.PRUNES, CLIENT, "", mdb.HASH, kit.MDB_STATUS, ERROR) + m.Cmdy(mdb.PRUNES, CLIENT, "", mdb.HASH, kit.MDB_STATUS, CLOSE) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Option(mdb.FIELDS, kit.Select(mdb.DETAIL, "time,hash,status,host,port,error,nread,nwrite", len(arg) == 0)) + m.Cmdy(mdb.SELECT, CLIENT, "", mdb.HASH, kit.MDB_HASH, arg) + m.PushAction("删除") + }}, + }, + }, nil) +} diff --git a/base/tcp/host.go b/base/tcp/host.go new file mode 100644 index 00000000..3f190e47 --- /dev/null +++ b/base/tcp/host.go @@ -0,0 +1,86 @@ +package tcp + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" + kit "github.com/shylinux/toolkits" + + "net" + "strings" +) + +func _host_list(m *ice.Message, ifname string) { + if ifs, e := net.Interfaces(); m.Assert(e) { + for _, v := range ifs { + if ifname != "" && !strings.Contains(v.Name, ifname) { + continue + } + if len(v.HardwareAddr.String()) == 0 { + continue + } + + if ips, e := v.Addrs(); m.Assert(e) { + for _, x := range ips { + ip := strings.Split(x.String(), "/") + if strings.Contains(ip[0], ":") || len(ip) == 0 { + continue + } + + m.Push("index", v.Index) + m.Push("name", v.Name) + m.Push("ip", ip[0]) + m.Push("mask", ip[1]) + m.Push("hard", v.HardwareAddr.String()) + } + } + } + } + + if len(m.Appendv("ip")) == 0 { + m.Push("index", -1) + m.Push("name", "local") + m.Push("ip", "127.0.0.1") + m.Push("mask", "255.0.0.0") + m.Push("hard", "") + } +} + +func _islocalhost(m *ice.Message, ip string) (ok bool) { + if ip == "::1" || strings.HasPrefix(ip, "127.") { + return true + } + if m.Richs(HOST, kit.Keys("meta.black"), ip, nil) != nil { + return false + } + if m.Richs(HOST, kit.Keys("meta.white"), ip, nil) != nil { + m.Log_AUTH(aaa.White, ip) + return true + } + return false +} +func IsLocalHost(m *ice.Message, ip string) bool { return _islocalhost(m, ip) } + +const HOST = "host" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + HOST: {Name: HOST, Help: "主机", Value: kit.Data( + aaa.Black, kit.Dict(kit.MDB_SHORT, kit.MDB_TEXT), + aaa.White, kit.Data(kit.MDB_SHORT, kit.MDB_TEXT), + )}, + }, + Commands: map[string]*ice.Command{ + HOST: {Name: "host name auto", Help: "主机", Action: map[string]*ice.Action{ + aaa.White: {Name: "white", Help: "白名单", Hand: func(m *ice.Message, arg ...string) { + m.Rich(HOST, kit.Keys("meta.white"), kit.Dict(kit.MDB_NAME, "", kit.MDB_TEXT, arg[0])) + }}, + aaa.Black: {Name: "black", Help: "黑名单", Hand: func(m *ice.Message, arg ...string) { + m.Rich(HOST, kit.Keys("meta.black"), kit.Dict(kit.MDB_NAME, "", kit.MDB_TEXT, arg[0])) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + _host_list(m, kit.Select("", arg, 0)) + }}, + }, + }, nil) +} diff --git a/base/tcp/port.go b/base/tcp/port.go new file mode 100644 index 00000000..e1c0fde4 --- /dev/null +++ b/base/tcp/port.go @@ -0,0 +1,72 @@ +package tcp + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" + "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/nfs" + kit "github.com/shylinux/toolkits" + + "net" + "os" + "path" +) + +func _port_list(m *ice.Message, port string, dir string) { + if m.Cmdy(nfs.DIR, path.Join("var/daemon", port, dir)); port == "" { + m.Table(func(index int, value map[string]string, head []string) { + m.Push(PORT, path.Base(value["path"])) + }) + } +} +func _port_right(m *ice.Message, begin string) string { + current := kit.Int(kit.Select(m.Conf(PORT, "meta.current"), begin)) + end := kit.Int(m.Conf(PORT, "meta.end")) + if current >= end { + current = kit.Int(m.Conf(PORT, "meta.begin")) + } + + for i := current; i < end; i++ { + if c, e := net.Dial("tcp", kit.Format(":%d", i)); e == nil { + m.Info("port exists %v", i) + defer c.Close() + continue + } + + m.Log_SELECT(PORT, i) + m.Conf(PORT, "meta.current", i) + return kit.Format("%d", i) + } + return "" +} + +const PORT = "port" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + PORT: {Name: PORT, Help: "端口", Value: kit.Data( + "begin", 10000, "current", 10000, "end", 20000, + )}, + }, + Commands: map[string]*ice.Command{ + PORT: {Name: "port port path auto", Help: "端口", Action: map[string]*ice.Action{ + aaa.Right: {Name: "right [begin]", Help: "分配", Hand: func(m *ice.Message, arg ...string) { + port, p := kit.Select("", arg, 0), "" + for i := 0; i < 10; i++ { + port = _port_right(m, port) + p = path.Join(m.Conf(cli.DAEMON, kit.META_PATH), port) + if _, e := os.Stat(p); e != nil && os.IsNotExist(e) { + os.MkdirAll(p, ice.MOD_DIR) + break + } + port = kit.Format(kit.Int(port) + 1) + } + m.Echo(port) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + _port_list(m, kit.Select("", arg, 0), kit.Select("", arg, 1)) + }}, + }, + }, nil) +} diff --git a/base/tcp/server.go b/base/tcp/server.go new file mode 100644 index 00000000..0ac169fe --- /dev/null +++ b/base/tcp/server.go @@ -0,0 +1,149 @@ +package tcp + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "net" + "strings" +) + +type Stat struct { + nc, nr, nw int +} + +type Conn struct { + h string + m *ice.Message + s *Stat + + net.Conn +} + +func (c *Conn) Read(b []byte) (int, error) { + n, e := c.Conn.Read(b) + c.s.nr += n + c.m.Conf(CLIENT, kit.Keys(kit.MDB_HASH, c.h, kit.MDB_META, "nwrite"), c.s.nw) + return n, e +} +func (c *Conn) Write(b []byte) (int, error) { + n, e := c.Conn.Write(b) + c.s.nw += n + c.m.Conf(CLIENT, kit.Keys(kit.MDB_HASH, c.h, kit.MDB_META, "nread"), c.s.nr) + return n, e +} +func (c *Conn) Close() error { + c.m.Cmd(mdb.MODIFY, CLIENT, "", mdb.HASH, kit.MDB_HASH, c.h, kit.MDB_STATUS, CLOSE, "nread", c.s.nr, "nwrite", c.s.nw) + return c.Conn.Close() +} + +type Listener struct { + h string + m *ice.Message + s *Stat + + net.Listener +} + +func (l Listener) Accept() (net.Conn, error) { + c, e := l.Listener.Accept() + l.s.nc += 1 + l.m.Conf(SERVER, kit.Keys(kit.MDB_HASH, l.h, kit.MDB_META, "nconn"), l.s.nc) + + ls := strings.Split(c.RemoteAddr().String(), ":") + if strings.Contains(c.RemoteAddr().String(), "[") { + ls = strings.Split(strings.TrimPrefix(c.RemoteAddr().String(), "["), "]:") + } + h := l.m.Cmdx(mdb.INSERT, CLIENT, "", mdb.HASH, HOST, ls[0], PORT, ls[1], kit.MDB_STATUS, kit.Select(ERROR, OPEN, e == nil), kit.MDB_ERROR, kit.Format(e)) + + c = &Conn{h: h, m: l.m, s: &Stat{}, Conn: c} + return c, e +} +func (l Listener) Close() error { + l.m.Cmd(mdb.MODIFY, SERVER, "", mdb.HASH, kit.MDB_HASH, l.h, kit.MDB_STATUS, CLOSE) + return l.Listener.Close() +} + +const ( + OPEN = "open" + CLOSE = "close" + ERROR = "error" +) +const ( + LISTEN_CB = "listen.cb" + LISTEN = "listen" +) + +const SERVER = "server" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data()}, + }, + Commands: map[string]*ice.Command{ + SERVER: {Name: "server hash auto 监听 清理", Help: "服务器", Action: map[string]*ice.Action{ + LISTEN: {Name: "LISTEN host=localhost port=9010", Help: "监听", Hand: func(m *ice.Message, arg ...string) { + l, e := net.Listen(TCP, m.Option(HOST)+":"+m.Option(PORT)) + h := m.Option(kit.MDB_HASH) + if h == "" { + h = m.Cmdx(mdb.INSERT, SERVER, "", mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME), HOST, m.Option(HOST), PORT, m.Option(PORT), kit.MDB_STATUS, kit.Select(ERROR, OPEN, e == nil), kit.MDB_ERROR, kit.Format(e)) + } + + l = &Listener{h: h, m: m, s: &Stat{}, Listener: l} + if e == nil { + defer l.Close() + } + + switch cb := m.Optionv(LISTEN_CB).(type) { + case func(net.Listener, error): + cb(l, e) + case func(net.Listener): + m.Assert(e) + cb(l) + case func(net.Conn): + for { + c, e := l.Accept() + if cb(c); e != nil { + break + } + } + case func(net.Conn, error): + for { + c, e := l.Accept() + if cb(c, e); e != nil { + break + } + } + default: + for { + c, e := l.Accept() + if e == nil { + b := make([]byte, 1024) + if n, e := c.Read(b); e == nil { + m.Info("nonce", string(b[:n])) + c.Write(b[:n]) + } + } else { + break + } + c.Close() + } + } + }}, + mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, SERVER, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) + }}, + mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.PRUNES, SERVER, "", mdb.HASH, kit.MDB_STATUS, ERROR) + m.Cmdy(mdb.PRUNES, SERVER, "", mdb.HASH, kit.MDB_STATUS, CLOSE) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Option(mdb.FIELDS, kit.Select(mdb.DETAIL, "time,hash,status,name,host,port,error,nconn", len(arg) == 0)) + m.Cmdy(mdb.SELECT, SERVER, "", mdb.HASH, kit.MDB_HASH, arg) + m.PushAction("删除") + }}, + }, + }, nil) +} diff --git a/base/tcp/tcp.go b/base/tcp/tcp.go index 5b101ad6..92019641 100644 --- a/base/tcp/tcp.go +++ b/base/tcp/tcp.go @@ -1,215 +1,31 @@ package tcp import ( - "os" - "path" - ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/aaa" - "github.com/shylinux/icebergs/base/cli" kit "github.com/shylinux/toolkits" - - "bufio" - "net" - "net/url" - "strings" ) -func _port_list(m *ice.Message) string { - return "" -} -func _port_get(m *ice.Message, begin string) string { - current := kit.Int(kit.Select(m.Conf(PORT, "meta.current"), begin)) - end := kit.Int(m.Conf(PORT, "meta.end")) - if current >= end { - current = kit.Int(m.Conf(PORT, "meta.begin")) - } - for i := current; i < end; i++ { - if c, e := net.Dial("tcp", kit.Format(":%d", i)); e == nil { - m.Info("port exists %v", i) - defer c.Close() - continue - } - m.Conf(PORT, "meta.current", i) - m.Log_SELECT(PORT, i) - return kit.Format("%d", i) - } - return "" -} +const TCP = "tcp" -func _ip_list(m *ice.Message, ifname string) { - if ifs, e := net.Interfaces(); m.Assert(e) { - for _, v := range ifs { - if ifname != "" && !strings.Contains(v.Name, ifname) { - continue - } - if ips, e := v.Addrs(); m.Assert(e) { - for _, x := range ips { - ip := strings.Split(x.String(), "/") - if strings.Contains(ip[0], ":") || len(ip) == 0 { - continue - } - if len(v.HardwareAddr.String()) == 0 { - continue - } - - m.Push("index", v.Index) - m.Push("name", v.Name) - m.Push("ip", ip[0]) - m.Push("mask", ip[1]) - m.Push("hard", v.HardwareAddr.String()) - } - } - } - } -} -func _ip_islocal(m *ice.Message, ip string) (ok bool) { - if ip == "::1" || strings.HasPrefix(ip, "127.") { - return true - } - - if m.Richs(IP, kit.Keys("meta.white"), ip, nil) == nil { - return false - } - m.Log_AUTH(aaa.White, ip) - return true -} -func IPIsLocal(m *ice.Message, ip string) bool { - return _ip_islocal(m, ip) -} - -const ( - IP = "ip" - PORT = "port" -) - -var Index = &ice.Context{Name: "tcp", Help: "通信模块", - Configs: map[string]*ice.Config{ - PORT: {Name: "port", Help: "端口", Value: kit.Data( - "begin", 10000, "current", 10000, "end", 20000, - )}, - IP: {Name: "ip", Help: "地址", Value: kit.Data( - "black", kit.Dict(), - "white", kit.Data(kit.MDB_SHORT, kit.MDB_TEXT), - )}, - }, +var Index = &ice.Context{Name: TCP, Help: "通信模块", Commands: map[string]*ice.Command{ ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() - m.Cmd(IP).Table(func(index int, value map[string]string, head []string) { - m.Cmd(IP, aaa.White, value[IP]) + m.Cmd(HOST).Table(func(index int, value map[string]string, head []string) { + m.Cmd(HOST, aaa.White, value["ip"]) }) - }}, - ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Save(PORT) }}, - - IP: {Name: "ip", Help: "地址", Action: map[string]*ice.Action{ - aaa.White: {Name: "show ip", Help: "白名单", Hand: func(m *ice.Message, arg ...string) { - m.Rich(IP, kit.Keys("meta.white"), kit.Dict( - kit.MDB_NAME, "", - kit.MDB_TEXT, arg[0], - )) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - _ip_list(m, "") - }}, - PORT: {Name: "port", Help: "端口", Action: map[string]*ice.Action{ - "get": {Name: "get", Help: "分配端口", Hand: func(m *ice.Message, arg ...string) { - m.Echo(_port_get(m, "")) - }}, - "select": {Name: "select [begin]", Help: "分配端口", Hand: func(m *ice.Message, arg ...string) { - port, p := kit.Select("", arg, 0), "" - for i := 0; i < 10; i++ { - port = _port_get(m, port) - p = path.Join(m.Conf(cli.DAEMON, kit.META_PATH), port) - if _, e := os.Stat(p); e != nil && os.IsNotExist(e) { - break - } - port = kit.Format(kit.Int(port) + 1) - } - os.MkdirAll(p, ice.MOD_DIR) - m.Echo(port) - }}, - }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - _port_list(m) - }}, - - "server": {Name: "server [tcp4|tcp6|udp4|udp6] addr", Help: "server", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - proto := "tcp4" - switch arg[0] { - case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip", "ip4", "ip6": - proto, arg = arg[0], arg[1:] - } - - if l, e := net.Listen(proto, arg[0]); m.Assert(e) { - m.Gos(m, func(m *ice.Message) { - // 启动服务 - m.Logs(ice.LOG_LISTEN, "addr", l.Addr()) - for { - if c, e := l.Accept(); m.Assert(e) { - m.Gos(m.Spawns(), func(msg *ice.Message) { - // 建立连接 - msg.Logs(ice.LOG_ACCEPT, "addr", c.RemoteAddr()) - msg.Option(ice.MSG_USERADDR, c.RemoteAddr()) - msg.Option(ice.MSG_USERNAME, "") - msg.Option(ice.MSG_USERROLE, "") - - switch msg.Cmdx("check", c.RemoteAddr().String()) { - case "local": - // 本机用户 - msg.Option(ice.MSG_USERNAME, msg.Conf(cli.RUNTIME, "boot.username")) - msg.Option(ice.MSG_USERROLE, msg.Cmdx(aaa.ROLE, "check", msg.Option(ice.MSG_USERNAME))) - msg.Logs(ice.LOG_AUTH, "name", msg.Option(ice.MSG_USERNAME), "role", msg.Option(ice.MSG_USERROLE)) - } - - cmds := []string{} - buf := bufio.NewWriter(c) - for bio := bufio.NewScanner(c); bio.Scan(); { - text := bio.Text() - msg.Logs("scan", "len", len(text), "text", text) - - if len(text) == 0 { - if len(cmds) > 0 { - msg.Cmd(aaa.ROLE, "right") - // 执行命令 - res := msg.Cmd(cmds) - - // 返回结果 - for _, str := range res.Resultv() { - buf.WriteString("result:") - buf.WriteString(url.QueryEscape(str)) - buf.WriteString("\n") - } - buf.WriteString("\n") - buf.Flush() - - cmds = cmds[:0] - } - continue - } - - // 解析请求 - line := strings.SplitN(bio.Text(), ":", 2) - line[0], e = url.QueryUnescape(line[0]) - m.Assert(e) - line[1], e = url.QueryUnescape(line[1]) - m.Assert(e) - switch line[0] { - case "cmds", ice.MSG_DETAIL: - cmds = append(cmds, line[1]) - default: - msg.Option(line[0], line[1]) - } - } - msg.Logs(ice.LOG_FINISH, "addr", c.RemoteAddr()) - }) - } - } - m.Logs(ice.LOG_FINISH, "addr", l.Addr()) - }) - } + ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Richs(CLIENT, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + kit.Value(value, "meta.status", CLOSE) + }) + m.Richs(SERVER, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + kit.Value(value, "meta.status", CLOSE) + }) + m.Save() }}, }, } -func init() { ice.Index.Register(Index, nil, IP, PORT) } +func init() { ice.Index.Register(Index, nil, HOST, PORT, CLIENT, SERVER) } diff --git a/base/tcp/tcp.shy b/base/tcp/tcp.shy new file mode 100644 index 00000000..5e20b5c4 --- /dev/null +++ b/base/tcp/tcp.shy @@ -0,0 +1,6 @@ +chapter "tcp" + +field host tcp.host +# field port tcp.port +field server tcp.server +field client tcp.client diff --git a/base/web/favor.go b/base/web/_favor.go similarity index 90% rename from base/web/favor.go rename to base/web/_favor.go index a123ae8d..1b29b768 100644 --- a/base/web/favor.go +++ b/base/web/_favor.go @@ -359,5 +359,45 @@ func init() { m.Option(kit.MDB_NAME), m.Option(kit.MDB_TEXT), m.Option(kit.MDB_EXTRA)) } }}, + "/share/": {Name: "/share/", Help: "共享链", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Richs(SHARE, nil, kit.Select(m.Option(kit.SSH_SHARE), arg, 0), func(key string, value map[string]interface{}) { + m.Log_SELECT(kit.MDB_META, SHARE, "arg", arg, "value", kit.Format(value)) + if m.Warn(m.Option(ice.MSG_USERROLE) != aaa.ROOT && kit.Time(kit.Format(value[kit.MDB_TIME])) < kit.Time(m.Time()), "expired") { + m.Echo("expired") + return + } + + switch value[kit.MDB_TYPE] { + case STORY: + value = _share_story(m, value, arg...) + } + + if _share_show(m, key, value, kit.Select("", arg, 1), kit.Select("", arg, 2)) { + return + } + + switch value[kit.MDB_TYPE] { + case TYPE_RIVER: + // 共享群组 + m.Render("redirect", "/", "share", key, "river", kit.Format(value["text"])) + + case TYPE_STORM: + // 共享应用 + m.Render("redirect", "/", "share", key, "storm", kit.Format(value["text"]), "river", kit.Format(kit.Value(value, "extra.river"))) + + case TYPE_ACTION: + _share_action(m, value, arg...) + + default: + // 查看数据 + m.Option(kit.MDB_VALUE, value) + m.Option(kit.MDB_TYPE, value[kit.MDB_TYPE]) + m.Option(kit.MDB_NAME, value[kit.MDB_NAME]) + m.Option(kit.MDB_TEXT, value[kit.MDB_TEXT]) + m.Render(ice.RENDER_TEMPLATE, m.Conf(SHARE, "meta.template.simple")) + m.Option(ice.MSG_OUTPUT, ice.RENDER_RESULT) + } + }) + }}, }}, nil) } diff --git a/base/web/_share.go b/base/web/_share.go new file mode 100644 index 00000000..a71b56be --- /dev/null +++ b/base/web/_share.go @@ -0,0 +1,201 @@ +package web + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" + "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/ctx" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "fmt" + "net/http" + "os" + "path" + "strings" + "time" +) + +func _share_list(m *ice.Message, key string, fields ...string) { + if key == "" { + m.Grows(SHARE, nil, "", "", func(index int, value map[string]interface{}) { + m.Push("", value, []string{kit.MDB_TIME, kit.SSH_SHARE, kit.MDB_TYPE, kit.MDB_NAME, kit.MDB_TEXT}) + m.Push(kit.MDB_LINK, fmt.Sprintf(m.Conf(SHARE, "meta.template.link"), m.Conf(SHARE, "meta.domain"), value[kit.SSH_SHARE], value[kit.SSH_SHARE])) + }) + return + } + + m.Richs(SHARE, nil, key, func(key string, value map[string]interface{}) { + m.Push("detail", value) + + m.Push(kit.MDB_KEY, kit.MDB_LINK) + m.Push(kit.MDB_VALUE, m.Cmdx(mdb.RENDER, RENDER.A, key, URL(m, kit.Format("/share/%s", key)))) + m.Push(kit.MDB_KEY, kit.SSH_SHARE) + m.Push(kit.MDB_VALUE, m.Cmdx(mdb.RENDER, RENDER.IMG, URL(m, kit.Format("/share/%s/share", key)))) + m.Push(kit.MDB_KEY, kit.MDB_VALUE) + m.Push(kit.MDB_VALUE, m.Cmdx(mdb.RENDER, RENDER.IMG, URL(m, kit.Format("/share/%s/value", key)))) + }) +} +func _share_show(m *ice.Message, key string, value map[string]interface{}, arg ...string) bool { + switch kit.Select("", arg, 0) { + case "check", "安全码": + m.Render(ice.RENDER_QRCODE, kit.Format(kit.Dict( + kit.MDB_TYPE, SHARE, kit.MDB_NAME, value[kit.MDB_TYPE], kit.MDB_TEXT, key, + ))) + case kit.SSH_SHARE, "共享码": + m.Render(ice.RENDER_QRCODE, kit.Format("%s/share/%s/?share=%s", m.Conf(SHARE, "meta.domain"), key, key)) + case kit.MDB_VALUE, "数据值": + m.Render(ice.RENDER_QRCODE, kit.Format(value), kit.Select("256", arg, 1)) + case kit.MDB_TEXT: + m.Render(ice.RENDER_QRCODE, kit.Format(value[kit.MDB_TEXT])) + case "detail", "详情": + m.Render(kit.Formats(value)) + case "download", "下载": + if strings.HasPrefix(kit.Format(value["text"]), m.Conf(CACHE, "meta.path")) { + m.Render(ice.RENDER_DOWNLOAD, value["text"], value["type"], value["name"]) + } else { + m.Render("%s", value["text"]) + } + default: + return false + } + return true +} +func _share_create(m *ice.Message, kind, name, text string, arg ...string) string { + h := m.Rich(SHARE, nil, kit.Dict( + kit.MDB_TIME, m.Time(m.Conf(SHARE, "meta.expire")), + kit.MDB_TYPE, kind, kit.MDB_NAME, name, kit.MDB_TEXT, text, + kit.MDB_EXTRA, kit.Dict( + aaa.USERROLE, m.Option(ice.MSG_USERROLE), + aaa.USERNAME, m.Option(ice.MSG_USERNAME), + "river", m.Option(ice.MSG_RIVER), + "storm", m.Option(ice.MSG_STORM), + arg), + )) + + // 创建列表 + m.Grow(SHARE, nil, kit.Dict( + kit.MDB_TYPE, kind, kit.MDB_NAME, name, kit.MDB_TEXT, text, + kit.SSH_SHARE, h, + )) + m.Log_CREATE(kit.SSH_SHARE, h, kit.MDB_TYPE, kind, kit.MDB_NAME, name) + m.Echo(h) + return h +} + +func _share_story(m *ice.Message, value map[string]interface{}, arg ...string) map[string]interface{} { + msg := m.Cmd(STORY, INDEX, value["text"]) + if msg.Append("text") == "" && kit.Value(value, "extra.pod") != "" { + msg = m.Cmd(SPACE, kit.Value(value, "extra.pod"), STORY, INDEX, value["text"]) + } + value = kit.Dict("type", msg.Append("scene"), "name", msg.Append("story"), "text", msg.Append("text"), "file", msg.Append("file")) + m.Log(ice.LOG_EXPORT, "%s: %v", arg, kit.Format(value)) + return value +} +func _share_action(m *ice.Message, value map[string]interface{}, arg ...string) bool { + if len(arg) == 1 || arg[1] == "" { + return _share_action_redirect(m, value, arg[0]) + } + if arg[1] == "" { + return _share_action_page(m, value) + } + if len(arg) == 2 { + return _share_action_list(m, value, arg[0], arg[1]) + } + + // 默认参数 + meta := kit.Value(value, kit.Format("extra.tool.%s", arg[2])).(map[string]interface{}) + if meta["single"] == "yes" && kit.Select("", arg, 3) != "action" { + arg = append(arg[:3], kit.Simple(kit.UnMarshal(kit.Format(meta["args"])))...) + for i := len(arg) - 1; i >= 0; i-- { + if arg[i] != "" { + return true + } + arg = arg[:i] + } + } + + // 执行命令 + cmds := kit.Simple(m.Space(meta["pod"]), kit.Keys(meta["ctx"], meta["cmd"]), arg[3:]) + m.Cmdy(cmds).Option("cmds", cmds) + m.Option("title", value["name"]) + if strings.HasPrefix(kit.Format(value["text"]), m.Conf(CACHE, "meta.path")) { + m.Render(ice.RENDER_DOWNLOAD, value["text"], value["type"], value["name"]) + } else { + m.Render("%s", value["text"]) + } + return true +} +func _share_action_redirect(m *ice.Message, value map[string]interface{}, share string) bool { + tool := kit.Value(value, "extra.tool.0").(map[string]interface{}) + m.Render("redirect", "/share", "share", share, "title", kit.Format(value["name"]), + "river", kit.Format(kit.Value(value, "extra.river")), + "storm", kit.Format(kit.Value(value, "extra.storm")), + "pod", kit.Format(tool["pod"]), kit.UnMarshal(kit.Format(tool["val"])), + ) + return true +} +func _share_action_page(m *ice.Message, value map[string]interface{}) bool { + Render(m, ice.RENDER_DOWNLOAD, m.Conf(SERVE, "meta.page.share")) + return true +} +func _share_action_list(m *ice.Message, value map[string]interface{}, river, storm string) bool { + value["count"] = kit.Int(value["count"]) + 1 + kit.Fetch(kit.Value(value, "extra.tool"), func(index int, value map[string]interface{}) { + m.Push("river", river) + m.Push("storm", storm) + m.Push("action", index) + + m.Push("node", value["pod"]) + m.Push("group", value["ctx"]) + m.Push("index", value["cmd"]) + m.Push("args", value["args"]) + m.Push("value", value["value"]) + + msg := m.Cmd(m.Space(value["pod"]), ctx.COMMAND, value["ctx"], value["cmd"]) + ls := strings.Split(kit.Format(value["cmd"]), ".") + m.Push("name", ls[len(ls)-1]) + m.Push("help", kit.Select(msg.Append("help"), kit.Format(value["help"]))) + m.Push("inputs", msg.Append("list")) + m.Push("feature", msg.Append("meta")) + }) + return true +} + +func _share_auth(m *ice.Message, share string, role string) { + m.Richs(SHARE, nil, share, func(key string, value map[string]interface{}) { + switch value["type"] { + case "active": + m.Cmdy(SPACE, value["name"], "sessid", m.Cmdx(aaa.SESS, "create", role)) + case "user": + m.Cmdy(aaa.ROLE, role, value["name"]) + default: + m.Cmdy(aaa.SESS, "auth", value["text"], role) + } + }) +} +func _share_check(m *ice.Message, share string) { + m.Richs(SHARE, nil, share, func(key string, value map[string]interface{}) { + m.Render(ice.RENDER_QRCODE, kit.Format(kit.Dict( + kit.MDB_TYPE, "share", kit.MDB_NAME, value["type"], kit.MDB_TEXT, key, + ))) + }) +} +func _trash(m *ice.Message, arg ...string) { + switch arg[0] { + case "invite": + arg = []string{arg[0], m.Cmdx(SHARE, "invite", kit.Select("tech", arg, 1), kit.Select("miss", arg, 2))} + fallthrough + case "check": + _share_check(m, arg[1]) + case "auth": + _share_auth(m, arg[1], arg[2]) + case "add": + _share_create(m, arg[1], arg[2], arg[3], arg[4:]...) + default: + if len(arg) == 1 { + _share_list(m, arg[0]) + break + } + } +} diff --git a/base/web/cache.go b/base/web/cache.go index 5cf18735..8bd355fc 100644 --- a/base/web/cache.go +++ b/base/web/cache.go @@ -120,10 +120,10 @@ func _cache_download(m *ice.Message, r *http.Response) (file, size string) { value = value[kit.MDB_META].(map[string]interface{}) s := size * 100 / total - if s != kit.Int(value[kit.MDB_STEP]) && s%10 == 0 { - m.Log_IMPORT(kit.MDB_FILE, path.Base(cb[2]), kit.MDB_STEP, s, kit.MDB_SIZE, kit.FmtSize(int64(size)), kit.MDB_TOTAL, kit.FmtSize(int64(total))) + if s != kit.Int(value[kit.SSH_STEP]) && s%10 == 0 { + m.Log_IMPORT(kit.MDB_FILE, path.Base(cb[2]), kit.SSH_STEP, s, kit.MDB_SIZE, kit.FmtSize(int64(size)), kit.MDB_TOTAL, kit.FmtSize(int64(total))) } - value[kit.MDB_STEP], value[kit.MDB_SIZE], value[kit.MDB_TOTAL] = kit.Format(s), size, total + value[kit.SSH_STEP], value[kit.MDB_SIZE], value[kit.MDB_TOTAL] = kit.Format(s), size, total }) case func(int, int): cb(size, total) diff --git a/base/web/dream.go b/base/web/dream.go index 604d4f52..96c154cc 100644 --- a/base/web/dream.go +++ b/base/web/dream.go @@ -99,7 +99,7 @@ ish_miss_prepare_install Commands: map[string]*ice.Command{ DREAM: {Name: "dream [name [cmd...]] auto", Help: "梦想家", Meta: kit.Dict("detail", []interface{}{"启动", "停止"}), Action: map[string]*ice.Action{ gdb.START: {Name: "start type name", Help: "启动", Hand: func(m *ice.Message, arg ...string) { - m.Option(kit.MDB_NAME, kit.Select(path.Base(m.Option(kit.MDB_REPOS)), m.Option(kit.MDB_NAME))) + m.Option(kit.MDB_NAME, kit.Select(path.Base(m.Option(kit.SSH_REPOS)), m.Option(kit.MDB_NAME))) _dream_show(m, m.Option(kit.MDB_NAME)) }}, gdb.STOP: {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) { diff --git a/base/web/label.go b/base/web/label.go index ada9a60a..a04a5add 100644 --- a/base/web/label.go +++ b/base/web/label.go @@ -8,14 +8,14 @@ import ( ) func _label_add(m *ice.Message, cmd string) { - if m.Option(cmd) != "" && m.Option(kit.MDB_GROUP) != "" && m.Option(kit.MDB_NAME) != "" { - m.Cmdy(cmd, m.Option(cmd), "add", m.Option(kit.MDB_GROUP), m.Option(kit.MDB_NAME)) + if m.Option(cmd) != "" && m.Option(kit.SSH_GROUP) != "" && m.Option(kit.MDB_NAME) != "" { + m.Cmdy(cmd, m.Option(cmd), "add", m.Option(kit.SSH_GROUP), m.Option(kit.MDB_NAME)) m.Option(ice.FIELD_RELOAD, "true") } } func _label_del(m *ice.Message, cmd string) { - if m.Option(cmd) != "" && m.Option(kit.MDB_GROUP) != "" && m.Option(kit.MDB_NAME) != "" { - m.Cmdy(cmd, m.Option(cmd), "del", m.Option(kit.MDB_GROUP), m.Option(kit.MDB_NAME)) + if m.Option(cmd) != "" && m.Option(kit.SSH_GROUP) != "" && m.Option(kit.MDB_NAME) != "" { + m.Cmdy(cmd, m.Option(cmd), "del", m.Option(kit.SSH_GROUP), m.Option(kit.MDB_NAME)) m.Option(ice.FIELD_RELOAD, "true") } } @@ -23,7 +23,7 @@ func _label_prune(m *ice.Message, cmd string) { m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) { m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(sub string, value map[string]interface{}) { if value[kit.MDB_STATUS] != "busy" { - m.Cmdy(cmd, m.Option(cmd), "del", value[kit.MDB_GROUP], value[kit.MDB_NAME]) + m.Cmdy(cmd, m.Option(cmd), "del", value[kit.SSH_GROUP], value[kit.MDB_NAME]) m.Option(ice.FIELD_RELOAD, "true") } }) @@ -70,7 +70,7 @@ func _label_select(m *ice.Message, cmd string, arg ...string) { if len(arg) < 2 { // 二级列表 m.Option(ice.FIELD_DETAIL, "添加", "退还", "清理", "清空") - m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_GROUP, kit.MDB_STATUS, kit.MDB_NAME}) + m.Push(key, value, []string{kit.MDB_TIME, kit.SSH_GROUP, kit.MDB_STATUS, kit.MDB_NAME}) return } // 分组详情 @@ -94,7 +94,7 @@ func _label_create(m *ice.Message, cmd string, key string, arg ...string) { }) == nil { m.Logs(ice.LOG_INSERT, cmd, arg[0], kit.MDB_NAME, pod) m.Rich(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict( - kit.MDB_NAME, pod, kit.MDB_GROUP, arg[2], kit.MDB_STATUS, "free", + kit.MDB_NAME, pod, kit.SSH_GROUP, arg[2], kit.MDB_STATUS, "free", )) } m.Echo(arg[0]) @@ -105,7 +105,7 @@ func _label_remove(m *ice.Message, cmd string, key string, arg ...string) { if value[kit.MDB_STATUS] == "free" { value[kit.MDB_STATUS] = "void" m.Logs(ice.LOG_MODIFY, cmd, arg[0], kit.MDB_NAME, arg[3], kit.MDB_STATUS, "void") - m.Cmdx(GROUP, value[kit.MDB_GROUP], "put", arg[3]) + m.Cmdx(GROUP, value[kit.SSH_GROUP], "put", arg[3]) m.Echo(arg[3]) } }) @@ -176,7 +176,7 @@ func init() { if arg[0] == "route" { m.Cmd(ROUTE).Table(func(index int, value map[string]string, field []string) { m.Rich(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict( - kit.MDB_NAME, value["name"], kit.MDB_GROUP, arg[0], kit.MDB_STATUS, "free", + kit.MDB_NAME, value["name"], kit.SSH_GROUP, arg[0], kit.MDB_STATUS, "free", )) }) } diff --git a/base/web/route.go b/base/web/route.go index e224f175..d9bb9635 100644 --- a/base/web/route.go +++ b/base/web/route.go @@ -21,19 +21,19 @@ func _route_travel(m *ice.Message, route string) { // 远程查询 m.Cmd(SPACE, val[kit.MDB_NAME], ROUTE).Table(func(index int, value map[string]string, head []string) { m.Push(kit.MDB_TYPE, value[kit.MDB_TYPE]) - m.Push(kit.MDB_ROUTE, kit.Keys(val[kit.MDB_NAME], value[kit.MDB_ROUTE])) + m.Push(kit.SSH_ROUTE, kit.Keys(val[kit.MDB_NAME], value[kit.SSH_ROUTE])) }) fallthrough case WORKER: // 本机查询 m.Push(kit.MDB_TYPE, val[kit.MDB_TYPE]) - m.Push(kit.MDB_ROUTE, val[kit.MDB_NAME]) + m.Push(kit.SSH_ROUTE, val[kit.MDB_NAME]) } }) } else { m.Cmd(SPACE, route, ROUTE).Table(func(index int, value map[string]string, head []string) { m.Push(kit.MDB_TYPE, value[kit.MDB_TYPE]) - m.Push(kit.MDB_ROUTE, kit.Keys(route, value[kit.MDB_ROUTE])) + m.Push(kit.SSH_ROUTE, kit.Keys(route, value[kit.SSH_ROUTE])) }) } } @@ -43,7 +43,7 @@ const ROUTE = "route" func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ - ROUTE: {Name: ROUTE, Help: "路由器", Value: kit.Data(kit.MDB_SHORT, kit.MDB_ROUTE)}, + ROUTE: {Name: ROUTE, Help: "路由器", Value: kit.Data(kit.MDB_SHORT, kit.SSH_ROUTE)}, }, Commands: map[string]*ice.Command{ ROUTE: {Name: "route route ctx cmd auto 添加", Help: "路由", Action: map[string]*ice.Action{ @@ -112,8 +112,8 @@ func init() { m.Push("route", MYSELF) m.Table(func(index int, value map[string]string, field []string) { - m.PushRender(kit.MDB_LINK, "a", value[kit.MDB_ROUTE], - kit.MergeURL(m.Option(ice.MSG_USERWEB), "pod", kit.Keys(m.Option("pod", value[kit.MDB_ROUTE])))) + m.PushRender(kit.MDB_LINK, "a", value[kit.SSH_ROUTE], + kit.MergeURL(m.Option(ice.MSG_USERWEB), "pod", kit.Keys(m.Option("pod", value[kit.SSH_ROUTE])))) switch value[kit.MDB_TYPE] { case MYSELF, SERVER: m.PushRender("action", "button", "启动") @@ -121,7 +121,7 @@ func init() { m.PushRender("action", "button", "结束") } }) - m.Sort(kit.MDB_ROUTE) + m.Sort(kit.SSH_ROUTE) }}, "/route/": {Name: "/route/", Help: "路由器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch arg[0] { diff --git a/base/web/serve.go b/base/web/serve.go index 3f997b24..0007e5c3 100644 --- a/base/web/serve.go +++ b/base/web/serve.go @@ -27,7 +27,7 @@ func _serve_login(msg *ice.Message, cmds []string, w http.ResponseWriter, r *htt aaa.SessCheck(msg, msg.Option(ice.MSG_SESSID)) } - if !msg.Options(ice.MSG_USERNAME) && tcp.IPIsLocal(msg, msg.Option(ice.MSG_USERIP)) { + if !msg.Options(ice.MSG_USERNAME) && tcp.IsLocalHost(msg, msg.Option(ice.MSG_USERIP)) { // 自动认证 if aaa.UserLogin(msg, cli.UserName, cli.PassWord) { if strings.HasPrefix(msg.Option(ice.MSG_USERUA), "Mozilla/5.0") { diff --git a/base/web/share.go b/base/web/share.go index f3a19b81..ee647441 100644 --- a/base/web/share.go +++ b/base/web/share.go @@ -4,11 +4,9 @@ import ( ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" - "github.com/shylinux/icebergs/base/ctx" "github.com/shylinux/icebergs/base/mdb" kit "github.com/shylinux/toolkits" - "fmt" "net/http" "os" "path" @@ -16,51 +14,6 @@ import ( "time" ) -func _share_list(m *ice.Message, key string, fields ...string) { - if key == "" { - m.Grows(SHARE, nil, "", "", func(index int, value map[string]interface{}) { - m.Push("", value, []string{kit.MDB_TIME, kit.MDB_SHARE, kit.MDB_TYPE, kit.MDB_NAME, kit.MDB_TEXT}) - m.Push(kit.MDB_LINK, fmt.Sprintf(m.Conf(SHARE, "meta.template.link"), m.Conf(SHARE, "meta.domain"), value[kit.MDB_SHARE], value[kit.MDB_SHARE])) - }) - return - } - - m.Richs(SHARE, nil, key, func(key string, value map[string]interface{}) { - m.Push("detail", value) - - m.Push(kit.MDB_KEY, kit.MDB_LINK) - m.Push(kit.MDB_VALUE, m.Cmdx(mdb.RENDER, RENDER.A, key, URL(m, kit.Format("/share/%s", key)))) - m.Push(kit.MDB_KEY, kit.MDB_SHARE) - m.Push(kit.MDB_VALUE, m.Cmdx(mdb.RENDER, RENDER.IMG, URL(m, kit.Format("/share/%s/share", key)))) - m.Push(kit.MDB_KEY, kit.MDB_VALUE) - m.Push(kit.MDB_VALUE, m.Cmdx(mdb.RENDER, RENDER.IMG, URL(m, kit.Format("/share/%s/value", key)))) - }) -} -func _share_show(m *ice.Message, key string, value map[string]interface{}, arg ...string) bool { - switch kit.Select("", arg, 0) { - case "check", "安全码": - m.Render(ice.RENDER_QRCODE, kit.Format(kit.Dict( - kit.MDB_TYPE, SHARE, kit.MDB_NAME, value[kit.MDB_TYPE], kit.MDB_TEXT, key, - ))) - case kit.MDB_SHARE, "共享码": - m.Render(ice.RENDER_QRCODE, kit.Format("%s/share/%s/?share=%s", m.Conf(SHARE, "meta.domain"), key, key)) - case kit.MDB_VALUE, "数据值": - m.Render(ice.RENDER_QRCODE, kit.Format(value), kit.Select("256", arg, 1)) - case kit.MDB_TEXT: - m.Render(ice.RENDER_QRCODE, kit.Format(value[kit.MDB_TEXT])) - case "detail", "详情": - m.Render(kit.Formats(value)) - case "download", "下载": - if strings.HasPrefix(kit.Format(value["text"]), m.Conf(CACHE, "meta.path")) { - m.Render(ice.RENDER_DOWNLOAD, value["text"], value["type"], value["name"]) - } else { - m.Render("%s", value["text"]) - } - default: - return false - } - return true -} func _share_repos(m *ice.Message, repos string, arg ...string) { prefix := m.Conf(SERVE, "meta.volcanos.require") if _, e := os.Stat(path.Join(prefix, repos)); e != nil { @@ -68,6 +21,10 @@ func _share_repos(m *ice.Message, repos string, arg ...string) { } m.Render(ice.RENDER_DOWNLOAD, path.Join(prefix, repos, path.Join(arg...))) } +func _share_remote(m *ice.Message, pod string, arg ...string) { + m.Cmdy(SPACE, pod, "web./publish/", arg) + m.Render(ice.RENDER_RESULT) +} func _share_local(m *ice.Message, arg ...string) { p := path.Join(arg...) switch ls := strings.Split(p, "/"); ls[0] { @@ -114,148 +71,6 @@ func _share_cache(m *ice.Message, arg ...string) { msg := m.Cmd(CACHE, arg[0]) m.Render(ice.RENDER_DOWNLOAD, msg.Append(kit.MDB_FILE), msg.Append(kit.MDB_TYPE), msg.Append(kit.MDB_NAME)) } -func _share_remote(m *ice.Message, pod string, arg ...string) { - m.Cmdy(SPACE, pod, "web./publish/", arg) - m.Render(ice.RENDER_RESULT) -} -func _share_create(m *ice.Message, kind, name, text string, arg ...string) string { - h := m.Rich(SHARE, nil, kit.Dict( - kit.MDB_TIME, m.Time(m.Conf(SHARE, "meta.expire")), - kit.MDB_TYPE, kind, kit.MDB_NAME, name, kit.MDB_TEXT, text, - kit.MDB_EXTRA, kit.Dict( - aaa.USERROLE, m.Option(ice.MSG_USERROLE), - aaa.USERNAME, m.Option(ice.MSG_USERNAME), - "river", m.Option(ice.MSG_RIVER), - "storm", m.Option(ice.MSG_STORM), - arg), - )) - - // 创建列表 - m.Grow(SHARE, nil, kit.Dict( - kit.MDB_TYPE, kind, kit.MDB_NAME, name, kit.MDB_TEXT, text, - kit.MDB_SHARE, h, - )) - m.Log_CREATE(kit.MDB_SHARE, h, kit.MDB_TYPE, kind, kit.MDB_NAME, name) - m.Echo(h) - return h -} - -func _share_story(m *ice.Message, value map[string]interface{}, arg ...string) map[string]interface{} { - msg := m.Cmd(STORY, INDEX, value["text"]) - if msg.Append("text") == "" && kit.Value(value, "extra.pod") != "" { - msg = m.Cmd(SPACE, kit.Value(value, "extra.pod"), STORY, INDEX, value["text"]) - } - value = kit.Dict("type", msg.Append("scene"), "name", msg.Append("story"), "text", msg.Append("text"), "file", msg.Append("file")) - m.Log(ice.LOG_EXPORT, "%s: %v", arg, kit.Format(value)) - return value -} -func _share_action(m *ice.Message, value map[string]interface{}, arg ...string) bool { - if len(arg) == 1 || arg[1] == "" { - return _share_action_redirect(m, value, arg[0]) - } - if arg[1] == "" { - return _share_action_page(m, value) - } - if len(arg) == 2 { - return _share_action_list(m, value, arg[0], arg[1]) - } - - // 默认参数 - meta := kit.Value(value, kit.Format("extra.tool.%s", arg[2])).(map[string]interface{}) - if meta["single"] == "yes" && kit.Select("", arg, 3) != "action" { - arg = append(arg[:3], kit.Simple(kit.UnMarshal(kit.Format(meta["args"])))...) - for i := len(arg) - 1; i >= 0; i-- { - if arg[i] != "" { - return true - } - arg = arg[:i] - } - } - - // 执行命令 - cmds := kit.Simple(m.Space(meta["pod"]), kit.Keys(meta["ctx"], meta["cmd"]), arg[3:]) - m.Cmdy(cmds).Option("cmds", cmds) - m.Option("title", value["name"]) - if strings.HasPrefix(kit.Format(value["text"]), m.Conf(CACHE, "meta.path")) { - m.Render(ice.RENDER_DOWNLOAD, value["text"], value["type"], value["name"]) - } else { - m.Render("%s", value["text"]) - } - return true -} -func _share_action_redirect(m *ice.Message, value map[string]interface{}, share string) bool { - tool := kit.Value(value, "extra.tool.0").(map[string]interface{}) - m.Render("redirect", "/share", "share", share, "title", kit.Format(value["name"]), - "river", kit.Format(kit.Value(value, "extra.river")), - "storm", kit.Format(kit.Value(value, "extra.storm")), - "pod", kit.Format(tool["pod"]), kit.UnMarshal(kit.Format(tool["val"])), - ) - return true -} -func _share_action_page(m *ice.Message, value map[string]interface{}) bool { - Render(m, ice.RENDER_DOWNLOAD, m.Conf(SERVE, "meta.page.share")) - return true -} -func _share_action_list(m *ice.Message, value map[string]interface{}, river, storm string) bool { - value["count"] = kit.Int(value["count"]) + 1 - kit.Fetch(kit.Value(value, "extra.tool"), func(index int, value map[string]interface{}) { - m.Push("river", river) - m.Push("storm", storm) - m.Push("action", index) - - m.Push("node", value["pod"]) - m.Push("group", value["ctx"]) - m.Push("index", value["cmd"]) - m.Push("args", value["args"]) - m.Push("value", value["value"]) - - msg := m.Cmd(m.Space(value["pod"]), ctx.COMMAND, value["ctx"], value["cmd"]) - ls := strings.Split(kit.Format(value["cmd"]), ".") - m.Push("name", ls[len(ls)-1]) - m.Push("help", kit.Select(msg.Append("help"), kit.Format(value["help"]))) - m.Push("inputs", msg.Append("list")) - m.Push("feature", msg.Append("meta")) - }) - return true -} - -func _share_auth(m *ice.Message, share string, role string) { - m.Richs(SHARE, nil, share, func(key string, value map[string]interface{}) { - switch value["type"] { - case "active": - m.Cmdy(SPACE, value["name"], "sessid", m.Cmdx(aaa.SESS, "create", role)) - case "user": - m.Cmdy(aaa.ROLE, role, value["name"]) - default: - m.Cmdy(aaa.SESS, "auth", value["text"], role) - } - }) -} -func _share_check(m *ice.Message, share string) { - m.Richs(SHARE, nil, share, func(key string, value map[string]interface{}) { - m.Render(ice.RENDER_QRCODE, kit.Format(kit.Dict( - kit.MDB_TYPE, "share", kit.MDB_NAME, value["type"], kit.MDB_TEXT, key, - ))) - }) -} -func _trash(m *ice.Message, arg ...string) { - switch arg[0] { - case "invite": - arg = []string{arg[0], m.Cmdx(SHARE, "invite", kit.Select("tech", arg, 1), kit.Select("miss", arg, 2))} - fallthrough - case "check": - _share_check(m, arg[1]) - case "auth": - _share_auth(m, arg[1], arg[2]) - case "add": - _share_create(m, arg[1], arg[2], arg[3], arg[4:]...) - default: - if len(arg) == 1 { - _share_list(m, arg[0]) - break - } - } -} const SHARE = "share" @@ -292,46 +107,6 @@ func init() { "/share/cache/": {Name: "/share/cache/", Help: "缓存池", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { _share_cache(m, arg...) }}, - "/share/": {Name: "/share/", Help: "共享链", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Richs(SHARE, nil, kit.Select(m.Option(kit.MDB_SHARE), arg, 0), func(key string, value map[string]interface{}) { - m.Log_SELECT(kit.MDB_META, SHARE, "arg", arg, "value", kit.Format(value)) - if m.Warn(m.Option(ice.MSG_USERROLE) != aaa.ROOT && kit.Time(kit.Format(value[kit.MDB_TIME])) < kit.Time(m.Time()), "expired") { - m.Echo("expired") - return - } - - switch value[kit.MDB_TYPE] { - case STORY: - value = _share_story(m, value, arg...) - } - - if _share_show(m, key, value, kit.Select("", arg, 1), kit.Select("", arg, 2)) { - return - } - - switch value[kit.MDB_TYPE] { - case TYPE_RIVER: - // 共享群组 - m.Render("redirect", "/", "share", key, "river", kit.Format(value["text"])) - - case TYPE_STORM: - // 共享应用 - m.Render("redirect", "/", "share", key, "storm", kit.Format(value["text"]), "river", kit.Format(kit.Value(value, "extra.river"))) - - case TYPE_ACTION: - _share_action(m, value, arg...) - - default: - // 查看数据 - m.Option(kit.MDB_VALUE, value) - m.Option(kit.MDB_TYPE, value[kit.MDB_TYPE]) - m.Option(kit.MDB_NAME, value[kit.MDB_NAME]) - m.Option(kit.MDB_TEXT, value[kit.MDB_TEXT]) - m.Render(ice.RENDER_TEMPLATE, m.Conf(SHARE, "meta.template.simple")) - m.Option(ice.MSG_OUTPUT, ice.RENDER_RESULT) - } - }) - }}, "/plugin/github.com/": {Name: "/space/", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { _share_repos(m, path.Join(strings.Split(cmd, "/")[2:5]...), arg[6:]...) }}, diff --git a/base/web/spide.go b/base/web/spide.go index 458c7779..7be5b6c4 100644 --- a/base/web/spide.go +++ b/base/web/spide.go @@ -2,6 +2,7 @@ package web import ( ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/tcp" @@ -61,7 +62,7 @@ func _spide_login(m *ice.Message, name string) { func _spide_create(m *ice.Message, name, address string, arg ...string) { if uri, e := url.Parse(address); e == nil && address != "" { if uri.Host == "random" { - uri.Host = ":" + m.Cmdx(tcp.PORT, "get") + uri.Host = ":" + m.Cmdx(tcp.PORT, aaa.Right) address = strings.Replace(address, "random", uri.Host, -1) } diff --git a/base/web/web.go b/base/web/web.go index 717e1a49..9fbc5d2a 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -7,10 +7,13 @@ import ( "github.com/shylinux/icebergs/base/ctx" "github.com/shylinux/icebergs/base/gdb" "github.com/shylinux/icebergs/base/mdb" + "github.com/shylinux/icebergs/base/tcp" kit "github.com/shylinux/toolkits" + "net" "net/http" "path" + "strings" ) type Frame struct { @@ -70,19 +73,18 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool { } }) - // TODO simple m.Richs(SPIDE, nil, arg[0], func(key string, value map[string]interface{}) { client := value["client"].(map[string]interface{}) - // 服务地址 - port := m.Cap(ice.CTX_STREAM, client["hostname"]) - m.Log("serve", "listen %s %s %v", arg[0], port, m.Conf(cli.RUNTIME, "node")) + web.m, web.Server = m, &http.Server{Handler: web} + m.Option(tcp.LISTEN_CB, func(l net.Listener) { + m.Event(gdb.SERVE_START, arg[0]) + m.Warn(true, "listen %s", web.Server.Serve(l)) + m.Event(gdb.SERVE_CLOSE, arg[0]) + }) - // 启动服务 - web.m, web.Server = m, &http.Server{Addr: port, Handler: web} - m.Event(gdb.SERVE_START, arg[0]) - m.Warn(true, "listen %s", web.Server.ListenAndServe()) - m.Event(gdb.SERVE_CLOSE, arg[0]) + ls := strings.Split(m.Cap(ice.CTX_STREAM, client["hostname"]), ":") + m.Cmd(tcp.SERVER, tcp.LISTEN, kit.MDB_NAME, "web", tcp.HOST, ls[0], tcp.PORT, ls[1]) }) return true } @@ -104,7 +106,6 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", m.Cmd(aaa.ROLE, aaa.White, aaa.VOID, "web", "/publish/") m.Cmd(aaa.ROLE, aaa.White, aaa.VOID, ctx.COMMAND) - m.Cmd(mdb.SEARCH, mdb.CREATE, FAVOR) m.Cmd(mdb.SEARCH, mdb.CREATE, SPIDE) m.Cmd(mdb.RENDER, mdb.CREATE, SPIDE) m.Cmd(mdb.SEARCH, mdb.CREATE, SPACE) @@ -116,8 +117,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", }) }}, ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Save(SPIDE, SERVE, GROUP, LABEL, - FAVOR, CACHE, STORY, SHARE) + m.Save(SPIDE, SERVE, CACHE, SHARE, STORY) m.Done() m.Richs(SPACE, nil, "*", func(key string, value map[string]interface{}) { @@ -131,7 +131,6 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", func init() { ice.Index.Register(Index, &Frame{}, - SPIDE, SERVE, SPACE, DREAM, - CACHE, FAVOR, STORY, SHARE, + SPIDE, SERVE, SPACE, DREAM, CACHE, SHARE, STORY, ) } diff --git a/conf.go b/conf.go index 539dffd6..a398c5a2 100644 --- a/conf.go +++ b/conf.go @@ -100,8 +100,8 @@ const ( // RENDER RENDER_OUTPUT = "_output" RENDER_RESULT = "_result" RENDER_QRCODE = "_qrcode" - RENDER_TEMPLATE = "_template" RENDER_DOWNLOAD = "_download" + RENDER_TEMPLATE = "_template" ) const ( // TODO diff --git a/core/chat/action.go b/core/chat/action.go index 7b9c96e8..3a8e7acf 100644 --- a/core/chat/action.go +++ b/core/chat/action.go @@ -36,7 +36,7 @@ func _action_show(m *ice.Message, river, storm, index string, arg ...string) { prefix := kit.Keys(kit.MDB_HASH, river, TOOL, kit.MDB_HASH, storm) if m.Grows(RIVER, prefix, kit.MDB_ID, index, func(index int, value map[string]interface{}) { if cmds = kit.Simple(kit.Keys(value[CTX], value[CMD])); kit.Format(value[POD]) != "" { - m.Option(kit.GDB_POD, value[POD]) + m.Option(kit.SSH_POD, value[POD]) } }) == nil && m.Warn(!m.Right(cmds), ice.ErrNotAuth) { return diff --git a/core/chat/river.go b/core/chat/river.go index 619014c3..fc4b0946 100644 --- a/core/chat/river.go +++ b/core/chat/river.go @@ -124,7 +124,7 @@ func init() { m.Cmdy(mdb.SELECT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), NODE), mdb.HASH) m.Table(func(index int, value map[string]string, head []string) { m.PushRender(kit.MDB_LINK, "a", value[kit.MDB_NAME], - kit.MergeURL(m.Option(ice.MSG_USERWEB), kit.GDB_POD, kit.Keys(m.Option(kit.GDB_POD), value[kit.MDB_NAME]))) + kit.MergeURL(m.Option(ice.MSG_USERWEB), kit.SSH_POD, kit.Keys(m.Option(kit.SSH_POD), value[kit.MDB_NAME]))) }) m.PushAction("删除") return diff --git a/core/code/_trash.go b/core/code/_trash.go new file mode 100644 index 00000000..80619ac6 --- /dev/null +++ b/core/code/_trash.go @@ -0,0 +1,59 @@ +package code + +func _pprof_show(m *ice.Message, zone string, id string) { + favor := m.Conf(PPROF, kit.Keys(kit.MDB_META, web.FAVOR)) + + m.Richs(PPROF, nil, zone, func(key string, val map[string]interface{}) { + val = val[kit.MDB_META].(map[string]interface{}) + + list := []string{} + task.Put(val, func(task *task.Task) error { + m.Sleep("1s") + m.Grows(PPROF, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) { + // 压测命令 + m.Log_EXPORT(kit.MDB_META, PPROF, kit.MDB_ZONE, zone, kit.MDB_VALUE, kit.Format(value)) + cmd := kit.Format(value[kit.MDB_TYPE]) + arg := kit.Format(value[kit.MDB_TEXT]) + res := m.Cmd(mdb.ENGINE, value[kit.MDB_TYPE], value[kit.MDB_NAME], value[kit.MDB_TEXT], value[kit.MDB_EXTRA]).Result() + m.Cmd(web.FAVOR, favor, cmd, arg, res) + list = append(list, cmd+": "+arg, res) + }) + return nil + }) + + // 收藏程序 + msg := m.Cmd(web.CACHE, web.CATCH, kit.MIME_FILE, kit.Format(val[BINNARY])) + bin := msg.Append(kit.MDB_TEXT) + m.Cmd(web.FAVOR, favor, kit.MIME_FILE, bin, val[BINNARY]) + + // 性能分析 + msg = m.Cmd(web.SPIDE, "self", web.CACHE, http.MethodGet, kit.Select("/code/pprof/profile", val[SERVICE]), "seconds", kit.Select("5", kit.Format(val[SECONDS]))) + m.Cmd(web.FAVOR, favor, PPROF, msg.Append(kit.MDB_TEXT), kit.Keys(zone, "pd.gz")) + + // 结果摘要 + cmd := kit.Simple(m.Confv(PPROF, "meta.pprof"), "-text", val[BINNARY], msg.Append(kit.MDB_TEXT)) + res := strings.Split(m.Cmdx(cli.SYSTEM, cmd), "\n") + if len(res) > 20 { + res = res[:20] + } + m.Cmd(web.FAVOR, favor, web.TYPE_SHELL, strings.Join(cmd, " "), strings.Join(res, "\n")) + list = append(list, web.TYPE_SHELL+": "+strings.Join(cmd, " "), strings.Join(res, "\n")) + + // 结果展示 + u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) + p := kit.Format("%s:%s", u.Hostname(), m.Cmdx(tcp.PORT, aaa.Right)) + m.Option(cli.CMD_STDOUT, "var/daemon/stdout") + m.Option(cli.CMD_STDERR, "var/daemon/stderr") + m.Cmd(cli.DAEMON, m.Confv(PPROF, "meta.pprof"), "-http="+p, val[BINNARY], msg.Append(kit.MDB_TEXT)) + + url := u.Scheme + "://" + p + "/ui/top" + m.Cmd(web.FAVOR, favor, web.SPIDE, url, msg.Append(kit.MDB_TEXT)) + m.Set(ice.MSG_RESULT).Echo(url).Echo(" \n").Echo("\n") + m.Echo(strings.Join(list, "\n")).Echo("\n") + + m.Push("url", url) + m.Push(PPROF, msg.Append(kit.MDB_TEXT)) + m.Push(SERVICE, strings.Replace(kit.Format(val[SERVICE]), "profile", "", -1)) + m.Push("bin", bin) + }) +} diff --git a/core/code/install.go b/core/code/install.go index eb49a790..e6354d74 100644 --- a/core/code/install.go +++ b/core/code/install.go @@ -2,6 +2,7 @@ package code import ( ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" @@ -49,10 +50,10 @@ func init() { value = value[kit.MDB_META].(map[string]interface{}) m.Optionv("progress", func(size int, total int) { s := size * 100 / total - if s != kit.Int(value[kit.MDB_STEP]) && s%10 == 0 { - m.Log_IMPORT(kit.MDB_FILE, name, kit.MDB_STEP, s, kit.MDB_SIZE, kit.FmtSize(int64(size)), kit.MDB_TOTAL, kit.FmtSize(int64(total))) + if s != kit.Int(value[kit.SSH_STEP]) && s%10 == 0 { + m.Log_IMPORT(kit.MDB_FILE, name, kit.SSH_STEP, s, kit.MDB_SIZE, kit.FmtSize(int64(size)), kit.MDB_TOTAL, kit.FmtSize(int64(total))) } - value[kit.MDB_STEP], value[kit.MDB_SIZE], value[kit.MDB_TOTAL] = s, size, total + value[kit.SSH_STEP], value[kit.MDB_SIZE], value[kit.MDB_TOTAL] = s, size, total }) }) @@ -85,7 +86,7 @@ func init() { m.Cmdy(cli.SYSTEM, "make", "PREFIX="+kit.Path(path.Join(p, kit.Select("_install", m.Option("install")))), "install") }}, "spawn": {Name: "spawn link", Help: "新建", Hand: func(m *ice.Message, arg ...string) { - port := m.Cmdx(tcp.PORT, "select") + port := m.Cmdx(tcp.PORT, aaa.Right) target := path.Join(m.Conf(cli.DAEMON, kit.META_PATH), port) source := path.Join(m.Conf(INSTALL, kit.META_PATH), kit.TrimExt(arg[0])) @@ -122,10 +123,10 @@ func init() { // 服务列表 if strings.Contains(value[kit.MDB_NAME], key) { m.Push(kit.MDB_TIME, value[kit.MDB_TIME]) - m.Push(kit.MDB_PORT, path.Base(value[kit.MDB_DIR])) + m.Push(kit.SSH_PORT, path.Base(value[kit.SSH_DIR])) m.Push(kit.MDB_STATUS, value[kit.MDB_STATUS]) m.Push(kit.MDB_NAME, value[kit.MDB_NAME]) - m.PushRender(kit.MDB_LINK, "a", kit.Format("http://%s:%s", u.Hostname(), path.Base(value[kit.MDB_DIR]))) + m.PushRender(kit.MDB_LINK, "a", kit.Format("http://%s:%s", u.Hostname(), path.Base(value[kit.SSH_DIR]))) } }) return diff --git a/core/code/pprof.go b/core/code/pprof.go index 9e9d9437..6f4b72c0 100644 --- a/core/code/pprof.go +++ b/core/code/pprof.go @@ -2,12 +2,9 @@ package code import ( ice "github.com/shylinux/icebergs" - "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" - "github.com/shylinux/icebergs/base/tcp" "github.com/shylinux/icebergs/base/web" kit "github.com/shylinux/toolkits" - "github.com/shylinux/toolkits/task" "net/http" _ "net/http/pprof" @@ -36,63 +33,6 @@ func _pprof_list(m *ice.Message, zone string, id string, field ...interface{}) { } }) } -func _pprof_show(m *ice.Message, zone string, id string) { - favor := m.Conf(PPROF, kit.Keys(kit.MDB_META, web.FAVOR)) - - m.Richs(PPROF, nil, zone, func(key string, val map[string]interface{}) { - val = val[kit.MDB_META].(map[string]interface{}) - - list := []string{} - task.Put(val, func(task *task.Task) error { - m.Sleep("1s") - m.Grows(PPROF, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) { - // 压测命令 - m.Log_EXPORT(kit.MDB_META, PPROF, kit.MDB_ZONE, zone, kit.MDB_VALUE, kit.Format(value)) - cmd := kit.Format(value[kit.MDB_TYPE]) - arg := kit.Format(value[kit.MDB_TEXT]) - res := m.Cmd(mdb.ENGINE, value[kit.MDB_TYPE], value[kit.MDB_NAME], value[kit.MDB_TEXT], value[kit.MDB_EXTRA]).Result() - m.Cmd(web.FAVOR, favor, cmd, arg, res) - list = append(list, cmd+": "+arg, res) - }) - return nil - }) - - // 收藏程序 - msg := m.Cmd(web.CACHE, web.CATCH, kit.MIME_FILE, kit.Format(val[BINNARY])) - bin := msg.Append(kit.MDB_TEXT) - m.Cmd(web.FAVOR, favor, kit.MIME_FILE, bin, val[BINNARY]) - - // 性能分析 - msg = m.Cmd(web.SPIDE, "self", web.CACHE, http.MethodGet, kit.Select("/code/pprof/profile", val[SERVICE]), "seconds", kit.Select("5", kit.Format(val[SECONDS]))) - m.Cmd(web.FAVOR, favor, PPROF, msg.Append(kit.MDB_TEXT), kit.Keys(zone, "pd.gz")) - - // 结果摘要 - cmd := kit.Simple(m.Confv(PPROF, "meta.pprof"), "-text", val[BINNARY], msg.Append(kit.MDB_TEXT)) - res := strings.Split(m.Cmdx(cli.SYSTEM, cmd), "\n") - if len(res) > 20 { - res = res[:20] - } - m.Cmd(web.FAVOR, favor, web.TYPE_SHELL, strings.Join(cmd, " "), strings.Join(res, "\n")) - list = append(list, web.TYPE_SHELL+": "+strings.Join(cmd, " "), strings.Join(res, "\n")) - - // 结果展示 - u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) - p := kit.Format("%s:%s", u.Hostname(), m.Cmdx(tcp.PORT, "get")) - m.Option(cli.CMD_STDOUT, "var/daemon/stdout") - m.Option(cli.CMD_STDERR, "var/daemon/stderr") - m.Cmd(cli.DAEMON, m.Confv(PPROF, "meta.pprof"), "-http="+p, val[BINNARY], msg.Append(kit.MDB_TEXT)) - - url := u.Scheme + "://" + p + "/ui/top" - m.Cmd(web.FAVOR, favor, web.SPIDE, url, msg.Append(kit.MDB_TEXT)) - m.Set(ice.MSG_RESULT).Echo(url).Echo(" \n").Echo("\n") - m.Echo(strings.Join(list, "\n")).Echo("\n") - - m.Push("url", url) - m.Push(PPROF, msg.Append(kit.MDB_TEXT)) - m.Push(SERVICE, strings.Replace(kit.Format(val[SERVICE]), "profile", "", -1)) - m.Push("bin", bin) - }) -} func _pprof_modify(m *ice.Message, zone, id, k, v, old string) { k = kit.Select(k, m.Option(kit.MDB_KEY)) m.Richs(PPROF, nil, kit.Select(kit.MDB_FOREACH, zone), func(key string, val map[string]interface{}) { @@ -141,7 +81,7 @@ func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ PPROF: {Name: "pprof", Help: "性能分析", Value: kit.Data(kit.MDB_SHORT, kit.MDB_ZONE, - web.FAVOR, "pprof", PPROF, []string{"go", "tool", "pprof"}, + PPROF, []string{"go", "tool", "pprof"}, )}, }, Commands: map[string]*ice.Command{ @@ -163,7 +103,7 @@ func init() { _pprof_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), arg[0], arg[1], kit.Select("", arg, 2)) }}, kit.MDB_SHOW: {Name: "show type name text arg...", Help: "运行", Hand: func(m *ice.Message, arg ...string) { - _pprof_show(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID)) + // _pprof_show(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID)) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { _pprof_list(m, kit.Select(kit.MDB_FOREACH, arg, 0), kit.Select("", arg, 1)) diff --git a/core/team/plan.go b/core/team/plan.go index 0e3e2a42..86fdd5c7 100644 --- a/core/team/plan.go +++ b/core/team/plan.go @@ -7,7 +7,6 @@ import ( "github.com/shylinux/icebergs/base/mdb" kit "github.com/shylinux/toolkits" - "path" "time" ) @@ -20,7 +19,6 @@ func init() { "display", "/plugin/local/team/plan.js", "style", "plan", ), Action: map[string]*ice.Action{ mdb.INSERT: {Name: "insert zone type=once,step,week name text begin_time@date close_time@date", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - _task_create(m, arg[1]) _task_insert(m, arg[1], arg[2:]...) }}, mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { @@ -30,20 +28,20 @@ func init() { _task_delete(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID)) }}, mdb.EXPORT: {Name: "export file", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - _task_export(m, kit.Select(path.Join(EXPORT, m.Option(ice.MSG_DOMAIN), "list.csv"))) + _task_export(m, m.Option(kit.MDB_FILE)) }}, mdb.IMPORT: {Name: "import file", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - _task_import(m, kit.Select(path.Join(EXPORT, m.Option(ice.MSG_DOMAIN), "list.csv"))) + _task_import(m, m.Option(kit.MDB_FILE)) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { - _task_input(m, kit.Select("", arg, 0), kit.Select("", arg, 1)) + _task_inputs(m, kit.Select("", arg, 0), kit.Select("", arg, 1)) }}, gdb.BEGIN: {Name: "begin", Help: "开始", Hand: func(m *ice.Message, arg ...string) { - _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), STATUS, StatusProcess) + _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), TaskField.STATUS, TaskStatus.PROCESS) }}, gdb.END: {Name: "end", Help: "完成", Hand: func(m *ice.Message, arg ...string) { - _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), STATUS, StatusFinish) + _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), TaskField.STATUS, TaskStatus.FINISH) }}, "command": {Name: "command", Help: "命令", Hand: func(m *ice.Message, arg ...string) { @@ -54,21 +52,20 @@ func init() { m.Cmdy(arg[0], arg[1:]) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - begin_time, end_time := _task_scope(m, arg...) - - m.Set(ice.MSG_OPTION, "end_time") + begin_time, end_time := _task_scope(m, 8, arg...) m.Set(ice.MSG_OPTION, "begin_time") - m.Richs(TASK, kit.Keys(kit.MDB_HASH, m.Optionv(ice.MSG_DOMAIN)), kit.Select(kit.MDB_FOREACH, m.Option(kit.MDB_ZONE)), func(key string, val map[string]interface{}) { - zone := kit.Format(kit.Value(val, "meta.zone")) - m.Grows(TASK, kit.Keys(kit.MDB_HASH, m.Optionv(ice.MSG_DOMAIN), kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) { - begin, _ := time.ParseInLocation(ice.MOD_TIME, kit.Format(value[BEGIN_TIME]), time.Local) - if begin_time.Before(begin) && begin.Before(end_time) { - m.Push(zone, value) - m.Push(kit.MDB_ZONE, zone) - m.PushAction(_task_action(m, value[STATUS], "插件")) - } - }) + m.Set(ice.MSG_OPTION, "end_time") + + m.Option(mdb.FIELDS, "begin_time,close_time,zone,id,level,status,score,type,name,text,extra") + m.Option("cache.cb", func(key string, fields []string, value, val map[string]interface{}) { + begin, _ := time.ParseInLocation(ice.MOD_TIME, kit.Format(value[TaskField.BEGIN_TIME]), time.Local) + if begin_time.After(begin) || begin.After(end_time) { + return + } + m.Push(key, value, fields, val) + m.PushRender(kit.MDB_ACTION, kit.MDB_BUTTON, _task_action(m, value[TaskField.STATUS], "插件")) }) + m.Cmdy(mdb.SELECT, m.Prefix(TASK), kit.Keys(m.Option(ice.MSG_DOMAIN)), mdb.ZONE) }}, }, }, nil) diff --git a/core/team/task.go b/core/team/task.go index 56ace9f4..a2ff777e 100644 --- a/core/team/task.go +++ b/core/team/task.go @@ -6,60 +6,84 @@ import ( "github.com/shylinux/icebergs/base/mdb" kit "github.com/shylinux/toolkits" - "path" "strings" "time" ) func _sub_key(m *ice.Message, zone string) string { - return kit.Keys(m.Optionv(ice.MSG_DOMAIN), kit.MDB_HASH, kit.Hashs(zone)) + return kit.Keys(m.Option(ice.MSG_DOMAIN), kit.MDB_HASH, kit.Hashs(zone)) } +func _task_action(m *ice.Message, status interface{}, action ...string) string { + switch status { + case TaskStatus.PREPARE: + action = append(action, "开始") + case TaskStatus.PROCESS: + action = append(action, "完成") + case TaskStatus.CANCEL: + case TaskStatus.FINISH: + } + return strings.Join(action, ",") +} func _task_list(m *ice.Message, zone string, id string) { - m.Option(mdb.FIELDS, "begin_time,zone,id,status,level,type,name,text") - m.Cmdy(mdb.SELECT, m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN)), mdb.ZONE, zone, id) + if zone == "" { + m.Option(mdb.FIELDS, "time,zone,count") + } else if id == "" { + m.Option(mdb.FIELDS, "begin_time,id,status,level,score,type,name,text") + defer m.Table(func(index int, value map[string]string, head []string) { + m.PushRender(kit.MDB_ACTION, kit.MDB_BUTTON, _task_action(m, value[TaskField.STATUS])) + }) + } else { + m.Option(mdb.FIELDS, mdb.DETAIL) + defer m.Table(func(index int, value map[string]string, head []string) { + if value[kit.MDB_KEY] == kit.MDB_STATUS { + m.Push(kit.MDB_KEY, kit.MDB_ACTION) + m.PushRender(kit.MDB_VALUE, kit.MDB_BUTTON, _task_action(m, value[kit.MDB_VALUE])) + } + }) + } + m.Cmdy(mdb.SELECT, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.ZONE, zone, id) } func _task_create(m *ice.Message, zone string) { - m.Conf(m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN), kit.MDB_META, kit.MDB_SHORT), kit.MDB_ZONE) - m.Cmdy(mdb.INSERT, m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN)), mdb.HASH, kit.MDB_ZONE, zone) + if msg := m.Cmd(mdb.SELECT, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.HASH, kit.MDB_ZONE, zone); len(msg.Appendv(kit.MDB_HASH)) == 0 { + m.Conf(m.Prefix(TASK), kit.Keys(m.Option(ice.MSG_DOMAIN), kit.MDB_META, kit.MDB_SHORT), kit.MDB_ZONE) + m.Cmdy(mdb.INSERT, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.HASH, kit.MDB_ZONE, zone) + } } func _task_insert(m *ice.Message, zone string, arg ...string) { - if msg := m.Cmd(mdb.SELECT, m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN)), mdb.HASH, kit.MDB_ZONE, zone); len(msg.Appendv(kit.MDB_HASH)) == 0 { - m.Debug("what %v", msg.Formats("meta")) - _task_create(m, zone) - } - m.Cmdy(mdb.INSERT, m.Prefix(TASK), _sub_key(m, zone), mdb.LIST, - BEGIN_TIME, m.Time(), CLOSE_TIME, m.Time("30m"), STATUS, StatusPrepare, LEVEL, 3, SCORE, 3, arg, + TaskField.BEGIN_TIME, m.Time(), TaskField.CLOSE_TIME, m.Time("30m"), + TaskField.STATUS, TaskStatus.PREPARE, TaskField.LEVEL, 3, TaskField.SCORE, 3, + arg, ) } func _task_modify(m *ice.Message, zone, id, field, value string, arg ...string) { - if field == STATUS { + if field == TaskField.STATUS { switch value { - case StatusProcess: - arg = append(arg, BEGIN_TIME, m.Time()) - case StatusCancel, StatusFinish: - arg = append(arg, CLOSE_TIME, m.Time()) + case TaskStatus.PROCESS: + arg = append(arg, TaskField.BEGIN_TIME, m.Time()) + case TaskStatus.CANCEL, TaskStatus.FINISH: + arg = append(arg, TaskField.CLOSE_TIME, m.Time()) } } m.Cmdy(mdb.MODIFY, m.Prefix(TASK), _sub_key(m, zone), mdb.LIST, kit.MDB_ID, id, field, value, arg) } func _task_delete(m *ice.Message, zone, id string) { - m.Cmdy(mdb.MODIFY, m.Prefix(TASK), _sub_key(m, zone), mdb.LIST, kit.MDB_ID, id, STATUS, StatusCancel) + m.Cmdy(mdb.MODIFY, m.Prefix(TASK), _sub_key(m, zone), mdb.LIST, kit.MDB_ID, id, TaskField.STATUS, TaskStatus.CANCEL) } func _task_export(m *ice.Message, file string) { m.Option(mdb.FIELDS, "zone,id,time,type,name,text,level,status,score,begin_time,close_time,extra") - m.Cmdy(mdb.EXPORT, m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN)), mdb.ZONE) + m.Cmdy(mdb.EXPORT, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.ZONE, file) } func _task_import(m *ice.Message, file string) { - m.Option(mdb.FIELDS, kit.MDB_ZONE) - m.Cmdy(mdb.IMPORT, m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN)), mdb.ZONE, file) + m.Option(mdb.FIELDS, "zone") + m.Cmdy(mdb.IMPORT, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.ZONE, file) } -func _task_input(m *ice.Message, field, value string) { +func _task_inputs(m *ice.Message, field, value string) { switch field { case kit.MDB_ZONE: - m.Cmdy(mdb.INPUTS, m.Prefix(TASK), kit.Keys(m.Optionv(ice.MSG_DOMAIN)), mdb.HASH, field, value) - case kit.MDB_NAME, kit.MDB_TEXT: + m.Cmdy(mdb.INPUTS, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.HASH, field, value) + case kit.MDB_TYPE, kit.MDB_NAME, kit.MDB_TEXT: m.Cmdy(mdb.INPUTS, m.Prefix(TASK), _sub_key(m, m.Option(kit.MDB_ZONE)), mdb.LIST, field, value) } } @@ -89,95 +113,88 @@ func _task_render(m *ice.Message, kind, name, text string, arg ...string) { }) }) } -func _task_action(m *ice.Message, status interface{}, action ...string) []string { - switch status { - case StatusPrepare: - action = append(action, "开始") - case StatusProcess: - action = append(action, "完成") - case StatusCancel, StatusFinish: - } - return action -} -func _task_scope(m *ice.Message, arg ...string) (time.Time, time.Time) { +func _task_scope(m *ice.Message, tz int, arg ...string) (time.Time, time.Time) { begin_time := time.Now() if len(arg) > 1 { begin_time, _ = time.ParseInLocation(ice.MOD_TIME, arg[1], time.Local) } - end_time := begin_time - switch begin_time = begin_time.Add(-time.Duration(begin_time.UnixNano()) % (24 * time.Hour)); arg[0] { - case ScaleDay: + end_time := begin_time + switch begin_time = begin_time.Add(-time.Duration(begin_time.UnixNano())%(24*time.Hour) - time.Duration(tz)*time.Hour); arg[0] { + case TaskScale.DAY: end_time = begin_time.AddDate(0, 0, 1) - case ScaleWeek: + case TaskScale.WEEK: begin_time = begin_time.AddDate(0, 0, -int(begin_time.Weekday())) end_time = begin_time.AddDate(0, 0, 7) - case ScaleMonth: + case TaskScale.MONTH: begin_time = begin_time.AddDate(0, 0, -begin_time.Day()+1) end_time = begin_time.AddDate(0, 1, 0) - case ScaleYear: + case TaskScale.YEAR: begin_time = begin_time.AddDate(0, 0, -begin_time.YearDay()+1) end_time = begin_time.AddDate(1, 0, 0) - case ScaleLong: + case TaskScale.LONG: begin_time = begin_time.AddDate(0, 0, -begin_time.YearDay()+1) begin_time = begin_time.AddDate(-begin_time.Year()%5, 0, 0) end_time = begin_time.AddDate(5, 0, 0) } - begin_time = begin_time.Add(-8 * time.Hour) - end_time = end_time.Add(-8 * time.Hour) return begin_time, end_time } -const ( - LEVEL = "level" - STATUS = "status" - SCORE = "score" +var TaskField = struct{ LEVEL, STATUS, SCORE, BEGIN_TIME, CLOSE_TIME string }{ + LEVEL: "level", + STATUS: "status", + SCORE: "score", - BEGIN_TIME = "begin_time" - CLOSE_TIME = "close_time" + BEGIN_TIME: "begin_time", + CLOSE_TIME: "close_time", +} +var TaskStatus = struct{ PREPARE, PROCESS, CANCEL, FINISH string }{ + PREPARE: "prepare", + PROCESS: "process", + CANCEL: "cancel", + FINISH: "finish", +} +var TaskType = struct{ ONCE, STEP, WEEK string }{ + ONCE: "once", + STEP: "step", + WEEK: "week", +} +var TaskScale = struct{ DAY, WEEK, MONTH, YEAR, LONG string }{ + DAY: "day", + WEEK: "week", + MONTH: "month", + YEAR: "year", + LONG: "long", +} - EXPORT = "usr/export/web.team.task/" -) -const ( - ScaleDay = "day" - ScaleWeek = "week" - ScaleMonth = "month" - ScaleYear = "year" - ScaleLong = "long" -) -const ( - StatusPrepare = "prepare" - StatusProcess = "process" - StatusCancel = "cancel" - StatusFinish = "finish" -) const TASK = "task" func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ - TASK: {Name: "task", Help: "task", Value: kit.Data(kit.MDB_SHORT, kit.MDB_ZONE)}, + TASK: {Name: TASK, Help: "任务", Value: kit.Data(kit.MDB_SHORT, kit.MDB_ZONE)}, }, Commands: map[string]*ice.Command{ TASK: {Name: "task zone id auto 添加 导出 导入", Help: "任务", Action: map[string]*ice.Action{ mdb.INSERT: {Name: "insert zone@key type=once,step,week name@key text@key begin_time@date close_time@date", Help: "添加", Hand: func(m *ice.Message, arg ...string) { + _task_create(m, arg[1]) _task_insert(m, arg[1], arg[2:]...) }}, - mdb.MODIFY: {Name: "modify key value", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { + mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), arg[0], arg[1]) }}, mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) { _task_delete(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID)) }}, - mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - _task_export(m, kit.Select(path.Join(EXPORT, m.Option(ice.MSG_DOMAIN), "list.csv"), arg, 0)) + mdb.EXPORT: {Name: "export file", Help: "导出", Hand: func(m *ice.Message, arg ...string) { + _task_export(m, m.Option(kit.MDB_FILE)) }}, - mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - _task_import(m, kit.Select(path.Join(EXPORT, m.Option(ice.MSG_DOMAIN), "list.csv"), arg, 0)) + mdb.IMPORT: {Name: "import file", Help: "导入", Hand: func(m *ice.Message, arg ...string) { + _task_import(m, m.Option(kit.MDB_FILE)) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { - _task_input(m, kit.Select("", arg, 0), kit.Select("", arg, 1)) + _task_inputs(m, kit.Select("", arg, 0), kit.Select("", arg, 1)) }}, mdb.SEARCH: {Name: "search type name text", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { @@ -188,18 +205,13 @@ func init() { }}, gdb.BEGIN: {Name: "begin", Help: "开始", Hand: func(m *ice.Message, arg ...string) { - _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), STATUS, StatusProcess) + _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), TaskField.STATUS, TaskStatus.PROCESS) }}, gdb.END: {Name: "end", Help: "完成", Hand: func(m *ice.Message, arg ...string) { - _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), STATUS, StatusFinish) + _task_modify(m, m.Option(kit.MDB_ZONE), m.Option(kit.MDB_ID), TaskField.STATUS, TaskStatus.FINISH) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Cmdy(mdb.SELECT, m.Prefix(TASK), m.Option(ice.MSG_DOMAIN), mdb.ZONE, arg) - if len(arg) > 0 { - m.Table(func(index int, value map[string]string, head []string) { - m.PushRender("action", "button", "", _task_action(m, value[STATUS])...) - }) - } + _task_list(m, kit.Select("", arg, 0), kit.Select("", arg, 1)) }}, }, }, nil) diff --git a/core/wiki/word.go b/core/wiki/word.go index c6070fb1..618842fe 100644 --- a/core/wiki/word.go +++ b/core/wiki/word.go @@ -387,7 +387,9 @@ func init() { arg = append(arg, kit.Select(ns[len(ns)-1], "")) } - arg = _name(m, arg) + if len(arg) == 1 { + arg = append(arg, "") + } _title_show(m, arg[0], kit.Select(arg[0], arg[1]), arg[2:]...) }}, BRIEF: {Name: "brief [name] text", Help: "摘要", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/init.go b/init.go index bc76f091..eac8ce0e 100644 --- a/init.go +++ b/init.go @@ -97,7 +97,7 @@ var Index = &Context{Name: "ice", Help: "冰山模块", m.root.Cmd(CTX_INIT) m.target.root.wg = &sync.WaitGroup{} - for _, k := range kit.Split(kit.Select("gdb,log,ssh,ctx", os.Getenv("ctx_mod"))) { + for _, k := range kit.Split(kit.Select("gdb,log,ssh")) { m.Start(k) } @@ -186,20 +186,6 @@ func Run(arg ...string) string { var names = map[string]interface{}{} -var ErrNameExists = "name already exists:" - -type Error struct { - Arg []interface{} - FileLine string -} - -func NewError(n int, arg ...interface{}) *Error { - return &Error{Arg: arg, FileLine: kit.FileLine(n, 3)} -} -func (e *Error) Error() string { - return e.FileLine + " " + strings.Join(kit.Simple(e.Arg), " ") -} - func Name(name string, value interface{}) string { if s, ok := names[name]; ok { last := "" diff --git a/misc.go b/misc.go index cbce850f..45af6264 100644 --- a/misc.go +++ b/misc.go @@ -89,8 +89,13 @@ func (m *Message) PushRender(key, view, name string, arg ...string) *Message { return m } func (m *Message) PushAction(list ...interface{}) { + if len(m.meta[MSG_APPEND]) > 0 && m.meta[MSG_APPEND][0] == kit.MDB_KEY { + m.Push(kit.MDB_KEY, kit.MDB_ACTION) + m.PushRender(kit.MDB_VALUE, kit.MDB_BUTTON, strings.Join(kit.Simple(list...), ",")) + return + } m.Table(func(index int, value map[string]string, head []string) { - m.PushRender("action", "button", strings.Join(kit.Simple(list...), ",")) + m.PushRender(kit.MDB_ACTION, kit.MDB_BUTTON, strings.Join(kit.Simple(list...), ",")) }) } func (m *Message) PushDetail(value interface{}, arg ...interface{}) *Message { @@ -98,3 +103,17 @@ func (m *Message) PushDetail(value interface{}, arg ...interface{}) *Message { } var BinPack = map[string][]byte{} + +var ErrNameExists = "name already exists:" + +type Error struct { + Arg []interface{} + FileLine string +} + +func (e *Error) Error() string { + return e.FileLine + " " + strings.Join(kit.Simple(e.Arg), " ") +} +func NewError(n int, arg ...interface{}) *Error { + return &Error{Arg: arg, FileLine: kit.FileLine(n, 3)} +} diff --git a/misc/alpha/alpha.go b/misc/alpha/alpha.go index de048c02..290692f1 100644 --- a/misc/alpha/alpha.go +++ b/misc/alpha/alpha.go @@ -63,7 +63,7 @@ var Index = &ice.Context{Name: ALPHA, Help: "英汉词典", ALPHA: {Name: ALPHA, Help: "英汉词典", Value: kit.Data( kit.MDB_LIMIT, "50000", kit.MDB_LEAST, "1000", kit.MDB_STORE, "usr/export/alpha", kit.MDB_FSIZE, "2000000", - kit.MDB_REPOS, "word-dict", kit.MDB_FIELD, []interface{}{"audio", "bnc", "collins", "definition", "detail", "exchange", "frq", "id", "oxford", "phonetic", "pos", "tag", "time", "translation", "word"}, + kit.SSH_REPOS, "word-dict", kit.MDB_FIELD, []interface{}{"audio", "bnc", "collins", "definition", "detail", "exchange", "frq", "id", "oxford", "phonetic", "pos", "tag", "time", "translation", "word"}, )}, }, Commands: map[string]*ice.Command{ diff --git a/misc/chrome/cache.go b/misc/chrome/cache.go index 56f658f7..16657a24 100644 --- a/misc/chrome/cache.go +++ b/misc/chrome/cache.go @@ -65,7 +65,7 @@ func init() { m.Cmdy(mdb.DELETE, m.Prefix(CACHE), "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.PRUNES, m.Prefix(CACHE), "", mdb.HASH, kit.MDB_STEP, "100") + m.Cmdy(mdb.PRUNES, m.Prefix(CACHE), "", mdb.HASH, kit.SSH_STEP, "100") }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Option(ice.MSG_ACTION, "删除") diff --git a/misc/mp/mp.go b/misc/mp/mp.go index d71e3d50..09139476 100644 --- a/misc/mp/mp.go +++ b/misc/mp/mp.go @@ -100,7 +100,7 @@ var Index = &ice.Context{Name: "mp", Help: "小程序", case "upload": msg := m.Cmd(web.CACHE, "upload") m.Cmd(web.STORY, web.WATCH, msg.Append("data"), path.Join("usr/local/mp/", path.Base(msg.Append("name")))) - m.Cmd(web.FAVOR, "device", "file", msg.Append("name"), msg.Append("data")) + // m.Cmd(web.FAVOR, "device", "file", msg.Append("name"), msg.Append("data")) m.Render(msg.Append("data")) case "cmds": diff --git a/misc/tmux/trash.go b/misc/tmux/_trash.go similarity index 100% rename from misc/tmux/trash.go rename to misc/tmux/_trash.go diff --git a/misc/vim/_trash.go b/misc/vim/_trash.go new file mode 100644 index 00000000..e0753f0e --- /dev/null +++ b/misc/vim/_trash.go @@ -0,0 +1,24 @@ +package vim + +/* + m.Conf(web.FAVOR, "meta.render.vimrc", m.AddCmd(&ice.Command{Name: "render favor id", Help: "渲染引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + value := m.Optionv("value").(map[string]interface{}) + switch value["name"] { + case "read", "write", "exec": + p := path.Join(kit.Format(kit.Value(value, "extra.pwd")), kit.Format(kit.Value(value, "extra.buf"))) + if strings.HasPrefix(kit.Format(kit.Value(value, "extra.buf")), "/") { + p = path.Join(kit.Format(kit.Value(value, "extra.buf"))) + } + + f, e := os.Open(p) + m.Assert(e) + defer f.Close() + b, e := ioutil.ReadAll(f) + m.Assert(e) + m.Echo(string(b)) + default: + m.Cmdy(cli.SYSTEM, "sed", "-n", fmt.Sprintf("/%s/,/^}$/p", value["text"]), kit.Value(value, "extra.buf")) + } + }})) + +*/ diff --git a/misc/vim/vim.go b/misc/vim/vim.go index 233fc316..6335c80e 100644 --- a/misc/vim/vim.go +++ b/misc/vim/vim.go @@ -2,15 +2,12 @@ package vim import ( ice "github.com/shylinux/icebergs" - "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" "github.com/shylinux/icebergs/base/web" "github.com/shylinux/icebergs/core/code" kit "github.com/shylinux/toolkits" - "fmt" - "io/ioutil" "os" "path" "strings" @@ -66,26 +63,6 @@ var Index = &ice.Context{Name: VIM, Help: "编辑器", ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() - m.Conf(web.FAVOR, "meta.render.vimrc", m.AddCmd(&ice.Command{Name: "render favor id", Help: "渲染引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - value := m.Optionv("value").(map[string]interface{}) - switch value["name"] { - case "read", "write", "exec": - p := path.Join(kit.Format(kit.Value(value, "extra.pwd")), kit.Format(kit.Value(value, "extra.buf"))) - if strings.HasPrefix(kit.Format(kit.Value(value, "extra.buf")), "/") { - p = path.Join(kit.Format(kit.Value(value, "extra.buf"))) - } - - f, e := os.Open(p) - m.Assert(e) - defer f.Close() - b, e := ioutil.ReadAll(f) - m.Assert(e) - m.Echo(string(b)) - default: - m.Cmdy(cli.SYSTEM, "sed", "-n", fmt.Sprintf("/%s/,/^}$/p", value["text"]), kit.Value(value, "extra.buf")) - } - }})) - m.Cmd(mdb.PLUGIN, mdb.CREATE, VIMRC, VIM, c.Cap(ice.CTX_FOLLOW)) m.Cmd(mdb.RENDER, mdb.CREATE, VIMRC, VIM, c.Cap(ice.CTX_FOLLOW)) m.Cmd(mdb.PLUGIN, mdb.CREATE, VIM, VIM, c.Cap(ice.CTX_FOLLOW))