mirror of
https://shylinux.com/x/icebergs
synced 2025-05-02 11:37:01 +08:00
opt some
This commit is contained in:
parent
3e4a939c33
commit
41c379a35f
186
base/web/label.go
Normal file
186
base/web/label.go
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/shylinux/icebergs"
|
||||||
|
"github.com/shylinux/toolkits"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func _label_add(m *ice.Message, cmd string) {
|
||||||
|
if m.Option(cmd) != "" && m.Option(kit.MDB_GROUP) != "" && m.Option(kit.MDB_NAME) != "" {
|
||||||
|
m.Cmdy(cmd, m.Option(cmd), "add", m.Option(kit.MDB_GROUP), m.Option(kit.MDB_NAME))
|
||||||
|
m.Option(ice.FIELD_RELOAD, "true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func _label_del(m *ice.Message, cmd string) {
|
||||||
|
if m.Option(cmd) != "" && m.Option(kit.MDB_GROUP) != "" && m.Option(kit.MDB_NAME) != "" {
|
||||||
|
m.Cmdy(cmd, m.Option(cmd), "del", m.Option(kit.MDB_GROUP), m.Option(kit.MDB_NAME))
|
||||||
|
m.Option(ice.FIELD_RELOAD, "true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func _label_prune(m *ice.Message, cmd string) {
|
||||||
|
m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) {
|
||||||
|
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(sub string, value map[string]interface{}) {
|
||||||
|
if value[kit.MDB_STATUS] != "busy" {
|
||||||
|
m.Cmdy(cmd, m.Option(cmd), "del", value[kit.MDB_GROUP], value[kit.MDB_NAME])
|
||||||
|
m.Option(ice.FIELD_RELOAD, "true")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func _label_clear(m *ice.Message, cmd string) {
|
||||||
|
m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) {
|
||||||
|
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(sub string, value map[string]interface{}) {
|
||||||
|
if value[kit.MDB_STATUS] == "void" {
|
||||||
|
last := m.Conf(cmd, kit.Keys(kit.MDB_HASH, key, kit.MDB_HASH, sub))
|
||||||
|
m.Logs(ice.LOG_DELETE, cmd, m.Option(cmd), kit.MDB_NAME, value[kit.MDB_NAME], kit.MDB_VALUE, last)
|
||||||
|
m.Conf(cmd, kit.Keys(kit.MDB_HASH, key, kit.MDB_HASH, sub), "")
|
||||||
|
m.Option(ice.FIELD_RELOAD, "true")
|
||||||
|
m.Echo(last)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func _label_delete(m *ice.Message, cmd string) {
|
||||||
|
m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) {
|
||||||
|
m.Echo(m.Conf(cmd, kit.Keys(kit.MDB_HASH, key)))
|
||||||
|
m.Logs(ice.LOG_REMOVE, cmd, m.Option(cmd), kit.MDB_VALUE, m.Conf(cmd, kit.Keys(kit.MDB_HASH, key)))
|
||||||
|
m.Conf(cmd, kit.Keys(kit.MDB_HASH, key), "")
|
||||||
|
m.Option(ice.FIELD_RELOAD, "true")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func _label_select(m *ice.Message, cmd string, arg ...string) {
|
||||||
|
m.Richs(cmd, nil, kit.Select("*", arg, 0), func(key string, value map[string]interface{}) {
|
||||||
|
if len(arg) < 1 {
|
||||||
|
// 一级列表
|
||||||
|
m.Option(ice.FIELD_DETAIL, "清理", "清空", "删除")
|
||||||
|
value = value[kit.MDB_META].(map[string]interface{})
|
||||||
|
m.Push(key, value, []string{kit.MDB_TIME})
|
||||||
|
status := map[string]int{}
|
||||||
|
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
|
||||||
|
status[kit.Format(value[kit.MDB_STATUS])]++
|
||||||
|
})
|
||||||
|
m.Push("count", kit.Format("%d/%d/%d", status["busy"], status["free"], status["void"]))
|
||||||
|
m.Push(key, value, []string{cmd})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.Select("*", arg, 1), func(key string, value map[string]interface{}) {
|
||||||
|
if len(arg) < 2 {
|
||||||
|
// 二级列表
|
||||||
|
m.Option(ice.FIELD_DETAIL, "添加", "退还", "清理", "清空")
|
||||||
|
m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_GROUP, kit.MDB_STATUS, kit.MDB_NAME})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 分组详情
|
||||||
|
m.Option(ice.FIELD_DETAIL, "添加", "退还")
|
||||||
|
m.Push("detail", value)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if len(arg) < 1 {
|
||||||
|
m.Sort(cmd)
|
||||||
|
} else if len(arg) < 2 {
|
||||||
|
m.Sort(kit.MDB_NAME)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func _label_create(m *ice.Message, cmd string, key string, arg ...string) {
|
||||||
|
if pod := m.Cmdx(ice.WEB_GROUP, arg[2], "get", arg[3:]); pod != "" {
|
||||||
|
if m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), pod, func(key string, value map[string]interface{}) {
|
||||||
|
if value[kit.MDB_STATUS] == "void" {
|
||||||
|
value[kit.MDB_STATUS] = "free"
|
||||||
|
m.Logs(ice.LOG_MODIFY, cmd, arg[0], kit.MDB_NAME, pod, kit.MDB_STATUS, value[kit.MDB_STATUS])
|
||||||
|
}
|
||||||
|
}) == nil {
|
||||||
|
m.Logs(ice.LOG_INSERT, cmd, arg[0], kit.MDB_NAME, pod)
|
||||||
|
m.Rich(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict(
|
||||||
|
kit.MDB_NAME, pod, kit.MDB_GROUP, arg[2], kit.MDB_STATUS, "free",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
m.Echo(arg[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func _label_remove(m *ice.Message, cmd string, key string, arg ...string) {
|
||||||
|
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), arg[3], func(sub string, value map[string]interface{}) {
|
||||||
|
if value[kit.MDB_STATUS] == "free" {
|
||||||
|
value[kit.MDB_STATUS] = "void"
|
||||||
|
m.Logs(ice.LOG_MODIFY, cmd, arg[0], kit.MDB_NAME, arg[3], kit.MDB_STATUS, "void")
|
||||||
|
m.Cmdx(ice.WEB_GROUP, value[kit.MDB_GROUP], "put", arg[3])
|
||||||
|
m.Echo(arg[3])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func _label_remote(m *ice.Message, cmd string, key string, arg ...string) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
m.Option("_async", "true")
|
||||||
|
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), arg[1], func(key string, value map[string]interface{}) {
|
||||||
|
wg.Add(1)
|
||||||
|
m.Option(ice.MSG_USERPOD, value[kit.MDB_NAME])
|
||||||
|
m.Cmd(ice.WEB_SPACE, value[kit.MDB_NAME], arg[2:]).Call(false, func(res *ice.Message) *ice.Message {
|
||||||
|
if wg.Done(); res != nil && m != nil {
|
||||||
|
m.Copy(res)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Index.Merge(&ice.Context{
|
||||||
|
Configs: map[string]*ice.Config{
|
||||||
|
ice.WEB_LABEL: {Name: "label", Help: "标签", Value: kit.Data(kit.MDB_SHORT, "label")},
|
||||||
|
},
|
||||||
|
Commands: map[string]*ice.Command{
|
||||||
|
ice.WEB_LABEL: {Name: "label label=auto name=auto auto", Help: "标签", Meta: kit.Dict(
|
||||||
|
"exports", []string{"lab", "label"}, "detail", []string{"归还"},
|
||||||
|
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
if len(arg) > 1 && arg[0] == "action" {
|
||||||
|
switch arg[1] {
|
||||||
|
case "add", "添加":
|
||||||
|
_label_add(m, cmd)
|
||||||
|
case "del", "退还":
|
||||||
|
_label_del(m, cmd)
|
||||||
|
case "prune", "清理":
|
||||||
|
_label_prune(m, cmd)
|
||||||
|
case "clear", "清空":
|
||||||
|
_label_clear(m, cmd)
|
||||||
|
case "delete", "删除":
|
||||||
|
_label_delete(m, cmd)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arg) < 3 {
|
||||||
|
// 查询分组
|
||||||
|
_label_select(m, cmd, arg...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Richs(cmd, nil, arg[0], nil) == nil {
|
||||||
|
// 添加分组
|
||||||
|
m.Logs(ice.LOG_CREATE, cmd, m.Rich(cmd, nil, kit.Data(
|
||||||
|
kit.MDB_SHORT, kit.MDB_NAME, cmd, arg[0],
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Richs(cmd, nil, arg[0], func(key string, value map[string]interface{}) {
|
||||||
|
switch arg[1] {
|
||||||
|
case "add": // 添加设备
|
||||||
|
_label_create(m, cmd, key, arg...)
|
||||||
|
case "del": // 删除设备
|
||||||
|
_label_remove(m, cmd, key, arg...)
|
||||||
|
default: // 远程命令
|
||||||
|
if arg[0] == "route" {
|
||||||
|
m.Cmd(ice.WEB_ROUTE).Table(func(index int, value map[string]string, field []string) {
|
||||||
|
m.Rich(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict(
|
||||||
|
kit.MDB_NAME, value["name"], kit.MDB_GROUP, arg[0], kit.MDB_STATUS, "free",
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_label_remote(m, cmd, key, arg...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}},
|
||||||
|
}}, nil)
|
||||||
|
}
|
96
base/web/route.go
Normal file
96
base/web/route.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/shylinux/icebergs"
|
||||||
|
"github.com/shylinux/toolkits"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func _route_split(arg ...string) (string, string) {
|
||||||
|
target, rest := "*", ""
|
||||||
|
if len(arg) > 0 {
|
||||||
|
ls := strings.SplitN(arg[0], ".", 2)
|
||||||
|
if target = ls[0]; len(ls) > 1 {
|
||||||
|
rest = ls[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target, rest
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Index.Merge(&ice.Context{
|
||||||
|
Configs: map[string]*ice.Config{
|
||||||
|
ice.WEB_ROUTE: {Name: "route", Help: "路由", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)},
|
||||||
|
},
|
||||||
|
Commands: map[string]*ice.Command{
|
||||||
|
ice.WEB_ROUTE: {Name: "route name cmd auto", Help: "路由", Meta: kit.Dict("detail", []string{"分组"}), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
if len(arg) > 1 && arg[0] == "action" {
|
||||||
|
switch arg[1] {
|
||||||
|
case "group", "分组":
|
||||||
|
if m.Option("grp") != "" && m.Option("name") != "" {
|
||||||
|
m.Cmdy(ice.WEB_GROUP, m.Option("grp"), "add", m.Option("name"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
target, rest := _route_split(arg...)
|
||||||
|
m.Richs(ice.WEB_SPACE, nil, target, func(key string, val map[string]interface{}) {
|
||||||
|
if len(arg) > 1 {
|
||||||
|
m.Call(false, func(res *ice.Message) *ice.Message { return res })
|
||||||
|
ls := []interface{}{ice.WEB_SPACE, val[kit.MDB_NAME]}
|
||||||
|
// 发送命令
|
||||||
|
if rest != "" {
|
||||||
|
ls = append(ls, ice.WEB_SPACE, rest)
|
||||||
|
}
|
||||||
|
m.Cmdy(ls, arg[1:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val[kit.MDB_TYPE] {
|
||||||
|
case ice.WEB_SERVER:
|
||||||
|
if val[kit.MDB_NAME] == m.Conf(ice.CLI_RUNTIME, "node.name") {
|
||||||
|
// 避免循环
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 远程查询
|
||||||
|
m.Cmd(ice.WEB_SPACE, val[kit.MDB_NAME], ice.WEB_ROUTE).Table(func(index int, value map[string]string, head []string) {
|
||||||
|
m.Push(kit.MDB_TYPE, value[kit.MDB_TYPE])
|
||||||
|
m.Push(kit.MDB_NAME, kit.Keys(val[kit.MDB_NAME], value[kit.MDB_NAME]))
|
||||||
|
})
|
||||||
|
fallthrough
|
||||||
|
case ice.WEB_WORKER:
|
||||||
|
// 本机查询
|
||||||
|
m.Push(kit.MDB_TYPE, val[kit.MDB_TYPE])
|
||||||
|
m.Push(kit.MDB_NAME, val[kit.MDB_NAME])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if m.W != nil {
|
||||||
|
m.Table(func(index int, value map[string]string, field []string) {
|
||||||
|
m.Push("link", Format("a", kit.MergeURL(m.Option(ice.MSG_USERWEB), "pod", value["name"]), value["name"]))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
"/route/": {Name: "/route/", Help: "路由器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
switch arg[0] {
|
||||||
|
case "login":
|
||||||
|
if m.Option(ice.MSG_USERNAME) != "" {
|
||||||
|
m.Push(ice.MSG_USERNAME, m.Option(ice.MSG_USERNAME))
|
||||||
|
m.Info("username: %v", m.Option(ice.MSG_USERNAME))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if m.Option(ice.MSG_SESSID) != "" && m.Cmdx(ice.AAA_SESS, "check", m.Option(ice.MSG_SESSID)) != "" {
|
||||||
|
m.Info("sessid: %v", m.Option(ice.MSG_SESSID))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
sessid := m.Cmdx(ice.AAA_SESS, "create", "")
|
||||||
|
share := m.Cmdx(ice.WEB_SHARE, "add", "login", m.Option(ice.MSG_USERIP), sessid)
|
||||||
|
Render(m, "cookie", sessid)
|
||||||
|
m.Render(share)
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
}}, nil)
|
||||||
|
}
|
386
base/web/story.go
Normal file
386
base/web/story.go
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/shylinux/icebergs"
|
||||||
|
"github.com/shylinux/toolkits"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Index.Merge(&ice.Context{
|
||||||
|
Configs: map[string]*ice.Config{
|
||||||
|
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"),
|
||||||
|
)},
|
||||||
|
},
|
||||||
|
Commands: map[string]*ice.Command{
|
||||||
|
ice.WEB_STORY: {Name: "story story=auto key=auto auto", Help: "故事会", Meta: kit.Dict(
|
||||||
|
"exports", []string{"top", "story"}, "detail", []string{"共享", "更新", "推送"},
|
||||||
|
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
if len(arg) > 1 && arg[0] == "action" {
|
||||||
|
story, list := m.Option("story"), m.Option("list")
|
||||||
|
switch arg[2] {
|
||||||
|
case "story":
|
||||||
|
story = arg[3]
|
||||||
|
case "list":
|
||||||
|
list = arg[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arg[1] {
|
||||||
|
case "share", "共享":
|
||||||
|
if m.Echo("share: "); list == "" {
|
||||||
|
msg := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, story)
|
||||||
|
m.Cmdy(ice.WEB_SHARE, "add", "story", story, msg.Append("list"))
|
||||||
|
} else {
|
||||||
|
msg := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, list)
|
||||||
|
m.Cmdy(ice.WEB_SHARE, "add", msg.Append("scene"), msg.Append("story"), msg.Append("text"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arg) == 0 {
|
||||||
|
// 故事列表
|
||||||
|
m.Richs(ice.WEB_STORY, "head", "*", func(key string, value map[string]interface{}) {
|
||||||
|
m.Push(key, value, []string{"time", "story", "count"})
|
||||||
|
})
|
||||||
|
m.Sort("time", "time_r")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arg[0] {
|
||||||
|
case ice.STORY_PULL: // story [spide [story]]
|
||||||
|
// 起止节点
|
||||||
|
prev, begin, end := "", arg[3], ""
|
||||||
|
repos := kit.Keys("remote", arg[2], arg[3])
|
||||||
|
m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, val map[string]interface{}) {
|
||||||
|
end = kit.Format(kit.Value(val, kit.Keys(repos, "pull", "list")))
|
||||||
|
prev = kit.Format(val["list"])
|
||||||
|
})
|
||||||
|
|
||||||
|
pull := end
|
||||||
|
var first map[string]interface{}
|
||||||
|
for begin != "" && begin != end {
|
||||||
|
if m.Cmd(ice.WEB_SPIDE, arg[2], "msg", "/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[2], "cache", "GET", "/story/download/"+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", arg[1], nil) == nil {
|
||||||
|
// 自动创建
|
||||||
|
h := m.Rich(ice.WEB_STORY, "head", kit.Dict(
|
||||||
|
"scene", node["scene"], "story", arg[1],
|
||||||
|
"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", arg[1], func(key string, val map[string]interface{}) {
|
||||||
|
prev = kit.Format(val["list"])
|
||||||
|
if kit.Int(node["count"]) > kit.Int(kit.Value(val, kit.Keys(repos, "pull", "count"))) {
|
||||||
|
// 更新分支
|
||||||
|
m.Log(ice.LOG_IMPORT, "%v: %v", arg[2], pull)
|
||||||
|
kit.Value(val, kit.Keys(repos, "pull"), kit.Dict(
|
||||||
|
"head", arg[3], "time", node["time"], "list", pull, "count", node["count"],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if prev == kit.Format(node["prev"]) || prev == kit.Format(node["push"]) {
|
||||||
|
// 快速合并
|
||||||
|
m.Log(ice.LOG_IMPORT, "%v: %v", pull, arg[2])
|
||||||
|
m.Richs(ice.WEB_STORY, "head", arg[1], 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"])
|
||||||
|
}).Appendv("list") == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ice.STORY_PUSH:
|
||||||
|
// 更新分支
|
||||||
|
m.Cmdx(ice.WEB_STORY, "pull", arg[1:])
|
||||||
|
|
||||||
|
repos := kit.Keys("remote", arg[2], arg[3])
|
||||||
|
// 查询索引
|
||||||
|
prev, pull, some, list := "", "", "", ""
|
||||||
|
m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, val map[string]interface{}) {
|
||||||
|
prev = kit.Format(val["list"])
|
||||||
|
pull = kit.Format(kit.Value(val, kit.Keys(repos, "pull", "list")))
|
||||||
|
for some = pull; prev != some && some != ""; {
|
||||||
|
local := m.Richs(ice.WEB_STORY, nil, prev, nil)
|
||||||
|
remote := m.Richs(ice.WEB_STORY, nil, some, nil)
|
||||||
|
if diff := kit.Time(kit.Format(remote["time"])) - kit.Time(kit.Format(local["time"])); diff > 0 {
|
||||||
|
some = kit.Format(remote["prev"])
|
||||||
|
} else if diff < 0 {
|
||||||
|
prev = kit.Format(local["prev"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if prev = kit.Format(val["list"]); prev == pull {
|
||||||
|
// 相同节点
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if some != pull {
|
||||||
|
// 合并节点
|
||||||
|
local := m.Richs(ice.WEB_STORY, nil, prev, nil)
|
||||||
|
remote := m.Richs(ice.WEB_STORY, nil, pull, nil)
|
||||||
|
list = m.Rich(ice.WEB_STORY, nil, kit.Dict(
|
||||||
|
"scene", val["scene"], "story", val["story"], "count", kit.Int(remote["count"])+1,
|
||||||
|
"data", local["data"], "prev", pull, "push", prev,
|
||||||
|
))
|
||||||
|
m.Log(ice.LOG_CREATE, "merge: %s %s->%s", list, prev, pull)
|
||||||
|
val["list"] = list
|
||||||
|
prev = list
|
||||||
|
val["count"] = kit.Int(remote["count"]) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询节点
|
||||||
|
nodes := []string{}
|
||||||
|
for list = prev; list != some; {
|
||||||
|
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{}) {
|
||||||
|
if kit.Format(save["file"]) != "" {
|
||||||
|
// 推送缓存
|
||||||
|
m.Cmd(ice.WEB_SPIDE, arg[2], "/story/upload",
|
||||||
|
"part", "upload", "@"+kit.Format(save["file"]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推送节点
|
||||||
|
m.Log(ice.LOG_EXPORT, "%s: %s", v, kit.Format(node))
|
||||||
|
m.Cmd(ice.WEB_SPIDE, arg[2], "/story/push",
|
||||||
|
"story", arg[3], "list", v, "node", kit.Format(node),
|
||||||
|
"data", node["data"], "save", kit.Format(save),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新分支
|
||||||
|
m.Cmd(ice.WEB_STORY, "pull", arg[1:])
|
||||||
|
|
||||||
|
case "commit":
|
||||||
|
// 查询索引
|
||||||
|
head, prev, value, count := "", "", map[string]interface{}{}, 0
|
||||||
|
m.Richs(ice.WEB_STORY, "head", arg[1], 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)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 提交信息
|
||||||
|
arg[2] = m.Cmdx(ice.WEB_STORY, "add", "submit", arg[2], "hostname,username")
|
||||||
|
|
||||||
|
// 节点信息
|
||||||
|
menu := map[string]string{}
|
||||||
|
for i := 3; i < len(arg); i++ {
|
||||||
|
menu[arg[i]] = m.Cmdx(ice.WEB_STORY, ice.STORY_INDEX, arg[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加节点
|
||||||
|
list := m.Rich(ice.WEB_STORY, nil, kit.Dict(
|
||||||
|
"scene", "commit", "story", arg[1], "count", count+1, "data", arg[2], "list", menu, "prev", prev,
|
||||||
|
))
|
||||||
|
m.Log(ice.LOG_CREATE, "commit: %s %s: %s", list, arg[1], arg[2])
|
||||||
|
m.Push("list", list)
|
||||||
|
|
||||||
|
if head == "" {
|
||||||
|
// 添加索引
|
||||||
|
m.Rich(ice.WEB_STORY, "head", kit.Dict("scene", "commit", "story", arg[1], "count", count+1, "list", list))
|
||||||
|
} else {
|
||||||
|
// 更新索引
|
||||||
|
value["count"] = count + 1
|
||||||
|
value["time"] = m.Time()
|
||||||
|
value["list"] = list
|
||||||
|
}
|
||||||
|
m.Echo(list)
|
||||||
|
|
||||||
|
case ice.STORY_TRASH:
|
||||||
|
bak := kit.Select(kit.Keys(arg[1], "bak"), arg, 2)
|
||||||
|
os.Remove(bak)
|
||||||
|
os.Rename(arg[1], bak)
|
||||||
|
|
||||||
|
case ice.STORY_WATCH:
|
||||||
|
// 备份文件
|
||||||
|
name := kit.Select(arg[1], arg, 2)
|
||||||
|
m.Cmd(ice.WEB_STORY, ice.STORY_TRASH, name)
|
||||||
|
|
||||||
|
if msg := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, arg[1]); msg.Append("file") != "" {
|
||||||
|
p := path.Dir(name)
|
||||||
|
os.MkdirAll(p, 0777)
|
||||||
|
|
||||||
|
// 导出文件
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Echo(name)
|
||||||
|
|
||||||
|
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", ice.STORY_UPLOAD, ice.STORY_DOWNLOAD:
|
||||||
|
if m.Richs(ice.WEB_CACHE, nil, kit.Select("", arg, 3), func(key string, value map[string]interface{}) {
|
||||||
|
// 复用缓存
|
||||||
|
arg[3] = key
|
||||||
|
}) == nil {
|
||||||
|
// 添加缓存
|
||||||
|
m.Cmdy(ice.WEB_CACHE, arg)
|
||||||
|
arg = []string{arg[0], m.Append("type"), m.Append("name"), m.Append("data")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询索引
|
||||||
|
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] {
|
||||||
|
// 重复提交
|
||||||
|
m.Echo(prev)
|
||||||
|
} else {
|
||||||
|
// 添加节点
|
||||||
|
list := m.Rich(ice.WEB_STORY, nil, kit.Dict(
|
||||||
|
"scene", arg[1], "story", arg[2], "count", count+1, "data", arg[3], "prev", prev,
|
||||||
|
))
|
||||||
|
m.Log(ice.LOG_CREATE, "story: %s %s: %s", list, arg[1], arg[2])
|
||||||
|
m.Push("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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分发数据
|
||||||
|
if p := kit.Select(m.Conf(ice.WEB_FAVOR, "meta.proxy"), m.Option("you")); p != "" {
|
||||||
|
m.Info("what %v", p)
|
||||||
|
m.Option("you", "")
|
||||||
|
m.Cmd(ice.WEB_PROXY, p, ice.WEB_STORY, ice.STORY_PULL, arg[2], "dev", arg[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
case ice.STORY_INDEX:
|
||||||
|
m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, value map[string]interface{}) {
|
||||||
|
// 查询索引
|
||||||
|
arg[1] = kit.Format(value["list"])
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Richs(ice.WEB_STORY, nil, arg[1], func(key string, value map[string]interface{}) {
|
||||||
|
// 查询节点
|
||||||
|
m.Push("list", key)
|
||||||
|
m.Push(key, value, []string{"scene", "story"})
|
||||||
|
arg[1] = kit.Format(value["data"])
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Richs(ice.WEB_CACHE, nil, arg[1], func(key string, value map[string]interface{}) {
|
||||||
|
// 查询数据
|
||||||
|
m.Push("data", key)
|
||||||
|
m.Push(key, value, []string{"text", "time", "size", "type", "name", "file"})
|
||||||
|
m.Echo("%s", value["text"])
|
||||||
|
})
|
||||||
|
|
||||||
|
case ice.STORY_HISTORY:
|
||||||
|
// 历史记录
|
||||||
|
list := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, arg[1]).Append("list")
|
||||||
|
for i := 0; i < kit.Int(kit.Select("30", m.Option("cache.limit"))) && list != ""; i++ {
|
||||||
|
|
||||||
|
m.Richs(ice.WEB_STORY, nil, list, func(key string, value map[string]interface{}) {
|
||||||
|
// 直连节点
|
||||||
|
m.Push(key, value, []string{"time", "key", "count", "scene", "story"})
|
||||||
|
m.Richs(ice.WEB_CACHE, nil, value["data"], func(key string, value map[string]interface{}) {
|
||||||
|
m.Push("drama", value["text"])
|
||||||
|
m.Push("data", key)
|
||||||
|
})
|
||||||
|
|
||||||
|
kit.Fetch(value["list"], func(key string, val string) {
|
||||||
|
m.Richs(ice.WEB_STORY, nil, val, func(key string, value map[string]interface{}) {
|
||||||
|
// 复合节点
|
||||||
|
m.Push(key, value, []string{"time", "key", "count", "scene", "story"})
|
||||||
|
m.Richs(ice.WEB_CACHE, nil, value["data"], func(key string, value map[string]interface{}) {
|
||||||
|
m.Push("drama", value["text"])
|
||||||
|
m.Push("data", key)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 切换节点
|
||||||
|
list = kit.Format(value["prev"])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
if len(arg) == 1 {
|
||||||
|
// 故事记录
|
||||||
|
m.Cmdy(ice.WEB_STORY, "history", arg)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// 故事详情
|
||||||
|
m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, arg[1]).Table(func(index int, value map[string]string, head []string) {
|
||||||
|
for k, v := range value {
|
||||||
|
m.Push("key", k)
|
||||||
|
m.Push("value", v)
|
||||||
|
}
|
||||||
|
m.Sort("key")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
}}, nil)
|
||||||
|
}
|
579
base/web/web.go
579
base/web/web.go
@ -39,6 +39,13 @@ func Count(m *ice.Message, cmd, key, name string) int {
|
|||||||
m.Conf(cmd, kit.Keys(key, name), count+1)
|
m.Conf(cmd, kit.Keys(key, name), count+1)
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
func Format(key string, arg ...interface{}) string {
|
||||||
|
switch args := kit.Simple(arg); key {
|
||||||
|
case "a":
|
||||||
|
return fmt.Sprintf("<a href='%s' target='_blank'>%s</a>", kit.Format(args[0]), kit.Select(kit.Format(args[0]), args, 1))
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
func Render(msg *ice.Message, cmd string, args ...interface{}) {
|
func Render(msg *ice.Message, cmd string, args ...interface{}) {
|
||||||
msg.Log(ice.LOG_EXPORT, "%s: %v", cmd, args)
|
msg.Log(ice.LOG_EXPORT, "%s: %v", cmd, args)
|
||||||
switch arg := kit.Simple(args...); cmd {
|
switch arg := kit.Simple(args...); cmd {
|
||||||
@ -479,16 +486,9 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
ice.WEB_CACHE: {Name: "cache", Help: "缓存池", Value: kit.Data(
|
ice.WEB_CACHE: {Name: "cache", Help: "缓存池", Value: kit.Data(
|
||||||
kit.MDB_SHORT, "text", "path", "var/file", "store", "var/data", "fsize", "100000", "limit", "50", "least", "30",
|
kit.MDB_SHORT, "text", "path", "var/file", "store", "var/data", "fsize", "100000", "limit", "50", "least", "30",
|
||||||
)},
|
)},
|
||||||
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_ROUTE: {Name: "route", Help: "路由", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)},
|
|
||||||
ice.WEB_PROXY: {Name: "proxy", Help: "代理", Value: kit.Data(kit.MDB_SHORT, "proxy")},
|
ice.WEB_PROXY: {Name: "proxy", Help: "代理", Value: kit.Data(kit.MDB_SHORT, "proxy")},
|
||||||
ice.WEB_GROUP: {Name: "group", Help: "分组", Value: kit.Data(kit.MDB_SHORT, "group")},
|
ice.WEB_GROUP: {Name: "group", Help: "分组", Value: kit.Data(kit.MDB_SHORT, "group")},
|
||||||
ice.WEB_LABEL: {Name: "label", Help: "标签", Value: kit.Data(kit.MDB_SHORT, "label")},
|
|
||||||
},
|
},
|
||||||
Commands: map[string]*ice.Command{
|
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) {
|
||||||
@ -1359,420 +1359,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
m.Echo(arg[2])
|
m.Echo(arg[2])
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
ice.WEB_STORY: {Name: "story story=auto key=auto auto", Help: "故事会", Meta: kit.Dict(
|
|
||||||
"exports", []string{"top", "story"}, "detail", []string{"共享", "更新", "推送"},
|
|
||||||
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
|
||||||
if len(arg) > 1 && arg[0] == "action" {
|
|
||||||
story, list := m.Option("story"), m.Option("list")
|
|
||||||
switch arg[2] {
|
|
||||||
case "story":
|
|
||||||
story = arg[3]
|
|
||||||
case "list":
|
|
||||||
list = arg[3]
|
|
||||||
}
|
|
||||||
|
|
||||||
switch arg[1] {
|
|
||||||
case "share", "共享":
|
|
||||||
if m.Echo("share: "); list == "" {
|
|
||||||
msg := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, story)
|
|
||||||
m.Cmdy(ice.WEB_SHARE, "add", "story", story, msg.Append("list"))
|
|
||||||
} else {
|
|
||||||
msg := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, list)
|
|
||||||
m.Cmdy(ice.WEB_SHARE, "add", msg.Append("scene"), msg.Append("story"), msg.Append("text"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(arg) == 0 {
|
|
||||||
// 故事列表
|
|
||||||
m.Richs(ice.WEB_STORY, "head", "*", func(key string, value map[string]interface{}) {
|
|
||||||
m.Push(key, value, []string{"time", "story", "count"})
|
|
||||||
})
|
|
||||||
m.Sort("time", "time_r")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch arg[0] {
|
|
||||||
case ice.STORY_PULL: // story [spide [story]]
|
|
||||||
// 起止节点
|
|
||||||
prev, begin, end := "", arg[3], ""
|
|
||||||
repos := kit.Keys("remote", arg[2], arg[3])
|
|
||||||
m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, val map[string]interface{}) {
|
|
||||||
end = kit.Format(kit.Value(val, kit.Keys(repos, "pull", "list")))
|
|
||||||
prev = kit.Format(val["list"])
|
|
||||||
})
|
|
||||||
|
|
||||||
pull := end
|
|
||||||
var first map[string]interface{}
|
|
||||||
for begin != "" && begin != end {
|
|
||||||
if m.Cmd(ice.WEB_SPIDE, arg[2], "msg", "/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[2], "cache", "GET", "/story/download/"+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", arg[1], nil) == nil {
|
|
||||||
// 自动创建
|
|
||||||
h := m.Rich(ice.WEB_STORY, "head", kit.Dict(
|
|
||||||
"scene", node["scene"], "story", arg[1],
|
|
||||||
"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", arg[1], func(key string, val map[string]interface{}) {
|
|
||||||
prev = kit.Format(val["list"])
|
|
||||||
if kit.Int(node["count"]) > kit.Int(kit.Value(val, kit.Keys(repos, "pull", "count"))) {
|
|
||||||
// 更新分支
|
|
||||||
m.Log(ice.LOG_IMPORT, "%v: %v", arg[2], pull)
|
|
||||||
kit.Value(val, kit.Keys(repos, "pull"), kit.Dict(
|
|
||||||
"head", arg[3], "time", node["time"], "list", pull, "count", node["count"],
|
|
||||||
))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if prev == kit.Format(node["prev"]) || prev == kit.Format(node["push"]) {
|
|
||||||
// 快速合并
|
|
||||||
m.Log(ice.LOG_IMPORT, "%v: %v", pull, arg[2])
|
|
||||||
m.Richs(ice.WEB_STORY, "head", arg[1], 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"])
|
|
||||||
}).Appendv("list") == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case ice.STORY_PUSH:
|
|
||||||
// 更新分支
|
|
||||||
m.Cmdx(ice.WEB_STORY, "pull", arg[1:])
|
|
||||||
|
|
||||||
repos := kit.Keys("remote", arg[2], arg[3])
|
|
||||||
// 查询索引
|
|
||||||
prev, pull, some, list := "", "", "", ""
|
|
||||||
m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, val map[string]interface{}) {
|
|
||||||
prev = kit.Format(val["list"])
|
|
||||||
pull = kit.Format(kit.Value(val, kit.Keys(repos, "pull", "list")))
|
|
||||||
for some = pull; prev != some && some != ""; {
|
|
||||||
local := m.Richs(ice.WEB_STORY, nil, prev, nil)
|
|
||||||
remote := m.Richs(ice.WEB_STORY, nil, some, nil)
|
|
||||||
if diff := kit.Time(kit.Format(remote["time"])) - kit.Time(kit.Format(local["time"])); diff > 0 {
|
|
||||||
some = kit.Format(remote["prev"])
|
|
||||||
} else if diff < 0 {
|
|
||||||
prev = kit.Format(local["prev"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if prev = kit.Format(val["list"]); prev == pull {
|
|
||||||
// 相同节点
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if some != pull {
|
|
||||||
// 合并节点
|
|
||||||
local := m.Richs(ice.WEB_STORY, nil, prev, nil)
|
|
||||||
remote := m.Richs(ice.WEB_STORY, nil, pull, nil)
|
|
||||||
list = m.Rich(ice.WEB_STORY, nil, kit.Dict(
|
|
||||||
"scene", val["scene"], "story", val["story"], "count", kit.Int(remote["count"])+1,
|
|
||||||
"data", local["data"], "prev", pull, "push", prev,
|
|
||||||
))
|
|
||||||
m.Log(ice.LOG_CREATE, "merge: %s %s->%s", list, prev, pull)
|
|
||||||
val["list"] = list
|
|
||||||
prev = list
|
|
||||||
val["count"] = kit.Int(remote["count"]) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询节点
|
|
||||||
nodes := []string{}
|
|
||||||
for list = prev; list != some; {
|
|
||||||
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{}) {
|
|
||||||
if kit.Format(save["file"]) != "" {
|
|
||||||
// 推送缓存
|
|
||||||
m.Cmd(ice.WEB_SPIDE, arg[2], "/story/upload",
|
|
||||||
"part", "upload", "@"+kit.Format(save["file"]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 推送节点
|
|
||||||
m.Log(ice.LOG_EXPORT, "%s: %s", v, kit.Format(node))
|
|
||||||
m.Cmd(ice.WEB_SPIDE, arg[2], "/story/push",
|
|
||||||
"story", arg[3], "list", v, "node", kit.Format(node),
|
|
||||||
"data", node["data"], "save", kit.Format(save),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 更新分支
|
|
||||||
m.Cmd(ice.WEB_STORY, "pull", arg[1:])
|
|
||||||
|
|
||||||
case "commit":
|
|
||||||
// 查询索引
|
|
||||||
head, prev, value, count := "", "", map[string]interface{}{}, 0
|
|
||||||
m.Richs(ice.WEB_STORY, "head", arg[1], 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)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 提交信息
|
|
||||||
arg[2] = m.Cmdx(ice.WEB_STORY, "add", "submit", arg[2], "hostname,username")
|
|
||||||
|
|
||||||
// 节点信息
|
|
||||||
menu := map[string]string{}
|
|
||||||
for i := 3; i < len(arg); i++ {
|
|
||||||
menu[arg[i]] = m.Cmdx(ice.WEB_STORY, ice.STORY_INDEX, arg[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加节点
|
|
||||||
list := m.Rich(ice.WEB_STORY, nil, kit.Dict(
|
|
||||||
"scene", "commit", "story", arg[1], "count", count+1, "data", arg[2], "list", menu, "prev", prev,
|
|
||||||
))
|
|
||||||
m.Log(ice.LOG_CREATE, "commit: %s %s: %s", list, arg[1], arg[2])
|
|
||||||
m.Push("list", list)
|
|
||||||
|
|
||||||
if head == "" {
|
|
||||||
// 添加索引
|
|
||||||
m.Rich(ice.WEB_STORY, "head", kit.Dict("scene", "commit", "story", arg[1], "count", count+1, "list", list))
|
|
||||||
} else {
|
|
||||||
// 更新索引
|
|
||||||
value["count"] = count + 1
|
|
||||||
value["time"] = m.Time()
|
|
||||||
value["list"] = list
|
|
||||||
}
|
|
||||||
m.Echo(list)
|
|
||||||
|
|
||||||
case ice.STORY_TRASH:
|
|
||||||
bak := kit.Select(kit.Keys(arg[1], "bak"), arg, 2)
|
|
||||||
os.Remove(bak)
|
|
||||||
os.Rename(arg[1], bak)
|
|
||||||
|
|
||||||
case ice.STORY_WATCH:
|
|
||||||
// 备份文件
|
|
||||||
name := kit.Select(arg[1], arg, 2)
|
|
||||||
m.Cmd(ice.WEB_STORY, ice.STORY_TRASH, name)
|
|
||||||
|
|
||||||
if msg := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, arg[1]); msg.Append("file") != "" {
|
|
||||||
p := path.Dir(name)
|
|
||||||
os.MkdirAll(p, 0777)
|
|
||||||
|
|
||||||
// 导出文件
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.Echo(name)
|
|
||||||
|
|
||||||
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", ice.STORY_UPLOAD, ice.STORY_DOWNLOAD:
|
|
||||||
if m.Richs(ice.WEB_CACHE, nil, kit.Select("", arg, 3), func(key string, value map[string]interface{}) {
|
|
||||||
// 复用缓存
|
|
||||||
arg[3] = key
|
|
||||||
}) == nil {
|
|
||||||
// 添加缓存
|
|
||||||
m.Cmdy(ice.WEB_CACHE, arg)
|
|
||||||
arg = []string{arg[0], m.Append("type"), m.Append("name"), m.Append("data")}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询索引
|
|
||||||
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] {
|
|
||||||
// 重复提交
|
|
||||||
m.Echo(prev)
|
|
||||||
} else {
|
|
||||||
// 添加节点
|
|
||||||
list := m.Rich(ice.WEB_STORY, nil, kit.Dict(
|
|
||||||
"scene", arg[1], "story", arg[2], "count", count+1, "data", arg[3], "prev", prev,
|
|
||||||
))
|
|
||||||
m.Log(ice.LOG_CREATE, "story: %s %s: %s", list, arg[1], arg[2])
|
|
||||||
m.Push("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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分发数据
|
|
||||||
if p := kit.Select(m.Conf(ice.WEB_FAVOR, "meta.proxy"), m.Option("you")); p != "" {
|
|
||||||
m.Info("what %v", p)
|
|
||||||
m.Option("you", "")
|
|
||||||
m.Cmd(ice.WEB_PROXY, p, ice.WEB_STORY, ice.STORY_PULL, arg[2], "dev", arg[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
case ice.STORY_INDEX:
|
|
||||||
m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, value map[string]interface{}) {
|
|
||||||
// 查询索引
|
|
||||||
arg[1] = kit.Format(value["list"])
|
|
||||||
})
|
|
||||||
|
|
||||||
m.Richs(ice.WEB_STORY, nil, arg[1], func(key string, value map[string]interface{}) {
|
|
||||||
// 查询节点
|
|
||||||
m.Push("list", key)
|
|
||||||
m.Push(key, value, []string{"scene", "story"})
|
|
||||||
arg[1] = kit.Format(value["data"])
|
|
||||||
})
|
|
||||||
|
|
||||||
m.Richs(ice.WEB_CACHE, nil, arg[1], func(key string, value map[string]interface{}) {
|
|
||||||
// 查询数据
|
|
||||||
m.Push("data", key)
|
|
||||||
m.Push(key, value, []string{"text", "time", "size", "type", "name", "file"})
|
|
||||||
m.Echo("%s", value["text"])
|
|
||||||
})
|
|
||||||
|
|
||||||
case ice.STORY_HISTORY:
|
|
||||||
// 历史记录
|
|
||||||
list := m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, arg[1]).Append("list")
|
|
||||||
for i := 0; i < kit.Int(kit.Select("30", m.Option("cache.limit"))) && list != ""; i++ {
|
|
||||||
|
|
||||||
m.Richs(ice.WEB_STORY, nil, list, func(key string, value map[string]interface{}) {
|
|
||||||
// 直连节点
|
|
||||||
m.Push(key, value, []string{"time", "key", "count", "scene", "story"})
|
|
||||||
m.Richs(ice.WEB_CACHE, nil, value["data"], func(key string, value map[string]interface{}) {
|
|
||||||
m.Push("drama", value["text"])
|
|
||||||
m.Push("data", key)
|
|
||||||
})
|
|
||||||
|
|
||||||
kit.Fetch(value["list"], func(key string, val string) {
|
|
||||||
m.Richs(ice.WEB_STORY, nil, val, func(key string, value map[string]interface{}) {
|
|
||||||
// 复合节点
|
|
||||||
m.Push(key, value, []string{"time", "key", "count", "scene", "story"})
|
|
||||||
m.Richs(ice.WEB_CACHE, nil, value["data"], func(key string, value map[string]interface{}) {
|
|
||||||
m.Push("drama", value["text"])
|
|
||||||
m.Push("data", key)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// 切换节点
|
|
||||||
list = kit.Format(value["prev"])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if len(arg) == 1 {
|
|
||||||
// 故事记录
|
|
||||||
m.Cmdy(ice.WEB_STORY, "history", arg)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// 故事详情
|
|
||||||
m.Cmd(ice.WEB_STORY, ice.STORY_INDEX, arg[1]).Table(func(index int, value map[string]string, head []string) {
|
|
||||||
for k, v := range value {
|
|
||||||
m.Push("key", k)
|
|
||||||
m.Push("value", v)
|
|
||||||
}
|
|
||||||
m.Sort("key")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}},
|
|
||||||
|
|
||||||
ice.WEB_ROUTE: {Name: "route name cmd auto", Help: "路由", Meta: kit.Dict("detail", []string{"分组"}), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
|
||||||
if len(arg) > 1 && arg[0] == "action" {
|
|
||||||
switch arg[1] {
|
|
||||||
case "group", "分组":
|
|
||||||
if m.Option("grp") != "" && m.Option("name") != "" {
|
|
||||||
m.Cmdy(ice.WEB_GROUP, m.Option("grp"), "add", m.Option("name"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
target, rest := "*", ""
|
|
||||||
if len(arg) > 0 {
|
|
||||||
ls := strings.SplitN(arg[0], ".", 2)
|
|
||||||
if target = ls[0]; len(ls) > 1 {
|
|
||||||
rest = ls[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.Richs(ice.WEB_SPACE, nil, target, func(key string, val map[string]interface{}) {
|
|
||||||
if len(arg) > 1 {
|
|
||||||
m.Call(false, func(res *ice.Message) *ice.Message { return res })
|
|
||||||
ls := []interface{}{ice.WEB_SPACE, val[kit.MDB_NAME]}
|
|
||||||
// 发送命令
|
|
||||||
if rest != "" {
|
|
||||||
ls = append(ls, ice.WEB_SPACE, rest)
|
|
||||||
}
|
|
||||||
m.Cmdy(ls, arg[1:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch val[kit.MDB_TYPE] {
|
|
||||||
case ice.WEB_SERVER:
|
|
||||||
if val[kit.MDB_NAME] == m.Conf(ice.CLI_RUNTIME, "node.name") {
|
|
||||||
// 避免循环
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 远程查询
|
|
||||||
m.Cmd(ice.WEB_SPACE, val[kit.MDB_NAME], ice.WEB_ROUTE).Table(func(index int, value map[string]string, head []string) {
|
|
||||||
m.Push(kit.MDB_TYPE, value[kit.MDB_TYPE])
|
|
||||||
m.Push(kit.MDB_NAME, kit.Keys(val[kit.MDB_NAME], value[kit.MDB_NAME]))
|
|
||||||
})
|
|
||||||
fallthrough
|
|
||||||
case ice.WEB_WORKER:
|
|
||||||
// 本机查询
|
|
||||||
m.Push(kit.MDB_TYPE, val[kit.MDB_TYPE])
|
|
||||||
m.Push(kit.MDB_NAME, val[kit.MDB_NAME])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}},
|
|
||||||
ice.WEB_PROXY: {Name: "proxy name cmd auto", Help: "代理", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
ice.WEB_PROXY: {Name: "proxy name cmd auto", Help: "代理", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
switch arg[0] {
|
switch arg[0] {
|
||||||
case "add":
|
case "add":
|
||||||
@ -1934,159 +1521,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}},
|
}},
|
||||||
ice.WEB_LABEL: {Name: "label label=auto name=auto auto", Help: "标签", Meta: kit.Dict(
|
|
||||||
"exports", []string{"lab", "label"}, "detail", []string{"归还"},
|
|
||||||
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
|
||||||
if len(arg) > 1 && arg[0] == "action" {
|
|
||||||
switch arg[1] {
|
|
||||||
case "add", "添加":
|
|
||||||
if m.Option(cmd) != "" && m.Option(kit.MDB_GROUP) != "" && m.Option(kit.MDB_NAME) != "" {
|
|
||||||
m.Cmdy(cmd, m.Option(cmd), "add", m.Option(kit.MDB_GROUP), m.Option(kit.MDB_NAME))
|
|
||||||
m.Option(ice.FIELD_RELOAD, "true")
|
|
||||||
}
|
|
||||||
case "del", "退还":
|
|
||||||
if m.Option(cmd) != "" && m.Option(kit.MDB_GROUP) != "" && m.Option(kit.MDB_NAME) != "" {
|
|
||||||
m.Cmdy(cmd, m.Option(cmd), "del", m.Option(kit.MDB_GROUP), m.Option(kit.MDB_NAME))
|
|
||||||
m.Option(ice.FIELD_RELOAD, "true")
|
|
||||||
}
|
|
||||||
case "prune", "清理":
|
|
||||||
m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) {
|
|
||||||
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(sub string, value map[string]interface{}) {
|
|
||||||
if value[kit.MDB_STATUS] != "busy" {
|
|
||||||
m.Cmdy(cmd, m.Option(cmd), "del", value[kit.MDB_GROUP], value[kit.MDB_NAME])
|
|
||||||
m.Option(ice.FIELD_RELOAD, "true")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
case "clear", "清空":
|
|
||||||
m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) {
|
|
||||||
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(sub string, value map[string]interface{}) {
|
|
||||||
if value[kit.MDB_STATUS] == "void" {
|
|
||||||
last := m.Conf(cmd, kit.Keys(kit.MDB_HASH, key, kit.MDB_HASH, sub))
|
|
||||||
m.Logs(ice.LOG_DELETE, cmd, m.Option(cmd), kit.MDB_NAME, value[kit.MDB_NAME], kit.MDB_VALUE, last)
|
|
||||||
m.Conf(cmd, kit.Keys(kit.MDB_HASH, key, kit.MDB_HASH, sub), "")
|
|
||||||
m.Option(ice.FIELD_RELOAD, "true")
|
|
||||||
m.Echo(last)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
case "delete", "删除":
|
|
||||||
m.Richs(cmd, nil, m.Option(cmd), func(key string, value map[string]interface{}) {
|
|
||||||
m.Echo(m.Conf(cmd, kit.Keys(kit.MDB_HASH, key)))
|
|
||||||
m.Logs(ice.LOG_REMOVE, cmd, m.Option(cmd), kit.MDB_VALUE, m.Conf(cmd, kit.Keys(kit.MDB_HASH, key)))
|
|
||||||
m.Conf(cmd, kit.Keys(kit.MDB_HASH, key), "")
|
|
||||||
m.Option(ice.FIELD_RELOAD, "true")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(arg) < 3 {
|
|
||||||
m.Richs(cmd, nil, kit.Select("*", arg, 0), func(key string, value map[string]interface{}) {
|
|
||||||
if len(arg) < 1 {
|
|
||||||
// 一级列表
|
|
||||||
m.Option(ice.FIELD_DETAIL, "清理", "清空", "删除")
|
|
||||||
value = value[kit.MDB_META].(map[string]interface{})
|
|
||||||
m.Push(key, value, []string{kit.MDB_TIME})
|
|
||||||
status := map[string]int{}
|
|
||||||
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
|
|
||||||
status[kit.Format(value[kit.MDB_STATUS])]++
|
|
||||||
})
|
|
||||||
m.Push("count", kit.Format("%d/%d/%d", status["busy"], status["free"], status["void"]))
|
|
||||||
m.Push(key, value, []string{cmd})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), kit.Select("*", arg, 1), func(key string, value map[string]interface{}) {
|
|
||||||
if len(arg) < 2 {
|
|
||||||
// 二级列表
|
|
||||||
m.Option(ice.FIELD_DETAIL, "添加", "退还", "清理", "清空")
|
|
||||||
m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_GROUP, kit.MDB_STATUS, kit.MDB_NAME})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 分组详情
|
|
||||||
m.Option(ice.FIELD_DETAIL, "添加", "退还")
|
|
||||||
m.Push("detail", value)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if len(arg) < 1 {
|
|
||||||
m.Sort(cmd)
|
|
||||||
} else if len(arg) < 2 {
|
|
||||||
m.Sort(kit.MDB_NAME)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.Richs(cmd, nil, arg[0], nil) == nil {
|
|
||||||
// 添加分组
|
|
||||||
m.Logs(ice.LOG_CREATE, cmd, m.Rich(cmd, nil, kit.Data(
|
|
||||||
kit.MDB_SHORT, kit.MDB_NAME, cmd, arg[0],
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Richs(cmd, nil, arg[0], func(key string, value map[string]interface{}) {
|
|
||||||
switch arg[1] {
|
|
||||||
case "add": // 添加设备
|
|
||||||
if pod := m.Cmdx(ice.WEB_GROUP, arg[2], "get", arg[3:]); pod != "" {
|
|
||||||
if m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), pod, func(key string, value map[string]interface{}) {
|
|
||||||
if value[kit.MDB_STATUS] == "void" {
|
|
||||||
value[kit.MDB_STATUS] = "free"
|
|
||||||
m.Logs(ice.LOG_MODIFY, cmd, arg[0], kit.MDB_NAME, pod, kit.MDB_STATUS, value[kit.MDB_STATUS])
|
|
||||||
}
|
|
||||||
}) == nil {
|
|
||||||
m.Logs(ice.LOG_INSERT, cmd, arg[0], kit.MDB_NAME, pod)
|
|
||||||
m.Rich(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict(
|
|
||||||
kit.MDB_NAME, pod, kit.MDB_GROUP, arg[2], kit.MDB_STATUS, "free",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
m.Echo(arg[0])
|
|
||||||
}
|
|
||||||
case "del": // 删除设备
|
|
||||||
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), arg[3], func(sub string, value map[string]interface{}) {
|
|
||||||
if value[kit.MDB_STATUS] == "free" {
|
|
||||||
value[kit.MDB_STATUS] = "void"
|
|
||||||
m.Logs(ice.LOG_MODIFY, cmd, arg[0], kit.MDB_NAME, arg[3], kit.MDB_STATUS, "void")
|
|
||||||
m.Cmdx(ice.WEB_GROUP, value[kit.MDB_GROUP], "put", arg[3])
|
|
||||||
m.Echo(arg[3])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
wg := &sync.WaitGroup{}
|
|
||||||
m.Option("_async", "true")
|
|
||||||
m.Richs(cmd, kit.Keys(kit.MDB_HASH, key), arg[1], func(key string, value map[string]interface{}) {
|
|
||||||
wg.Add(1)
|
|
||||||
// 远程命令
|
|
||||||
m.Option(ice.MSG_USERPOD, value[kit.MDB_NAME])
|
|
||||||
m.Cmd(ice.WEB_SPACE, value[kit.MDB_NAME], arg[2:]).Call(false, func(res *ice.Message) *ice.Message {
|
|
||||||
if wg.Done(); res != nil && m != nil {
|
|
||||||
m.Copy(res)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}},
|
|
||||||
|
|
||||||
"/route/": {Name: "/route/", Help: "路由器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
|
||||||
switch arg[0] {
|
|
||||||
case "login":
|
|
||||||
if m.Option(ice.MSG_USERNAME) != "" {
|
|
||||||
m.Push(ice.MSG_USERNAME, m.Option(ice.MSG_USERNAME))
|
|
||||||
m.Info("username: %v", m.Option(ice.MSG_USERNAME))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if m.Option(ice.MSG_SESSID) != "" && m.Cmdx(ice.AAA_SESS, "check", m.Option(ice.MSG_SESSID)) != "" {
|
|
||||||
m.Info("sessid: %v", m.Option(ice.MSG_SESSID))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
sessid := m.Cmdx(ice.AAA_SESS, "create", "")
|
|
||||||
share := m.Cmdx(ice.WEB_SHARE, "add", "login", m.Option(ice.MSG_USERIP), sessid)
|
|
||||||
Render(m, "cookie", sessid)
|
|
||||||
m.Render(share)
|
|
||||||
}
|
|
||||||
}},
|
|
||||||
"/space/": {Name: "/space/", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
"/space/": {Name: "/space/", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
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) {
|
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(kit.Select(m.Option(ice.MSG_USERADDR), m.Option("name")), ".", "_", -1))
|
m.Option("name", strings.Replace(kit.Select(m.Option(ice.MSG_USERADDR), m.Option("name")), ".", "_", -1))
|
||||||
|
@ -87,7 +87,6 @@ var Index = &ice.Context{Name: "chat", Help: "聊天中心",
|
|||||||
}),
|
}),
|
||||||
"fe", "volcanos",
|
"fe", "volcanos",
|
||||||
)},
|
)},
|
||||||
"search": {Name: "search", Help: "search", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)},
|
|
||||||
"commend": {Name: "commend", Help: "commend", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME, "user", kit.Data(kit.MDB_SHORT, kit.MDB_NAME))},
|
"commend": {Name: "commend", Help: "commend", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME, "user", kit.Data(kit.MDB_SHORT, kit.MDB_NAME))},
|
||||||
},
|
},
|
||||||
Commands: map[string]*ice.Command{
|
Commands: map[string]*ice.Command{
|
||||||
@ -375,65 +374,6 @@ var Index = &ice.Context{Name: "chat", Help: "聊天中心",
|
|||||||
"/target": {Name: "/target", Help: "对话框", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
|
"/target": {Name: "/target", Help: "对话框", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
|
||||||
"/source": {Name: "/source", Help: "输入框", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
|
"/source": {Name: "/source", Help: "输入框", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
|
||||||
|
|
||||||
"search": {Name: "search label pod engine word", Help: "搜索引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
|
||||||
if len(arg) < 2 {
|
|
||||||
m.Cmdy(ice.WEB_LABEL, arg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch arg[0] {
|
|
||||||
case "add":
|
|
||||||
if m.Richs(cmd, nil, arg[1], nil) == nil {
|
|
||||||
m.Rich(cmd, nil, kit.Data(kit.MDB_NAME, arg[1]))
|
|
||||||
}
|
|
||||||
m.Richs(cmd, nil, arg[1], func(key string, value map[string]interface{}) {
|
|
||||||
m.Grow(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict(
|
|
||||||
kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3:],
|
|
||||||
))
|
|
||||||
})
|
|
||||||
case "get":
|
|
||||||
wg := &sync.WaitGroup{}
|
|
||||||
m.Richs(cmd, nil, arg[1], func(key string, value map[string]interface{}) {
|
|
||||||
wg.Add(1)
|
|
||||||
m.Gos(m, func(m *ice.Message) {
|
|
||||||
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
|
||||||
m.Cmdy(value[kit.MDB_TEXT], arg[2:])
|
|
||||||
})
|
|
||||||
wg.Done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
wg.Wait()
|
|
||||||
case "set":
|
|
||||||
if arg[1] != "" {
|
|
||||||
m.Cmdy(ice.WEB_SPACE, arg[1], "web.chat.search", "set", "", arg[2:])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Richs(cmd, nil, arg[2], func(key string, value map[string]interface{}) {
|
|
||||||
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
|
||||||
m.Cmdy(value[kit.MDB_TEXT], "set", arg[3:])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
if len(arg) < 4 {
|
|
||||||
m.Richs(cmd, nil, kit.Select(kit.MDB_FOREACH, arg, 2), func(key string, val map[string]interface{}) {
|
|
||||||
if len(arg) < 3 {
|
|
||||||
m.Push(key, val[kit.MDB_META], []string{kit.MDB_TIME, kit.MDB_NAME, kit.MDB_COUNT})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
|
||||||
m.Push("", value, []string{kit.MDB_TIME})
|
|
||||||
m.Push("group", arg[2])
|
|
||||||
m.Push("", value, []string{kit.MDB_NAME, kit.MDB_TEXT})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
m.Option("pod", "")
|
|
||||||
m.Cmdy(ice.WEB_LABEL, arg[0], arg[1], "web.chat.search", "get", arg[2:])
|
|
||||||
m.Sort("time", "time_r")
|
|
||||||
}
|
|
||||||
}},
|
|
||||||
"commend": {Name: "commend label pod engine work auto", Help: "推荐引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
"commend": {Name: "commend label pod engine work auto", Help: "推荐引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
if len(arg) < 2 {
|
if len(arg) < 2 {
|
||||||
m.Cmdy(ice.WEB_LABEL, arg)
|
m.Cmdy(ice.WEB_LABEL, arg)
|
||||||
|
75
core/chat/search.go
Normal file
75
core/chat/search.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package chat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/shylinux/icebergs"
|
||||||
|
"github.com/shylinux/toolkits"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Index.Merge(&ice.Context{
|
||||||
|
Configs: map[string]*ice.Config{
|
||||||
|
"search": {Name: "search", Help: "search", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)},
|
||||||
|
},
|
||||||
|
Commands: map[string]*ice.Command{
|
||||||
|
"search": {Name: "search label pod engine word", Help: "搜索引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
if len(arg) < 2 {
|
||||||
|
m.Cmdy(ice.WEB_LABEL, arg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arg[0] {
|
||||||
|
case "add":
|
||||||
|
if m.Richs(cmd, nil, arg[1], nil) == nil {
|
||||||
|
m.Rich(cmd, nil, kit.Data(kit.MDB_NAME, arg[1]))
|
||||||
|
}
|
||||||
|
m.Richs(cmd, nil, arg[1], func(key string, value map[string]interface{}) {
|
||||||
|
m.Grow(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict(
|
||||||
|
kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3:],
|
||||||
|
))
|
||||||
|
})
|
||||||
|
case "get":
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
m.Richs(cmd, nil, arg[1], func(key string, value map[string]interface{}) {
|
||||||
|
wg.Add(1)
|
||||||
|
m.Gos(m, func(m *ice.Message) {
|
||||||
|
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
||||||
|
m.Cmdy(value[kit.MDB_TEXT], arg[2:])
|
||||||
|
})
|
||||||
|
wg.Done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
wg.Wait()
|
||||||
|
case "set":
|
||||||
|
if arg[1] != "" {
|
||||||
|
m.Cmdy(ice.WEB_SPACE, arg[1], "web.chat.search", "set", "", arg[2:])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Richs(cmd, nil, arg[2], func(key string, value map[string]interface{}) {
|
||||||
|
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
||||||
|
m.Cmdy(value[kit.MDB_TEXT], "set", arg[3:])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
if len(arg) < 4 {
|
||||||
|
m.Richs(cmd, nil, kit.Select(kit.MDB_FOREACH, arg, 2), func(key string, val map[string]interface{}) {
|
||||||
|
if len(arg) < 3 {
|
||||||
|
m.Push(key, val[kit.MDB_META], []string{kit.MDB_TIME, kit.MDB_NAME, kit.MDB_COUNT})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
||||||
|
m.Push("", value, []string{kit.MDB_TIME})
|
||||||
|
m.Push("group", arg[2])
|
||||||
|
m.Push("", value, []string{kit.MDB_NAME, kit.MDB_TEXT})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m.Option("pod", "")
|
||||||
|
m.Cmdy(ice.WEB_LABEL, arg[0], arg[1], "web.chat.search", "get", arg[2:])
|
||||||
|
m.Sort("time", "time_r")
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
}}, nil)
|
||||||
|
}
|
462
data.go
Normal file
462
data.go
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
package ice
|
||||||
|
|
||||||
|
import (
|
||||||
|
kit "github.com/shylinux/toolkits"
|
||||||
|
|
||||||
|
"encoding/csv"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Message) Prefile(favor string, id string) map[string]string {
|
||||||
|
res := map[string]string{}
|
||||||
|
m.Option("render", "")
|
||||||
|
m.Option("_action", "")
|
||||||
|
m.Cmd(WEB_FAVOR, kit.Select(m.Option("favor"), favor), id).Table(func(index int, value map[string]string, head []string) {
|
||||||
|
res[value["key"]] = value["value"]
|
||||||
|
})
|
||||||
|
|
||||||
|
res["content"] = m.Cmdx(CLI_SYSTEM, "sed", "-n", kit.Format("%d,%dp", kit.Int(res["extra.row"]), kit.Int(res["extra.row"])+3), res["extra.buf"])
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func (m *Message) Prefix(arg ...string) string {
|
||||||
|
return kit.Keys(m.Cap(CTX_FOLLOW), arg)
|
||||||
|
}
|
||||||
|
func (m *Message) Save(arg ...string) *Message {
|
||||||
|
list := []string{}
|
||||||
|
for _, k := range arg {
|
||||||
|
list = append(list, kit.Keys(m.Cap(CTX_FOLLOW), k))
|
||||||
|
}
|
||||||
|
m.Cmd(CTX_CONFIG, "save", kit.Keys(m.Cap(CTX_FOLLOW), "json"), list)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Load(arg ...string) *Message {
|
||||||
|
list := []string{}
|
||||||
|
for _, k := range arg {
|
||||||
|
list = append(list, kit.Keys(m.Cap(CTX_FOLLOW), k))
|
||||||
|
}
|
||||||
|
m.Cmd(CTX_CONFIG, "load", kit.Keys(m.Cap(CTX_FOLLOW), "json"), list)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Message) Richs(key string, chain interface{}, raw interface{}, cb interface{}) (res map[string]interface{}) {
|
||||||
|
// 数据结构
|
||||||
|
cache := m.Confm(key, chain)
|
||||||
|
if cache == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
meta, ok := cache[kit.MDB_META].(map[string]interface{})
|
||||||
|
hash, ok := cache[kit.MDB_HASH].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
h := kit.Format(raw)
|
||||||
|
switch h {
|
||||||
|
case "*":
|
||||||
|
// 全部遍历
|
||||||
|
switch cb := cb.(type) {
|
||||||
|
case func(string, string):
|
||||||
|
for k, v := range hash {
|
||||||
|
cb(k, kit.Format(v))
|
||||||
|
}
|
||||||
|
case func(string, map[string]interface{}):
|
||||||
|
for k, v := range hash {
|
||||||
|
res = v.(map[string]interface{})
|
||||||
|
cb(k, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
case "%":
|
||||||
|
// 随机选取
|
||||||
|
if len(hash) > 0 {
|
||||||
|
list := []string{}
|
||||||
|
for k := range hash {
|
||||||
|
list = append(list, k)
|
||||||
|
}
|
||||||
|
h = list[rand.Intn(len(list))]
|
||||||
|
res, _ = hash[h].(map[string]interface{})
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// 单个查询
|
||||||
|
if res, ok = hash[h].(map[string]interface{}); !ok {
|
||||||
|
switch kit.Format(kit.Value(meta, kit.MDB_SHORT)) {
|
||||||
|
case "", "uniq":
|
||||||
|
default:
|
||||||
|
hh := kit.Hashs(h)
|
||||||
|
if res, ok = hash[hh].(map[string]interface{}); ok {
|
||||||
|
h = hh
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := path.Join(kit.Select(m.Conf(WEB_CACHE, "meta.store"), kit.Format(meta["store"])), key)
|
||||||
|
for _, k := range []string{h, hh} {
|
||||||
|
if f, e := os.Open(path.Join(prefix, kit.Keys(k, "json"))); e == nil {
|
||||||
|
defer f.Close()
|
||||||
|
if b, e := ioutil.ReadAll(f); e == nil {
|
||||||
|
if json.Unmarshal(b, &res) == e {
|
||||||
|
h = k
|
||||||
|
m.Log(LOG_IMPORT, "%s/%s.json", prefix, k)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回数据
|
||||||
|
if res != nil {
|
||||||
|
switch cb := cb.(type) {
|
||||||
|
case func(map[string]interface{}):
|
||||||
|
cb(res)
|
||||||
|
case func(string, map[string]interface{}):
|
||||||
|
cb(h, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
func (m *Message) Rich(key string, chain interface{}, data interface{}) string {
|
||||||
|
// 数据结构
|
||||||
|
cache := m.Confm(key, chain)
|
||||||
|
if cache == nil {
|
||||||
|
cache = map[string]interface{}{}
|
||||||
|
m.Confv(key, chain, cache)
|
||||||
|
}
|
||||||
|
meta, ok := cache[kit.MDB_META].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
meta = map[string]interface{}{}
|
||||||
|
cache[kit.MDB_META] = meta
|
||||||
|
}
|
||||||
|
hash, ok := cache[kit.MDB_HASH].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
hash = map[string]interface{}{}
|
||||||
|
cache[kit.MDB_HASH] = hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用数据
|
||||||
|
prefix := kit.Select("", "meta.", kit.Value(data, "meta") != nil)
|
||||||
|
if kit.Value(data, prefix+kit.MDB_TIME) == nil {
|
||||||
|
kit.Value(data, prefix+kit.MDB_TIME, m.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成键值
|
||||||
|
h := ""
|
||||||
|
switch short := kit.Format(kit.Value(meta, kit.MDB_SHORT)); short {
|
||||||
|
case "":
|
||||||
|
h = kit.ShortKey(hash, 6)
|
||||||
|
case "uniq":
|
||||||
|
h = kit.Hashs("uniq")
|
||||||
|
case "data":
|
||||||
|
h = kit.Hashs(kit.Format(data))
|
||||||
|
default:
|
||||||
|
if kit.Value(data, "meta") != nil {
|
||||||
|
h = kit.Hashs(kit.Format(kit.Value(data, "meta."+short)))
|
||||||
|
} else {
|
||||||
|
h = kit.Hashs(kit.Format(kit.Value(data, short)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加数据
|
||||||
|
if hash[h] = data; len(hash) >= kit.Int(kit.Select(m.Conf(WEB_CACHE, "meta.limit"), kit.Format(meta["limit"]))) {
|
||||||
|
least := kit.Int(kit.Select(m.Conf(WEB_CACHE, "meta.least"), kit.Format(meta["least"])))
|
||||||
|
|
||||||
|
// 时间淘汰
|
||||||
|
list := []int{}
|
||||||
|
for _, v := range hash {
|
||||||
|
list = append(list, kit.Time(kit.Format(kit.Value(v, "time"))))
|
||||||
|
}
|
||||||
|
sort.Ints(list)
|
||||||
|
dead := list[len(list)-1-least]
|
||||||
|
|
||||||
|
prefix := path.Join(kit.Select(m.Conf(WEB_CACHE, "meta.store"), kit.Format(meta["store"])), key)
|
||||||
|
for k, v := range hash {
|
||||||
|
if kit.Time(kit.Format(kit.Value(v, "time"))) > dead {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
name := path.Join(prefix, kit.Keys(k, "json"))
|
||||||
|
if f, p, e := kit.Create(name); m.Assert(e) {
|
||||||
|
defer f.Close()
|
||||||
|
// 保存数据
|
||||||
|
if n, e := f.WriteString(kit.Format(v)); m.Assert(e) {
|
||||||
|
m.Log(LOG_EXPORT, "%s: %d", p, n)
|
||||||
|
delete(hash, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
func (m *Message) Grow(key string, chain interface{}, data interface{}) int {
|
||||||
|
// 数据结构
|
||||||
|
cache := m.Confm(key, chain)
|
||||||
|
if cache == nil {
|
||||||
|
cache = map[string]interface{}{}
|
||||||
|
m.Confv(key, chain, cache)
|
||||||
|
}
|
||||||
|
meta, ok := cache[kit.MDB_META].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
meta = map[string]interface{}{}
|
||||||
|
cache[kit.MDB_META] = meta
|
||||||
|
}
|
||||||
|
list, _ := cache[kit.MDB_LIST].([]interface{})
|
||||||
|
|
||||||
|
// 通用数据
|
||||||
|
id := kit.Int(meta["count"]) + 1
|
||||||
|
prefix := kit.Select("", "meta.", kit.Value(data, "meta") != nil)
|
||||||
|
if kit.Value(data, prefix+kit.MDB_ID, id); kit.Value(data, prefix+kit.MDB_TIME) == nil {
|
||||||
|
kit.Value(data, prefix+kit.MDB_TIME, kit.Select(m.Time(), m.Option("time")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加数据
|
||||||
|
list = append(list, data)
|
||||||
|
cache[kit.MDB_LIST] = list
|
||||||
|
meta["count"] = id
|
||||||
|
|
||||||
|
// 保存数据
|
||||||
|
if len(list) >= kit.Int(kit.Select(m.Conf(WEB_CACHE, "meta.limit"), kit.Format(meta["limit"]))) {
|
||||||
|
least := kit.Int(kit.Select(m.Conf(WEB_CACHE, "meta.least"), kit.Format(meta["least"])))
|
||||||
|
|
||||||
|
record, _ := meta["record"].([]interface{})
|
||||||
|
|
||||||
|
// 文件命名
|
||||||
|
prefix := path.Join(kit.Select(m.Conf(WEB_CACHE, "meta.store"), kit.Format(meta["store"])), key)
|
||||||
|
name := path.Join(prefix, kit.Keys(kit.Select("list", chain), "csv"))
|
||||||
|
if len(record) > 0 {
|
||||||
|
name = kit.Format(kit.Value(record, kit.Keys(len(record)-1, "file")))
|
||||||
|
if s, e := os.Stat(name); e == nil {
|
||||||
|
if s.Size() > kit.Int64(kit.Select(m.Conf(WEB_CACHE, "meta.fsize"), kit.Format(meta["fsize"]))) {
|
||||||
|
name = fmt.Sprintf("%s/%s_%d.csv", prefix, kit.Select("list", chain), kit.Int(meta["offset"]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开文件
|
||||||
|
f, e := os.OpenFile(name, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
|
||||||
|
if e != nil {
|
||||||
|
f, _, e = kit.Create(name)
|
||||||
|
m.Info("%s.%v create: %s", key, chain, name)
|
||||||
|
} else {
|
||||||
|
m.Info("%s.%v append: %s", key, chain, name)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
s, e := f.Stat()
|
||||||
|
m.Assert(e)
|
||||||
|
|
||||||
|
// 保存表头
|
||||||
|
keys := []string{}
|
||||||
|
w := csv.NewWriter(f)
|
||||||
|
if s.Size() == 0 {
|
||||||
|
for k := range list[0].(map[string]interface{}) {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
w.Write(keys)
|
||||||
|
m.Info("write head: %v", keys)
|
||||||
|
w.Flush()
|
||||||
|
s, e = f.Stat()
|
||||||
|
} else {
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
keys, e = r.Read()
|
||||||
|
m.Info("read head: %v", keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建索引
|
||||||
|
count := len(list) - least
|
||||||
|
offset := kit.Int(meta["offset"])
|
||||||
|
meta["record"] = append(record, map[string]interface{}{
|
||||||
|
"time": m.Time(), "offset": offset, "count": count,
|
||||||
|
"file": name, "position": s.Size(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// 保存数据
|
||||||
|
for i, v := range list {
|
||||||
|
if i >= count {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
val := v.(map[string]interface{})
|
||||||
|
|
||||||
|
values := []string{}
|
||||||
|
for _, k := range keys {
|
||||||
|
values = append(values, kit.Format(val[k]))
|
||||||
|
}
|
||||||
|
w.Write(values)
|
||||||
|
|
||||||
|
if i < least {
|
||||||
|
list[i] = list[count+i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Log(LOG_INFO, "%s.%v save %s offset %v+%v", key, chain, name, offset, count)
|
||||||
|
meta["offset"] = offset + count
|
||||||
|
list = list[count:]
|
||||||
|
cache[kit.MDB_LIST] = list
|
||||||
|
w.Flush()
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
func (m *Message) Grows(key string, chain interface{}, match string, value string, cb interface{}) map[string]interface{} {
|
||||||
|
// 数据结构
|
||||||
|
cache := m.Confm(key, chain)
|
||||||
|
if cache == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
meta, ok := cache[kit.MDB_META].(map[string]interface{})
|
||||||
|
list, ok := cache[kit.MDB_LIST].([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据范围
|
||||||
|
offend := kit.Int(kit.Select("0", m.Option("cache.offend")))
|
||||||
|
limit := kit.Int(kit.Select("10", m.Option("cache.limit")))
|
||||||
|
current := kit.Int(meta["offset"])
|
||||||
|
end := current + len(list) - offend
|
||||||
|
begin := end - limit
|
||||||
|
switch limit {
|
||||||
|
case -1:
|
||||||
|
begin = current
|
||||||
|
case -2:
|
||||||
|
begin = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if match == kit.MDB_ID {
|
||||||
|
begin, end = kit.Int(value)-1, kit.Int(value)
|
||||||
|
match, value = "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
order := 0
|
||||||
|
if begin < current {
|
||||||
|
// 读取文件
|
||||||
|
m.Log(LOG_INFO, "%s.%v read %v-%v from %v-%v", key, chain, begin, end, current, current+len(list))
|
||||||
|
store, _ := meta["record"].([]interface{})
|
||||||
|
for s := len(store) - 1; s > -1; s-- {
|
||||||
|
item, _ := store[s].(map[string]interface{})
|
||||||
|
line := kit.Int(item["offset"])
|
||||||
|
m.Logs(LOG_INFO, "action", "check", "record", s, "offset", line, "count", item["count"])
|
||||||
|
if begin < line && s > 0 {
|
||||||
|
if kit.Int(item["count"]) != 0 {
|
||||||
|
s -= (line - begin) / kit.Int(item["count"])
|
||||||
|
}
|
||||||
|
// 向后查找
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; begin < end && s < len(store); s++ {
|
||||||
|
item, _ := store[s].(map[string]interface{})
|
||||||
|
name := kit.Format(item["file"])
|
||||||
|
pos := kit.Int(item["position"])
|
||||||
|
offset := kit.Int(item["offset"])
|
||||||
|
if offset+kit.Int(item["count"]) <= begin {
|
||||||
|
m.Logs(LOG_INFO, "action", "check", "record", s, "offset", line, "count", item["count"])
|
||||||
|
// 向前查找
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if f, e := os.Open(name); m.Assert(e) {
|
||||||
|
defer f.Close()
|
||||||
|
// 打开文件
|
||||||
|
r := csv.NewReader(f)
|
||||||
|
heads, _ := r.Read()
|
||||||
|
m.Logs(LOG_IMPORT, "head", heads)
|
||||||
|
|
||||||
|
f.Seek(int64(pos), os.SEEK_SET)
|
||||||
|
r = csv.NewReader(f)
|
||||||
|
for i := offset; i < end; i++ {
|
||||||
|
lines, e := r.Read()
|
||||||
|
if e != nil {
|
||||||
|
m.Log(LOG_IMPORT, "load head %v", e)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if i < begin {
|
||||||
|
m.Logs(LOG_INFO, "action", "skip", "offset", i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取数据
|
||||||
|
item := map[string]interface{}{}
|
||||||
|
for i := range heads {
|
||||||
|
if heads[i] == "extra" {
|
||||||
|
item[heads[i]] = kit.UnMarshal(lines[i])
|
||||||
|
} else {
|
||||||
|
item[heads[i]] = lines[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Logs(LOG_IMPORT, "offset", i, "type", item["type"], "name", item["name"], "text", item["text"])
|
||||||
|
|
||||||
|
if match == "" || strings.Contains(kit.Format(item[match]), value) {
|
||||||
|
// 匹配成功
|
||||||
|
switch cb := cb.(type) {
|
||||||
|
case func(int, map[string]interface{}):
|
||||||
|
cb(order, item)
|
||||||
|
case func(int, map[string]interface{}) bool:
|
||||||
|
if cb(order, item) {
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
order++
|
||||||
|
}
|
||||||
|
begin = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if begin < current {
|
||||||
|
begin = current
|
||||||
|
}
|
||||||
|
for i := begin - current; i < end-current; i++ {
|
||||||
|
// 读取缓存
|
||||||
|
if match == "" || strings.Contains(kit.Format(kit.Value(list[i], match)), value) {
|
||||||
|
switch cb := cb.(type) {
|
||||||
|
case func(int, map[string]interface{}):
|
||||||
|
cb(order, list[i].(map[string]interface{}))
|
||||||
|
case func(int, map[string]interface{}) bool:
|
||||||
|
if cb(order, list[i].(map[string]interface{})) {
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
order++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
func (m *Message) Show(cmd string, arg ...string) bool {
|
||||||
|
if len(arg) == 0 {
|
||||||
|
// 日志分类
|
||||||
|
m.Richs(cmd, nil, "*", func(key string, value map[string]interface{}) {
|
||||||
|
m.Push(key, value["meta"])
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(arg) < 3 {
|
||||||
|
if m.Richs(cmd, nil, arg[0], func(key string, val map[string]interface{}) {
|
||||||
|
if len(arg) == 1 {
|
||||||
|
// 日志列表
|
||||||
|
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) {
|
||||||
|
m.Push(key, value)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 日志详情
|
||||||
|
m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "id", arg[1], func(index int, value map[string]interface{}) {
|
||||||
|
m.Push("detail", value)
|
||||||
|
})
|
||||||
|
}) != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
92
info.go
Normal file
92
info.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package ice
|
||||||
|
|
||||||
|
import (
|
||||||
|
kit "github.com/shylinux/toolkits"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Message) Logs(level string, arg ...interface{}) *Message {
|
||||||
|
list := []string{}
|
||||||
|
for i := 0; i < len(arg)-1; i += 2 {
|
||||||
|
list = append(list, fmt.Sprintf("%v: %v", arg[i], arg[i+1]))
|
||||||
|
}
|
||||||
|
m.Log(level, strings.Join(list, " "))
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Log(level string, str string, arg ...interface{}) *Message {
|
||||||
|
return m.log(level, str, arg...)
|
||||||
|
}
|
||||||
|
func (m *Message) log(level string, str string, arg ...interface{}) *Message {
|
||||||
|
if str = strings.TrimSpace(fmt.Sprintf(str, arg...)); Log != nil {
|
||||||
|
// 日志模块
|
||||||
|
Log(m, level, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日志颜色
|
||||||
|
prefix, suffix := "", ""
|
||||||
|
switch level {
|
||||||
|
case LOG_ENABLE, LOG_IMPORT, LOG_CREATE, LOG_INSERT, LOG_EXPORT:
|
||||||
|
prefix, suffix = "\033[36;44m", "\033[0m"
|
||||||
|
|
||||||
|
case LOG_LISTEN, LOG_SIGNAL, LOG_TIMERS, LOG_EVENTS:
|
||||||
|
prefix, suffix = "\033[33m", "\033[0m"
|
||||||
|
|
||||||
|
case LOG_CMDS, LOG_START, LOG_SERVE:
|
||||||
|
prefix, suffix = "\033[32m", "\033[0m"
|
||||||
|
case LOG_COST:
|
||||||
|
prefix, suffix = "\033[33m", "\033[0m"
|
||||||
|
case LOG_WARN, LOG_ERROR, LOG_CLOSE:
|
||||||
|
prefix, suffix = "\033[31m", "\033[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
_, file, line, _ := runtime.Caller(2)
|
||||||
|
ls := strings.Split(file, "/")
|
||||||
|
if len(ls) > 2 {
|
||||||
|
ls = ls[len(ls)-2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("ctx_mod") != "" && m != nil {
|
||||||
|
// 输出日志
|
||||||
|
fmt.Fprintf(os.Stderr, "%s %02d %9s %s%s %s%s %s\n",
|
||||||
|
m.time.Format(ICE_TIME), m.code, fmt.Sprintf("%4s->%-4s", m.source.Name, m.target.Name),
|
||||||
|
prefix, level, str, suffix,
|
||||||
|
fmt.Sprintf("%s:%d", strings.Join(ls, "/"), line),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Cost(str string, arg ...interface{}) *Message {
|
||||||
|
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...)
|
||||||
|
}
|
||||||
|
func (m *Message) Warn(err bool, str string, arg ...interface{}) bool {
|
||||||
|
if err {
|
||||||
|
_, file, line, _ := runtime.Caller(1)
|
||||||
|
m.Echo("warn: ").Echo(str, arg...)
|
||||||
|
return m.log(LOG_WARN, "%s:%d %s", file, line, fmt.Sprintf(str, arg...)) != nil
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (m *Message) Error(err bool, str string, arg ...interface{}) bool {
|
||||||
|
if err {
|
||||||
|
m.Echo("error: ").Echo(str, arg...)
|
||||||
|
m.log(LOG_ERROR, m.Format("stack"))
|
||||||
|
m.log(LOG_ERROR, str, arg...)
|
||||||
|
m.log(LOG_ERROR, m.Format("chain"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (m *Message) Trace(key string, str string, arg ...interface{}) *Message {
|
||||||
|
if m.Options(key) {
|
||||||
|
m.Echo("trace: ").Echo(str, arg...)
|
||||||
|
return m.log(LOG_TRACE, str, arg...)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
462
meta.go
Normal file
462
meta.go
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
package ice
|
||||||
|
|
||||||
|
import (
|
||||||
|
kit "github.com/shylinux/toolkits"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Message) Add(key string, arg ...string) *Message {
|
||||||
|
switch key {
|
||||||
|
case MSG_DETAIL, MSG_RESULT:
|
||||||
|
m.meta[key] = append(m.meta[key], arg...)
|
||||||
|
|
||||||
|
case MSG_OPTION, MSG_APPEND:
|
||||||
|
if len(arg) > 0 {
|
||||||
|
if kit.IndexOf(m.meta[key], arg[0]) == -1 {
|
||||||
|
m.meta[key] = append(m.meta[key], arg[0])
|
||||||
|
}
|
||||||
|
m.meta[arg[0]] = append(m.meta[arg[0]], arg[1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Set(key string, arg ...string) *Message {
|
||||||
|
switch key {
|
||||||
|
case MSG_DETAIL, MSG_RESULT:
|
||||||
|
delete(m.meta, key)
|
||||||
|
case MSG_OPTION, MSG_APPEND:
|
||||||
|
if len(arg) > 0 {
|
||||||
|
if delete(m.meta, arg[0]); len(arg) == 1 {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, k := range m.meta[key] {
|
||||||
|
delete(m.meta, k)
|
||||||
|
}
|
||||||
|
delete(m.meta, key)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
delete(m.meta, key)
|
||||||
|
}
|
||||||
|
return m.Add(key, arg...)
|
||||||
|
}
|
||||||
|
func (m *Message) Push(key string, value interface{}, arg ...interface{}) *Message {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case map[string]string:
|
||||||
|
case map[string]interface{}:
|
||||||
|
if key == "detail" {
|
||||||
|
// 格式转换
|
||||||
|
value = kit.KeyValue(map[string]interface{}{}, "", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 键值排序
|
||||||
|
list := []string{}
|
||||||
|
if len(arg) > 0 {
|
||||||
|
list = kit.Simple(arg[0])
|
||||||
|
} else {
|
||||||
|
for k := range value {
|
||||||
|
list = append(list, k)
|
||||||
|
}
|
||||||
|
sort.Strings(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 追加数据
|
||||||
|
for _, k := range list {
|
||||||
|
switch key {
|
||||||
|
case "detail":
|
||||||
|
m.Add(MSG_APPEND, "key", k)
|
||||||
|
m.Add(MSG_APPEND, "value", kit.Format(value[k]))
|
||||||
|
default:
|
||||||
|
if k == "key" {
|
||||||
|
m.Add(MSG_APPEND, k, key)
|
||||||
|
} else {
|
||||||
|
m.Add(MSG_APPEND, k, kit.Format(kit.Value(value, k)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range kit.Simple(value) {
|
||||||
|
m.Add(MSG_APPEND, key, v)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Echo(str string, arg ...interface{}) *Message {
|
||||||
|
if len(arg) > 0 {
|
||||||
|
str = fmt.Sprintf(str, arg...)
|
||||||
|
}
|
||||||
|
m.meta[MSG_RESULT] = append(m.meta[MSG_RESULT], str)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Copy(msg *Message, arg ...string) *Message {
|
||||||
|
if m == msg {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
if len(arg) > 0 {
|
||||||
|
// 精确复制
|
||||||
|
for _, k := range arg[1:] {
|
||||||
|
if kit.IndexOf(m.meta[arg[0]], k) == -1 {
|
||||||
|
m.meta[arg[0]] = append(m.meta[arg[0]], k)
|
||||||
|
}
|
||||||
|
m.meta[k] = append(m.meta[k], msg.meta[k]...)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制选项
|
||||||
|
for _, k := range msg.meta[MSG_OPTION] {
|
||||||
|
if kit.IndexOf(m.meta[MSG_OPTION], k) == -1 {
|
||||||
|
m.meta[MSG_OPTION] = append(m.meta[MSG_OPTION], k)
|
||||||
|
}
|
||||||
|
if _, ok := msg.meta[k]; ok {
|
||||||
|
m.meta[k] = msg.meta[k]
|
||||||
|
} else {
|
||||||
|
m.data[k] = msg.data[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制数据
|
||||||
|
for _, k := range msg.meta[MSG_APPEND] {
|
||||||
|
if kit.IndexOf(m.meta[MSG_OPTION], k) > -1 && len(m.meta[k]) > 0 {
|
||||||
|
m.meta[k] = m.meta[k][:0]
|
||||||
|
}
|
||||||
|
if kit.IndexOf(m.meta[MSG_APPEND], k) == -1 {
|
||||||
|
m.meta[MSG_APPEND] = append(m.meta[MSG_APPEND], k)
|
||||||
|
}
|
||||||
|
m.meta[k] = append(m.meta[k], msg.meta[k]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制文本
|
||||||
|
m.meta[MSG_RESULT] = append(m.meta[MSG_RESULT], msg.meta[MSG_RESULT]...)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Sort(key string, arg ...string) *Message {
|
||||||
|
// 排序方法
|
||||||
|
cmp := "str"
|
||||||
|
if len(arg) > 0 && arg[0] != "" {
|
||||||
|
cmp = arg[0]
|
||||||
|
} else {
|
||||||
|
cmp = "int"
|
||||||
|
for _, v := range m.meta[key] {
|
||||||
|
if _, e := strconv.Atoi(v); e != nil {
|
||||||
|
cmp = "str"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序因子
|
||||||
|
number := map[int]int{}
|
||||||
|
table := []map[string]string{}
|
||||||
|
m.Table(func(index int, line map[string]string, head []string) {
|
||||||
|
table = append(table, line)
|
||||||
|
switch cmp {
|
||||||
|
case "int":
|
||||||
|
number[index] = kit.Int(line[key])
|
||||||
|
case "int_r":
|
||||||
|
number[index] = -kit.Int(line[key])
|
||||||
|
case "time":
|
||||||
|
number[index] = kit.Time(line[key])
|
||||||
|
case "time_r":
|
||||||
|
number[index] = -kit.Time(line[key])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 排序数据
|
||||||
|
for i := 0; i < len(table)-1; i++ {
|
||||||
|
for j := i + 1; j < len(table); j++ {
|
||||||
|
result := false
|
||||||
|
switch cmp {
|
||||||
|
case "", "str":
|
||||||
|
if table[i][key] > table[j][key] {
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
case "str_r":
|
||||||
|
if table[i][key] < table[j][key] {
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if number[i] > number[j] {
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result {
|
||||||
|
table[i], table[j] = table[j], table[i]
|
||||||
|
number[i], number[j] = number[j], number[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出数据
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
delete(m.meta, k)
|
||||||
|
}
|
||||||
|
for _, v := range table {
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
m.Add(MSG_APPEND, k, v[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Table(cbs ...interface{}) *Message {
|
||||||
|
if len(cbs) > 0 {
|
||||||
|
switch cb := cbs[0].(type) {
|
||||||
|
case func(int, map[string]string, []string):
|
||||||
|
nrow := 0
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
if len(m.meta[k]) > nrow {
|
||||||
|
nrow = len(m.meta[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < nrow; i++ {
|
||||||
|
line := map[string]string{}
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
line[k] = kit.Select("", m.meta[k], i)
|
||||||
|
}
|
||||||
|
// 依次回调
|
||||||
|
cb(i, line, m.meta[MSG_APPEND])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
//计算列宽
|
||||||
|
space := kit.Select(" ", m.Option("table.space"))
|
||||||
|
depth, width := 0, map[string]int{}
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
if len(m.meta[k]) > depth {
|
||||||
|
depth = len(m.meta[k])
|
||||||
|
}
|
||||||
|
width[k] = kit.Width(k, len(space))
|
||||||
|
for _, v := range m.meta[k] {
|
||||||
|
if kit.Width(v, len(space)) > width[k] {
|
||||||
|
width[k] = kit.Width(v, len(space))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回调函数
|
||||||
|
rows := kit.Select("\n", m.Option("table.row_sep"))
|
||||||
|
cols := kit.Select(" ", m.Option("table.col_sep"))
|
||||||
|
compact := m.Option("table.compact") == "true"
|
||||||
|
cb := func(value map[string]string, field []string, index int) bool {
|
||||||
|
for i, v := range field {
|
||||||
|
if k := m.meta[MSG_APPEND][i]; compact {
|
||||||
|
v = value[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Echo(v); i < len(field)-1 {
|
||||||
|
m.Echo(cols)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Echo(rows)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出表头
|
||||||
|
row := map[string]string{}
|
||||||
|
wor := []string{}
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
row[k], wor = k, append(wor, k+strings.Repeat(space, width[k]-kit.Width(k, len(space))))
|
||||||
|
}
|
||||||
|
if !cb(row, wor, -1) {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出数据
|
||||||
|
for i := 0; i < depth; i++ {
|
||||||
|
row := map[string]string{}
|
||||||
|
wor := []string{}
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
data := ""
|
||||||
|
if i < len(m.meta[k]) {
|
||||||
|
data = m.meta[k][i]
|
||||||
|
}
|
||||||
|
|
||||||
|
row[k], wor = data, append(wor, data+strings.Repeat(space, width[k]-kit.Width(data, len(space))))
|
||||||
|
}
|
||||||
|
// 依次回调
|
||||||
|
if !cb(row, wor, i) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Render(cmd string, args ...interface{}) *Message {
|
||||||
|
m.Log(LOG_EXPORT, "%s: %v", cmd, args)
|
||||||
|
m.Optionv(MSG_OUTPUT, cmd)
|
||||||
|
m.Optionv(MSG_ARGS, args)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case RENDER_TEMPLATE:
|
||||||
|
if len(args) == 1 {
|
||||||
|
args = append(args, m)
|
||||||
|
}
|
||||||
|
if res, err := kit.Render(args[0].(string), args[1]); m.Assert(err) {
|
||||||
|
m.Echo(string(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Parse(meta string, key string, arg ...string) *Message {
|
||||||
|
list := []string{}
|
||||||
|
for _, line := range kit.Split(strings.Join(arg, " "), "\n") {
|
||||||
|
ls := kit.Split(line)
|
||||||
|
for i := 0; i < len(ls); i++ {
|
||||||
|
if strings.HasPrefix(ls[i], "#") {
|
||||||
|
ls = ls[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list = append(list, ls...)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch data := kit.Parse(nil, "", list...); meta {
|
||||||
|
case MSG_OPTION:
|
||||||
|
m.Option(key, data)
|
||||||
|
case MSG_APPEND:
|
||||||
|
m.Append(key, data)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) Split(str string, field string, space string, enter string) *Message {
|
||||||
|
indexs := []int{}
|
||||||
|
fields := kit.Split(field, space, "{}")
|
||||||
|
for i, l := range kit.Split(str, enter, "{}") {
|
||||||
|
if i == 0 && (field == "" || field == "index") {
|
||||||
|
// 表头行
|
||||||
|
fields = kit.Split(l, space)
|
||||||
|
if field == "index" {
|
||||||
|
for _, v := range fields {
|
||||||
|
indexs = append(indexs, strings.Index(l, v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(indexs) > 0 {
|
||||||
|
// 数据行
|
||||||
|
for i, v := range indexs {
|
||||||
|
if i == len(indexs)-1 {
|
||||||
|
m.Push(kit.Select("some", fields, i), l[v:])
|
||||||
|
} else {
|
||||||
|
m.Push(kit.Select("some", fields, i), l[v:indexs[i+1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range kit.Split(l, space) {
|
||||||
|
m.Push(kit.Select("some", fields, i), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func (m *Message) CSV(text string) *Message {
|
||||||
|
bio := bytes.NewBufferString(text)
|
||||||
|
r := csv.NewReader(bio)
|
||||||
|
heads, _ := r.Read()
|
||||||
|
for {
|
||||||
|
lines, e := r.Read()
|
||||||
|
if e != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for i, k := range heads {
|
||||||
|
m.Push(k, kit.Select("", lines, i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Message) Detail(arg ...interface{}) string {
|
||||||
|
return kit.Select("", m.meta[MSG_DETAIL], 0)
|
||||||
|
}
|
||||||
|
func (m *Message) Detailv(arg ...interface{}) []string {
|
||||||
|
return m.meta[MSG_DETAIL]
|
||||||
|
}
|
||||||
|
func (m *Message) Optionv(key string, arg ...interface{}) interface{} {
|
||||||
|
if len(arg) > 0 {
|
||||||
|
// 写数据
|
||||||
|
if kit.IndexOf(m.meta[MSG_OPTION], key) == -1 {
|
||||||
|
m.meta[MSG_OPTION] = append(m.meta[MSG_OPTION], key)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch str := arg[0].(type) {
|
||||||
|
case nil:
|
||||||
|
delete(m.meta, key)
|
||||||
|
case string:
|
||||||
|
m.meta[key] = kit.Simple(arg)
|
||||||
|
case []string:
|
||||||
|
m.meta[key] = str
|
||||||
|
default:
|
||||||
|
m.data[key] = str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for msg := m; msg != nil; msg = msg.message {
|
||||||
|
if list, ok := msg.data[key]; ok {
|
||||||
|
// 读数据
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
if list, ok := msg.meta[key]; ok {
|
||||||
|
// 读选项
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *Message) Options(key string, arg ...interface{}) bool {
|
||||||
|
return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0) != ""
|
||||||
|
}
|
||||||
|
func (m *Message) Option(key string, arg ...interface{}) string {
|
||||||
|
return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0)
|
||||||
|
}
|
||||||
|
func (m *Message) Append(key string, arg ...interface{}) string {
|
||||||
|
return kit.Select("", m.Appendv(key, arg...), 0)
|
||||||
|
}
|
||||||
|
func (m *Message) Appendv(key string, arg ...interface{}) []string {
|
||||||
|
if key == "_index" {
|
||||||
|
max := 0
|
||||||
|
for _, k := range m.meta[MSG_APPEND] {
|
||||||
|
if len(m.meta[k]) > max {
|
||||||
|
max = len(m.meta[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index := []string{}
|
||||||
|
for i := 0; i < max; i++ {
|
||||||
|
index = append(index, kit.Format(i))
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
if len(arg) > 0 {
|
||||||
|
m.meta[key] = kit.Simple(arg...)
|
||||||
|
}
|
||||||
|
return m.meta[key]
|
||||||
|
}
|
||||||
|
func (m *Message) Resultv(arg ...interface{}) []string {
|
||||||
|
if len(arg) > 0 {
|
||||||
|
m.meta[MSG_RESULT] = kit.Simple(arg...)
|
||||||
|
}
|
||||||
|
return m.meta[MSG_RESULT]
|
||||||
|
}
|
||||||
|
func (m *Message) Result(arg ...interface{}) string {
|
||||||
|
if len(arg) > 0 {
|
||||||
|
switch v := arg[0].(type) {
|
||||||
|
case int:
|
||||||
|
return kit.Select("", m.meta[MSG_RESULT], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(m.Resultv(arg...), "")
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user