forked from x/icebergs
opt wss
This commit is contained in:
parent
b1fff2bb15
commit
1478d3ebde
112
base/web/web.go
112
base/web/web.go
@ -108,8 +108,8 @@ func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request
|
|||||||
if msg.Options(ice.MSG_SESSID) {
|
if msg.Options(ice.MSG_SESSID) {
|
||||||
// 会话认证
|
// 会话认证
|
||||||
sub := msg.Cmd(ice.AAA_SESS, "check", msg.Option(ice.MSG_SESSID))
|
sub := msg.Cmd(ice.AAA_SESS, "check", msg.Option(ice.MSG_SESSID))
|
||||||
msg.Log(ice.LOG_AUTH, "role: %s user: %s", msg.Option(ice.MSG_USERROLE, sub.Append("userrole")),
|
msg.Logs(ice.LOG_AUTH, "role", msg.Option(ice.MSG_USERROLE, sub.Append("userrole")),
|
||||||
msg.Option(ice.MSG_USERNAME, sub.Append("username")))
|
"user", msg.Option(ice.MSG_USERNAME, sub.Append("username")))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !msg.Options(ice.MSG_USERNAME) && IsLocalIP(msg, msg.Option(ice.MSG_USERIP)) {
|
if !msg.Options(ice.MSG_USERNAME) && IsLocalIP(msg, msg.Option(ice.MSG_USERIP)) {
|
||||||
@ -120,7 +120,7 @@ func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request
|
|||||||
msg.Option(ice.MSG_SESSID, msg.Cmdx(ice.AAA_SESS, "create", msg.Option(ice.MSG_USERNAME), msg.Option(ice.MSG_USERROLE)))
|
msg.Option(ice.MSG_SESSID, msg.Cmdx(ice.AAA_SESS, "create", msg.Option(ice.MSG_USERNAME), msg.Option(ice.MSG_USERROLE)))
|
||||||
msg.Render("cookie", msg.Option(ice.MSG_SESSID))
|
msg.Render("cookie", msg.Option(ice.MSG_SESSID))
|
||||||
}
|
}
|
||||||
msg.Log(ice.LOG_AUTH, "user: %s role: %s sess: %s", msg.Option(ice.MSG_USERNAME), msg.Option(ice.MSG_USERROLE), msg.Option(ice.MSG_SESSID))
|
msg.Logs(ice.LOG_AUTH, "role", msg.Option(ice.MSG_USERROLE), "user", msg.Option(ice.MSG_USERNAME), "sess", msg.Option(ice.MSG_SESSID))
|
||||||
}
|
}
|
||||||
|
|
||||||
if s, ok := msg.Target().Commands[ice.WEB_LOGIN]; ok {
|
if s, ok := msg.Target().Commands[ice.WEB_LOGIN]; ok {
|
||||||
@ -148,61 +148,59 @@ func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request
|
|||||||
func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn, name string) bool {
|
func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn, name string) bool {
|
||||||
for running := true; running; {
|
for running := true; running; {
|
||||||
if t, b, e := c.ReadMessage(); m.Warn(e != nil, "space recv %d msg %v", t, e) {
|
if t, b, e := c.ReadMessage(); m.Warn(e != nil, "space recv %d msg %v", t, e) {
|
||||||
|
// 解析失败
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
switch t {
|
socket, msg := c, m.Spawns(b)
|
||||||
case MSG_MAPS:
|
target := kit.Simple(msg.Optionv(ice.MSG_TARGET))
|
||||||
// 接收报文
|
source := kit.Simple(msg.Optionv(ice.MSG_SOURCE), name)
|
||||||
socket, msg := c, m.Spawn(b)
|
msg.Info("recv %v<-%v %v", target, source, msg.Format("meta"))
|
||||||
source := kit.Simple(msg.Optionv(ice.MSG_SOURCE), name)
|
|
||||||
target := kit.Simple(msg.Optionv(ice.MSG_TARGET))
|
|
||||||
msg.Info("recv %v<-%v %v", target, source, msg.Format("meta"))
|
|
||||||
|
|
||||||
if len(target) == 0 {
|
if len(target) == 0 {
|
||||||
|
msg.Option(ice.MSG_USERROLE, msg.Cmdx(ice.AAA_ROLE, "check", msg.Option(ice.MSG_USERNAME)))
|
||||||
|
msg.Logs(ice.LOG_AUTH, "role", msg.Option(ice.MSG_USERROLE), "user", msg.Option(ice.MSG_USERNAME))
|
||||||
|
if msg.Optionv(ice.MSG_HANDLE, "true"); !msg.Warn(!safe, "no right") {
|
||||||
// 本地执行
|
// 本地执行
|
||||||
msg.Option(ice.MSG_USERROLE, msg.Cmdx(ice.AAA_ROLE, "check", msg.Option(ice.MSG_USERNAME)))
|
m.Option("_dev", name)
|
||||||
msg.Log("some", "%s: %s", msg.Option(ice.MSG_USERROLE), msg.Option(ice.MSG_USERNAME))
|
msg = msg.Cmd()
|
||||||
if msg.Optionv(ice.MSG_HANDLE, "true"); !msg.Warn(!safe, "no right") {
|
|
||||||
m.Option("_dev", name)
|
|
||||||
msg = msg.Cmd()
|
|
||||||
}
|
|
||||||
if source, target = []string{}, kit.Revert(source)[1:]; msg.Detail() == "exit" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if msg.Richs(ice.WEB_SPACE, nil, target[0], func(key string, value map[string]interface{}) {
|
|
||||||
if s, ok := value["socket"].(*websocket.Conn); ok {
|
|
||||||
socket, source, target = s, source, target[1:]
|
|
||||||
} else {
|
|
||||||
socket, source, target = s, source, target[1:]
|
|
||||||
}
|
|
||||||
}) != nil {
|
|
||||||
// 转发报文
|
|
||||||
msg.Info("space route")
|
|
||||||
|
|
||||||
} else if call, ok := web.send[msg.Option(ice.MSG_TARGET)]; len(target) == 1 && ok {
|
|
||||||
// 接收响应
|
|
||||||
delete(web.send, msg.Option(ice.MSG_TARGET))
|
|
||||||
call.Back(msg)
|
|
||||||
break
|
|
||||||
|
|
||||||
} else if msg.Warn(msg.Option("_handle") == "true", "space miss") {
|
|
||||||
// 回复失败
|
|
||||||
break
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// 下发失败
|
|
||||||
msg.Warn(true, "space error")
|
|
||||||
source, target = []string{}, kit.Revert(source)[1:]
|
|
||||||
}
|
}
|
||||||
|
if source, target = []string{}, kit.Revert(source)[1:]; msg.Detail() == "exit" {
|
||||||
|
// 重启进程
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if msg.Richs(ice.WEB_SPACE, nil, target[0], func(key string, value map[string]interface{}) {
|
||||||
|
// 查询节点
|
||||||
|
if s, ok := value["socket"].(*websocket.Conn); ok {
|
||||||
|
socket, source, target = s, source, target[1:]
|
||||||
|
} else {
|
||||||
|
socket, source, target = s, source, target[1:]
|
||||||
|
}
|
||||||
|
}) != nil {
|
||||||
|
// 转发报文
|
||||||
|
|
||||||
// 发送报文
|
} else if res, ok := web.send[msg.Option(ice.MSG_TARGET)]; len(target) == 1 && ok {
|
||||||
msg.Optionv(ice.MSG_SOURCE, source)
|
// 接收响应
|
||||||
msg.Optionv(ice.MSG_TARGET, target)
|
delete(web.send, msg.Option(ice.MSG_TARGET))
|
||||||
socket.WriteMessage(t, []byte(msg.Format("meta")))
|
res.Cost("%v->%v %v %v", target, source, res.Detailv(), msg.Format("append"))
|
||||||
msg.Info("send %v %v->%v %v", t, source, target, msg.Format("meta"))
|
res.Back(msg)
|
||||||
msg.Log("cost", "%s: ", msg.Format("cost"))
|
continue
|
||||||
|
|
||||||
|
} else if msg.Warn(msg.Option("_handle") == "true", "space miss") {
|
||||||
|
// 回复失败
|
||||||
|
continue
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 下发失败
|
||||||
|
msg.Warn(true, "space error")
|
||||||
|
source, target = []string{}, kit.Revert(source)[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发送报文
|
||||||
|
msg.Optionv(ice.MSG_SOURCE, source)
|
||||||
|
msg.Optionv(ice.MSG_TARGET, target)
|
||||||
|
socket.WriteMessage(t, []byte(msg.Format("meta")))
|
||||||
|
msg.Info("send %v %v->%v %v", t, source, target, msg.Format("meta"))
|
||||||
|
msg.Cost("%v->%v %v %v", source, target, msg.Detailv(), msg.Format("append"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -904,7 +902,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
"proxy", kit.Select("master", arg, 3), "group", kit.Select("worker", arg, 4), "share", value["share"])); msg.Assert(e) {
|
"proxy", kit.Select("master", arg, 3), "group", kit.Select("worker", arg, 4), "share", value["share"])); msg.Assert(e) {
|
||||||
if s, e := net.Dial("tcp", host); !msg.Warn(e != nil, "%s", e) {
|
if s, e := net.Dial("tcp", host); !msg.Warn(e != nil, "%s", e) {
|
||||||
if s, _, e := websocket.NewClient(s, u, nil, kit.Int(msg.Conf(ice.WEB_SPACE, "meta.buffer.r")), kit.Int(msg.Conf(ice.WEB_SPACE, "meta.buffer.w"))); !msg.Warn(e != nil, "%s", e) {
|
if s, _, e := websocket.NewClient(s, u, nil, kit.Int(msg.Conf(ice.WEB_SPACE, "meta.buffer.r")), kit.Int(msg.Conf(ice.WEB_SPACE, "meta.buffer.w"))); !msg.Warn(e != nil, "%s", e) {
|
||||||
msg = m.Spawn()
|
msg = m.Spawns()
|
||||||
|
|
||||||
// 连接成功
|
// 连接成功
|
||||||
msg.Rich(ice.WEB_SPACE, nil, kit.Dict(
|
msg.Rich(ice.WEB_SPACE, nil, kit.Dict(
|
||||||
@ -920,7 +918,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
|
|
||||||
// 断线重连
|
// 断线重连
|
||||||
sleep := time.Duration(rand.Intn(kit.Int(msg.Conf(ice.WEB_SPACE, "meta.redial.a"))*i+2)+kit.Int(msg.Conf(ice.WEB_SPACE, "meta.redial.b"))) * time.Millisecond
|
sleep := time.Duration(rand.Intn(kit.Int(msg.Conf(ice.WEB_SPACE, "meta.redial.a"))*i+2)+kit.Int(msg.Conf(ice.WEB_SPACE, "meta.redial.b"))) * time.Millisecond
|
||||||
msg.Info("%d sleep: %s reconnect: %s", i, sleep, u)
|
msg.Cost("order: %d sleep: %s reconnect: %s", i, sleep, u)
|
||||||
time.Sleep(sleep)
|
time.Sleep(sleep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -951,19 +949,20 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
// 复制选项
|
// 复制选项
|
||||||
for _, k := range kit.Simple(m.Optionv("_option")) {
|
for _, k := range kit.Simple(m.Optionv("_option")) {
|
||||||
switch k {
|
switch k {
|
||||||
case "detail", "cmds":
|
case "detail", "cmds", ice.MSG_SESSID:
|
||||||
default:
|
default:
|
||||||
m.Optionv(k, m.Optionv(k))
|
m.Optionv(k, m.Optionv(k))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.Optionv("_option", m.Optionv("_option"))
|
m.Optionv("_option", m.Optionv("_option"))
|
||||||
|
m.Optionv("option", nil)
|
||||||
|
|
||||||
// 构造路由
|
// 构造路由
|
||||||
id := kit.Format(c.ID())
|
id := kit.Format(c.ID())
|
||||||
m.Set(ice.MSG_DETAIL, arg[1:]...)
|
m.Set(ice.MSG_DETAIL, arg[1:]...)
|
||||||
m.Optionv(ice.MSG_TARGET, target[1:])
|
m.Optionv(ice.MSG_TARGET, target[1:])
|
||||||
m.Optionv(ice.MSG_SOURCE, []string{id})
|
m.Optionv(ice.MSG_SOURCE, []string{id})
|
||||||
m.Info("send %s->%v %s", id, target, m.Format("meta"))
|
m.Info("send [%s]->%v %s", id, target, m.Format("meta"))
|
||||||
|
|
||||||
// 下发命令
|
// 下发命令
|
||||||
m.Target().Server().(*Frame).send[id] = m
|
m.Target().Server().(*Frame).send[id] = m
|
||||||
@ -972,7 +971,6 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
m.Call(m.Option("_async") == "", func(res *ice.Message) *ice.Message {
|
m.Call(m.Option("_async") == "", func(res *ice.Message) *ice.Message {
|
||||||
if res != nil && m != nil {
|
if res != nil && m != nil {
|
||||||
// 返回结果
|
// 返回结果
|
||||||
m.Log("cost", "%s: %s %v %v", m.Format("cost"), arg[0], arg[1:], res.Format("append"))
|
|
||||||
return m.Copy(res)
|
return m.Copy(res)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -2132,7 +2130,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
// 远程命令
|
// 远程命令
|
||||||
m.Option(ice.MSG_USERPOD, value[kit.MDB_NAME])
|
m.Option(ice.MSG_USERPOD, value[kit.MDB_NAME])
|
||||||
m.Cmd(ice.WEB_PROXY, value[kit.MDB_NAME], arg[2:]).Call(false, func(res *ice.Message) *ice.Message {
|
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 {
|
if wg.Done(); res != nil && m != nil {
|
||||||
m.Copy(res)
|
m.Copy(res)
|
||||||
}
|
}
|
||||||
|
@ -598,6 +598,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天中心",
|
|||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
m.Option("pod", "")
|
||||||
m.Cmdy(ice.WEB_LABEL, arg[0], arg[1], "web.chat.search", "get", arg[2:])
|
m.Cmdy(ice.WEB_LABEL, arg[0], arg[1], "web.chat.search", "get", arg[2:])
|
||||||
m.Sort("time", "time_r")
|
m.Sort("time", "time_r")
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -17,7 +18,14 @@ var Index = &ice.Context{Name: "code", Help: "编程中心",
|
|||||||
Caches: map[string]*ice.Cache{},
|
Caches: map[string]*ice.Cache{},
|
||||||
Configs: map[string]*ice.Config{
|
Configs: map[string]*ice.Config{
|
||||||
"install": {Name: "install", Help: "安装", Value: kit.Data("path", "usr/install",
|
"install": {Name: "install", Help: "安装", Value: kit.Data("path", "usr/install",
|
||||||
"source", "https://dl.google.com/go/go1.14.2.src.tar.gz", "target", "usr/local",
|
"linux", "https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz",
|
||||||
|
"darwin", "https://dl.google.com/go/go1.14.2.darwin-amd64.pkg",
|
||||||
|
"windows", "https://dl.google.com/go/go1.14.2.windows-amd64.msi",
|
||||||
|
"source", "https://dl.google.com/go/go1.14.2.src.tar.gz",
|
||||||
|
"target", "usr/local", "script", ".ish/pluged/golang/init.sh", "export", kit.Dict(
|
||||||
|
"GOPROXY", "https://goproxy.cn,direct",
|
||||||
|
"GOPRIVATE", "https://github.com",
|
||||||
|
),
|
||||||
)},
|
)},
|
||||||
"prepare": {Name: "prepare", Help: "配置", Value: kit.Data("path", "usr/prepare")},
|
"prepare": {Name: "prepare", Help: "配置", Value: kit.Data("path", "usr/prepare")},
|
||||||
"project": {Name: "project", Help: "项目", Value: kit.Data("path", "usr/project")},
|
"project": {Name: "project", Help: "项目", Value: kit.Data("path", "usr/project")},
|
||||||
@ -45,15 +53,29 @@ var Index = &ice.Context{Name: "code", Help: "编程中心",
|
|||||||
}},
|
}},
|
||||||
|
|
||||||
ice.CODE_INSTALL: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
ice.CODE_INSTALL: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
p := path.Join(m.Conf("install", "meta.path"), "go")
|
p := path.Join(m.Conf("install", "meta.path"), path.Base(m.Conf("install", kit.Keys("meta", runtime.GOOS))))
|
||||||
|
// 下载
|
||||||
if _, e := os.Stat(p); e != nil {
|
if _, e := os.Stat(p); e != nil {
|
||||||
// 下载源码
|
|
||||||
m.Option("cmd_dir", m.Conf("install", "meta.path"))
|
m.Option("cmd_dir", m.Conf("install", "meta.path"))
|
||||||
m.Cmd(ice.CLI_SYSTEM, "wget", "-O", "go.tar.gz", m.Conf("install", "meta.source"))
|
m.Cmd(ice.CLI_SYSTEM, "wget", m.Conf("install", kit.Keys("meta", runtime.GOOS)))
|
||||||
m.Cmd(ice.CLI_SYSTEM, "tar", "xvf", "go.tar.gz")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 安装
|
||||||
|
m.Option("cmd_dir", "")
|
||||||
|
os.MkdirAll(m.Conf("install", kit.Keys("meta.target")), 0777)
|
||||||
|
m.Cmdy(ice.CLI_SYSTEM, "tar", "xvf", p, "-C", m.Conf("install", kit.Keys("meta.target")))
|
||||||
}},
|
}},
|
||||||
ice.CODE_PREPARE: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
ice.CODE_PREPARE: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
export := []string{}
|
||||||
|
kit.Fetch(m.Confv("install", "meta.export"), func(key string, val string) {
|
||||||
|
export = append(export, key+"="+val)
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Cmd("nfs.save", m.Conf("install", "meta.script"), kit.Format(`
|
||||||
|
export GOROOT=%s GOPATH=%s:$GOPATH GOBIN=%s
|
||||||
|
export PATH=$GOBIN:$GOROOT/bin:$PATH
|
||||||
|
export %s
|
||||||
|
`, kit.Path(m.Conf("install", kit.Keys("meta.target")), "go"), kit.Path("src"), kit.Path("bin"), strings.Join(export, " ")))
|
||||||
}},
|
}},
|
||||||
ice.CODE_PROJECT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
ice.CODE_PROJECT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
}},
|
}},
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
kit "github.com/shylinux/toolkits"
|
kit "github.com/shylinux/toolkits"
|
||||||
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
@ -14,7 +16,14 @@ import (
|
|||||||
var Index = &ice.Context{Name: "zsh", Help: "命令行",
|
var Index = &ice.Context{Name: "zsh", Help: "命令行",
|
||||||
Caches: map[string]*ice.Cache{},
|
Caches: map[string]*ice.Cache{},
|
||||||
Configs: map[string]*ice.Config{
|
Configs: map[string]*ice.Config{
|
||||||
"zsh": {Name: "zsh", Help: "命令行", Value: kit.Data("history", "zsh.history")},
|
"zsh": {Name: "zsh", Help: "命令行", Value: kit.Data(
|
||||||
|
"history", "zsh.history", "script", []interface{}{
|
||||||
|
".bashrc", "etc/conf/bashrc",
|
||||||
|
".zshrc", "etc/conf/zshrc",
|
||||||
|
".ish/init.sh", "etc/conf/ishrc",
|
||||||
|
".vim/syntax/sh.vim", "etc/conf/sh.vim",
|
||||||
|
},
|
||||||
|
)},
|
||||||
},
|
},
|
||||||
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) {
|
||||||
@ -28,6 +37,12 @@ var Index = &ice.Context{Name: "zsh", Help: "命令行",
|
|||||||
m.Cmdy(kit.Split(kit.Format(value["text"])))
|
m.Cmdy(kit.Split(kit.Format(value["text"])))
|
||||||
}}))
|
}}))
|
||||||
}},
|
}},
|
||||||
|
ice.CODE_PREPARE: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
|
list := kit.Simple(m.Confv("zsh", "meta.script"))
|
||||||
|
for i := 0; i < len(list); i += 2 {
|
||||||
|
m.Cmd("nfs.link", path.Join(os.Getenv("HOME"), list[i]), list[i+1])
|
||||||
|
}
|
||||||
|
}},
|
||||||
ice.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
ice.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||||
if f, _, e := m.R.FormFile("sub"); e == nil {
|
if f, _, e := m.R.FormFile("sub"); e == nil {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
2
type.go
2
type.go
@ -728,6 +728,8 @@ func (m *Message) Optionv(key string, arg ...interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch str := arg[0].(type) {
|
switch str := arg[0].(type) {
|
||||||
|
case nil:
|
||||||
|
delete(m.meta, key)
|
||||||
case string:
|
case string:
|
||||||
m.meta[key] = kit.Simple(arg)
|
m.meta[key] = kit.Simple(arg)
|
||||||
case []string:
|
case []string:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user