1
0
forked from x/icebergs

mix github

This commit is contained in:
shylinux 2020-01-02 19:11:26 +08:00
commit daee4f8811
17 changed files with 684 additions and 152 deletions

View File

@ -38,7 +38,9 @@ func (f *Frame) Start(m *Message, arg ...string) bool {
return true
}
func (f *Frame) Close(m *Message, arg ...string) bool {
m.target.wg.Wait()
m.TryCatch(m, true, func(m *Message) {
m.target.wg.Wait()
})
list := map[*Context]*Message{m.target: m}
m.Travel(func(p *Context, s *Context) {
if msg, ok := list[p]; ok && msg != nil {

View File

@ -18,7 +18,9 @@ import (
func dir(m *ice.Message, root string, name string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string, format string) {
if fs, e := ioutil.ReadDir(path.Join(root, name)); m.Assert(e) {
if fs, e := ioutil.ReadDir(path.Join(root, name)); e != nil {
m.Log(ice.LOG_WARN, "%s", e)
} else {
for _, f := range fs {
if f.Name() == "." || f.Name() == ".." {
continue
@ -73,7 +75,7 @@ func dir(m *ice.Message, root string, name string, level int, deep bool, dir_typ
m.Push("tree", strings.Repeat("| ", level-1)+"|-"+f.Name())
}
case "size":
m.Push("size", f.Size())
m.Push("size", kit.FmtSize(f.Size()))
case "line":
if f.IsDir() {
if d, e := ioutil.ReadDir(p); m.Assert(e) {

View File

@ -5,6 +5,13 @@ import (
)
var share_template = kit.Dict(
"story.prefix", `<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
`, "story.suffix", `</body>`,
"download", `<a href="/code/zsh?cmd=download&arg=%s" target="_blank">%s</a>`,
"share", `<a href="/share/%s" target="_blank">%s</a>`,
"shy/story", `{{.}}`,

View File

@ -4,6 +4,7 @@ import (
"github.com/gorilla/websocket"
"github.com/shylinux/icebergs"
"github.com/shylinux/toolkits"
"github.com/skip2/go-qrcode"
"bytes"
"encoding/json"
@ -41,8 +42,9 @@ func Cookie(msg *ice.Message, sessid string) string {
return sessid
}
func IsLocalIP(ip string) bool {
return ip == "::1" || ip == "127.0.0.1"
return ip == "::1" || strings.HasPrefix(ip, "127.")
}
func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
if msg.Options(ice.WEB_SESS) {
// 会话认证
@ -50,6 +52,9 @@ func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request
msg.Info("role: %s user: %s", msg.Option(ice.MSG_USERROLE, sub.Append("userrole")),
msg.Option(ice.MSG_USERNAME, sub.Append("username")))
}
if strings.HasPrefix(msg.Option(ice.MSG_USERURL), "/space/") {
return true
}
if (!msg.Options(ice.MSG_SESSID) || !msg.Options(ice.MSG_USERNAME)) && IsLocalIP(msg.Option(ice.MSG_USERIP)) {
// 自动认证
@ -169,6 +174,7 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
msg.Option(ice.MSG_USERUA, r.Header.Get("User-Agent"))
msg.Option(ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
msg.Option(ice.MSG_USERURL, r.URL.Path)
msg.Option(ice.MSG_USERNAME, "")
msg.Option(ice.WEB_SESS, "")
msg.R, msg.W = r, w
@ -208,6 +214,10 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
msg.Optionv(k, v)
}
if msg.Optionv("cmds") == nil {
msg.Optionv("cmds", strings.Split(msg.Option(ice.MSG_USERURL), "/")[2:])
}
// 执行命令
if web.Login(msg, w, r) && msg.Target().Run(msg, cmd, msg.Option(ice.MSG_USERURL), kit.Simple(msg.Optionv("cmds"))...) != nil {
// 输出响应
@ -218,6 +228,11 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
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 "qrcode":
if qr, e := qrcode.New(msg.Append("qrcode"), qrcode.Medium); m.Assert(e) {
w.Header().Set("Content-Type", "image/png")
m.Assert(qr.Write(256, w))
}
case "result":
w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type")))
fmt.Fprint(w, msg.Result())
@ -347,13 +362,18 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
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,
"timeout.c", "30s",
)},
ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Value: kit.Data("path", "usr/local/work",
"cmd", []interface{}{ice.CLI_SYSTEM, "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"), "head", kit.Data(kit.MDB_SHORT, "story"))},
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"),
"mime", kit.Dict("md", "txt"),
)},
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()},
@ -377,6 +397,14 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Done()
m.Done()
p := m.Conf(ice.WEB_CACHE, "meta.store")
m.Richs(ice.WEB_CACHE, nil, "*", func(key string, value map[string]interface{}) {
if f, _, e := kit.Create(path.Join(p, key[:2], key)); e == nil {
defer f.Close()
f.WriteString(kit.Formats(value))
}
})
// m.Conf(ice.WEB_CACHE, "hash", kit.Dict())
m.Cmd(ice.CTX_CONFIG, "save", "web.json", ice.WEB_SPIDE, ice.WEB_FAVOR, ice.WEB_CACHE, ice.WEB_STORY, ice.WEB_SHARE)
}},
@ -540,8 +568,14 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
// 验证结果
if m.Cost("%s %s: %s", res.Status, res.Header.Get("Content-Length"), res.Header.Get("Content-Type")); m.Warn(e != nil, "%s", e) {
if cache != "" {
m.Set("result")
}
return
} else if m.Warn(res.StatusCode != http.StatusOK, "%s", res.Status) {
if cache != "" {
m.Set("result")
}
return
}
@ -572,10 +606,18 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
m.Conf(ice.CLI_RUNTIME, "node.type", ice.WEB_SERVER)
// 启动服务
m.Target().Start(m, kit.Select("self", arg, 0))
m.Richs(ice.WEB_SPIDE, nil, "dev", func(key string, value map[string]interface{}) {
m.Cmd(ice.WEB_SPACE, "connect", "dev")
})
switch kit.Select("self", arg, 0) {
case "dev":
m.Event(ice.SYSTEM_INIT)
fallthrough
case "self":
m.Target().Start(m, "self")
fallthrough
default:
m.Richs(ice.WEB_SPIDE, nil, "dev", func(key string, value map[string]interface{}) {
m.Cmd(ice.WEB_SPACE, "connect", "dev")
})
}
}},
ice.WEB_SPACE: {Name: "space", Help: "空间站", Meta: kit.Dict("exports", []string{"pod", "name"}), List: kit.List(
kit.MDB_INPUT, "text", "name", "pod",
@ -635,7 +677,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
// 连接成功
m.Rich(ice.WEB_SPACE, nil, kit.Dict(kit.MDB_TYPE, ice.WEB_MASTER, kit.MDB_NAME, dev))
m.Info("%d conn %s success %s", i, dev, u)
m.Log(ice.LOG_CMDS, "%d conn %s success %s", i, dev, u)
if i = 0; web.HandleWSS(m, true, s, dev) {
break
}
@ -682,9 +724,14 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
// 下发命令
m.Target().Server().(*Frame).send[id] = m
socket.WriteMessage(MSG_MAPS, []byte(m.Format("meta")))
t := time.AfterFunc(kit.Duration(m.Conf(ice.WEB_SPACE, "meta.timeout.c")), func() {
m.Log(ice.LOG_WARN, "timeout")
m.Back(nil)
})
m.Call(true, func(msg *ice.Message) *ice.Message {
// 返回结果
m.Copy(msg).Log("cost", "%s: %s %v", m.Format("cost"), arg[0], arg[1:])
t.Stop()
return nil
})
}
@ -714,7 +761,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
if len(arg) > 0 {
// 规范命名
if !strings.Contains(arg[0], "-") {
if !strings.Contains(arg[0], "-") || !strings.HasPrefix(arg[0], "20") {
arg[0] = m.Time("20060102-") + arg[0]
}
@ -748,6 +795,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
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",
kit.MDB_INPUT, "text", "name", "id", "action", "auto",
@ -766,6 +814,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
})
})
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{}) {
@ -773,8 +822,13 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
})
})
arg = []string{m.Option("hot")}
case "执行":
m.Event(ice.FAVOR_START, m.Option("you"), kit.Select(m.Option("hot"), arg[3], arg[2] == "favor"))
arg = arg[:0]
}
}
if len(arg) > 0 {
switch arg[0] {
case "import":
@ -813,22 +867,15 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
favor := ""
if m.Richs(ice.WEB_FAVOR, nil, arg[0], func(key string, value map[string]interface{}) {
favor = key
}) == nil {
}) == nil && len(arg) > 1 {
favor = m.Rich(ice.WEB_FAVOR, nil, kit.Data(kit.MDB_NAME, arg[0]))
m.Info("create favor: %s name: %s", favor, arg[0])
m.Log(ice.LOG_CREATE, "favor: %s name: %s", favor, arg[0])
}
extras := []string{}
if len(arg) == 3 && arg[1] == "extra" {
extras, arg = strings.Split(arg[2], " "), arg[:1]
}
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, kit.MDB_TEXT})
for _, k := range extras {
m.Push(k, kit.Select("", kit.Value(value, "extra."+k)))
}
})
return
}
@ -887,7 +934,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
case "upload", "download":
// 打开文件
if m.R != nil {
if f, h, e := m.R.FormFile(kit.Select("upload", arg, 1)); m.Assert(e) {
if f, h, e := m.R.FormFile(kit.Select("upload", arg, 1)); e == nil {
defer f.Close()
// 创建文件
@ -983,9 +1030,154 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
// head list data time text file
switch arg[0] {
case "catch":
case ice.STORY_PULL:
// 起止节点
prev, begin, end := "", arg[2], ""
m.Richs(ice.WEB_STORY, "head", arg[2], func(key string, val map[string]interface{}) {
prev, end = kit.Format(val["list"]), kit.Format(kit.Value(val, kit.Keys("remote", arg[1], "pull", "list")))
})
pull := end
var first map[string]interface{}
for begin != end {
if m.Cmd(ice.WEB_SPIDE, arg[1], "/story/pull", "begin", begin, "end", end).Table(func(index int, value map[string]string, head []string) {
if m.Richs(ice.WEB_CACHE, nil, value["data"], nil) == nil {
// 导入缓存
m.Log(ice.LOG_IMPORT, "%v: %v", value["data"], value["save"])
if node := kit.UnMarshal(value["save"]); kit.Format(kit.Value(node, "file")) != "" {
m.Cmd(ice.WEB_SPIDE, arg[1], "cache", "GET", "/story/download/"+kit.Format(value["data"]))
} else {
m.Conf(ice.WEB_CACHE, kit.Keys("hash", value["data"]), node)
}
}
node := kit.UnMarshal(value["node"]).(map[string]interface{})
if m.Richs(ice.WEB_STORY, nil, value["list"], nil) == nil {
// 导入节点
m.Log(ice.LOG_IMPORT, "%v: %v", value["list"], value["node"])
m.Conf(ice.WEB_STORY, kit.Keys("hash", value["list"]), node)
}
if first == nil {
if m.Richs(ice.WEB_STORY, "head", node["story"], nil) == nil {
// 自动创建
h := m.Rich(ice.WEB_STORY, "head", kit.Dict(
"scene", node["scene"], "story", node["story"],
"count", node["count"], "list", value["list"],
))
m.Log(ice.LOG_CREATE, "%v: %v", h, node["story"])
}
pull, first = kit.Format(value["list"]), node
m.Richs(ice.WEB_STORY, "head", node["story"], func(key string, val map[string]interface{}) {
prev = kit.Format(val["list"])
if kit.Int(node["count"]) > kit.Int(kit.Value(val, kit.Keys("remote", arg[1], "pull", "count"))) {
// 更新分支
m.Log(ice.LOG_IMPORT, "%v: %v", pull, arg[1])
kit.Value(val, kit.Keys("remote", arg[1], "pull"), kit.Dict(
"time", node["time"], "list", pull, "count", node["count"],
))
}
})
}
if prev == kit.Format(node["prev"]) || prev == kit.Format(node["pull"]) {
// 快速合并
m.Log(ice.LOG_IMPORT, "%v: %v", pull, arg[2])
m.Richs(ice.WEB_STORY, "head", node["story"], func(key string, val map[string]interface{}) {
val["count"] = first["count"]
val["time"] = first["time"]
val["list"] = pull
})
prev = pull
}
begin = kit.Format(node["prev"])
}).Append("list") == "" {
break
}
}
if !m.Warn(prev != pull, "unmerge: %s", pull) {
m.Echo(pull)
}
case ice.STORY_PUSH:
// 更新分支
m.Cmdx(ice.WEB_STORY, "pull", arg[1:])
// 查询索引
push, list := "", m.Cmd(ice.WEB_STORY, "index", arg[2]).Append("list")
m.Richs(ice.WEB_STORY, "head", arg[2], func(key string, val map[string]interface{}) {
push = kit.Format(kit.Value(val, kit.Keys("remote", arg[1], "push", "list")))
})
// 查询节点
nodes := []string{}
for list != "" && list != push {
m.Richs(ice.WEB_STORY, nil, list, func(key string, value map[string]interface{}) {
nodes, list = append(nodes, list), kit.Format(value["prev"])
})
}
for _, v := range kit.Revert(nodes) {
m.Richs(ice.WEB_STORY, nil, v, func(list string, node map[string]interface{}) {
m.Richs(ice.WEB_CACHE, nil, node["data"], func(data string, save map[string]interface{}) {
// 推送节点
m.Log(ice.LOG_EXPORT, "%s: %s", v, kit.Format(node))
m.Cmd(ice.WEB_SPIDE, arg[1], "/story/push",
"list", v, "node", kit.Format(node),
"data", node["data"], "save", kit.Format(save),
)
if kit.Format(save["file"]) != "" {
// 推送缓存
m.Cmd(ice.WEB_SPIDE, arg[1], "/story/upload",
"part", "upload", "@"+kit.Format(save["file"]),
)
}
})
})
}
// 更新分支
m.Cmd(ice.WEB_STORY, "pull", arg[1:])
case ice.STORY_WATCH:
msg := m.Cmd(ice.WEB_STORY, "index", arg[1])
name := kit.Select(arg[1], arg, 2)
os.Rename(name, kit.Keys(name, "bak"))
if msg.Append("file") != "" {
os.Link(msg.Append("file"), name)
m.Log(ice.LOG_EXPORT, "%s: %s", msg.Append("file"), name)
} else {
if f, p, e := kit.Create(name); m.Assert(e) {
defer f.Close()
f.WriteString(msg.Append("text"))
m.Log(ice.LOG_EXPORT, "%s: %s", msg.Append("text"), p)
}
}
case ice.STORY_CATCH:
if last := m.Richs(ice.WEB_STORY, "head", arg[2], nil); last != nil {
if t, e := time.ParseInLocation(ice.ICE_TIME, kit.Format(last["time"]), time.Local); e == nil {
if s, e := os.Stat(arg[2]); e == nil && s.ModTime().Before(t) {
m.Info("%s last: %s", arg[2], kit.Format(t))
m.Echo("%s", last["list"])
break
}
}
}
fallthrough
case "add", "upload":
case "add", ice.STORY_UPLOAD:
pull := ""
if arg[0] == ice.STORY_CATCH {
pull, arg = kit.Select("", arg, 3), arg[:3]
m.Richs(ice.WEB_STORY, "head", pull, func(key string, value map[string]interface{}) {
// 合并分支
pull = kit.Format(kit.Value(value, kit.Keys("remote", pull, "pull", "list")))
})
}
// 保存数据
if m.Richs(ice.WEB_CACHE, nil, kit.Select("", arg, 3), nil) == nil {
m.Cmdy(ice.WEB_CACHE, arg)
@ -993,33 +1185,40 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
}
// 查询索引
head, prev, count := "", "", 0
m.Richs(ice.WEB_STORY, "head", arg[2], func(key string, value map[string]interface{}) {
head, prev, count = key, kit.Format(value["list"]), kit.Int(value["count"])
head, prev, value, count := "", "", map[string]interface{}{}, 0
m.Richs(ice.WEB_STORY, "head", arg[2], func(key string, val map[string]interface{}) {
head, prev, value, count = key, kit.Format(val["list"]), val, kit.Int(val["count"])
m.Log("info", "head: %v prev: %v count: %v", head, prev, count)
})
if last := m.Richs(ice.WEB_STORY, nil, prev, nil); prev != "" && last != nil && last["data"] == arg[3] {
// 重复提交
break
}
// 添加节点
list := m.Rich(ice.WEB_STORY, nil, kit.Dict(
"count", count+1, "scene", arg[1], "story", arg[2], "data", arg[3], "prev", prev,
"scene", arg[1], "story", arg[2], "count", count+1, "data", arg[3], "prev", prev, "pull", pull,
))
m.Log(ice.LOG_CREATE, "story: %s %s: %s", list, arg[1], arg[2])
m.Push("list", list)
m.Push("pull", pull)
// 添加索引
m.Rich(ice.WEB_STORY, "head", kit.Dict(
"count", count+1, "scene", arg[1], "story", arg[2], "list", list,
))
if head == "" {
// 添加索引
m.Rich(ice.WEB_STORY, "head", kit.Dict("scene", arg[1], "story", arg[2], "count", count+1, "list", list))
} else {
// 更新索引
value["count"] = count + 1
value["time"] = m.Time()
value["list"] = list
}
m.Echo(list)
case "download":
case ice.STORY_DOWNLOAD:
// 下载文件
if m.Cmdy(ice.WEB_STORY, "index", arg[1]); m.Append("file") != "" {
m.Push("_output", "file")
} else {
m.Push("_output", "result")
}
m.Cmdy(ice.WEB_STORY, "index", arg[1])
m.Push("_output", kit.Select("file", "result", m.Append("file") == ""))
case "commit":
// 查询索引
@ -1064,12 +1263,18 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
for i := 0; i < 10 && list != ""; i++ {
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", "count", "scene", "story"})
val := m.Confm(ice.WEB_CACHE, kit.Keys("hash", value["data"]))
if val == nil {
data := kit.Format(value["data"])
if f, e := os.Open(path.Join(m.Conf(ice.WEB_CACHE, "meta.store"), data[:2], data)); e != nil ||
json.NewDecoder(f).Decode(&val) != nil {
return
}
}
m.Push(list, value, []string{"key", "time", "count", "scene", "story"})
m.Push("drama", val["text"])
m.Push("data", value["data"])
})
m.Push("drama", val["text"])
m.Push("data", value["data"])
// 复合节点
kit.Fetch(value["list"], func(key string, val string) {
@ -1102,13 +1307,24 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
}
// 查询数据
if node := m.Confm(ice.WEB_CACHE, kit.Keys("hash", arg[1])); node != nil {
m.Push("data", arg[1])
m.Push(arg[1], node, []string{"text", "time", "size", "type", "name", "file"})
m.Echo("%s", node["text"])
node := m.Confm(ice.WEB_CACHE, kit.Keys("hash", arg[1]))
if node == nil {
if f, e := os.Open(path.Join(m.Conf(ice.WEB_CACHE, "meta.store"), arg[1][:2], arg[1])); e != nil ||
json.NewDecoder(f).Decode(&node) != nil {
return
}
}
m.Push("data", arg[1])
m.Push(arg[1], node, []string{"text", "time", "size", "type", "name", "file"})
m.Echo("%s", node["text"])
default:
if len(arg) == 1 {
if _, e := os.Stat(arg[0]); e == nil {
if scene := m.Conf(ice.WEB_STORY, kit.Keys("mime", strings.TrimPrefix(path.Ext(arg[0]), "."))); scene != "" {
m.Cmd(ice.WEB_STORY, ice.STORY_CATCH, scene, arg[0])
}
}
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"])
@ -1147,24 +1363,28 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
switch arg[0] {
case "add":
arg = arg[1:]
fallthrough
default:
// 创建共享
extra := kit.Dict()
for i := 4; i < len(arg)-1; i += 2 {
for i := 3; 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],
kit.MDB_TYPE, arg[0], kit.MDB_NAME, arg[1], kit.MDB_TEXT, arg[2],
"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],
kit.MDB_TYPE, arg[0], kit.MDB_NAME, arg[1], kit.MDB_TEXT, arg[2],
"share", h,
))
m.Log(ice.LOG_CREATE, "share: %s extra: %s", h, kit.Format(extra))
m.Echo(h)
}
}},
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) {
@ -1174,36 +1394,168 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
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) {
}},
"/share/": {Name: "/share/", 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 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") == ""))
switch arg[0] {
case "login":
Cookie(m, m.Cmdx(ice.AAA_USER, "login", m.Option("username"), m.Option("password")))
default:
if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" {
m.Push("_output", "file")
} else {
default:
m.Richs(ice.WEB_SHARE, nil, arg[0], func(key string, value map[string]interface{}) {
m.Info("share %s %v", arg, kit.Format(value))
switch value["type"] {
case ice.TYPE_STORY:
if m.Cmdy(ice.WEB_STORY, "index", kit.Value(value, "text")).Append("text") == "" {
m.Cmdy(ice.WEB_SPACE, kit.Value(value, "extra.pod"), ice.WEB_STORY, "index", kit.Value(value, "text"))
}
p := path.Join("tmp/file", m.Append("data"))
if _, e := os.Stat(p); e == nil {
m.Append("_output", "file")
m.Append("file", p)
break
}
m.Set("result")
m.Render(m.Conf(ice.WEB_SHARE, "meta.template.story.prefix"))
m.Cmdy("web.wiki._text", m.Append("file"))
m.Render(m.Conf(ice.WEB_SHARE, "meta.template.story.suffix"))
m.Push("_output", "result")
if f, p, e := kit.Create(p); e == nil {
defer f.Close()
if n, e := f.WriteString(m.Result()); e == nil {
m.Log(ice.LOG_EXPORT, "%d: %s", n, p)
}
}
case "qrcode":
m.Push("_output", "qrcode")
m.Push("qrcode", value["text"])
default:
if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" {
m.Push("_output", "file")
} else {
m.Push("_output", "result")
}
}
})
}
}},
"/story/": {Name: "/story/", Help: "故事会", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[0] {
case ice.STORY_PULL:
// 下载节点
list := m.Cmd(ice.WEB_STORY, "index", m.Option("begin")).Append("list")
for i := 0; i < 10 && list != "" && list != m.Option("end"); i++ {
if m.Richs(ice.WEB_STORY, nil, list, func(key string, value map[string]interface{}) {
// 节点信息
m.Push("list", key)
m.Push("node", kit.Format(value))
m.Push("data", value["data"])
m.Push("save", kit.Format(m.Richs(ice.WEB_CACHE, nil, value["data"], nil)))
list = kit.Format(value["prev"])
}) == nil {
break
}
}
})
case ice.STORY_PUSH:
// 上传节点
if m.Richs(ice.WEB_CACHE, nil, m.Option("data"), nil) == nil {
// 导入缓存
m.Log(ice.LOG_IMPORT, "%v: %v", m.Option("data"), m.Option("save"))
node := kit.UnMarshal(m.Option("save"))
m.Conf(ice.WEB_CACHE, kit.Keys("hash", m.Option("data")), node)
}
node := kit.UnMarshal(m.Option("node")).(map[string]interface{})
if m.Richs(ice.WEB_STORY, nil, m.Option("list"), nil) == nil {
// 导入节点
m.Log(ice.LOG_IMPORT, "%v: %v", m.Option("list"), m.Option("node"))
m.Conf(ice.WEB_STORY, kit.Keys("hash", m.Option("list")), node)
}
if head := m.Richs(ice.WEB_STORY, "head", node["story"], nil); head == nil {
// 自动创建
h := m.Rich(ice.WEB_STORY, "head", kit.Dict(
"scene", node["scene"], "story", node["story"],
"count", node["count"], "list", m.Option("list"),
))
m.Log(ice.LOG_CREATE, "%v: %v", h, node["story"])
} else if head["list"] == kit.Format(node["prev"]) || head["list"] == kit.Format(node["pull"]) {
// 快速合并
head["list"] = m.Option("list")
head["count"] = node["count"]
head["time"] = node["time"]
} else {
// 推送失败
}
case ice.STORY_UPLOAD:
// 上传数据
m.Cmdy(ice.WEB_CACHE, "upload")
case ice.STORY_DOWNLOAD:
// 下载数据
m.Cmdy(ice.WEB_STORY, "index", arg[1])
m.Push("_output", kit.Select("file", "result", m.Append("file") == ""))
}
}},
"/space/": {Name: "/space/", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
list := strings.Split(cmd, "/")
switch list[2] {
case "login":
m.Option(ice.MSG_SESSID, Cookie(m, m.Cmdx(ice.AAA_USER, "login", m.Option("username"), m.Option("password"))))
return
case "share":
m.Cmdy(ice.WEB_SHARE, list[3:])
return
case "pull":
node := m.Cmd(ice.WEB_STORY, "index", list[3]).Append("list")
for i := 0; i < 10 && node != "" && node != list[4]; i++ {
m.Confm(ice.WEB_STORY, kit.Keys("hash", node), func(value map[string]interface{}) {
m.Push("list", node)
m.Push("node", kit.Format(value))
m.Push("data", value["data"])
m.Push("save", kit.Format(m.Confm(ice.WEB_CACHE, kit.Keys("hash", value["data"]))))
node = kit.Format(value["prev"])
})
}
return
case "push":
if m.Confm(ice.WEB_CACHE, kit.Keys("hash", m.Option("data"))) == nil {
// 导入缓存
m.Log(ice.LOG_IMPORT, "%v: %v", m.Option("data"), m.Option("save"))
node := kit.UnMarshal(m.Option("save"))
m.Conf(ice.WEB_CACHE, kit.Keys("hash", m.Option("data")), node)
}
node := kit.UnMarshal(m.Option("node")).(map[string]interface{})
if m.Confm(ice.WEB_STORY, kit.Keys("hash", m.Option("list"))) == nil {
// 导入节点
m.Log(ice.LOG_IMPORT, "%v: %v", m.Option("list"), m.Option("node"))
m.Conf(ice.WEB_STORY, kit.Keys("hash", m.Option("list")), node)
}
if head := m.Richs(ice.WEB_STORY, "head", node["story"], nil); head == nil {
// 自动创建
h := m.Rich(ice.WEB_STORY, "head", kit.Dict(
"count", node["count"], "scene", node["scene"], "story", node["story"], "list", m.Option("list"),
))
m.Log(ice.LOG_CREATE, "%v: %v", h, node["story"])
} else if head["list"] == kit.Format(node["prev"]) || head["list"] == kit.Format(node["pull"]) {
// 更新索引
head["list"] = m.Option("list")
head["count"] = node["count"]
head["time"] = node["time"]
} else {
// 推送失败
}
return
case "upload":
m.Cmdy(ice.WEB_CACHE, "upload")
return
@ -1214,6 +1566,8 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
}
if s, e := websocket.Upgrade(m.W, m.R, nil, m.Confi(ice.WEB_SPACE, "meta.buffer.r"), m.Confi(ice.WEB_SPACE, "meta.buffer.w")); m.Assert(e) {
m.Option("name", strings.Replace(m.Option("name"), ".", "_", -1))
// 共享空间
share := m.Option("share")
if m.Richs(ice.WEB_SHARE, nil, share, nil) == nil {

View File

@ -20,6 +20,8 @@ END
[ -f Makefile ] || cat >> Makefile <<END
all:
@echo
@date
go build -o ice.bin main.go && chmod u+x ice.bin && ./ice.sh restart
END
@ -27,7 +29,8 @@ END
#! /bin/sh
export PATH=\${PWD}:\$PATH
export ctx_pid=var/run/ice.pid
export ctx_pid=\${ctx_pid:=var/run/ice.pid}
export ctx_log=\${ctx_log:=boot.log}
prepare() {
[ -e ice.sh ] || curl \$ctx_dev/publish/ice.sh -o ice.sh && chmod u+x ice.sh
@ -47,10 +50,13 @@ prepare() {
curl \$ctx_dev/publish/\${bin} -o ice.bin && chmod u+x ice.bin
}
start() {
prepare && shutdown && while true; do
date && ice.bin \$@ 2>boot.log && echo -e "\n\nrestarting..." || break
trap HUP hup && while true; do
date && ice.bin \$@ 2>\$ctx_log && echo -e "\n\nrestarting..." || break
done
}
serve() {
prepare && shutdown && start \$@
}
restart() {
[ -e \$ctx_pid ] && kill -2 \`cat \$ctx_pid\` || echo
}
@ -58,7 +64,7 @@ shutdown() {
[ -e \$ctx_pid ] && kill -3 \`cat \$ctx_pid\` || echo
}
cmd=\$1 && [ -n "\$cmd" ] && shift || cmd=start
cmd=\$1 && [ -n "\$cmd" ] && shift || cmd=serve
\$cmd \$*
END
chmod u+x ice.sh
@ -66,7 +72,7 @@ END
build() {
miss=./ && [ "$1" != "" ] && miss=$1 && shift && mkdir $miss
cd $miss && prepare && go build -o ice.bin main.go && chmod u+x ice.bin && ./ice.sh start
cd $miss && prepare && go build -o ice.bin main.go && chmod u+x ice.bin && ./ice.sh start serve dev
}
cmd=build && [ "$1" != "" ] && cmd=$1 && shift

19
conf.go
View File

@ -71,6 +71,7 @@ const ( // WEB
const ( // LOG
LOG_ENABLE = "enable"
LOG_IMPORT = "import"
LOG_MODIFY = "modify"
LOG_CREATE = "create"
LOG_INSERT = "insert"
LOG_EXPORT = "export"
@ -97,6 +98,8 @@ const ( // GDB
GDB_TIMER = "timer"
GDB_EVENT = "event"
SYSTEM_INIT = "system.init"
SERVE_START = "serve.start"
SERVE_CLOSE = "serve.close"
SPACE_START = "space.start"
@ -105,6 +108,7 @@ const ( // GDB
DREAM_CLOSE = "dream.close"
USER_CREATE = "user.create"
MISS_CREATE = "miss.create"
)
const ( // MDB
MDB_REDIS = "redis"
@ -137,6 +141,7 @@ const ( // TYPE
TYPE_RIVER = "river"
TYPE_STORM = "storm"
TYPE_DRIVE = "drive"
TYPE_STORY = "story"
TYPE_SHELL = "shell"
TYPE_VIMRC = "vimrc"
@ -148,6 +153,20 @@ const ( // FAVOR
FAVOR_CHAT = "chat.init"
FAVOR_TMUX = "tmux.init"
FAVOR_RIVER = "river.init"
FAVOR_START = "favor.start"
)
const ( // STORY
STORY_CATCH = "catch"
STORY_WATCH = "watch"
STORY_STATUS = "status"
STORY_COMMIT = "commit"
STORY_BRANCH = "branch"
STORY_HISTORY = "history"
STORY_PULL = "pull"
STORY_PUSH = "push"
STORY_UPLOAD = "upload"
STORY_DOWNLOAD = "download"
)
var Alias = map[string]string{

View File

@ -7,7 +7,7 @@ import (
"github.com/shylinux/toolkits"
)
var Index = &ice.Context{Name: "chat", Help: "聊天模块",
var Index = &ice.Context{Name: "chat", Help: "聊天中心",
Caches: map[string]*ice.Cache{},
Configs: map[string]*ice.Config{
ice.CHAT_RIVER: {Name: "river", Help: "群组", Value: kit.Data()},
@ -16,10 +16,18 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块",
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Cmd(ice.CTX_CONFIG, "load", "chat.json")
if m.Conf(ice.CLI_RUNTIME, "boot.count") == "1" {
m.Watch(ice.SYSTEM_INIT, "web.chat.init")
m.Watch(ice.USER_CREATE, "web.chat./ocean", "spawn", "")
}},
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_RIVER)
}},
"init": {Name: "init", Help: "初始化", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(m.Confm(ice.CHAT_RIVER, "hash")) == 0 {
// 系统群组
m.Option(ice.MSG_USERNAME, m.Conf(ice.CLI_RUNTIME, "boot.username"))
m.Option(ice.MSG_USERROLE, ice.ROLE_ROOT)
m.Option(ice.MSG_USERNAME, m.Conf(ice.CLI_RUNTIME, "boot.username"))
river := m.Cmdx("web.chat./ocean", "spawn", "meet", m.Conf(ice.CLI_RUNTIME, "boot.username"))
river = m.Cmdx("web.chat./steam", river, "spawn", "miss",
"", "", "spide", "",
@ -41,13 +49,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块",
m.Cmd(ice.AAA_ROLE, "black", ice.ROLE_VOID, "enable", "dream.停止")
}
// 用户群组
m.Watch(ice.USER_CREATE, "web.chat./ocean", "spawn", "")
}},
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_RIVER)
}},
ice.WEB_LOGIN: {Name: "login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 0 {
switch arg[0] {
@ -172,6 +174,9 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块",
))
m.Log("insert", "storm: %s %d: %v", arg[1], id, arg[i:i+4])
}
case "share":
m.Cmdy(ice.WEB_SHARE, "add", arg[3:])
case "rename":
// 重命名应用
old := m.Conf(ice.CHAT_RIVER, kit.Keys(prefix, kit.MDB_HASH, arg[1], kit.MDB_META, kit.MDB_NAME))

View File

@ -33,11 +33,22 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
"compile": {Name: "compile", Help: "编译", Value: kit.Data("path", "usr/publish")},
"publish": {Name: "publish", Help: "发布", Value: kit.Data("path", "usr/publish")},
"upgrade": {Name: "upgrade", Help: "升级", Value: kit.Data("path", "usr/publish")},
"upgrade": {Name: "upgrade", Help: "升级", Value: kit.Dict(
kit.MDB_HASH, kit.Dict(
"system", kit.Dict(
kit.MDB_LIST, kit.List(
kit.MDB_INPUT, "bin", "file", "ice.sh", "path", "ice.sh",
kit.MDB_INPUT, "bin", "file", "ice.bin", "path", "ice.bin",
),
),
),
)},
},
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")
m.Watch(ice.SYSTEM_INIT, "compile", "linux")
m.Watch(ice.SYSTEM_INIT, "publish", "ice.sh")
}},
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")
@ -46,7 +57,7 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
"compile": {Name: "compile", Help: "编译", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
// 目录列表
m.Cmdy("nfs.dir", "", m.Conf("publish", "meta.path"))
m.Cmdy("nfs.dir", "", m.Conf("publish", "meta.path"), "time size path")
return
}
@ -69,7 +80,7 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
"publish": {Name: "publish", Help: "发布", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
// 目录列表
m.Cmdy("nfs.dir", "", m.Conf("publish", "meta.path"))
m.Cmdy("nfs.dir", "", m.Conf("publish", "meta.path"), "time size path")
return
}
@ -92,12 +103,28 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
m.Log(ice.LOG_EXPORT, "%s: %s", arg[0], target)
}},
"upgrade": {Name: "upgrade", Help: "升级", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
os.Rename("ice.sh", "ice.sh.bak")
os.Link(m.Cmd(ice.WEB_STORY, "index", m.Cmdx(ice.WEB_SPIDE, "dev", "cache", "/publish/ice.sh")).Append("file"), "ice.sh")
exit := true
m.Grows("upgrade", "hash.system", "", "", func(index int, value map[string]interface{}) {
if value["file"] == "ice.bin" {
value["file"] = kit.Keys("ice", m.Conf(ice.CLI_RUNTIME, "host.GOOS"), m.Conf(ice.CLI_RUNTIME, "host.GOARCH"))
}
os.Rename("ice.bin", "ice.bin.bak")
os.Link(m.Cmd(ice.WEB_STORY, "index", m.Cmdx(ice.WEB_SPIDE, "dev", "cache", kit.Keys("/publish/ice",
m.Conf(ice.CLI_RUNTIME, "host.GOOS"), m.Conf(ice.CLI_RUNTIME, "host.GOARCH")))).Append("file"), "ice.bin")
h := m.Cmdx(ice.WEB_SPIDE, "dev", "cache", "GET", "/publish/"+kit.Format(value["file"]))
if h == "" {
exit = false
return
}
m.Cmd(ice.WEB_STORY, "add", "bin", value["path"], h)
os.Rename(kit.Format(value["path"]), kit.Keys(value["path"], "bak"))
os.Link(m.Cmd(ice.WEB_STORY, "index", h).Append("file"), kit.Format(value["path"]))
os.Chmod(kit.Format(value["path"]), 777)
m.Log(ice.LOG_EXPORT, "%s: %s", h, value["path"])
})
if exit {
m.Cmd("exit")
}
}},
"login": {Name: "login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -162,7 +189,9 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
m.Cmdy("login", "exit")
case "upload":
// 缓存文件
msg := m.Cmd(ice.WEB_CACHE, "upload")
you := m.Option("you")
m.Option("you", "")
msg := m.Cmd(ice.WEB_STORY, "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"))
@ -171,6 +200,7 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
m.Push("_output", "result")
// 下发文件
m.Option("you", you)
m.Cmd(ice.WEB_SPACE, msg.Option("you"), ice.WEB_SPACE, "download", msg.Append("type"), msg.Append("name"), "self", msg.Append("data"))
case "download":

View File

@ -12,10 +12,20 @@ import (
var Index = &ice.Context{Name: "team", Help: "团队模块",
Caches: map[string]*ice.Cache{},
Configs: map[string]*ice.Config{
ice.APP_MISS: {Name: "miss", Help: "任务", Value: kit.Data()},
ice.APP_MISS: {Name: "miss", Help: "任务", Value: kit.Data(
"mis", []interface{}{"已取消", "准备中", "开发中", "测试中", "发布中", "已完成"}, "fsm", kit.Dict(
"准备中", kit.Dict("next", "开发中"),
"开发中", kit.Dict("next", "测试中", "prev", "准备中"),
"测试中", kit.Dict("next", "发布中", "prev", "开发中"),
"发布中", kit.Dict("next", "已完成", "prev", "测试中"),
"已完成", kit.Dict(),
"已取消", kit.Dict(),
),
)},
},
Commands: map[string]*ice.Command{
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Watch(ice.MISS_CREATE, ice.APP_MISS)
m.Cmd(ice.CTX_CONFIG, "load", "team.json")
}},
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -27,8 +37,11 @@ var Index = &ice.Context{Name: "team", Help: "团队模块",
switch arg[1] {
case "modify":
// 修改任务
m.Grows(ice.APP_MISS, nil, "id", arg[0], func(index int, value map[string]interface{}) {
value[arg[2]] = arg[3]
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "id", arg[0], func(index int, value map[string]interface{}) {
m.Log(ice.LOG_MODIFY, "%s: %s->%s", arg[2], arg[4], arg[3])
kit.Value(value, arg[2], arg[3])
})
})
arg = arg[:0]
}
@ -36,22 +49,19 @@ var Index = &ice.Context{Name: "team", Help: "团队模块",
if len(arg) == 0 {
// 任务列表
m.Grows(ice.APP_MISS, nil, "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(index), value, []string{"begin_time", "close_time", "status", "id", "type", "name", "text"})
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(index), value, []string{"extra.begin_time", "extra.close_time", "extra.status", "id", "type", "name", "text"})
})
})
return
}
// 添加任务
h := m.Grow(ice.APP_MISS, nil, kit.Dict(
kit.MDB_NAME, arg[0],
kit.MDB_TYPE, kit.Select("开发", arg, 1),
kit.MDB_TEXT, kit.Select("功能开发", arg, 2),
"status", kit.Select("准备中", arg, 3),
m.Cmdy(ice.WEB_FAVOR, kit.Select("miss", m.Option("hot")), ice.TYPE_DRIVE, arg[0], arg[1],
"begin_time", m.Time(), "close_time", m.Time(),
))
m.Info("miss: %d", h)
m.Echo("%d", h)
"status", kit.Select("准备中", arg, 3),
)
}},
"date": {Name: "date", Help: "日历", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
show := map[int]string{0: "周日", 1: "周一", 2: "周二", 3: "周三", 4: "周四", 5: "周五", 6: "周六"}
@ -107,49 +117,45 @@ var Index = &ice.Context{Name: "team", Help: "团队模块",
"detail", []string{"回退", "前进", "取消", "完成"},
), Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) > 0 {
m.Grows(ice.APP_MISS, nil, "id", arg[0], func(index int, value map[string]interface{}) {
switch value["status"] {
case "准备中":
switch arg[1] {
case "开始":
value["status"] = "进行中"
value["begin_time"] = m.Time()
value["close_time"] = m.Time("30m")
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "id", arg[0], func(index int, value map[string]interface{}) {
switch value = value["extra"].(map[string]interface{}); arg[1] {
case "前进":
if value["status"] == "准备中" {
value["begin_time"] = m.Time()
value["close_time"] = m.Time("30m")
}
if next := m.Conf(ice.APP_MISS, kit.Keys("meta.fsm", value["status"], "next")); next != "" {
value["status"] = next
}
case "回退":
if prev := m.Conf(ice.APP_MISS, kit.Keys("meta.fsm", value["status"], "prev")); prev != "" {
value["status"] = prev
}
case "取消":
value["status"] = "已取消"
value["close_time"] = m.Time()
case "完成":
value["status"] = "已完成"
value["close_time"] = m.Time()
}
case "进行中":
switch arg[1] {
case "准备":
value["status"] = "准备中"
value["begin_time"] = m.Time()
value["close_time"] = m.Time()
case "取消":
value["status"] = "已取消"
value["close_time"] = m.Time()
case "完成":
value["status"] = "已完成"
value["close_time"] = m.Time()
}
}
})
})
}
m.Push("准备中", "")
m.Push("开发中", "")
m.Push("测试中", "")
m.Push("发布中", "")
m.Push("已取消", "")
m.Push("已完成", "")
m.Grows(ice.APP_MISS, nil, "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(value["status"]),
kit.Format(`<span title="%v" data-id="%v">%v</span>`,
kit.Format("%s-%s\n%s", value["begin_time"], value["close_time"], value["text"]),
value["id"], value["name"]))
m.Confm(ice.APP_MISS, "meta.mis", func(index int, value string) {
m.Push(value, "")
})
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(kit.Value(value, "extra.status")),
kit.Format(`<span title="%v" data-id="%v">%v</span>`,
kit.Format("%s-%s\n%s", kit.Value(value, "extra.begin_time"), kit.Value(value, "extra.close_time"), value["text"]),
value["id"], value["name"]))
})
})
}},
},

View File

@ -143,7 +143,7 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
// 生成文章
buffer := bytes.NewBuffer([]byte{})
f := m.Target().Server().(*web.Frame)
tmpl := f.HandleCGI(m, m.Confm("note", ice.Meta("alias")), path.Join(m.Conf("note", ice.Meta("path")), arg[0]))
tmpl := f.HandleCGI(m, m.Confm("note", ice.Meta("alias")), arg[0])
m.Assert(tmpl.ExecuteTemplate(buffer, m.Option("filename", path.Base(arg[0])), m))
// 缓存文章
@ -158,8 +158,8 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
m.Echo(string(markdown.ToHTML(buffer.Bytes(), nil, nil)))
}},
"_tree": {Name: "_tree path", Help: "文库", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Cmdy("nfs.dir", m.Conf("note", ice.Meta("path")),
kit.Select("", arg, 0), m.Conf("note", ice.Meta("head")))
m.Cmdy("nfs.dir", m.Conf("note", "meta.path"),
kit.Select("", arg, 0), m.Conf("note", "meta.head"))
}},
"note": {Name: "note file", Help: "笔记", Meta: map[string]interface{}{
"remote": "you", "display": "inner",
@ -180,6 +180,9 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
}
return
}
if len(arg) > 0 && strings.HasSuffix(arg[0], ".md") {
arg[0] = path.Join(m.Conf("note", "meta.path"), arg[0])
}
m.Cmdy(kit.Select("_tree", "_text", len(arg) > 0 && strings.HasSuffix(arg[0], ".md")), arg)
}},
"index": {Name: "index hash", Help: "索引", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {

1
go.mod
View File

@ -6,4 +6,5 @@ require (
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03
github.com/gorilla/websocket v1.4.1
github.com/shylinux/toolkits v0.1.0
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
)

2
go.sum
View File

@ -6,4 +6,6 @@ github.com/shylinux/toolkits v0.0.0-20191225132906-3c11db083b5b h1:BXDEMcpHmwuwo
github.com/shylinux/toolkits v0.0.0-20191225132906-3c11db083b5b/go.mod h1:Y68Ot6xOmo1bun67YvqC3chDGeU2gDxtsUnvVDGJm4g=
github.com/shylinux/toolkits v0.1.0 h1:7ghnVEjuwLf7zBsyeR37ahm2gaOKIyjSw9F9Pp9oTBU=
github.com/shylinux/toolkits v0.1.0/go.mod h1:Y68Ot6xOmo1bun67YvqC3chDGeU2gDxtsUnvVDGJm4g=
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 h1:RYiqpb2ii2Z6J4x0wxK46kvPBbFuZcdhS+CIztmYgZs=
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=

View File

@ -21,7 +21,7 @@ var Index = &ice.Context{Name: "git", Help: "代码管理",
"name", "volcanos", "path", "usr/volcanos", "branch", "master",
"remote", "https://github.com/shylinux/volcanos",
))
m.Watch(ice.SERVE_START, "cli.git.check", "volcanos")
m.Watch(ice.SYSTEM_INIT, "cli.git.check", "volcanos")
}},
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},

View File

@ -4,6 +4,7 @@ import (
"github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/cli"
"github.com/shylinux/toolkits"
"os"
"path"
"strings"
"time"
@ -52,21 +53,31 @@ 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.Watch(ice.SYSTEM_INIT, "cli.tmux.init")
m.Watch(ice.DREAM_START, "cli.tmux.auto")
return
m.Watch(ice.SERVE_START, "cli.tmux.auto")
for _, p := range []string{"auto.sh", "auto.vim"} {
if m.Richs(ice.WEB_STORY, "head", p, nil) == nil {
m.Cmd(ice.WEB_STORY, "add", ice.TYPE_SHELL, p, m.Cmdx(ice.WEB_SPIDE, "shy", "cache", "GET", "/publish/"+p))
}
}
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`)
}
m.Watch(ice.FAVOR_START, "cli.tmux.auto")
}},
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},
"init": {Name: "init", Help: "初始化", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
for _, v := range []string{"auto.sh", "auto.vim"} {
p := path.Join(m.Conf("web.code.publish", "meta.path"), v)
if _, e := os.Stat(p); e != nil && os.IsNotExist(e) {
if h := m.Cmdx(ice.WEB_SPIDE, "shy", "cache", "GET", "/publish/"+v); h != "" {
os.Link(m.Cmd(ice.WEB_STORY, "index", h).Append("file"), p)
m.Log(ice.LOG_EXPORT, "%s: %s", h, p)
}
}
}
if m.Richs(ice.WEB_FAVOR, nil, "tmux.auto", nil) == nil {
m.Cmd(ice.WEB_FAVOR, "tmux.auto", ice.TYPE_SHELL, "下载脚本", `curl -s "$ctx_dev/publish/auto.sh" -o auto.sh`)
m.Cmd(ice.WEB_FAVOR, "tmux.auto", ice.TYPE_SHELL, "加载脚本", `source auto.sh`)
}
if m.Richs(ice.WEB_FAVOR, nil, "tmux.init", nil) == nil {
m.Cmd(ice.WEB_FAVOR, "tmux.init", ice.TYPE_SHELL, "一键启动", `curl -s "$ctx_dev/publish/ice.sh" |sh`)
}
}},
"buffer": {Name: "buffer", Help: "终端",
List: kit.List(
@ -224,6 +235,13 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块",
}},
"auto": {Name: "auto", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
prefix := []string{"cli.system", "tmux"}
if arg[0] == "" {
m.Cmd("cli.tmux.session").Table(func(index int, value map[string]string, head []string) {
if value["tag"] == "1" {
arg[0] = value["session"]
}
})
}
m.Option("cmd_env", "TMUX", "")
m.Option("cmd_dir", path.Join(m.Conf(ice.WEB_DREAM, "meta.path"), arg[0]))
@ -233,12 +251,12 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块",
m.Cmd(prefix, "new-session", "-ds", arg[0])
}
m.Cmdy(prefix, "send-keys", "-t", arg[0], "export ctx_dev=", kit.Select(m.Conf(ice.CLI_RUNTIME, "conf.ctx_dev"), m.Conf(ice.CLI_RUNTIME, "host.ctx_self")), "Enter")
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.Cmd(ice.WEB_FAVOR, kit.Select("tmux.init", arg, 1)).Table(func(index int, value map[string]string, head []string) {
m.Cmd(ice.WEB_FAVOR, kit.Select("tmux.auto", 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")

10
miss/go.mod Normal file
View File

@ -0,0 +1,10 @@
module miss
go 1.13
require github.com/shylinux/icebergs v0.1.0 // indirect
replace (
github.com/shylinux/icebergs => ../
github.com/shylinux/toolkits => ../../toolkits
)

View File

@ -2,10 +2,54 @@
icebergs是一个后端框架通过模块化、集群化实现资源的无限的扩展与自由的组合。
{{chain "icebergs" `
icebergs
type.go
msg.Detail
msg.Option
msg.Append
msg.Result
msg.Travel
msg.Search
msg.Conf
msg.Cmd
msg.Cap
base.go bg blue
Begin
_init
Start bg red
code
wiki
chat
ocean
river
action
storm
steam
team
mall
_exit
Close
conf.go
init
host
boot
node
user
work
auth
data
file
` "" "" 16}}
一键创建项目
```
mkdir miss; cd miss && curl -s https://shylinux.com/publish/build.sh | sh
```
一键启动项目
```
mkdir miss; cd miss && curl -s https://shylinux.com/publish/ice.sh | sh
```
## 命令模块 base/cli
@ -14,10 +58,22 @@ cli模块用于与系统进行交互。
- 系统信息 ice.CLI_RUNTIME
- 系统命令 ice.CLI_SYSTEM
## 网络模块 base/tcp
tcp模块用于管理网络的读写
## 文件模块 base/nfs
nfs模块用于管理文件的读写。
## 终端模块 base/ssh
ssh模块用于与终端交互。
## 数据模块 base/mdb
mdb模块用于管理数据的读写。
## 日志模块 base/log
log模块负责输出日志。

11
type.go
View File

@ -190,6 +190,12 @@ func (m *Message) Format(key interface{}) string {
return kit.FmtTime(kit.Int64(time.Now().Sub(m.time)))
case "meta":
return kit.Format(m.meta)
case "append":
if len(m.meta["append"]) == 0 {
return fmt.Sprintf("%dx%d %s", 0, len(m.meta["append"]), kit.Format(m.meta["append"]))
} else {
return fmt.Sprintf("%dx%d %s", len(m.meta[m.meta["append"][0]]), len(m.meta["append"]), kit.Format(m.meta["append"]))
}
case "time":
return m.Time()
case "ship":
@ -279,6 +285,8 @@ func (m *Message) Spawn(arg ...interface{}) *Message {
source: m.target,
target: m.target,
R: m.R,
W: m.W,
}
if len(arg) > 0 {
@ -331,6 +339,9 @@ func (m *Message) Set(key string, arg ...string) *Message {
return m.Add(key, arg...)
}
func (m *Message) Copy(msg *Message) *Message {
if msg == nil {
return m
}
for _, k := range msg.meta[MSG_APPEND] {
if kit.IndexOf(m.meta[MSG_APPEND], k) == -1 {
m.meta[MSG_APPEND] = append(m.meta[MSG_APPEND], k)