diff --git a/README.md b/README.md index c6147774..7af15020 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ icebergs是一个后端框架,通过模块化、集群化实现资源的无限 一键创建项目 ``` -mkdir miss; cd miss && curl -s https://raw.githubusercontent.com/shylinux/icebergs/master/demo/build.sh | sh +mkdir miss; cd miss && curl -s https://shylinux.com/publish/build.sh | sh ``` ## 1 原型 type.go diff --git a/base.go b/base.go index 85526bc4..609e48d4 100644 --- a/base.go +++ b/base.go @@ -28,11 +28,13 @@ func (f *Frame) Begin(m *Message, arg ...string) Server { } }) m.target.wg = &sync.WaitGroup{} + m.root.Cost("begin") return f } func (f *Frame) Start(m *Message, arg ...string) bool { m.Log(LOG_START, "ice") m.Cmd(ICE_INIT).Cmd("init", arg) + m.root.Cost("start") return true } func (f *Frame) Close(m *Message, arg ...string) bool { @@ -81,6 +83,7 @@ var Index = &Context{Name: "ice", Help: "冰山模块", }) }}, "init": {Name: "init", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) { + m.root.Cost("_init") m.Start("log", arg...) m.Start("gdb", arg...) m.Start("ssh", arg...) diff --git a/base/aaa/aaa.go b/base/aaa/aaa.go index 7f2f4c18..e804599d 100644 --- a/base/aaa/aaa.go +++ b/base/aaa/aaa.go @@ -13,8 +13,12 @@ var Index = &ice.Context{Name: "aaa", Help: "认证模块", ice.AAA_SESS: {Name: "sess", Help: "会话", Value: kit.Data(kit.MDB_SHORT, "uniq", "expire", "720h")}, }, Commands: map[string]*ice.Command{ - ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, - ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, + ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd(ice.CTX_CONFIG, "load", "aaa.json") + }}, + ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd(ice.CTX_CONFIG, "save", "aaa.json", ice.AAA_ROLE, ice.AAA_USER, ice.AAA_SESS) + }}, ice.AAA_ROLE: {Name: "role", Help: "角色", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch arg[0] { case "check": diff --git a/base/cli/cli.go b/base/cli/cli.go index 1e963e08..416a1308 100644 --- a/base/cli/cli.go +++ b/base/cli/cli.go @@ -22,6 +22,8 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块", ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmd(ice.CTX_CONFIG, "load", "cli.json") + m.Conf(ice.CLI_RUNTIME, "host.ctx_self", os.Getenv("ctx_self")) + m.Conf(ice.CLI_RUNTIME, "host.ctx_dev", os.Getenv("ctx_dev")) m.Conf(ice.CLI_RUNTIME, "host.GOARCH", runtime.GOARCH) m.Conf(ice.CLI_RUNTIME, "host.GOOS", runtime.GOOS) m.Conf(ice.CLI_RUNTIME, "host.pid", os.Getpid()) diff --git a/base/ctx/ctx.go b/base/ctx/ctx.go index 1c1110af..6d415e96 100644 --- a/base/ctx/ctx.go +++ b/base/ctx/ctx.go @@ -56,17 +56,23 @@ var Index = &ice.Context{Name: "ctx", Help: "元始模块", return } - m.Search(arg[0]+"."+arg[1], func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) { - if len(arg) == 2 { + chain := arg[0] + if len(arg) > 1 { + chain = arg[0] + "." + arg[1] + arg = arg[1:] + } + arg = arg[1:] + m.Search(chain, func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) { + if len(arg) == 0 { m.Push("name", cmd.Name) m.Push("help", cmd.Help) m.Push("meta", kit.Format(cmd.Meta)) m.Push("list", kit.Format(cmd.List)) } else { if you := m.Option(kit.Format(kit.Value(cmd.Meta, "remote"))); you != "" { - m.Copy(m.Spawns(s).Cmd("web.space", you, "ctx.command", arg[0], arg[1], "run", arg[3:])) + m.Copy(m.Spawns(s).Cmd("web.space", you, "ctx.command", chain, "run", arg[1:])) } else { - m.Copy(s.Run(m.Spawns(s), cmd, key, arg[3:]...)) + m.Copy(s.Run(m.Spawns(s), cmd, key, arg[1:]...)) } } }) diff --git a/base/gdb/gdb.go b/base/gdb/gdb.go index dc0a9758..396473d4 100644 --- a/base/gdb/gdb.go +++ b/base/gdb/gdb.go @@ -56,7 +56,7 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { } m.Info("%s: %v", ice.GDB_EVENT, d) m.Grows(ice.GDB_EVENT, d[0], "", "", func(index int, value map[string]interface{}) { - m.Cmd(value["cmd"], d[1:]) + m.Cmd(value["cmd"], d[1:]).Cost("event %v", d) }) } } diff --git a/base/ssh/ssh.go b/base/ssh/ssh.go index 5d19835b..e52a0af9 100644 --- a/base/ssh/ssh.go +++ b/base/ssh/ssh.go @@ -35,11 +35,11 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { fmt.Fprintf(f.out, m.Time(prompt, count, target.Name)) for bio.Scan() { ls := kit.Split(bio.Text()) - m.Log("info", "input %v", ls) + m.Log("info", "stdin input %v", ls) - msg := m.Spawn(target) + msg := m.Spawns(target) if msg.Cmdy(ls); !msg.Hand { - msg = msg.Cmdy("cli.system", ls) + msg = msg.Set("result").Cmdy(ice.CLI_SYSTEM, ls) } res := msg.Result() if res == "" { @@ -52,6 +52,7 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { fmt.Fprint(f.out, "\n") } fmt.Fprintf(f.out, m.Time(prompt, count, target.Name)) + msg.Cost("stdin %v", ls) count++ } return true diff --git a/base/web/web.go b/base/web/web.go index 708fe7fe..132a749a 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -11,6 +11,7 @@ import ( "io" "io/ioutil" "math/rand" + "mime/multipart" "net" "net/http" "net/url" @@ -197,12 +198,11 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) { } } default: - r.ParseMultipartForm(4096) + r.ParseMultipartForm(kit.Int64(kit.Select(r.Header.Get("Content-Length"), "4096"))) if r.ParseForm(); len(r.PostForm) > 0 { for k, v := range r.PostForm { msg.Info("%s: %v", k, v) } - msg.Info("") } } @@ -218,10 +218,9 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) { case "void": case "file": msg.Info("_output: %s %s", msg.Append("_output"), msg.Append("file")) - w.Header().Set("Content-Disposition", fmt.Sprintf("filename=%s", kit.Select("hi.txt", msg.Append("name")))) + w.Header().Set("Content-Disposition", fmt.Sprintf("filename=%s", kit.Select(msg.Append("name"), msg.Append("story")))) w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type"))) http.ServeFile(w, r, msg.Append("file")) - case "result": w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type"))) fmt.Fprint(w, msg.Result()) @@ -340,7 +339,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", "template", map[string]interface{}{"path": "usr/template", "list": []interface{}{ `{{define "raw"}}{{.Result}}{{end}}`, }}, - "logheaders", "false", + "logheaders", "true", )}, ice.WEB_SPACE: {Name: "space", Help: "空间站", Value: kit.Data(kit.MDB_SHORT, "name", "redial.a", 3000, "redial.b", 1000, "redial.c", 10, @@ -353,14 +352,21 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", ice.WEB_CACHE: {Name: "cache", Help: "缓存池", Value: kit.Data(kit.MDB_SHORT, "text", "path", "var/file", "store", "var/data", "limit", "30", "least", "10")}, ice.WEB_STORY: {Name: "story", Help: "故事会", Value: kit.Dict(kit.MDB_META, kit.Dict(kit.MDB_SHORT, "data"), "head", kit.Data(kit.MDB_SHORT, "story"))}, ice.WEB_SHARE: {Name: "share", Help: "共享链", Value: kit.Data("template", share_template)}, - ice.WEB_ROUTE: {Name: "route", Help: "路由表", Value: kit.Data()}, - ice.WEB_PROXY: {Name: "proxy", Help: "代理商", Value: kit.Data()}, + ice.WEB_ROUTE: {Name: "route", Help: "路由", Value: kit.Data()}, + ice.WEB_PROXY: {Name: "proxy", Help: "代理", Value: kit.Data()}, + ice.WEB_GROUP: {Name: "group", Help: "分组", Value: kit.Data()}, + ice.WEB_LABEL: {Name: "label", Help: "标签", Value: kit.Data()}, }, Commands: map[string]*ice.Command{ ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd(ice.CTX_CONFIG, "load", "web.json") m.Cmd(ice.WEB_SPIDE, "add", "self", "http://:9020") + m.Cmd(ice.WEB_SPIDE, "add", "shy", "https://shylinux.com") + }}, + ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Done() + m.Cmd(ice.CTX_CONFIG, "save", "web.json", ice.WEB_SPIDE, ice.WEB_FAVOR, ice.WEB_CACHE, ice.WEB_STORY, ice.WEB_SHARE) }}, - ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Done() }}, ice.WEB_SPIDE: {Name: "spide", Help: "客户端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { @@ -383,7 +389,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", "client", kit.Dict( "logheaders", false, "timeout", "100s", - "method", "GET", + "method", "POST", "protocol", uri.Scheme, "hostname", uri.Host, "path", dir, @@ -396,20 +402,99 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", default: m.Richs(ice.WEB_SPIDE, nil, arg[0], func(key string, value map[string]interface{}) { client := value["client"].(map[string]interface{}) - method := kit.Select("GET", client["method"]) - uri := kit.MergeURL(kit.Format(client["url"]), arg[1:]) - - body, ok := m.Optionv("body").(io.Reader) - if !ok && method == "POST" { - if ls := strings.Split(uri, "?"); len(ls) > 0 { - uri, body = ls[0], bytes.NewReader([]byte(ls[1])) - } + // 解析方法 + parse := "" + switch arg[1] { + case "parse": + parse, arg = "parse", arg[1:] } + // 请求方法 + method := kit.Select("POST", client["method"]) + switch arg = arg[1:]; arg[0] { + case "POST": + method, arg = "POST", arg[1:] + case "GET": + method, arg = "GET", arg[1:] + } + + // 请求地址 + uri, arg := arg[0], arg[1:] + + // 请求数据 + head := map[string]string{} + body, ok := m.Optionv("body").(io.Reader) + if !ok && len(arg) > 0 { + switch arg[0] { + case "file": + if f, e := os.Open(arg[1]); m.Warn(e != nil, "%s", e) { + return + } else { + defer f.Close() + body, arg = f, arg[2:] + } + case "data": + body, arg = bytes.NewBufferString(arg[1]), arg[2:] + case "form": + data := []string{} + for i := 1; i < len(arg)-1; i += 2 { + data = append(data, url.QueryEscape(arg[i])+"="+url.QueryEscape(arg[i+1])) + } + body = bytes.NewBufferString(strings.Join(data, "&")) + head["Content-Type"] = "application/x-www-form-urlencoded" + case "part": + buf := &bytes.Buffer{} + mp := multipart.NewWriter(buf) + for i := 1; i < len(arg)-1; i += 2 { + if strings.HasPrefix(arg[i+1], "@") { + if f, e := os.Open(arg[i+1][1:]); m.Assert(e) { + defer f.Close() + if p, e := mp.CreateFormFile(arg[i], path.Base(arg[i+1][1:])); m.Assert(e) { + io.Copy(p, f) + } + } + } else { + mp.WriteField(arg[i], arg[i+1]) + } + } + mp.Close() + head["Content-Type"] = mp.FormDataContentType() + body = buf + default: + data := map[string]interface{}{} + for i := 0; i < len(arg)-1; i += 2 { + kit.Value(data, arg[i], arg[i+1]) + } + if b, e := json.Marshal(data); m.Assert(e) { + head["Content-Type"] = "application/json" + body = bytes.NewBuffer(b) + } + } + arg = arg[:0] + } + + // 构造请求 + uri = kit.MergeURL2(kit.Format(client["url"]), uri, arg) req, e := http.NewRequest(method, uri, body) - m.Log("info", "%s %s", req.Method, req.URL) + m.Info("%s %s", req.Method, req.URL) m.Assert(e) + // 请求参数 + for k, v := range head { + req.Header.Set(k, v) + } + kit.Fetch(client["header"], func(key string, value string) { + req.Header.Set(key, value) + }) + kit.Fetch(client["cookie"], func(key string, value string) { + req.AddCookie(&http.Cookie{Name: key, Value: value}) + m.Info("%s: %s", key, value) + }) + if method == "POST" { + m.Info("%s: %s", req.Header.Get("Content-Length"), req.Header.Get("Content-Type")) + } + + // 请求代理 web := m.Target().Server().(*Frame) if web.Client == nil { web.Client = &http.Client{Timeout: kit.Duration(kit.Format(client["timeout"]))} @@ -417,16 +502,38 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", // 发送请求 res, e := web.Client.Do(req) + + // 缓存参数 + for _, v := range res.Cookies() { + kit.Value(client, "cookie."+v.Name, v.Value) + m.Info("%s: %s", v.Name, v.Value) + } + + // 验证结果 if m.Warn(e != nil, "%s", e) { return - } - - if m.Warn(res.StatusCode != http.StatusOK, "%s", res.Status) { + } else if m.Warn(res.StatusCode != http.StatusOK, "%s", res.Status) { return } - if buf, e := ioutil.ReadAll(res.Body); m.Assert(e) { - m.Echo(string(buf)) + switch parse { + case "parse": + data := map[string]interface{}{} + m.Assert(json.NewDecoder(res.Body).Decode(&data)) + for k, v := range data { + switch v := v.(type) { + case []interface{}: + m.Append(k, v) + default: + m.Append(k, kit.Format(v)) + } + } + + default: + // 缓存结果 + m.Cost("%s %s: %s", res.Status, res.Header.Get("Content-Length"), res.Header.Get("Content-Type")) + m.Optionv("response", res) + m.Echo(m.Cmd(ice.WEB_CACHE, "download", res.Header.Get("Content-Type"), uri).Append("data")) } }) } @@ -455,11 +562,34 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Richs(ice.WEB_SPACE, nil, "", func(key string, value map[string]interface{}) { m.Push(key, value, []string{"time", "type", "name", "user"}) }) + m.Sort("name") return } web := m.Target().Server().(*Frame) switch arg[0] { + case "share": + switch arg[1] { + case "add": + m.Cmdy(ice.WEB_SPIDE, "self", "parse", path.Join("/space/share/add", path.Join(arg[2:]...))) + default: + m.Richs(ice.WEB_SPIDE, nil, "self", func(key string, value map[string]interface{}) { + value["share"] = arg[1] + }) + } + + case "upload": + for _, file := range arg[2:] { + msg := m.Cmd(ice.WEB_STORY, "index", file) + m.Cmdy(ice.WEB_SPIDE, arg[1], "POST", "/space/upload", "part", + "type", msg.Append("type"), "name", msg.Append("name"), + "text", msg.Append("text"), "upload", "@"+msg.Append("file"), + ) + } + case "download": + m.Cmd(ice.WEB_STORY, "add", arg[1], arg[2], + m.Cmdx(ice.WEB_SPIDE, arg[3], "/space/download/"+arg[4])) + case "connect": // 基本信息 node := m.Conf(ice.CLI_RUNTIME, "node.type") @@ -469,7 +599,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Richs(ice.WEB_SPIDE, nil, kit.Select("self", arg, 1), func(key string, value map[string]interface{}) { host := kit.Format(kit.Value(value, "client.hostname")) - if u, e := url.Parse(kit.MergeURL("ws://"+host+"/space/", "node", node, "name", name, "user", user)); m.Assert(e) { + if u, e := url.Parse(kit.MergeURL("ws://"+host+"/space/", "node", node, "name", name, "user", user, "share", value["share"])); m.Assert(e) { for i := 0; i < m.Confi(ice.WEB_SPACE, "meta.redial.c"); i++ { if s, e := net.Dial("tcp", host); !m.Warn(e != nil, "%s", e) { if s, _, e := websocket.NewClient(s, u, nil, m.Confi(ice.WEB_SPACE, "meta.buffer.r"), m.Confi(ice.WEB_SPACE, "meta.buffer.w")); !m.Warn(e != nil, "%s", e) { @@ -504,6 +634,8 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Optionv(ice.MSG_SOURCE, []string{id, target[0]}) m.Optionv(ice.MSG_TARGET, target[1:]) m.Set(ice.MSG_DETAIL, arg[1:]...) + m.Option("hot", m.Option("hot")) + m.Option("top", m.Option("top")) m.Info("send %s %s", id, m.Format("meta")) // 下发命令 @@ -562,8 +694,16 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", // 任务列表 m.Cmdy("nfs.dir", m.Conf(ice.WEB_DREAM, "meta.path"), "", "time name") m.Table(func(index int, value map[string]string, head []string) { - m.Push("status", kit.Select("start", "stop", m.Richs(ice.WEB_SPACE, nil, value["name"], nil) == nil)) + if m.Richs(ice.WEB_SPACE, nil, value["name"], func(key string, value map[string]interface{}) { + m.Push("type", value["type"]) + m.Push("status", "start") + }) == nil { + m.Push("type", "none") + m.Push("status", "stop") + } }) + m.Sort("name") + m.Sort("status") }}, ice.WEB_FAVOR: {Name: "favor", Help: "收藏夹", Meta: kit.Dict("remote", "you", "exports", []string{"hot", "favor"}, "detail", []string{"执行", "编辑", "收录", "下载"}), List: kit.List( kit.MDB_INPUT, "text", "name", "hot", "action", "auto", @@ -586,7 +726,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", case "收录": m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) { m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, key), "id", id, func(index int, value map[string]interface{}) { - m.Cmd(ice.WEB_STORY, "add", value["type"], value["name"], value["text"]) + m.Cmd(ice.WEB_STORY, "add", value["type"], m.Option("top"), value["text"]) }) }) arg = []string{m.Option("hot")} @@ -638,7 +778,6 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", // 收藏列表 m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), "", "", func(index int, value map[string]interface{}) { m.Push(kit.Format(index), value, []string{kit.MDB_TIME, kit.MDB_ID, kit.MDB_TYPE, kit.MDB_NAME, kit.MDB_TEXT}) - m.Push("link", kit.Format(m.Conf(ice.WEB_SHARE, "meta.template.download"), value["data"], kit.Short(value["data"]))) }) return } @@ -647,7 +786,13 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", // 收藏详情 m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), "id", arg[1], func(index int, value map[string]interface{}) { for k, v := range value { - m.Push("key", k).Push("value", v) + if k == "extra" { + for k, v := range v.(map[string]interface{}) { + m.Push("key", "extra."+k).Push("value", kit.Format(v)) + } + } else { + m.Push("key", k).Push("value", kit.Format(v)) + } } m.Sort("key") }) @@ -669,7 +814,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Info("create favor: %s index: %d name: %s", favor, index, arg[2]) m.Echo("%d", index) }}, - ice.WEB_CACHE: {Name: "cache", Help: "缓存池", Meta: kit.Dict("remote", "you"), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + ice.WEB_CACHE: {Name: "cache", Help: "缓存池", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { // 记录列表 m.Grows(ice.WEB_CACHE, nil, "", "", func(index int, value map[string]interface{}) { @@ -681,22 +826,34 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", } switch arg[0] { - case "upload": + case "upload", "download": // 打开文件 - r := m.Optionv("request").(*http.Request) - if f, h, e := r.FormFile(kit.Select("upload", arg, 1)); m.Assert(e) { - defer f.Close() + if r, ok := m.Optionv("request").(*http.Request); ok { + if f, h, e := r.FormFile(kit.Select("upload", arg, 1)); m.Assert(e) { + defer f.Close() - // 创建文件 - file := kit.Hashs(f) - if o, p, e := kit.Create(path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), file[:2], file)); m.Assert(e) { - defer o.Close() + // 创建文件 + file := kit.Hashs(f) + if o, p, e := kit.Create(path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), file[:2], file)); m.Assert(e) { + defer o.Close() - // 保存文件 - f.Seek(0, os.SEEK_SET) - if n, e := io.Copy(o, f); m.Assert(e) { - m.Info("upload: %s file: %s", kit.FmtSize(n), p) - arg = kit.Simple(arg[0], h.Header.Get("Content-Type"), h.Filename, p, p, n) + // 保存文件 + f.Seek(0, os.SEEK_SET) + if n, e := io.Copy(o, f); m.Assert(e) { + m.Info("upload: %s file: %s", kit.FmtSize(n), p) + arg = kit.Simple(arg[0], h.Header.Get("Content-Type"), h.Filename, p, p, n) + } + } + } + } else if r, ok := m.Optionv("response").(*http.Response); ok { + if buf, e := ioutil.ReadAll(r.Body); m.Assert(e) { + file := kit.Hashs(string(buf)) + if o, p, e := kit.Create(path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), file[:2], file)); m.Assert(e) { + defer o.Close() + if n, e := o.Write(buf); m.Assert(e) { + m.Info("download: %s file: %s", kit.FmtSize(int64(n)), p) + arg = kit.Simple(arg[0], arg[1], arg[2], p, p, n) + } } } } @@ -704,13 +861,21 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", case "add": // 添加数据 size := kit.Select(kit.Format(len(arg[3])), arg, 5) - h := m.Rich(ice.WEB_CACHE, nil, kit.Dict( + data := kit.Dict( kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], - kit.MDB_FILE, kit.Select("", arg, 4), - kit.MDB_SIZE, size, arg[1], arg[3], - )) + kit.MDB_FILE, kit.Select("", arg, 4), kit.MDB_SIZE, size, + ) + h := m.Rich(ice.WEB_CACHE, nil, data) m.Info("cache: %s type: %s name: %s", h, arg[1], arg[2]) + // 保存数据 + if arg[0] == "add" && len(arg) == 4 { + p := path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), h[:2], h) + if m.Cmd("nfs.save", p, arg[3]); kit.Int(size) > 512 { + data["text"], data["file"], arg[3] = p, p, p + } + } + // 添加记录 m.Grow(ice.WEB_CACHE, nil, kit.Dict( kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], @@ -724,11 +889,6 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Push("text", arg[3]) m.Push("size", size) m.Push("data", h) - - // 保存数据 - if arg[0] == "add" { - m.Cmd("nfs.save", path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), h[:2], h), arg[3]) - } } }}, ice.WEB_STORY: {Name: "story", Help: "故事会", Meta: kit.Dict("remote", "you", "exports", []string{"top", "story"}, "detail", []string{"归档", "共享", "下载"}), List: kit.List( @@ -740,12 +900,15 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", switch arg[1] { case "共享": switch arg[2] { - case "story": - m.Cmd(ice.WEB_SHARE, "add", "story", arg[3], arg[3]) - arg = []string{} - case "list": - m.Cmd(ice.WEB_SHARE, "add", "story", m.Option("top"), arg[3]) - arg = []string{m.Option("top")} + case "story", "list": + pod := "" + if list := kit.Simple(m.Optionv("_source")); len(list) > 0 { + pod = strings.Join(list[1:], ".") + } + msg := m.Cmd(ice.WEB_STORY, "index", arg[3]) + m.Cmdy(ice.WEB_SPACE, "share", "add", ice.TYPE_STORY, + msg.Append("story"), arg[3], "pod", pod, "data", arg[3]) + return } } } @@ -755,6 +918,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Richs(ice.WEB_STORY, "head", "", func(key string, value map[string]interface{}) { m.Push(key, value, []string{"time", "scene", "story", "count"}) }) + m.Sort("time", "time_r") return } @@ -762,8 +926,10 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", switch arg[0] { case "add", "upload": // 保存数据 - m.Cmdy(ice.WEB_CACHE, arg) - arg = []string{arg[0], m.Append("type"), m.Append("name"), m.Append("data")} + if m.Richs(ice.WEB_CACHE, nil, arg[3], nil) == nil { + m.Cmdy(ice.WEB_CACHE, arg) + arg = []string{arg[0], m.Append("type"), m.Append("name"), m.Append("data")} + } // 查询索引 head, prev, count := "", "", 0 @@ -867,7 +1033,6 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", }) == nil { arg[1] = kit.Select(arg[1], m.Conf(ice.WEB_STORY, kit.Keys("head.hash", arg[1], "list"))) } - // 查询节点 if node := m.Confm(ice.WEB_STORY, kit.Keys("hash", arg[1])); node != nil { m.Push("list", arg[1]) @@ -888,11 +1053,12 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Push("scene", value["scene"]) m.Push("story", value["story"]) m.Push("drama", value["drama"]) - m.Push("link", kit.Format(m.Conf(ice.WEB_SHARE, "meta.template.download"), value["data"], kit.Short(value["data"]))) + m.Push("link", kit.Format(m.Conf(ice.WEB_SHARE, "meta.template.download"), + kit.Format(value["data"])+"&pod="+m.Conf(ice.CLI_RUNTIME, "node.name"), kit.Short(value["data"]))) }) } }}, - ice.WEB_SHARE: {Name: "share", Help: "共享链", Meta: kit.Dict("remote", "you"), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + ice.WEB_SHARE: {Name: "share", Help: "共享链", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { // 共享列表 m.Grows(ice.WEB_SHARE, nil, "", "", func(key int, value map[string]interface{}) { @@ -905,20 +1071,30 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", switch arg[0] { case "add": // 创建共享 + extra := kit.Dict() + for i := 4; i < len(arg)-1; i += 2 { + kit.Value(extra, arg[i], arg[i+1]) + } + h := m.Rich(ice.WEB_SHARE, nil, kit.Dict( kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], + "extra", extra, )) m.Grow(ice.WEB_SHARE, nil, kit.Dict( kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], "share", h, )) - m.Info("share: %s", h) + m.Info("share: %s %s", h, extra) m.Echo(h) } }}, - ice.WEB_ROUTE: {Name: "route", Help: "路由表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + ice.WEB_ROUTE: {Name: "route", Help: "路由", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, - ice.WEB_PROXY: {Name: "proxy", Help: "代理商", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + ice.WEB_PROXY: {Name: "proxy", Help: "代理", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + }}, + ice.WEB_GROUP: {Name: "group", Help: "分组", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + }}, + ice.WEB_LABEL: {Name: "label", Help: "标签", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, "/proxy/": {Name: "/proxy/", Help: "代理商", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { @@ -928,12 +1104,12 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Confm(ice.WEB_SHARE, kit.Keys("hash", key), func(value map[string]interface{}) { m.Info("share %s %v", key, kit.Format(value)) switch value["type"] { - case kit.MIME_STORY: - if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" { - m.Push("_output", "file") - } else { - m.Push("_output", "result") + case ice.TYPE_STORY: + if m.Cmdy(ice.WEB_STORY, "index", kit.Value(value, "extra.data")).Append("text") == "" { + m.Cmdy(ice.WEB_SPACE, kit.Value(value, "extra.pod"), ice.WEB_STORY, "index", kit.Value(value, "extra.data")) } + m.Push("_output", kit.Select("file", "result", m.Append("file") == "")) + default: if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" { m.Push("_output", "file") @@ -947,15 +1123,34 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", "/space/": {Name: "/space/", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { r := m.Optionv("request").(*http.Request) w := m.Optionv("response").(http.ResponseWriter) + list := strings.Split(cmd, "/") + + switch list[2] { + case "share": + m.Cmdy(ice.WEB_SHARE, list[3:]) + return + case "upload": + m.Cmdy(ice.WEB_CACHE, "upload") + return + case "download": + m.Cmdy(ice.WEB_STORY, "index", list[3]) + m.Push("_output", kit.Select("file", "result", m.Append("file") == "")) + return + } if s, e := websocket.Upgrade(w, r, nil, m.Confi(ice.WEB_SPACE, "meta.buffer"), m.Confi(ice.WEB_SPACE, "meta.buffer")); m.Assert(e) { + // 共享空间 + share := m.Option("share") + if m.Richs(ice.WEB_SHARE, nil, share, nil) == nil { + share = m.Cmdx(ice.WEB_SHARE, "add", m.Option("node"), m.Option("name"), m.Option("user")) + } // 添加节点 h := m.Rich(ice.WEB_SPACE, nil, kit.Dict( kit.MDB_TYPE, m.Option("node"), kit.MDB_NAME, m.Option("name"), kit.MDB_USER, m.Option("user"), - "share", m.Cmdx(ice.WEB_SHARE, "add", m.Option("node"), m.Option("name"), m.Option("user")), + "share", share, "socket", s, )) m.Info("space: %s", m.Option(kit.MDB_NAME)) @@ -967,6 +1162,11 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Log("close", "%s: %s", m.Option(kit.MDB_NAME), kit.Format(m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, h)))) m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, h), "") }) + + // 共享空间 + if share != m.Option("share") { + m.Cmd(ice.WEB_SPACE, m.Option("name"), ice.WEB_SPACE, "share", share) + } } }}, "/static/volcanos/plugin/github.com/": {Name: "/space/", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/conf.go b/conf.go index 1e9dd9af..e23d17ea 100644 --- a/conf.go +++ b/conf.go @@ -46,6 +46,7 @@ const ( WEB_TMPL = "render" WEB_LOGIN = "_login" + WEB_SPIDE = "spide" WEB_SERVE = "serve" WEB_SPACE = "space" @@ -56,9 +57,11 @@ const ( WEB_SHARE = "share" WEB_ROUTE = "route" WEB_PROXY = "proxy" + WEB_GROUP = "group" + WEB_LABEL = "label" ) const ( - LOG_CMD = "cmd" + LOG_CMDS = "cmds" LOG_COST = "cost" LOG_INFO = "info" LOG_WARN = "warn" @@ -95,7 +98,24 @@ const ( ) const ( - CHAT_GROUP = "group" + CHAT_RIVER = "river" +) + +const ( + TYPE_SPACE = "space" + TYPE_RIVER = "river" + TYPE_STORM = "storm" + + TYPE_STORY = "story" + TYPE_SHELL = "shell" + TYPE_TABLE = "table" + TYPE_INNER = "inner" + TYPE_MEDIA = "media" +) +const ( + FAVOR_CHAT = "chat.init" + FAVOR_TMUX = "tmux.init" + FAVOR_RIVER = "river.init" ) var Alias = map[string]string{ @@ -120,6 +140,8 @@ var Alias = map[string]string{ WEB_SHARE: "web.share", WEB_ROUTE: "web.route", WEB_PROXY: "web.proxy", + WEB_GROUP: "web.group", + WEB_LABEL: "web.label", GDB_SIGNAL: "gdb.signal", GDB_TIMER: "gdb.timer", @@ -137,7 +159,7 @@ var Alias = map[string]string{ MDB_SELECT: "mdb.select", MDB_DELETE: "mdb.delete", - CHAT_GROUP: "web.chat.group", + CHAT_RIVER: "web.chat.river", "note": "web.wiki.note", } diff --git a/core/chat/chat.go b/core/chat/chat.go index 7d475bda..a65c1d9b 100644 --- a/core/chat/chat.go +++ b/core/chat/chat.go @@ -10,18 +10,26 @@ import ( var Index = &ice.Context{Name: "chat", Help: "聊天模块", Caches: map[string]*ice.Cache{}, Configs: map[string]*ice.Config{ - ice.CHAT_GROUP: {Name: "group", Help: "群组", Value: kit.Data()}, + ice.CHAT_RIVER: {Name: "river", Help: "群组", Value: kit.Data()}, }, Commands: map[string]*ice.Command{ ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Cmd(ice.CTX_CONFIG, "load", "aaa.json") - m.Cmd(ice.CTX_CONFIG, "load", "web.json") m.Cmd(ice.CTX_CONFIG, "load", "chat.json") + if m.Richs(ice.WEB_FAVOR, nil, ice.FAVOR_RIVER, nil) == nil { + // 群组模板 + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "river", "meet", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "user", m.Conf(ice.CLI_RUNTIME, "boot.username"), "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "storm", "miss", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "action", "space", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "action", "dream", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "action", "favor", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "action", "cache", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "action", "story", "root") + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_RIVER, "action", "share", "root") + } }}, ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Cmd(ice.CTX_CONFIG, "save", "chat.json", ice.CHAT_GROUP) - m.Cmd(ice.CTX_CONFIG, "save", "web.json", ice.WEB_SPIDE, ice.WEB_FAVOR, ice.WEB_CACHE, ice.WEB_STORY, ice.WEB_SHARE) - m.Cmd(ice.CTX_CONFIG, "save", "aaa.json", ice.AAA_ROLE, ice.AAA_USER, ice.AAA_SESS) + m.Cmd(ice.CTX_CONFIG, "save", "chat.json", ice.CHAT_RIVER) }}, ice.WEB_LOGIN: {Name: "login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { @@ -30,12 +38,29 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", case "login": // 用户登录 m.Option(ice.MSG_SESSID, (web.Cookie(m, m.Cmdx(ice.AAA_USER, "login", m.Option(ice.MSG_USERNAME, arg[1]), arg[2])))) + if m.Richs(ice.CHAT_RIVER, nil, "", nil) == nil { + // 默认群组 + m.Richs(ice.WEB_FAVOR, nil, "river.init", func(key string, value map[string]interface{}) { + m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) { + switch kit.Format(value["type"]) { + case "river": + m.Option("river", m.Cmdx("/ocean", "spawn", value["name"])) + case "user": + m.Cmd("/river", m.Option("river"), "add", value["name"]) + case "storm": + m.Option("storm", m.Cmdx("/steam", m.Option("river"), "spawn", value["name"])) + case "action": + m.Cmd("/storm", m.Option("river"), m.Option("storm"), "add", m.Conf(ice.CLI_RUNTIME, "node.name"), "", value["name"], value["text"]) + } + }) + }) + } default: // 用户群组 - m.Richs(ice.CHAT_GROUP, nil, arg[0], func(value map[string]interface{}) { + m.Richs(ice.CHAT_RIVER, nil, arg[0], func(value map[string]interface{}) { m.Option(ice.MSG_RIVER, arg[0]) if len(arg) > 1 { - m.Richs(ice.CHAT_GROUP, kit.Keys(kit.MDB_HASH, arg[0], "tool"), arg[1], func(value map[string]interface{}) { + m.Richs(ice.CHAT_RIVER, kit.Keys(kit.MDB_HASH, arg[0], "tool"), arg[1], func(value map[string]interface{}) { m.Option(ice.MSG_STORM, arg[1]) }) } @@ -79,21 +104,22 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", switch arg[0] { case "spawn": // 创建群组 - river := m.Rich(ice.CHAT_GROUP, nil, kit.Data(kit.MDB_NAME, arg[1])) + river := m.Rich(ice.CHAT_RIVER, nil, kit.Data(kit.MDB_NAME, arg[1])) m.Info("create river: %v name: %v", river, arg[1]) m.Cmd("/river", river, "add", arg[2:]) + m.Echo(river) } }}, "/river": {Name: "/river", Help: "小河流", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch len(arg) { case 0: // 群组列表 - m.Richs(ice.CHAT_GROUP, nil, "", func(key string, value map[string]interface{}) { + m.Richs(ice.CHAT_RIVER, nil, "", func(key string, value map[string]interface{}) { m.Push(key, value["meta"], []string{kit.MDB_KEY, kit.MDB_NAME}) }) case 1: // 群组详情 - m.Richs(ice.CHAT_GROUP, nil, arg[0], func(key string, value map[string]interface{}) { + m.Richs(ice.CHAT_RIVER, nil, arg[0], func(key string, value map[string]interface{}) { m.Push(key, value["meta"], []string{kit.MDB_KEY, kit.MDB_NAME}) }) default: @@ -101,7 +127,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", case "add": // 添加用户 for _, v := range arg[2:] { - user := m.Rich(ice.CHAT_GROUP, kit.Keys(kit.MDB_HASH, arg[0], "user"), kit.Data("username", v)) + user := m.Rich(ice.CHAT_RIVER, kit.Keys(kit.MDB_HASH, arg[0], "user"), kit.Data("username", v)) m.Info("add river: %s user: %s name: %s", arg[0], user, v) } } @@ -111,7 +137,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", prefix := kit.Keys(kit.MDB_HASH, arg[0], "tool") if len(arg) < 2 { // 应用列表 - m.Richs(ice.CHAT_GROUP, prefix, "", func(key string, value map[string]interface{}) { + m.Richs(ice.CHAT_RIVER, prefix, "", func(key string, value map[string]interface{}) { m.Push(key, value["meta"], []string{kit.MDB_KEY, kit.MDB_NAME}) }) m.Sort(kit.MDB_NAME) @@ -122,23 +148,23 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", case "add": // 添加命令 for i := 3; i < len(arg)-3; i += 4 { - id := m.Grow(ice.CHAT_GROUP, kit.Keys(prefix, kit.MDB_HASH, arg[1]), kit.Data( + id := m.Grow(ice.CHAT_RIVER, kit.Keys(prefix, kit.MDB_HASH, arg[1]), kit.Data( "pod", arg[i], "ctx", arg[i+1], "cmd", arg[i+2], "key", arg[i+3], )) m.Info("create tool %d %v", id, arg[i:i+4]) } case "rename": // 重命名应用 - old := m.Conf(ice.CHAT_GROUP, kit.Keys(prefix, kit.MDB_HASH, arg[1], kit.MDB_META, kit.MDB_NAME)) + old := m.Conf(ice.CHAT_RIVER, kit.Keys(prefix, kit.MDB_HASH, arg[1], kit.MDB_META, kit.MDB_NAME)) m.Info("rename storm: %s %s->%s", arg[1], old, arg[3]) - m.Conf(ice.CHAT_GROUP, kit.Keys(prefix, kit.MDB_HASH, arg[1], kit.MDB_META, kit.MDB_NAME), arg[3]) + m.Conf(ice.CHAT_RIVER, kit.Keys(prefix, kit.MDB_HASH, arg[1], kit.MDB_META, kit.MDB_NAME), arg[3]) case "remove": // 删除应用 - m.Richs(ice.CHAT_GROUP, kit.Keys(prefix), arg[1], func(value map[string]interface{}) { + m.Richs(ice.CHAT_RIVER, kit.Keys(prefix), arg[1], func(value map[string]interface{}) { m.Info("remove storm: %s %s", arg[1], kit.Format(value)) }) - m.Conf(ice.CHAT_GROUP, kit.Keys(prefix, kit.MDB_HASH, arg[1]), "") + m.Conf(ice.CHAT_RIVER, kit.Keys(prefix, kit.MDB_HASH, arg[1]), "") } }}, "/steam": {Name: "/steam", Help: "大气层", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { @@ -153,9 +179,10 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", switch arg[1] { case "spawn": // 创建应用 - storm := m.Rich(ice.CHAT_GROUP, kit.Keys(kit.MDB_HASH, arg[0], "tool"), kit.Data(kit.MDB_NAME, arg[2])) + storm := m.Rich(ice.CHAT_RIVER, kit.Keys(kit.MDB_HASH, arg[0], "tool"), kit.Data(kit.MDB_NAME, arg[2])) m.Info("create river: %s storm: %s name: %v", arg[0], storm, arg[2]) m.Cmd("/storm", arg[0], storm, "add", arg[3:]) + m.Echo(storm) default: // 命令列表 @@ -168,7 +195,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", if len(arg) == 2 { // 命令列表 m.Set(ice.MSG_OPTION) - m.Grows(ice.CHAT_GROUP, prefix, "", "", func(index int, value map[string]interface{}) { + m.Grows(ice.CHAT_RIVER, prefix, "", "", func(index int, value map[string]interface{}) { if meta, ok := kit.Value(value, "meta").(map[string]interface{}); ok { m.Push("river", arg[0]) m.Push("storm", arg[1]) @@ -188,16 +215,20 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块", return } - // 执行命令 - m.Grows(ice.CHAT_GROUP, prefix, kit.MDB_ID, kit.Format(kit.Int(arg[2])+1), func(index int, value map[string]interface{}) { + // 查询命令 + cmds := []string{} + m.Grows(ice.CHAT_RIVER, prefix, kit.MDB_ID, kit.Format(kit.Int(arg[2])+1), func(index int, value map[string]interface{}) { if meta, ok := kit.Value(value, "meta").(map[string]interface{}); ok { if kit.Format(meta["pod"]) == m.Conf(ice.CLI_RUNTIME, "node.name") { - m.Cmdy(kit.Keys(meta["ctx"], meta["cmd"]), arg[3:]) + cmds = kit.Simple(kit.Keys(meta["ctx"], meta["cmd"]), arg[3:]) } else { - m.Cmdy(ice.WEB_SPACE, meta["pod"], kit.Keys(meta["ctx"], meta["cmd"]), arg[3:]) + cmds = kit.Simple(ice.WEB_SPACE, meta["pod"], kit.Keys(meta["ctx"], meta["cmd"]), arg[3:]) } } }) + + // 执行命令 + m.Cmdy(cmds).Option("cmds", cmds) }}, }, } diff --git a/core/code/code.go b/core/code/code.go index 7a3b68d9..e870127c 100644 --- a/core/code/code.go +++ b/core/code/code.go @@ -33,6 +33,10 @@ var Index = &ice.Context{Name: "code", Help: "编程模块", }, Commands: map[string]*ice.Command{ ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd(ice.CTX_CONFIG, "load", "code.json") + }}, + ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmd(ice.CTX_CONFIG, "save", "code.json", "web.code.login") }}, "login": {Name: "login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { @@ -47,18 +51,19 @@ var Index = &ice.Context{Name: "code", Help: "编程模块", } } + you := m.Conf(ice.WEB_SHARE, kit.Keys("hash", m.Option("share"), "name")) // 添加终端 h := m.Rich("login", nil, kit.Dict( "status", "login", "type", kit.Select("zsh", arg, 1), - "you", m.Conf(ice.WEB_SHARE, kit.Keys("hash", m.Option("share"), "name")), + "you", you, "pwd", m.Option("pwd"), "pid", m.Option("pid"), "pane", m.Option("pane"), "hostname", m.Option("hostname"), "username", m.Option("username"), )) - m.Info("zsh %s", h) + m.Info("%s: %s", you, h) m.Echo(h) case "list": @@ -78,28 +83,34 @@ var Index = &ice.Context{Name: "code", Help: "编程模块", case "login": m.Cmdy("login", "init", cmd).Push("_output", "result") case "upload": - // 上传文件 - msg := m.Cmd(ice.WEB_STORY, "upload") - m.Push("_output", "result") - m.Echo("list: %s\n", msg.Append("list")) + // 缓存文件 + msg := m.Cmd(ice.WEB_CACHE, "upload") m.Echo("data: %s\n", msg.Append("data")) m.Echo("time: %s\n", msg.Append("time")) m.Echo("type: %s\n", msg.Append("type")) m.Echo("name: %s\n", msg.Append("name")) m.Echo("size: %s\n", msg.Append("size")) + m.Push("_output", "result") + + // 下发文件 + m.Cmd(ice.WEB_SPACE, msg.Option("you"), ice.WEB_SPACE, "download", msg.Append("type"), msg.Append("name"), "self", msg.Append("data")) case "download": // 下载文件 - m.Cmdy(ice.WEB_STORY, "download", m.Optionv("arg")) + m.Option("you", "") + if m.Cmdy(ice.WEB_STORY, "index", m.Option("arg")).Append("text") == "" { + m.Cmdy(ice.WEB_SPACE, m.Option("pod"), ice.WEB_STORY, "index", m.Optionv("arg")) + } + m.Push("_output", kit.Select("file", "result", m.Append("file") == "")) case "history": - m.Option("you", "") vs := strings.SplitN(strings.TrimSpace(m.Option("arg")), " ", 2) m.Cmd(ice.WEB_SPACE, m.Option("you"), ice.WEB_FAVOR, "zsh.history", "shell", m.Option("sid"), kit.Select("", vs, 1), "sid", m.Option("sid"), "num", vs[0], "pwd", m.Option("pwd")) m.Push("_output", "void") } }}, + "_tmux": {Name: "tmux [session [window [pane cmd]]]", Help: "窗口", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { prefix := kit.Simple(m.Confv("prefix", "tmux")) if len(arg) > 1 { diff --git a/demo/Makefile b/demo/Makefile index 94e5404e..0c095b2e 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -1,2 +1,2 @@ all: - go build -o bin/ice.bin main.go && chmod u+x bin/ice.bin && ./load.sh restart + go build -o bin/ice.bin main.go && chmod u+x bin/ice.bin && ./ice.sh restart diff --git a/misc/tmux/tmux.go b/misc/tmux/tmux.go index bba188f7..89495479 100644 --- a/misc/tmux/tmux.go +++ b/misc/tmux/tmux.go @@ -4,6 +4,7 @@ import ( "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/cli" "github.com/shylinux/toolkits" + "path" "strings" "time" ) @@ -51,7 +52,14 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", }, Commands: map[string]*ice.Command{ ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Cmd(ice.GDB_EVENT, "listen", ice.DREAM_START, "cli.tmux.session") + m.Cmd(ice.GDB_EVENT, "listen", ice.DREAM_START, "cli.tmux.auto") + if m.Richs(ice.WEB_STORY, "head", "auto.sh", nil) == nil { + m.Cmd(ice.WEB_STORY, "add", "shell", "auto.sh", m.Cmdx(ice.WEB_SPIDE, "shy", "GET", "/publish/auto.sh")) + } + if m.Richs(ice.WEB_FAVOR, nil, ice.FAVOR_TMUX, nil) == nil { + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_TMUX, ice.TYPE_SHELL, "下载脚本", `curl -s "$ctx_dev/code/zsh?cmd=download&arg=auto.sh" > auto.sh`) + m.Cmd(ice.WEB_FAVOR, ice.FAVOR_TMUX, ice.TYPE_SHELL, "加载脚本", `source auto.sh`) + } }}, ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, @@ -102,7 +110,7 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", case "session": target = arg[3] } - m.Cmd("run", target, m.Option("hot")) + m.Cmd("auto", target, m.Option("hot")) arg = arg[:0] case "select": @@ -167,7 +175,7 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", m.Option("cmd_env", "TMUX", "") m.Option("cmd_dir", m.Conf(ice.WEB_DREAM, "meta.path")) m.Cmd(prefix, "new-session", "-ds", arg[0]) - m.Cmd("run", arg[0], arg[1:]) + m.Cmd("auto", arg[0], arg[1:]) arg = arg[:1] } @@ -209,15 +217,23 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", "view": {Name: "view", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmdy("cli.system", "tmux", "capture-pane", "-pt", kit.Select("", arg, 0)).Set("append") }}, - "run": {Name: "view", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + "auto": {Name: "auto", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { prefix := []string{"cli.system", "tmux"} + m.Option("cmd_env", "TMUX", "") + m.Option("cmd_dir", path.Join(m.Conf(ice.WEB_DREAM, "meta.path"), arg[0])) + + // 创建会话 + if m.Cmd(prefix, "has-session", "-t", arg[0]).Append("code") != "0" { + m.Cmd(prefix, "new-session", "-ds", arg[0]) + } + m.Richs(ice.WEB_SPACE, nil, arg[0], func(key string, value map[string]interface{}) { + m.Cmdy(prefix, "send-keys", "-t", arg[0], "export ctx_dev=", kit.Select(m.Conf(ice.CLI_RUNTIME, "host.ctx_dev"), m.Conf(ice.CLI_RUNTIME, "host.ctx_self")), "Enter") m.Cmdy(prefix, "send-keys", "-t", arg[0], "export ctx_share=", value["share"], "Enter") }) - m.Option("cmd_env", "TMUX", "") - m.Cmd(ice.WEB_FAVOR, kit.Select("some", arg, 1)).Table(func(index int, value map[string]string, head []string) { + m.Cmd(ice.WEB_FAVOR, kit.Select("tmux.init", arg, 1)).Table(func(index int, value map[string]string, head []string) { switch value["type"] { case "shell": m.Cmdy(prefix, "send-keys", "-t", arg[0], value["text"], "Enter") diff --git a/type.go b/type.go index 5fdc7ff3..b9b471a8 100644 --- a/type.go +++ b/type.go @@ -77,7 +77,7 @@ func (c *Context) Server() Server { } func (c *Context) Run(m *Message, cmd *Command, key string, arg ...string) *Message { m.Hand = true - m.Log(LOG_CMD, "%s.%s %v", c.Name, key, arg) + m.Log(LOG_CMDS, "%s.%s %v", c.Name, key, arg) cmd.Hand(m, c, key, arg...) return m } @@ -599,21 +599,20 @@ func (m *Message) Log(level string, str string, arg ...interface{}) *Message { } prefix, suffix := "", "" switch level { - case LOG_CMD, "start", "serve": + case LOG_CMDS, "start", "serve": prefix, suffix = "\033[32m", "\033[0m" case LOG_COST: prefix, suffix = "\033[33m", "\033[0m" case LOG_WARN, LOG_ERROR, "close": prefix, suffix = "\033[31m", "\033[0m" } - fmt.Fprintf(os.Stderr, "%s %d %s->%s %s%s %s%s\n", - m.time.Format(ICE_TIME), m.code, m.source.Name, m.target.Name, + fmt.Fprintf(os.Stderr, "%s %02d %9s %s%s %s%s\n", + m.time.Format(ICE_TIME), m.code, fmt.Sprintf("%s->%s", m.source.Name, m.target.Name), prefix, level, str, suffix) return m } func (m *Message) Cost(str string, arg ...interface{}) *Message { - m.Log(LOG_COST, "%s: %s", m.Format("cost"), kit.Format(str, arg...)) - return m.Log(LOG_INFO, str, arg...) + return m.Log(LOG_COST, "%s: %s", m.Format("cost"), kit.Format(str, arg...)) } func (m *Message) Info(str string, arg ...interface{}) *Message { return m.Log(LOG_INFO, str, arg...) @@ -847,12 +846,14 @@ func (m *Message) Richs(key string, chain interface{}, raw interface{}, cb inter res, _ = hash[h].(map[string]interface{}) default: // 单个查询 - switch kit.Format(kit.Value(meta, kit.MDB_SHORT)) { - case "", "uniq": - default: - h = kit.Hashs(h) + if res, ok = hash[h].(map[string]interface{}); !ok { + switch kit.Format(kit.Value(meta, kit.MDB_SHORT)) { + case "", "uniq": + default: + h = kit.Hashs(h) + res, ok = hash[h].(map[string]interface{}) + } } - res, _ = hash[h].(map[string]interface{}) } // 返回数据