diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 75d14ef0..62db199f 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -4,6 +4,10 @@ import ( "github.com/shylinux/icebergs" "github.com/shylinux/toolkits" + "bytes" + "encoding/csv" + "encoding/json" + "sort" "strings" ) @@ -16,7 +20,6 @@ var Index = &ice.Context{Name: "mdb", Help: "数据模块", index := kit.Int(arg[2]) - kit.Int(meta["offset"]) - 1 data := m.Confm(arg[0], arg[1]+".list."+kit.Format(index)) - m.Log("what", "%v %v", arg[0], arg[1]+".list."+kit.Format(index)) for i := 3; i < len(arg)-1; i += 2 { kit.Value(data, arg[i], arg[i+1]) } @@ -37,6 +40,75 @@ var Index = &ice.Context{Name: "mdb", Help: "数据模块", }) } }}, + ice.MDB_IMPORT: {Name: "import", Help: "导入数据", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + msg := m.Cmd(ice.WEB_STORY, "index", arg[3]) + + switch arg[2] { + case kit.MDB_DICT: + case kit.MDB_META: + case kit.MDB_LIST: + buf := bytes.NewBufferString(msg.Append("text")) + r := csv.NewReader(buf) + head, _ := r.Read() + + for { + line, e := r.Read() + if e != nil { + break + } + + data := kit.Dict() + for i, k := range head { + data[k] = line[i] + } + m.Grow(arg[0], arg[1], data) + m.Info("import %v", data) + } + + case kit.MDB_HASH: + data := map[string]interface{}{} + m.Assert(json.Unmarshal([]byte(msg.Append("text")), &data)) + for k, v := range data { + m.Conf(arg[0], kit.Keys(arg[1], k), v) + m.Info("import %v", v) + } + } + }}, + ice.MDB_EXPORT: {Name: "export", Help: "导出数据", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + name := kit.Select(kit.Select(arg[0], arg[0]+":"+arg[1], arg[1] != ""), arg, 3) + + switch arg[2] { + case kit.MDB_DICT: + case kit.MDB_META: + case kit.MDB_LIST: + buf := bytes.NewBuffer(make([]byte, 0, 1024)) + w := csv.NewWriter(buf) + head := []string{} + m.Confm(arg[0], arg[1], func(index int, value map[string]interface{}) { + if index == 0 { + // 输出表头 + for k := range value { + head = append(head, k) + } + sort.Strings(head) + w.Write(head) + } + + // 输出数据 + data := []string{} + for _, k := range head { + data = append(data, kit.Format(value[k])) + } + w.Write(data) + }) + w.Flush() + + m.Cmd(ice.WEB_STORY, "add", "csv", name, string(buf.Bytes())) + + case kit.MDB_HASH: + m.Cmd(ice.WEB_STORY, "add", "json", name, kit.Formats(m.Confv(arg[0], arg[1]))) + } + }}, }, } diff --git a/base/web/template.go b/base/web/template.go index b251f166..e892063c 100644 --- a/base/web/template.go +++ b/base/web/template.go @@ -1,8 +1,14 @@ package web -var share_template = map[string]interface{}{ - "shy/story": `{{}}`, - "shy/chain": ` +import ( + "github.com/shylinux/toolkits" +) + +var share_template = kit.Dict( + "download", `%s`, + "share", `%s`, + "shy/story", `{{.}}`, + "shy/chain", ` @@ -14,4 +20,4 @@ var share_template = map[string]interface{}{ `, -} +) diff --git a/base/web/web.go b/base/web/web.go index 48120780..173c9bbb 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -68,9 +68,7 @@ func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) bool { if len(target) == 0 { // 本地执行 if msg.Optionv(ice.MSG_HANDLE, "true"); !msg.Warn(!safe, "no right") { - if msg = msg.Cmd(); msg.Detail() == "exit" { - return true - } + msg = msg.Cmd() } kit.Revert(source) source, target = []string{source[0]}, source[1:] @@ -102,6 +100,9 @@ func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) bool { msg.Optionv(ice.MSG_TARGET, target) socket.WriteMessage(t, []byte(msg.Format("meta"))) msg.Info("send %v %v->%v %v", t, source, target, msg.Format("meta")) + if msg.Detail() == "exit" { + return true + } } } } @@ -171,18 +172,6 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) { } } - // 请求参数 - r.ParseMultipartForm(4096) - if r.ParseForm(); len(r.PostForm) > 0 { - for k, v := range r.PostForm { - msg.Info("%s: %v", k, v) - } - msg.Info("") - } - for k, v := range r.Form { - msg.Optionv(k, v) - } - // 请求数据 switch r.Header.Get("Content-Type") { case "application/json": @@ -198,6 +187,19 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) { msg.Optionv(k, v) } } + default: + r.ParseMultipartForm(4096) + if r.ParseForm(); len(r.PostForm) > 0 { + for k, v := range r.PostForm { + msg.Info("%s: %v", k, v) + } + msg.Info("") + } + } + + // 请求参数 + for k, v := range r.Form { + msg.Optionv(k, v) } // 执行命令 @@ -300,13 +302,18 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool { } }) - // 服务地址 - port := m.Cap(ice.CTX_STREAM, kit.Select(m.Conf(ice.WEB_SPIDE, ice.Meta("self", "port")), arg, 0)) - m.Log("serve", "listen %s %v", port, m.Conf(ice.CLI_RUNTIME, "node")) + // TODO simple + m.Richs(ice.WEB_SPIDE, nil, arg[0], func(key string, value map[string]interface{}) { + client := value["client"].(map[string]interface{}) - // 启动服务 - web.m, web.Server = m, &http.Server{Addr: port, Handler: web} - m.Log("serve", "listen %s", web.Server.ListenAndServe()) + // 服务地址 + port := m.Cap(ice.CTX_STREAM, client["hostname"]) + m.Log("serve", "listen %s %s %v", arg[0], port, m.Conf(ice.CLI_RUNTIME, "node")) + + // 启动服务 + web.m, web.Server = m, &http.Server{Addr: port, Handler: web} + m.Log("serve", "listen %s", web.Server.ListenAndServe()) + }) return true } func (web *Frame) Close(m *ice.Message, arg ...string) bool { @@ -316,7 +323,7 @@ func (web *Frame) Close(m *ice.Message, arg ...string) bool { var Index = &ice.Context{Name: "web", Help: "网页模块", Caches: map[string]*ice.Cache{}, Configs: map[string]*ice.Config{ - ice.WEB_SPIDE: {Name: "spide", Help: "客户端", Value: kit.Data("self.port", ice.WEB_PORT, kit.MDB_SHORT, "name")}, + ice.WEB_SPIDE: {Name: "spide", Help: "客户端", Value: kit.Data(kit.MDB_SHORT, "name")}, ice.WEB_SERVE: {Name: "serve", Help: "服务器", Value: kit.Data( "static", map[string]interface{}{"/": "usr/volcanos/", "/static/volcanos/": "usr/volcanos/", @@ -326,35 +333,26 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", }}, "logheaders", "false", )}, - ice.WEB_SPACE: {Name: "space", Help: "空间站", Value: kit.Data( + ice.WEB_SPACE: {Name: "space", Help: "空间站", Value: kit.Data(kit.MDB_SHORT, "name", "redial.a", 3000, "redial.b", 1000, "redial.c", 10, "buffer.r", 4096, "buffer.w", 4096, - kit.MDB_SHORT, "name", )}, - ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Value: kit.Data( - "path", "usr/local/work", - "cmd", []interface{}{"cli.system", "sh", "ice.sh", "start", "web.space", "connect"}, + ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Value: kit.Data("path", "usr/local/work", + "cmd", []interface{}{ice.CLI_SYSTEM, "sh", "ice.sh", "start", ice.WEB_SPACE, "connect"}, )}, ice.WEB_FAVOR: {Name: "favor", Help: "收藏夹", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)}, - 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", - "download", `%s`), - "head", kit.Data(kit.MDB_SHORT, "story"), - )}, - ice.WEB_SHARE: {Name: "share", Help: "共享链", Value: kit.Data( - "href", `%s`, - "template", share_template, - )}, + 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()}, }, Commands: map[string]*ice.Command{ - ice.ICE_INIT: {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.WEB_SPIDE, "add", "self", "http://:9020") + }}, 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 { // 爬虫列表 @@ -433,7 +431,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", "name", m.Conf(ice.CLI_RUNTIME, "boot.hostname"), "user", m.Conf(ice.CLI_RUNTIME, "boot.username"), )) - m.Target().Start(m, arg...) + m.Target().Start(m, kit.Select("self", arg, 0)) }}, ice.WEB_SPACE: {Name: "space", Help: "空间站", Meta: kit.Dict("exports", []string{"pod", "name"}), List: kit.List( kit.MDB_INPUT, "text", "name", "node", @@ -455,26 +453,30 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", node := m.Conf(ice.CLI_RUNTIME, "node.type") name := kit.Select(m.Conf(ice.CLI_RUNTIME, "boot.pathname"), m.Conf(ice.CLI_RUNTIME, "boot.hostname"), node == kit.MIME_SERVER) user := m.Conf(ice.CLI_RUNTIME, "boot.username") - host := kit.Select(m.Conf(ice.WEB_SPIDE, "meta.self.port"), arg, 1) - if u, e := url.Parse(kit.MergeURL("ws://"+host+kit.Select("/space/", arg, 2), "node", node, "name", name, "user", user)); 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) { - // 连接成功 - m.Info("conn %d success %s", i, u) - if i = 0; web.HandleWSS(m, true, s) { - break + 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) { + 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) { + // 连接成功 + m.Info("conn %d success %s", i, u) + if i = 0; web.HandleWSS(m, true, s) { + break + } } } - } - // 断线重连 - sleep := time.Duration(rand.Intn(m.Confi(ice.WEB_SPACE, "meta.redial.a"))*i+i*m.Confi(ice.WEB_SPACE, "meta.redial.b")) * time.Millisecond - m.Info("%d sleep: %s reconnect: %s", i, sleep, u) - time.Sleep(sleep) + // 断线重连 + sleep := time.Duration(rand.Intn(m.Confi(ice.WEB_SPACE, "meta.redial.a"))*i+i*m.Confi(ice.WEB_SPACE, "meta.redial.b")) * time.Millisecond + m.Info("%d sleep: %s reconnect: %s", i, sleep, u) + time.Sleep(sleep) + } } - } + }) + default: // 本地命令 if arg[0] == "" || arg[0] == m.Conf(ice.CLI_RUNTIME, "node.name") { @@ -505,8 +507,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", }) == nil, "not found %s", arg[0]) } }}, - ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Meta: kit.Dict( - "exports", []interface{}{"you", "name"}, + ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Meta: kit.Dict("exports", []string{"you", "name"}, "detail", []interface{}{"启动", "停止"}, ), List: kit.List( kit.MDB_INPUT, "text", "value", "", "name", "name", @@ -516,9 +517,10 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", if len(arg) > 1 { switch arg[1] { case "启动": - case "停止": + case "停止", "stop": m.Cmd(ice.WEB_SPACE, arg[0], "exit", "1") - m.Cmd(ice.GDB_EVENT, "action", "miss.stop", arg[0]) + time.Sleep(time.Second * 3) + m.Cmd(ice.GDB_EVENT, "action", ice.DREAM_CLOSE, arg[0]) return } } @@ -539,8 +541,9 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", // 启动任务 m.Option("cmd_dir", p) m.Option("cmd_type", "daemon") - m.Cmd(ice.GDB_EVENT, "action", "miss.start", arg[0]) - m.Cmd(m.Confv(ice.WEB_DREAM, "meta.cmd")) + m.Cmd(m.Confv(ice.WEB_DREAM, "meta.cmd"), "self", arg[0]) + time.Sleep(time.Second * 3) + m.Cmd(ice.GDB_EVENT, "action", ice.DREAM_START, arg) } } @@ -550,15 +553,56 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Push("status", kit.Select("start", "stop", m.Richs(ice.WEB_SPACE, nil, value["name"], nil) == nil)) }) }}, - ice.WEB_FAVOR: {Name: "favor", Help: "收藏夹", Meta: kit.Dict( - "remote", "you", - "exports", []string{"hot", "favor"}, - ), List: kit.List( + 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", kit.MDB_INPUT, "text", "name", "id", "action", "auto", kit.MDB_INPUT, "button", "value", "查看", "action", "auto", kit.MDB_INPUT, "button", "value", "返回", "cb", "Last", ), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) > 3 { + id := kit.Select(arg[0], kit.Select(m.Option("id"), arg[3], arg[2] == "id")) + switch arg[1] { + case "modify": + // 编辑收藏 + 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.Info("modify favor: %s index: %d value: %v->%v", key, index, value[arg[2]], arg[3]) + kit.Value(value, arg[2], arg[3]) + }) + }) + arg = []string{m.Option("hot")} + 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"]) + }) + }) + arg = []string{m.Option("hot")} + } + } + if len(arg) > 0 { + switch arg[0] { + case "import": + if len(arg) == 2 { + m.Cmdy(ice.MDB_IMPORT, ice.WEB_FAVOR, kit.MDB_HASH, kit.MDB_HASH, arg[1]) + } else { + m.Richs(ice.WEB_FAVOR, nil, arg[2], func(key string, value map[string]interface{}) { + m.Cmdy(ice.MDB_IMPORT, ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, key), kit.MDB_LIST, arg[1]) + }) + } + return + case "export": + if len(arg) == 1 { + m.Cmdy(ice.MDB_EXPORT, ice.WEB_FAVOR, kit.MDB_HASH, kit.MDB_HASH, "favor.json") + } else { + m.Richs(ice.WEB_FAVOR, nil, arg[1], func(key string, value map[string]interface{}) { + m.Cmdy(ice.MDB_EXPORT, ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, key, kit.MDB_LIST), kit.MDB_LIST, arg[1]+".csv") + }) + } + return + } + } + if len(arg) == 0 { // 收藏门类 m.Richs(ice.WEB_FAVOR, nil, "", func(key string, value map[string]interface{}) { @@ -569,20 +613,6 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", return } - if len(arg) > 1 { - switch arg[1] { - case "modify": - // 编辑收藏 - 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", m.Option("id"), func(index int, value map[string]interface{}) { - m.Info("modify favor: %s index: %d value: %v->%v", key, index, value[arg[2]], arg[3]) - kit.Value(value, arg[2], arg[3]) - }) - }) - return - } - } - // 创建收藏 favor := "" if m.Richs(ice.WEB_FAVOR, nil, arg[0], func(key string, value map[string]interface{}) { @@ -595,14 +625,8 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", if len(arg) == 1 { // 收藏列表 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}) - switch kit.Format(value[kit.MDB_TYPE]) { - case kit.MIME_STORY: - m.Push(kit.MDB_TEXT, kit.Format(m.Conf(ice.WEB_STORY, kit.Keys(kit.MDB_META, "download")), - value[kit.MDB_TEXT], value[kit.MDB_TEXT])) - default: - m.Push(kit.MDB_TEXT, value[kit.MDB_TEXT]) - } + 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 } @@ -622,17 +646,24 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", } // 添加收藏 + extra := kit.Dict() + for i := 4; i < len(arg)-1; i += 2 { + kit.Value(extra, arg[i], arg[i+1]) + } index := m.Grow(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), kit.Dict( kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], + "extra", extra, )) 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) { if len(arg) == 0 { - // 缓存列表 - m.Richs(ice.WEB_CACHE, nil, "", func(key string, value map[string]interface{}) { - m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_NAME, kit.MDB_SIZE, kit.MDB_TYPE, kit.MDB_TEXT}) + // 记录列表 + m.Grows(ice.WEB_CACHE, nil, "", "", func(index int, value map[string]interface{}) { + m.Push(kit.Format(index), value, []string{kit.MDB_TIME, kit.MDB_SIZE, kit.MDB_TYPE, kit.MDB_NAME, kit.MDB_TEXT}) + m.Push(kit.MDB_LINK, kit.Format(m.Conf(ice.WEB_SHARE, "meta.template.download"), value["data"], kit.Short(value["data"]))) + }) return } @@ -668,6 +699,12 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", )) m.Info("cache: %s type: %s name: %s", h, arg[1], arg[2]) + // 添加记录 + m.Grow(ice.WEB_CACHE, nil, kit.Dict( + kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], + kit.MDB_SIZE, size, "data", h, + )) + // 返回结果 m.Push("time", m.Time()) m.Push("type", arg[1]) @@ -680,21 +717,31 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", if arg[0] == "add" { m.Cmd("nfs.save", path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), h[:2], h), arg[3]) } - default: } }}, - ice.WEB_STORY: {Name: "story", Help: "故事会", Meta: kit.Dict( - "remote", "you", - "exports", []string{"top", "story"}, - ), List: kit.List( + ice.WEB_STORY: {Name: "story", Help: "故事会", Meta: kit.Dict("remote", "you", "exports", []string{"top", "story"}, "detail", []string{"归档", "共享", "下载"}), List: kit.List( kit.MDB_INPUT, "text", "name", "top", "action", "auto", kit.MDB_INPUT, "button", "value", "查看", "action", "auto", kit.MDB_INPUT, "button", "value", "返回", "cb", "Last", ), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) > 1 { + 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")} + } + } + } + if len(arg) == 0 { // 故事列表 m.Richs(ice.WEB_STORY, "head", "", func(key string, value map[string]interface{}) { - m.Push(key, value, []string{"time", "story", "scene"}) + m.Push(key, value, []string{"time", "scene", "story", "count"}) }) return } @@ -707,22 +754,22 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", arg = []string{arg[0], m.Append("type"), m.Append("name"), m.Append("data")} // 查询索引 - head, prev := "", "" + head, prev, count := "", "", 0 m.Richs(ice.WEB_STORY, "head", arg[2], func(key string, value map[string]interface{}) { - head, prev = key, kit.Format(value["list"]) - m.Log("info", "head: %v prev: %v", head, prev) + head, prev, count = key, kit.Format(value["list"]), kit.Int(value["count"]) + m.Log("info", "head: %v prev: %v count: %v", head, prev, count) }) // 添加节点 list := m.Rich(ice.WEB_STORY, nil, kit.Dict( - "scene", arg[1], "story", arg[2], "data", arg[3], "prev", prev, + "count", count+1, "scene", arg[1], "story", arg[2], "data", arg[3], "prev", prev, )) m.Info("%s: %s story: %s", arg[1], arg[2], list) m.Push("list", list) // 添加索引 m.Rich(ice.WEB_STORY, "head", kit.Dict( - "scene", arg[1], "story", arg[2], "list", list, + "count", count+1, "scene", arg[1], "story", arg[2], "list", list, )) m.Echo(list) @@ -733,7 +780,6 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Push("_output", "file") } else { m.Push("_output", "result") - m.Echo(m.Append("text")) } case "commit": @@ -780,21 +826,21 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Confm(ice.WEB_STORY, kit.Keys("hash", list), func(value map[string]interface{}) { // 直连节点 m.Confm(ice.WEB_CACHE, kit.Keys("hash", value["data"]), func(val map[string]interface{}) { - m.Push(list, value, []string{"key", "time", "scene", "story"}) + m.Push(list, value, []string{"key", "time", "count", "scene", "story"}) - m.Push("text", val["text"]) + m.Push("drama", val["text"]) m.Push("data", value["data"]) }) // 复合节点 kit.Fetch(value["list"], func(key string, val string) { - m.Push(list, value, []string{"key", "time"}) + m.Push(list, value, []string{"key", "time", "count"}) node := m.Confm(ice.WEB_STORY, kit.Keys("hash", val)) m.Push("scene", node["scene"]) m.Push("story", kit.Keys(kit.Format(value["story"]), key)) - m.Push("text", m.Conf(ice.WEB_CACHE, kit.Keys("hash", node["data"], "text"))) + m.Push("drama", m.Conf(ice.WEB_CACHE, kit.Keys("hash", node["data"], "text"))) m.Push("data", node["data"]) }) @@ -826,28 +872,45 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", default: m.Cmd(ice.WEB_STORY, "history", arg).Table(func(index int, value map[string]string, head []string) { m.Push("time", value["time"]) + m.Push("list", value["key"]) + m.Push("scene", value["scene"]) m.Push("story", value["story"]) - m.Push("text", value["text"]) - m.Push("list", kit.Format(m.Conf(ice.WEB_STORY, kit.Keys(kit.MDB_META, "download")), value["key"], value["key"])) + m.Push("drama", value["drama"]) + m.Push("link", kit.Format(m.Conf(ice.WEB_SHARE, "meta.template.download"), value["data"], 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) { if len(arg) == 0 { // 共享列表 - m.Richs(ice.WEB_SHARE, nil, "", func(key string, value map[string]interface{}) { - m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_TYPE, kit.MDB_NAME}) - m.Push("link", fmt.Sprintf(m.Conf(ice.WEB_SHARE, kit.Keys(kit.MDB_META, "href")), key, key)) + m.Grows(ice.WEB_SHARE, nil, "", "", func(key int, value map[string]interface{}) { + m.Push(kit.Format(key), value, []string{kit.MDB_TIME, kit.MDB_TYPE, kit.MDB_NAME, kit.MDB_TEXT}) + m.Push("link", fmt.Sprintf(m.Conf(ice.WEB_SHARE, "meta.template.share"), value["share"], value["share"])) }) return } - // 创建共享 - h := m.Rich(ice.WEB_SHARE, nil, kit.Dict( - kit.MDB_TYPE, arg[0], kit.MDB_NAME, arg[1], kit.MDB_TEXT, kit.Select("", arg, 2), - )) - m.Info("share: %s", h) - m.Echo(h) + switch arg[0] { + case "add": + node := kit.Dict( + kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], + ) + switch arg[1] { + case "story": + node["data"] = arg[3] + default: + node["data"] = m.Cmd(ice.WEB_CACHE, "add", arg[1:]).Append("data") + } + + // 创建共享 + h := m.Rich(ice.WEB_SHARE, nil, node) + m.Grow(ice.WEB_SHARE, nil, kit.Dict( + kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3], + "data", node["data"], "share", h, + )) + m.Info("share: %s", h) + m.Echo(h) + } }}, ice.WEB_ROUTE: {Name: "route", Help: "路由表", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, @@ -855,20 +918,6 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", }}, "/proxy/": {Name: "/proxy/", Help: "代理商", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - key := kit.Select("", strings.Split(cmd, "/"), 2) - 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: - m.Cmdy(ice.WEB_STORY, "index", value["text"]).Push("_output", "file") - return - default: - m.Push("_output", "result").Push(key, value) - m.Render(m.Conf(ice.WEB_SHARE, kit.Keys(kit.MDB_META, "template", value["type"]))) - m.Append("type", "text/html") - } - - }) }}, "/share/": {Name: "/share/", Help: "共享链", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { key := kit.Select("", strings.Split(cmd, "/"), 2) @@ -876,12 +925,17 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", m.Info("share %s %v", key, kit.Format(value)) switch value["type"] { case kit.MIME_STORY: - m.Cmdy(ice.WEB_STORY, "index", value["text"]).Push("_output", "file") - return + if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" { + m.Push("_output", "file") + } else { + m.Push("_output", "result") + } default: - m.Push("_output", "result").Push(key, value) - m.Render(m.Conf(ice.WEB_SHARE, kit.Keys(kit.MDB_META, "template", value["type"]))) - m.Append("type", "text/html") + if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" { + m.Push("_output", "file") + } else { + m.Push("_output", "result") + } } }) @@ -891,11 +945,13 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", w := m.Optionv("response").(http.ResponseWriter) 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) { + // 添加节点 - m.Rich(ice.WEB_SPACE, nil, kit.Dict( + 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")), "socket", s, )) m.Info("conn %s", m.Option(kit.MDB_NAME)) @@ -905,7 +961,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块", web := m.Target().Server().(*Frame) web.HandleWSS(m, false, s) m.Info("close %s %s", m.Option(kit.MDB_NAME), kit.Format(m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_NAME))))) - m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_NAME)), "") + m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, h), "") }) } }}, diff --git a/conf.go b/conf.go index f16c3b99..a9394fb8 100644 --- a/conf.go +++ b/conf.go @@ -73,6 +73,24 @@ const ( GDB_SIGNAL = "signal" GDB_TIMER = "timer" GDB_EVENT = "event" + + DREAM_START = "dream.start" + DREAM_CLOSE = "dream.close" + SPACE_START = "space.start" + SPACE_CLOSE = "space.close" +) +const ( + MDB_REDIS = "redis" + MDB_MYSQL = "mysql" + MDB_CREATE = "create" + MDB_IMPORT = "import" + MDB_EXPORT = "export" + MDB_REMOVE = "remove" + + MDB_INESRT = "insert" + MDB_UPDATE = "update" + MDB_SELECT = "select" + MDB_DELETE = "delete" ) const ( @@ -106,6 +124,18 @@ var Alias = map[string]string{ GDB_TIMER: "gdb.timer", GDB_EVENT: "gdb.event", + MDB_REDIS: "mdb.redis", + MDB_MYSQL: "mdb.mysql", + MDB_CREATE: "mdb.create", + MDB_IMPORT: "mdb.import", + MDB_EXPORT: "mdb.export", + MDB_REMOVE: "mdb.remove", + + MDB_INESRT: "mdb.insert", + MDB_UPDATE: "mdb.update", + MDB_SELECT: "mdb.select", + MDB_DELETE: "mdb.delete", + CHAT_GROUP: "web.chat.group", "note": "web.wiki.note", diff --git a/core/code/code.go b/core/code/code.go index faf65138..7a3b68d9 100644 --- a/core/code/code.go +++ b/core/code/code.go @@ -29,38 +29,54 @@ CMD sh bin/boot.sh var Index = &ice.Context{Name: "code", Help: "编程模块", Caches: map[string]*ice.Cache{}, Configs: map[string]*ice.Config{ - "prefix": {Name: "prefix", Help: "外部命令", Value: map[string]interface{}{ - "zsh": []interface{}{"cli.system", "zsh"}, - "tmux": []interface{}{"cli.system", "tmux"}, - "docker": []interface{}{"cli.system", "docker"}, - "git": []interface{}{"cli.system", "git"}, - "vim": []interface{}{"cli.system", "vim"}, - }}, - "docker": {Name: "docker", Help: "容器", Value: map[string]interface{}{ - "template": map[string]interface{}{"shy": Dockfile}, - "output": "etc/Dockerfile", - }}, - "tmux": {Name: "tmux", Help: "终端", Value: map[string]interface{}{ - "favor": map[string]interface{}{ - "index": []interface{}{ - "ctx_dev ctx_share", - "curl -s $ctx_dev/publish/auto.sh >auto.sh", - "source auto.sh", - "ShyLogin", - }, - }, - }}, - "git": {Name: "git", Help: "记录", Value: map[string]interface{}{ - "alias": map[string]interface{}{"s": "status", "b": "branch"}, - }}, + "login": {Name: "login", Help: "登录", Value: kit.Data()}, }, Commands: map[string]*ice.Command{ ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, + + "login": {Name: "login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + switch kit.Select("list", arg, 0) { + case "open": + case "init": + if m.Option("sid") != "" { + if m.Confs("login", []string{"hash", m.Option("sid"), "status"}) { + m.Conf("login", []string{"hash", m.Option("sid"), "status"}, "login") + m.Echo(m.Option("sid")) + return + } + } + + // 添加终端 + 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")), + "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.Echo(h) + + case "list": + m.Richs("login", nil, "", func(key string, value map[string]interface{}) { + m.Push(key, value) + }) + } + }}, "/zsh": {Name: "/zsh", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Info("%s cmd: %s arg: %v sub: %v", cmd, m.Option("cmd"), m.Optionv("arg"), m.Optionv("sub")) + m.Option("you", "") + m.Richs("login", nil, m.Option("sid"), func(key string, value map[string]interface{}) { + m.Option("you", value["you"]) + }) + m.Info("%s%s %s arg: %v sub: %v", m.Option("you"), cmd, m.Option("cmd"), m.Optionv("arg"), m.Optionv("sub")) switch m.Option("cmd") { + case "login": + m.Cmdy("login", "init", cmd).Push("_output", "result") case "upload": // 上传文件 msg := m.Cmd(ice.WEB_STORY, "upload") @@ -75,6 +91,13 @@ var Index = &ice.Context{Name: "code", Help: "编程模块", case "download": // 下载文件 m.Cmdy(ice.WEB_STORY, "download", m.Optionv("arg")) + + 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) { diff --git a/core/wiki/wiki.go b/core/wiki/wiki.go index 10fcda7f..2e1639da 100644 --- a/core/wiki/wiki.go +++ b/core/wiki/wiki.go @@ -174,10 +174,11 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块", case "favor": m.Cmdy(ice.WEB_FAVOR, kit.Select("story", m.Option("hot")), arg[2:]) case "share": - m.Cmdy(ice.WEB_SHARE, arg[2:]) + m.Cmdy(ice.WEB_SHARE, "add", arg[2:]) default: m.Cmdy(arg) } + return } m.Cmdy(kit.Select("_tree", "_text", len(arg) > 0 && strings.HasSuffix(arg[0], ".md")), arg) }}, diff --git a/demo/Makefile b/demo/Makefile index a83a356a..b03c4690 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -1,2 +1,3 @@ all: + @echo && date sh build.sh build && sh build.sh restart diff --git a/demo/build.sh b/demo/build.sh index 815bc1c1..88573acb 100755 --- a/demo/build.sh +++ b/demo/build.sh @@ -2,8 +2,8 @@ export ice_app=${ice_app:="ice.app"} export ice_err=${ice_err:="boot.log"} -export ice_conf=${ice_app:="var/conf"} export ice_serve=${ice_serve:="web.serve"} +export ice_can=${ice_can:="https://github.com/shylinux/volcanos"} prepare() { [ -f main.go ] || cat >> main.go <> Makefile <> usr/template/common.tmpl <> usr/template/wiki/common.tmpl <$ice_err && log "\n\nrestarting..." || break + date && $ice_app $@ 2>$ice_err && echo -e "\n\nrestarting..." || break done } -log() { echo -e $*; } restart() { kill -2 `cat var/run/shy.pid` } shutdown() { kill -3 `cat var/run/shy.pid` } -help() { - echo "usage: $0 cmd arg" -} cmd=$1 && shift [ -z "$cmd" ] && cmd=start diff --git a/misc/tmux/tmux.go b/misc/tmux/tmux.go index 7383e85d..bba188f7 100644 --- a/misc/tmux/tmux.go +++ b/misc/tmux/tmux.go @@ -51,7 +51,7 @@ 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", "miss.start", "cli.tmux.session") + m.Cmd(ice.GDB_EVENT, "listen", ice.DREAM_START, "cli.tmux.session") }}, ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { }}, @@ -86,7 +86,7 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", // 查看缓存 m.Cmdy("cli.system", "tmux", "show-buffer", "-b", arg[0]).Set("append") }}, - "session": {Name: "session", Help: "会话", List: kit.List( + "session": {Name: "session", Help: "会话", Meta: kit.Dict("detail", []string{"选择", "运行", "编辑", "删除", "下载"}), List: kit.List( kit.MDB_INPUT, "text", "name", "session", "action", "auto", kit.MDB_INPUT, "text", "name", "window", "action", "auto", kit.MDB_INPUT, "text", "name", "pane", "action", "auto", @@ -96,6 +96,15 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", prefix := []string{"cli.system", "tmux"} if len(arg) > 3 { switch arg[1] { + case "运行": + target := "" + switch arg[2] { + case "session": + target = arg[3] + } + m.Cmd("run", target, m.Option("hot")) + arg = arg[:0] + case "select": if arg[2] == "session" { // 选择会话 @@ -156,7 +165,10 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块", if m.Cmd(prefix, "has-session", "-t", target).Append("code") != "0" { // 创建会话 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:]) + arg = arg[:1] } if len(arg) == 1 { @@ -197,6 +209,21 @@ 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) { + prefix := []string{"cli.system", "tmux"} + + 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_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) { + 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 6c0ed03f..ad40dbf3 100644 --- a/type.go +++ b/type.go @@ -356,6 +356,7 @@ func (m *Message) Push(key string, value interface{}, arg ...interface{}) *Messa } sort.Strings(list) } + for _, k := range list { if k == "key" { m.Add(MSG_APPEND, k, key)