forked from x/icebergs
opt chat.river
This commit is contained in:
parent
0302e97674
commit
8f8c671bfb
@ -287,6 +287,7 @@ const (
|
|||||||
RENAME = "rename"
|
RENAME = "rename"
|
||||||
REMOVE = "remove"
|
REMOVE = "remove"
|
||||||
COMMIT = "commit"
|
COMMIT = "commit"
|
||||||
|
INVITE = "invite"
|
||||||
|
|
||||||
INSERT = "insert"
|
INSERT = "insert"
|
||||||
DELETE = "delete"
|
DELETE = "delete"
|
||||||
|
@ -258,6 +258,7 @@ func (f *Frame) parse(m *ice.Message, line string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
func (f *Frame) scan(m *ice.Message, file, line string, r io.Reader) *Frame {
|
func (f *Frame) scan(m *ice.Message, file, line string, r io.Reader) *Frame {
|
||||||
|
m.Option("ssh.return", func() { f.exit = true })
|
||||||
f.ps1 = kit.Simple(m.Confv("prompt", "meta.PS1"))
|
f.ps1 = kit.Simple(m.Confv("prompt", "meta.PS1"))
|
||||||
f.ps2 = kit.Simple(m.Confv("prompt", "meta.PS2"))
|
f.ps2 = kit.Simple(m.Confv("prompt", "meta.PS2"))
|
||||||
ps := f.ps1
|
ps := f.ps1
|
||||||
@ -423,8 +424,10 @@ var Index = &ice.Context{Name: "ssh", Help: "终端模块",
|
|||||||
f.printf(m, m.Cmdx(cli.PYTHON, "qrcode", strings.Join(arg, "")))
|
f.printf(m, m.Cmdx(cli.PYTHON, "qrcode", strings.Join(arg, "")))
|
||||||
}},
|
}},
|
||||||
RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
f := m.Target().Server().(*Frame)
|
switch cb := m.Optionv("ssh.return").(type) {
|
||||||
f.exit = true
|
case func():
|
||||||
|
cb()
|
||||||
|
}
|
||||||
}},
|
}},
|
||||||
|
|
||||||
REMOTE: {Name: "remote user remote port local", Help: "远程连接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
REMOTE: {Name: "remote user remote port local", Help: "远程连接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
@ -82,10 +82,9 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(arg) > 2 && arg[0] != "" {
|
if len(arg) > 2 && arg[0] != "" {
|
||||||
// m.Cmdy(SPACE, arg[0], kit.Split(kit.Keys(arg[1], strings.Join(arg[2:], " "))))
|
|
||||||
m.Cmdy(SPACE, arg[0], "context", arg[1], "command", arg[2])
|
m.Cmdy(SPACE, arg[0], "context", arg[1], "command", arg[2])
|
||||||
m.Option("_process", "_field")
|
|
||||||
m.Option("_prefix", arg[0], arg[1], arg[2], "run")
|
m.Option("_prefix", arg[0], arg[1], arg[2], "run")
|
||||||
|
m.Option("_process", "_field")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(arg) > 1 && arg[0] != "" {
|
if len(arg) > 1 && arg[0] != "" {
|
||||||
|
@ -29,12 +29,12 @@ func _serve_login(msg *ice.Message, cmds []string, w http.ResponseWriter, r *htt
|
|||||||
|
|
||||||
if !msg.Options(ice.MSG_USERNAME) && tcp.IPIsLocal(msg, msg.Option(ice.MSG_USERIP)) {
|
if !msg.Options(ice.MSG_USERNAME) && tcp.IPIsLocal(msg, msg.Option(ice.MSG_USERIP)) {
|
||||||
// 自动认证
|
// 自动认证
|
||||||
// if aaa.UserLogin(msg, cli.UserName, cli.PassWord) {
|
if aaa.UserLogin(msg, cli.UserName, cli.PassWord) {
|
||||||
// if strings.HasPrefix(msg.Option(ice.MSG_USERUA), "Mozilla/5.0") {
|
if strings.HasPrefix(msg.Option(ice.MSG_USERUA), "Mozilla/5.0") {
|
||||||
// // msg.Option(ice.MSG_SESSID, aaa.SessCreate(msg, msg.Option(ice.MSG_USERNAME), msg.Option(ice.MSG_USERROLE)))
|
// msg.Option(ice.MSG_SESSID, aaa.SessCreate(msg, msg.Option(ice.MSG_USERNAME), msg.Option(ice.MSG_USERROLE)))
|
||||||
// // Render(msg, "cookie", msg.Option(ice.MSG_SESSID))
|
// Render(msg, "cookie", msg.Option(ice.MSG_SESSID))
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := msg.Target().Commands[LOGIN]; ok {
|
if _, ok := msg.Target().Commands[LOGIN]; ok {
|
||||||
|
@ -175,6 +175,7 @@ func _space_handle(m *ice.Message, safe bool, send map[string]*ice.Message, c *w
|
|||||||
// 下发失败
|
// 下发失败
|
||||||
msg.Warn(true, "space error")
|
msg.Warn(true, "space error")
|
||||||
source, target = []string{}, kit.Revert(source)[1:]
|
source, target = []string{}, kit.Revert(source)[1:]
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
_space_echo(msg, source, target, socket, name)
|
_space_echo(msg, source, target, socket, name)
|
||||||
@ -266,7 +267,8 @@ func init() {
|
|||||||
m.Event(SPACE_START, "type", kind, "name", name, "share", share, "river", river)
|
m.Event(SPACE_START, "type", kind, "name", name, "share", share, "river", river)
|
||||||
defer m.Event(SPACE_CLOSE, "type", kind, "name", name, "share", share, "river", river)
|
defer m.Event(SPACE_CLOSE, "type", kind, "name", name, "share", share, "river", river)
|
||||||
}
|
}
|
||||||
_space_handle(m, false, m.Target().Server().(*Frame).send, s, name)
|
frame := m.Target().Server().(*Frame)
|
||||||
|
_space_handle(m, false, frame.send, s, name)
|
||||||
m.Log(ice.LOG_CLOSE, "%s: %s", name, kit.Format(m.Confv(SPACE, kit.Keys(kit.MDB_HASH, h))))
|
m.Log(ice.LOG_CLOSE, "%s: %s", name, kit.Format(m.Confv(SPACE, kit.Keys(kit.MDB_HASH, h))))
|
||||||
m.Confv(SPACE, kit.Keys(kit.MDB_HASH, h), "")
|
m.Confv(SPACE, kit.Keys(kit.MDB_HASH, h), "")
|
||||||
return nil
|
return nil
|
||||||
|
@ -16,10 +16,10 @@ var Index = &ice.Context{Name: CHAT, Help: "聊天中心",
|
|||||||
"base", kit.Dict(
|
"base", kit.Dict(
|
||||||
"info", []interface{}{
|
"info", []interface{}{
|
||||||
"web.chat.info",
|
"web.chat.info",
|
||||||
"web.chat.code",
|
"web.chat.auth",
|
||||||
"web.chat.node",
|
|
||||||
"web.chat.tool",
|
|
||||||
"web.chat.user",
|
"web.chat.user",
|
||||||
|
"web.chat.tool",
|
||||||
|
"web.chat.node",
|
||||||
},
|
},
|
||||||
"miss", []interface{}{
|
"miss", []interface{}{
|
||||||
"web.team.task",
|
"web.team.task",
|
||||||
|
@ -6,15 +6,18 @@ import (
|
|||||||
"github.com/shylinux/icebergs/base/ctx"
|
"github.com/shylinux/icebergs/base/ctx"
|
||||||
"github.com/shylinux/icebergs/base/mdb"
|
"github.com/shylinux/icebergs/base/mdb"
|
||||||
"github.com/shylinux/icebergs/base/web"
|
"github.com/shylinux/icebergs/base/web"
|
||||||
|
"github.com/shylinux/icebergs/core/code"
|
||||||
|
"github.com/shylinux/icebergs/core/wiki"
|
||||||
kit "github.com/shylinux/toolkits"
|
kit "github.com/shylinux/toolkits"
|
||||||
)
|
)
|
||||||
|
|
||||||
func _river_list(m *ice.Message) {
|
func _river_list(m *ice.Message) {
|
||||||
if m.Option("share") != "" && m.Option("share") != "" {
|
if m.Option("share") != "" && m.Option("share") != "" {
|
||||||
m.Option(ice.MSG_RIVER, m.Option("river"))
|
m.Option(ice.MSG_RIVER, m.Option("river"))
|
||||||
if m.Cmd(CODE, m.Option("share")).Append(kit.MDB_TYPE) == USER {
|
if m.Cmd(AUTH, m.Option("share")).Append(kit.MDB_TYPE) == USER {
|
||||||
if m.Cmd(USER, m.Option(ice.MSG_USERNAME)).Append(ice.MSG_USERNAME) == "" {
|
if m.Cmd(USER, m.Option(ice.MSG_USERNAME)).Append(ice.MSG_USERNAME) == "" {
|
||||||
m.Cmd(USER, mdb.INSERT, aaa.USERNAME, m.Option(ice.MSG_USERNAME))
|
m.Cmd(USER, mdb.INSERT, aaa.USERNAME, m.Option(ice.MSG_USERNAME))
|
||||||
|
// 加入群组
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,19 +27,27 @@ func _river_list(m *ice.Message) {
|
|||||||
|
|
||||||
if p := m.Option(POD); p != "" {
|
if p := m.Option(POD); p != "" {
|
||||||
m.Option(POD, "")
|
m.Option(POD, "")
|
||||||
// 代理列表
|
|
||||||
m.Cmdy(web.SPACE, p, "web.chat./river")
|
m.Cmdy(web.SPACE, p, "web.chat./river")
|
||||||
|
// 代理列表
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Richs(RIVER, nil, kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
|
m.Richs(RIVER, nil, kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
|
||||||
m.Richs(RIVER, kit.Keys(kit.MDB_HASH, key, USER), m.Option(ice.MSG_USERNAME), func(k string, val map[string]interface{}) {
|
m.Richs(RIVER, kit.Keys(kit.MDB_HASH, key, USER), m.Option(ice.MSG_USERNAME), func(k string, val map[string]interface{}) {
|
||||||
m.Push(key, value[kit.MDB_META], []string{kit.MDB_HASH, kit.MDB_NAME}, val[kit.MDB_META])
|
m.Push(key, value[kit.MDB_META], []string{kit.MDB_HASH, kit.MDB_NAME}, val[kit.MDB_META])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
func _river_proxy(m *ice.Message, pod string) (proxy []string) {
|
||||||
|
if p := kit.Select(m.Option(POD), pod); p != "" {
|
||||||
|
proxy = append(proxy, web.SPACE, p)
|
||||||
|
m.Option(POD, "")
|
||||||
|
}
|
||||||
|
return proxy
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
INFO = "info"
|
INFO = "info"
|
||||||
CODE = "code"
|
AUTH = "auth"
|
||||||
NODE = "node"
|
NODE = "node"
|
||||||
TOOL = "tool"
|
TOOL = "tool"
|
||||||
USER = "user"
|
USER = "user"
|
||||||
@ -57,51 +68,43 @@ func init() {
|
|||||||
m.Option(mdb.FIELDS, mdb.DETAIL)
|
m.Option(mdb.FIELDS, mdb.DETAIL)
|
||||||
m.Cmdy(mdb.SELECT, RIVER, "", mdb.HASH, kit.MDB_HASH, m.Option(ice.MSG_RIVER))
|
m.Cmdy(mdb.SELECT, RIVER, "", mdb.HASH, kit.MDB_HASH, m.Option(ice.MSG_RIVER))
|
||||||
}},
|
}},
|
||||||
CODE: {Name: "code hash auto 添加", Help: "共享", Action: map[string]*ice.Action{
|
AUTH: {Name: "auth hash auto 添加", Help: "授权", Action: map[string]*ice.Action{
|
||||||
mdb.CREATE: {Name: "create type=node,user name text", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
mdb.CREATE: {Name: "create type=node,user name text", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), CODE), mdb.HASH,
|
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), AUTH), mdb.HASH,
|
||||||
aaa.USERROLE, m.Option(ice.MSG_USERROLE), aaa.USERNAME, m.Option(ice.MSG_USERNAME),
|
aaa.USERROLE, m.Option(ice.MSG_USERROLE), aaa.USERNAME, m.Option(ice.MSG_USERNAME),
|
||||||
kit.MDB_TIME, m.Time("72h"), arg)
|
kit.MDB_TIME, m.Time("72h"), arg)
|
||||||
}},
|
}},
|
||||||
mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
|
mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.MODIFY, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), CODE), mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), arg)
|
m.Cmdy(mdb.MODIFY, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), AUTH), mdb.HASH,
|
||||||
|
kit.MDB_HASH, m.Option(kit.MDB_HASH), arg)
|
||||||
}},
|
}},
|
||||||
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), CODE), mdb.HASH,
|
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), AUTH), mdb.HASH,
|
||||||
kit.MDB_HASH, m.Option(kit.MDB_HASH))
|
kit.MDB_HASH, m.Option(kit.MDB_HASH))
|
||||||
}},
|
}},
|
||||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
m.Option(mdb.FIELDS, "time,hash,userrole,username,type,name,text")
|
m.Option(mdb.FIELDS, "time,hash,userrole,username,type,name,text")
|
||||||
m.Cmdy(mdb.SELECT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), CODE), mdb.HASH, kit.MDB_HASH, arg)
|
m.Cmdy(mdb.SELECT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), AUTH), mdb.HASH, kit.MDB_HASH, arg)
|
||||||
m.PushAction("删除")
|
m.PushAction("删除")
|
||||||
}},
|
}},
|
||||||
NODE: {Name: "node name ctx cmd auto 邀请", Help: "设备", Action: map[string]*ice.Action{
|
NODE: {Name: "node name ctx cmd auto 邀请", Help: "设备", Action: map[string]*ice.Action{
|
||||||
"invite": {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
|
mdb.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Option(web.SHARE, m.Cmdx(CODE, mdb.CREATE, "type", NODE))
|
m.Option(web.SHARE, m.Cmdx(AUTH, mdb.CREATE, kit.MDB_TYPE, NODE))
|
||||||
m.Cmdy("web.code.publish", "contexts", "tool")
|
m.Cmdy(code.PUBLISH, "contexts", "tool")
|
||||||
}},
|
}},
|
||||||
web.SPACE_START: {Name: "start type name share river", Help: "启动", Hand: func(m *ice.Message, arg ...string) {
|
web.SPACE_START: {Name: "start type name share river", Help: "启动", Hand: func(m *ice.Message, arg ...string) {
|
||||||
if m.Option(ice.MSG_RIVER, m.Option(RIVER)) == "" {
|
if m.Option(ice.MSG_RIVER, m.Option(RIVER)) == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if msg := m.Cmd(CODE, m.Option("share")); msg.Append(kit.MDB_TYPE) == NODE {
|
if msg := m.Cmd(AUTH, m.Option("share")); msg.Append(kit.MDB_TYPE) == NODE {
|
||||||
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(RIVER), NODE), mdb.HASH, arg)
|
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(RIVER), NODE), mdb.HASH, arg)
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
web.SPACE_CLOSE: {Name: "close", Help: "关闭", Hand: func(m *ice.Message, arg ...string) {
|
web.SPACE_CLOSE: {Name: "close", Help: "关闭", Hand: func(m *ice.Message, arg ...string) {
|
||||||
}},
|
}},
|
||||||
|
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
||||||
// mdb.INSERT: {Name: "insert route", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(RIVER), NODE), mdb.HASH,
|
||||||
// m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), NODE), mdb.HASH, arg)
|
kit.MDB_NAME, m.Option(kit.MDB_NAME))
|
||||||
// }},
|
|
||||||
// mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
|
||||||
// m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), NODE), mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH))
|
|
||||||
// }},
|
|
||||||
mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
|
|
||||||
m.Cmdy(web.ROUTE)
|
|
||||||
}},
|
|
||||||
mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
|
||||||
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(RIVER), NODE), mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME))
|
|
||||||
}},
|
}},
|
||||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
if len(arg) == 0 {
|
if len(arg) == 0 {
|
||||||
@ -112,7 +115,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
m.Cmdy(web.ROUTE, arg)
|
m.Cmdy(web.ROUTE, arg)
|
||||||
}},
|
}},
|
||||||
TOOL: {Name: "tool hash auto 添加 创建", Help: "工具", Action: map[string]*ice.Action{
|
TOOL: {Name: "tool hash id auto 添加 创建", Help: "工具", Action: map[string]*ice.Action{
|
||||||
mdb.CREATE: {Name: "create type=public,protected,private name=hi text=hello", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
|
mdb.CREATE: {Name: "create type=public,protected,private name=hi text=hello", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL), mdb.HASH, arg)
|
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL), mdb.HASH, arg)
|
||||||
}},
|
}},
|
||||||
@ -121,33 +124,36 @@ func init() {
|
|||||||
}},
|
}},
|
||||||
mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
|
mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
|
||||||
if m.Option(kit.MDB_ID) != "" {
|
if m.Option(kit.MDB_ID) != "" {
|
||||||
m.Cmdy(mdb.MODIFY, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL, kit.MDB_HASH, m.Option(kit.MDB_HASH)), mdb.LIST, kit.MDB_ID, m.Option(kit.MDB_ID), arg)
|
m.Cmdy(mdb.MODIFY, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL, kit.MDB_HASH, m.Option(kit.MDB_HASH)), mdb.LIST,
|
||||||
|
kit.MDB_ID, m.Option(kit.MDB_ID), arg)
|
||||||
} else {
|
} else {
|
||||||
m.Cmdy(mdb.MODIFY, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL), mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), arg)
|
m.Cmdy(mdb.MODIFY, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL), mdb.HASH,
|
||||||
|
kit.MDB_HASH, m.Option(kit.MDB_HASH), arg)
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL), mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH))
|
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL), mdb.HASH,
|
||||||
|
kit.MDB_HASH, m.Option(kit.MDB_HASH))
|
||||||
}},
|
}},
|
||||||
mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
|
mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
|
||||||
switch arg[0] {
|
switch arg[0] {
|
||||||
case "hash":
|
case kit.MDB_HASH:
|
||||||
m.Cmd(TOOL).Table(func(index int, value map[string]string, head []string) {
|
m.Cmd(TOOL).Table(func(index int, value map[string]string, head []string) {
|
||||||
m.Push("hash", value["hash"])
|
m.Push(kit.MDB_HASH, value[kit.MDB_HASH])
|
||||||
m.Push("name", value["name"])
|
m.Push(kit.MDB_NAME, value[kit.MDB_NAME])
|
||||||
})
|
})
|
||||||
case POD:
|
case POD:
|
||||||
m.Cmdy(web.ROUTE)
|
m.Cmdy(web.ROUTE)
|
||||||
case CTX:
|
case CTX:
|
||||||
m.Cmd(ctx.CONTEXT, "web").Table(func(index int, value map[string]string, head []string) {
|
m.Cmd(ctx.CONTEXT, "web").Table(func(index int, value map[string]string, head []string) {
|
||||||
m.Push(CTX, kit.Keys(kit.Select("", value["ups"], value["ups"] != "shy"), value["name"]))
|
m.Push(CTX, kit.Keys(kit.Select("", value["ups"], value["ups"] != "shy"), value[kit.MDB_NAME]))
|
||||||
m.Push("help", value["help"])
|
m.Push(kit.MDB_HELP, value[kit.MDB_HELP])
|
||||||
})
|
})
|
||||||
case CMD, "help":
|
case CMD, "help":
|
||||||
m.Cmd(ctx.CONTEXT, m.Option(CTX), ctx.COMMAND).Table(func(index int, value map[string]string, head []string) {
|
m.Cmd(ctx.CONTEXT, m.Option(CTX), ctx.COMMAND).Table(func(index int, value map[string]string, head []string) {
|
||||||
m.Push(CMD, value["key"])
|
m.Push(CMD, value[kit.MDB_KEY])
|
||||||
m.Push("name", value["name"])
|
m.Push(kit.MDB_NAME, value[kit.MDB_NAME])
|
||||||
m.Push("help", value["help"])
|
m.Push(kit.MDB_HELP, value[kit.MDB_HELP])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
@ -160,22 +166,36 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.Option(mdb.FIELDS, "time,id,pod,ctx,cmd,help")
|
m.Option(mdb.FIELDS, "time,id,pod,ctx,cmd,help")
|
||||||
m.Cmdy(mdb.SELECT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL, kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:])
|
msg := m.Cmd(mdb.SELECT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), TOOL, kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, kit.Select("", arg, 1))
|
||||||
if len(m.Appendv(CMD)) == 0 && len(arg) > 1 {
|
if len(msg.Appendv(CMD)) == 0 && len(arg) > 1 {
|
||||||
m.Push("cmd", arg[1])
|
msg.Push(CMD, arg[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(arg) > 2 && arg[2] == "run" {
|
||||||
|
m.Cmdy(_river_proxy(m, msg.Append(POD)), kit.Keys(msg.Append(CTX), msg.Append(CMD)), arg[3:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.Copy(msg); len(arg) < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Option("_process", "_field")
|
||||||
|
m.Option("_prefix", arg[0], arg[1], "run")
|
||||||
|
m.Table(func(index int, value map[string]string, head []string) {
|
||||||
|
m.Cmdy(web.SPACE, value[POD], ctx.CONTEXT, value[CTX], ctx.COMMAND, value[CMD])
|
||||||
|
})
|
||||||
}},
|
}},
|
||||||
USER: {Name: "user username auto 邀请", Help: "用户", Action: map[string]*ice.Action{
|
USER: {Name: "user username auto 邀请", Help: "用户", Action: map[string]*ice.Action{
|
||||||
"invite": {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
|
mdb.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
|
||||||
share := m.Option(web.SHARE, m.Cmdx(CODE, mdb.CREATE, kit.MDB_TYPE, USER))
|
share := m.Option(web.SHARE, m.Cmdx(AUTH, mdb.CREATE, kit.MDB_TYPE, USER))
|
||||||
m.Cmdy("web.wiki.spark", "inner", kit.MergeURL(m.Option(ice.MSG_USERWEB), "river", m.Option(ice.MSG_RIVER), "share", share))
|
m.Cmdy(wiki.SPARK, "inner", kit.MergeURL(m.Option(ice.MSG_USERWEB), "river", m.Option(ice.MSG_RIVER), "share", share))
|
||||||
m.Cmdy("web.wiki.image", "qrcode", kit.MergeURL(m.Option(ice.MSG_USERWEB), "river", m.Option(ice.MSG_RIVER), "share", share))
|
m.Cmdy(wiki.IMAGE, "qrcode", kit.MergeURL(m.Option(ice.MSG_USERWEB), "river", m.Option(ice.MSG_RIVER), "share", share))
|
||||||
m.Render("")
|
m.Render("")
|
||||||
}},
|
}},
|
||||||
mdb.INSERT: {Name: "insert", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
mdb.INSERT: {Name: "insert", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), USER), mdb.HASH, arg)
|
m.Cmdy(mdb.INSERT, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), USER), mdb.HASH, arg)
|
||||||
}},
|
}},
|
||||||
mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
|
||||||
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), USER), mdb.HASH, aaa.USERNAME, m.Option(aaa.USERNAME))
|
m.Cmdy(mdb.DELETE, RIVER, kit.Keys(kit.MDB_HASH, m.Option(ice.MSG_RIVER), USER), mdb.HASH, aaa.USERNAME, m.Option(aaa.USERNAME))
|
||||||
}},
|
}},
|
||||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
@ -202,7 +222,7 @@ func init() {
|
|||||||
|
|
||||||
kit.Fetch(value, func(index int, value string) {
|
kit.Fetch(value, func(index int, value string) {
|
||||||
m.Search(value, func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
|
m.Search(value, func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
|
||||||
m.Cmd(TOOL, mdb.INSERT, kit.MDB_HASH, h, "ctx", s.Cap(ice.CTX_FOLLOW), "cmd", key, "help", kit.Simple(cmd.Help)[0])
|
m.Cmd(TOOL, mdb.INSERT, kit.MDB_HASH, h, CTX, s.Cap(ice.CTX_FOLLOW), CMD, key, kit.MDB_HELP, kit.Simple(cmd.Help)[0])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -7,63 +7,30 @@ import (
|
|||||||
"github.com/shylinux/icebergs/base/web"
|
"github.com/shylinux/icebergs/base/web"
|
||||||
"github.com/shylinux/icebergs/core/wiki"
|
"github.com/shylinux/icebergs/core/wiki"
|
||||||
kit "github.com/shylinux/toolkits"
|
kit "github.com/shylinux/toolkits"
|
||||||
"github.com/shylinux/toolkits/task"
|
|
||||||
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func _alpha_find(m *ice.Message, method, word string) {
|
func _alpha_find(m *ice.Message, method, word string) {
|
||||||
// 搜索方法
|
// 搜索方法
|
||||||
switch word = strings.TrimSpace(word); method {
|
switch word = strings.TrimSpace(word); method {
|
||||||
case LINE:
|
case "line":
|
||||||
case WORD:
|
case "word":
|
||||||
word = "," + word + "$"
|
word = "," + word + "$"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索词汇
|
// 搜索词汇
|
||||||
msg := m.Cmd(cli.SYSTEM, "grep", "-rh", word, m.Conf(ALPHA, "meta.store"))
|
msg := m.Cmd(cli.SYSTEM, "grep", "-rh", word, m.Conf(ALPHA, "meta.store"))
|
||||||
msg.CSV(msg.Result(), kit.Simple(m.Confv(ALPHA, "meta.field"))...).Table(func(index int, line map[string]string, head []string) {
|
msg.CSV(msg.Result(), kit.Simple(m.Confv(ALPHA, "meta.field"))...).Table(func(index int, value map[string]string, head []string) {
|
||||||
if method == WORD && index == 0 {
|
if value["word"] == "" {
|
||||||
// 添加收藏
|
|
||||||
m.Cmd(web.FAVOR, m.Conf(ALPHA, "meta.favor"), ALPHA, line["word"], line["translation"],
|
|
||||||
"id", line["id"], "definition", line["definition"])
|
|
||||||
}
|
|
||||||
for _, k := range []string{"id", "word", "translation", "definition"} {
|
|
||||||
// 输出词汇
|
|
||||||
m.Push(k, line[k])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
func _alpha_find2(m *ice.Message, method, word string) {
|
|
||||||
p := path.Join(m.Conf(ALPHA, "meta.store"), ALPHA+".ecdict")
|
|
||||||
if ls, e := ioutil.ReadDir(p); m.Assert(e) {
|
|
||||||
args := []interface{}{}
|
|
||||||
for _, v := range ls {
|
|
||||||
args = append(args, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mu sync.Mutex
|
|
||||||
task.Wait(args, func(task *task.Task, lock *task.Lock) error {
|
|
||||||
info := task.Arg.(os.FileInfo)
|
|
||||||
file := path.Join(p, info.Name())
|
|
||||||
kit.CSV(file, 100000, func(index int, value map[string]string, head []string) {
|
|
||||||
if value["word"] != word {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
for _, k := range []string{"id", "word", "translation", "definition"} {
|
||||||
mu.Lock()
|
m.Push(k, value[k])
|
||||||
defer mu.Unlock()
|
|
||||||
m.Push("word", value["word"])
|
|
||||||
m.Push("translation", value["translation"])
|
|
||||||
m.Push("definition", value["definition"])
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
func _alpha_load(m *ice.Message, file, name string) {
|
func _alpha_load(m *ice.Message, file, name string) {
|
||||||
// 清空数据
|
// 清空数据
|
||||||
@ -89,36 +56,25 @@ func _alpha_load(m *ice.Message, file, name string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ALPHA = "alpha"
|
const ALPHA = "alpha"
|
||||||
const (
|
|
||||||
WORD = "word"
|
|
||||||
LINE = "line"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Index = &ice.Context{Name: "alpha", Help: "英汉词典",
|
var Index = &ice.Context{Name: ALPHA, Help: "英汉词典",
|
||||||
Configs: map[string]*ice.Config{
|
Configs: map[string]*ice.Config{
|
||||||
ALPHA: {Name: "alpha", Help: "英汉词典", Value: kit.Data(
|
ALPHA: {Name: ALPHA, Help: "英汉词典", Value: kit.Data(
|
||||||
kit.MDB_STORE, "usr/export/alpha", kit.MDB_FSIZE, "2000000",
|
|
||||||
kit.MDB_LIMIT, "50000", kit.MDB_LEAST, "1000",
|
kit.MDB_LIMIT, "50000", kit.MDB_LEAST, "1000",
|
||||||
"repos", "word-dict", "local", "person",
|
kit.MDB_STORE, "usr/export/alpha", kit.MDB_FSIZE, "2000000",
|
||||||
"field", []interface{}{"audio", "bnc", "collins", "definition", "detail", "exchange", "frq", "id", "oxford", "phonetic", "pos", "tag", "time", "translation", "word"},
|
kit.MDB_REPOS, "word-dict", kit.MDB_FIELD, []interface{}{"audio", "bnc", "collins", "definition", "detail", "exchange", "frq", "id", "oxford", "phonetic", "pos", "tag", "time", "translation", "word"},
|
||||||
web.FAVOR, "alpha.word",
|
|
||||||
)},
|
)},
|
||||||
},
|
},
|
||||||
Commands: map[string]*ice.Command{
|
Commands: map[string]*ice.Command{
|
||||||
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() }},
|
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() }},
|
||||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Save(ALPHA) }},
|
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Save() }},
|
||||||
|
|
||||||
"find": {Name: "find word=hi method auto", Help: "查找词汇", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
ALPHA: {Name: "alpha method=word,line word auto", Help: "英汉", Action: map[string]*ice.Action{
|
||||||
_alpha_find(m, kit.Select("word", arg, 1), arg[0])
|
mdb.IMPORT: {Name: "import file=usr/word-dict/ecdict name", Help: "加载词库", Hand: func(m *ice.Message, arg ...string) {
|
||||||
|
_alpha_load(m, m.Option(kit.MDB_FILE), kit.Select(path.Base(m.Option(kit.MDB_FILE)), m.Option(kit.MDB_NAME)))
|
||||||
}},
|
}},
|
||||||
"find2": {Name: "find word=hi method auto", Help: "查找词汇", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
_alpha_find2(m, kit.Select("word", arg, 1), arg[0])
|
_alpha_find(m, arg[0], arg[1])
|
||||||
}},
|
|
||||||
"load": {Name: "load file [name]", Help: "加载词库", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
|
||||||
if meta := m.Confm(ALPHA, "meta"); len(arg) == 0 {
|
|
||||||
arg = append(arg, path.Join("usr", kit.Format(meta["repos"]), "ecdict"))
|
|
||||||
}
|
|
||||||
_alpha_load(m, arg[0], kit.Select(path.Base(arg[0]), arg, 1))
|
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ func _input_find(m *ice.Message, method, word, limit string) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 输出词汇
|
// 输出词汇
|
||||||
m.Push(FILE, path.Base(line[0]))
|
// m.Push(FILE, path.Base(line[0]))
|
||||||
m.Push(kit.MDB_ID, line[3])
|
m.Push(kit.MDB_ID, line[3])
|
||||||
m.Push(CODE, line[2])
|
m.Push(CODE, line[2])
|
||||||
m.Push(TEXT, line[4])
|
m.Push(TEXT, line[4])
|
||||||
@ -149,9 +149,9 @@ const (
|
|||||||
LINE = "line"
|
LINE = "line"
|
||||||
)
|
)
|
||||||
const (
|
const (
|
||||||
INPUT = "input"
|
|
||||||
WUBI = "wubi"
|
WUBI = "wubi"
|
||||||
)
|
)
|
||||||
|
const INPUT = "input"
|
||||||
|
|
||||||
var Index = &ice.Context{Name: INPUT, Help: "输入法",
|
var Index = &ice.Context{Name: INPUT, Help: "输入法",
|
||||||
Configs: map[string]*ice.Config{
|
Configs: map[string]*ice.Config{
|
||||||
@ -165,13 +165,10 @@ var Index = &ice.Context{Name: INPUT, Help: "输入法",
|
|||||||
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() }},
|
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() }},
|
||||||
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Save(INPUT) }},
|
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Save(INPUT) }},
|
||||||
|
|
||||||
WUBI: {Name: "wubi path=auto auto 添加 导入", Help: "五笔", Action: map[string]*ice.Action{
|
WUBI: {Name: "wubi method=word,line code= auto", Help: "五笔", Action: map[string]*ice.Action{
|
||||||
mdb.INSERT: {Name: "insert zone=person text= code= weight=", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
mdb.INSERT: {Name: "insert zone=person text= code= weight=", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
|
||||||
_input_push(m, kit.Select("person", m.Option("zone")), m.Option("text"), m.Option("code"), m.Option("weight"))
|
_input_push(m, kit.Select("person", m.Option("zone")), m.Option("text"), m.Option("code"), m.Option("weight"))
|
||||||
}},
|
}},
|
||||||
mdb.SELECT: {Name: "select method=word code= ", Help: "查找", Hand: func(m *ice.Message, arg ...string) {
|
|
||||||
_input_find(m, kit.Select("word", m.Option("method")), m.Option("code"), m.Option("cache.limit"))
|
|
||||||
}},
|
|
||||||
mdb.EXPORT: {Name: "export file=usr/wubi-dict/person zone=person", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
|
mdb.EXPORT: {Name: "export file=usr/wubi-dict/person zone=person", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
|
||||||
// _input_save(m, kit.Select("usr/wubi-dict/person", m.Option("file")), m.Option("zone"))
|
// _input_save(m, kit.Select("usr/wubi-dict/person", m.Option("file")), m.Option("zone"))
|
||||||
}},
|
}},
|
||||||
@ -179,12 +176,7 @@ var Index = &ice.Context{Name: INPUT, Help: "输入法",
|
|||||||
_input_load(m, kit.Select("usr/wubi-dict/person", m.Option("file")), m.Option("zone"))
|
_input_load(m, kit.Select("usr/wubi-dict/person", m.Option("file")), m.Option("zone"))
|
||||||
}},
|
}},
|
||||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
m.Option(nfs.DIR_ROOT, m.Conf(INPUT, "meta.store"))
|
_input_find(m, arg[0], arg[1], m.Option("cache.limit"))
|
||||||
if len(arg) > 0 && strings.HasSuffix(arg[0], "csv") {
|
|
||||||
m.CSV(m.Cmdx(nfs.CAT, arg[0]))
|
|
||||||
} else {
|
|
||||||
m.Cmdy(nfs.DIR, kit.Select("./", arg, 0))
|
|
||||||
}
|
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 词汇列表
|
// 词汇列表
|
||||||
m.Cmd("web.code.input.wubi", "select", "code", arg[0]).Table(func(index int, value map[string]string, head []string) {
|
m.Cmd("web.code.input.wubi", "word", arg[0]).Table(func(index int, value map[string]string, head []string) {
|
||||||
m.Echo("%s\n", value["text"])
|
m.Echo("%s\n", value["text"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
22
type.go
22
type.go
@ -587,19 +587,19 @@ func (m *Message) Search(key interface{}, cb interface{}) *Message {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range []*Context{m.target, p, m.source} {
|
for _, p := range []*Context{p, m.target, m.source} {
|
||||||
for c := p; c != nil; c = c.context {
|
for s := p; s != nil; s = s.context {
|
||||||
if cmd, ok := c.Commands[key]; ok {
|
if cmd, ok := s.Commands[key]; ok {
|
||||||
cb(c, p, key, cmd)
|
cb(s.context, s, key, cmd)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case func(p *Context, s *Context, key string, conf *Config):
|
case func(p *Context, s *Context, key string, conf *Config):
|
||||||
for _, p := range []*Context{m.target, p, m.source} {
|
for _, p := range []*Context{p, m.target, m.source} {
|
||||||
for c := p; c != nil; c = c.context {
|
for s := p; s != nil; s = s.context {
|
||||||
if cmd, ok := c.Configs[key]; ok {
|
if cmd, ok := s.Configs[key]; ok {
|
||||||
cb(c.context, c, key, cmd)
|
cb(s.context, s, key, cmd)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,9 +626,9 @@ func (m *Message) Cmd(arg ...interface{}) *Message {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Search(list[0], func(p *Context, c *Context, key string, cmd *Command) {
|
m.Search(list[0], func(p *Context, s *Context, key string, cmd *Command) {
|
||||||
m.TryCatch(m.Spawns(c), true, func(msg *Message) {
|
m.TryCatch(m.Spawns(s), true, func(msg *Message) {
|
||||||
m = p.cmd(msg, cmd, key, list[1:]...)
|
m = s.cmd(msg, cmd, key, list[1:]...)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user