1
0
mirror of https://shylinux.com/x/icebergs synced 2025-06-26 10:27:31 +08:00
This commit is contained in:
harveyshao 2022-11-19 22:54:37 +08:00
parent deca0a8e8d
commit 15c6d3f064
25 changed files with 657 additions and 983 deletions

128
README.md
View File

@ -1,129 +1,3 @@
# icebergs
icebergs是一个应用框架通过模块化、集群化、自动化快速搭建起完整的个人云计算平台。
- 使用icebergs可以将各种模块或项目集成到一起快速开发出集中式的服务器。
- 使用icebergs可以将各种设备自由的组合在一起快速搭建起分布式的服务器。
## 0. 搭建服务
### 0.1 一键部署
```sh
mkdir miss; cd miss && curl -s https://shylinux.com/publish/ice.sh | sh
```
脚本会根据当前系统类型自动下载程序文件ice.bin并自动启动服务。
### 0.2 使用方式
**终端交互**
启动后的进程像bash一样是一个可交互的shell可以执行各种模块命令或系统命令。
**网页交互**
默认还会启动一个web服务访问地址 http://localhost:9020 ,就可以通过网页进行操作。
**重启服务**
在终端按Ctrl+C就可以重新启动服务。
**结束服务**
在终端按Ctrl+\,就可以停止服务。
### 0.3 使用示例
## 1. 项目开发
icebergs是一个应用框架如果官方模块无法满足使用需求还可以搜集第三方模块自行编译程序。
如果第三方模块也无法满足使用需求,还可以自己开发模块,
icebergs提供了模板可以一键创建新模块快速添加自己的功能模块。
### 1.1 部署环境
*开发环境需要提前安装好git和golang*
```sh
mkdir miss; cd miss && curl -s https://shylinux.com/publish/template.sh | sh
```
template.sh会自动创建出项目模板并自动编译生成程序然后启动服务。
为了方便以后创建项目与模块。
可以将辅助脚本template.sh下载并添加到可执行目录中。
### 1.2 添加第三方模块
在src/main.go文件中就可以import任意的第三方模块
执行一下make命令就会重新生成ice.bin。
重新启动服务,就可以使用第三方模块了。
### 1.3 开发模块
```sh
template.sh tutor hello
```
使用之前下载的template.sh调用tutor命令并指定模块名称hello就可以一键创建模块了。
在src/main.go 中import新加的模块
执行make命令程序编译完成后
重启服务,就可以使用新模块了。
### 1.4 开发框架
如果现有的框架,无法满足需求,还可以下载框架源码自行更改。
```sh
git clone https://shylinux.com/x/icebergs usr/icebergs
```
修改go.mod文件引用本地框架。
```go
replace shylinux.com/x/icebergs => ./usr/icebergs
```
## 2 原型 type.go
### 2.1 msg.Detail
### 2.2 msg.Option
### 2.3 msg.Append
### 2.4 msg.Result
### 2.5 msg.Travel
### 2.6 msg.Search
### 2.7 msg.Conf
### 2.8 msg.Cmd
### 2.9 msg.Cap
## 3 框架 base.go
### 3.1 注册模块 Register
### 3.2 创建资源 Begin
### 3.3 加载配置 _init
### 3.4 启动服务 Start
### 3.5 保存配置 _exit
### 3.6 释放资源 Close
## 4 基础模块 base/
### 4.1 模块中心 base/ctx/
### 4.2 命令中心 base/cli/
### 4.3 认证中心 base/aaa/
### 4.4 网页中心 base/web/
### 4.5 词法中心 base/lex/
### 4.6 语法中心 base/yac/
### 4.7 事件中心 base/gdb/
### 4.8 日志中心 base/log/
### 4.9 网络中心 base/tcp/
### 4.10 文件中心 base/nfs/
### 4.11 终端中心 base/ssh/
### 4.12 数据中心 base/mdb/
## 5 核心模块 core/
### 5.1 编程中心 core/code/
### 5.2 文档中心 core/wiki/
### 5.3 聊天中心 core/chat/
### 5.4 团队中心 core/team/
### 5.5 贸易中心 core/mall/
## 6 其它模块 misc/
### 6.1 终端管理 misc/zsh/
### 6.1 终端管理 misc/tmux/
### 6.1 代码管理 misc/git/
### 6.1 代码管理 misc/vim/
### 6.1 公众号 misc/mp/
### 6.1 小程序 misc/wx/
### 6.1 浏览器 misc/chrome/
### 6.1 机器人 misc/lark/
### 6.1 开发板 misc/pi/
icebergs 是一个应用框架,通过模块化、集群化、自动化方式,在各种设备上,一键部署完整的个人云计算与云研发平台。

View File

@ -83,11 +83,11 @@ func init() {
}
func UserRoot(m *ice.Message, arg ...string) *ice.Message { // password username userrole
userrole := m.Option(ice.MSG_USERROLE, ROOT)
username := m.Option(ice.MSG_USERNAME, kit.Select(ice.Info.UserName, arg, 1))
userrole := m.Option(ice.MSG_USERROLE, kit.Select(ROOT, arg, 2))
m.Option(ice.MSG_USERNICK, UserNick(m, username))
usernick := m.Option(ice.MSG_USERNICK, kit.Select(UserNick(m, username), arg, 2))
if len(arg) > 0 {
m.Cmd(USER, mdb.CREATE, username, kit.Select("", arg, 0), userrole, kit.Select("", arg, 3))
m.Cmd(USER, mdb.CREATE, username, kit.Select("", arg, 0), userrole, usernick)
ice.Info.UserName = username
}
return m

View File

@ -216,7 +216,7 @@ func init() {
}},
PROCKILL: {Name: "prockill", Help: "结束进程", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(gdb.SIGNAL, gdb.STOP, m.Option("PID"))
m.ProcessRefresh30ms()
m.ProcessRefresh()
}},
DISKINFO: {Name: "diskinfo", Help: "磁盘信息", Hand: func(m *ice.Message, arg ...string) {
_runtime_diskinfo(m)

View File

@ -191,7 +191,7 @@ var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands
}
}},
INSERT: {Name: "insert key sub type arg...", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
defer m.ProcessRefresh3ms()
defer m.ProcessRefresh()
switch arg[2] {
case ZONE: // insert key sub type zone arg...
_zone_insert(m, arg[0], arg[1], arg[3], arg[4:]...)
@ -202,7 +202,7 @@ var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands
}
}},
DELETE: {Name: "delete key sub type field value", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
defer m.ProcessRefresh3ms()
defer m.ProcessRefresh()
switch arg[2] {
case ZONE: // delete key sub type zone field value
// _list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5])

View File

@ -9,6 +9,13 @@ const SEARCH = "search"
func init() {
Index.MergeCommands(ice.Commands{SEARCH: {Name: "search type name text auto", Help: "搜索", Actions: RenderAction()}})
ice.AddMerges(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) (ice.Handler, ice.Handler) {
switch sub {
case SEARCH:
return func(m *ice.Message, arg ...string) { m.Cmd(SEARCH, CREATE, m.CommandKey(), m.PrefixKey()) }, nil
}
return nil, nil
})
}
func SearchAction() ice.Actions {
return ice.Actions{

View File

@ -36,6 +36,9 @@ func (f *Frame) prompt(m *ice.Message, list ...string) *Frame {
if f.source != STDIO {
return f
}
if m.Target().Cap(ice.CTX_STATUS) == ice.CTX_CLOSE {
return f
}
if len(list) == 0 {
list = append(list, f.ps1...)
}
@ -106,7 +109,6 @@ func (f *Frame) parse(m *ice.Message, h, line string) string {
if msg.Cmdy(ls); h == STDIO && msg.IsErrNotFound() {
msg.SetResult().Cmdy(cli.SYSTEM, ls)
}
f.res = Render(msg, msg.Option(ice.MSG_OUTPUT), msg.Optionv(ice.MSG_ARGS).([]ice.Any)...)
return ""
}

View File

@ -31,7 +31,7 @@ func _dream_list(m *ice.Message) *ice.Message {
m.PushButton(cli.START, nfs.TRASH)
}
})
return m.Sort("status,type,name").StatusTimeCount(cli.START, len(list))
return m.Sort("status,type,name", ice.STR, ice.STR, ice.STR_R).StatusTimeCount(cli.START, len(list))
}
func _dream_show(m *ice.Message, name string) {
if m.Warn(name == "", ice.ErrNotValid) {
@ -61,7 +61,7 @@ func _dream_show(m *ice.Message, name string) {
kit.EnvSimple(cli.HOME, cli.TERM, cli.SHELL), m.Configv(cli.ENV),
))
m.Optionv(cli.CMD_OUTPUT, path.Join(p, ice.BIN_BOOT_LOG))
defer m.OptionMulti(cli.CMD_DIR, "", cli.CMD_ENV, "", cli.CMD_OUTPUT, "")
defer m.Options(cli.CMD_DIR, "", cli.CMD_ENV, "", cli.CMD_OUTPUT, "")
gdb.Event(m, DREAM_CREATE, m.OptionSimple(mdb.NAME, mdb.TYPE))
defer ToastProcess(m)()

View File

@ -41,7 +41,7 @@ func _serve_rewrite(m *ice.Message) {
return Render(msg, ice.RENDER_DOWNLOAD, path.Join(msg.Config(kit.Keys(repos, nfs.PATH)), msg.Config(kit.Keys(repos, INDEX))))
case PP(ice.HELP):
r.URL.Path = P(ice.HELP, ice.TUTOR_SHY)
r.URL.Path = P(ice.HELP, "tutor.shy")
}
p := path.Join(ice.USR, repos, r.URL.Path)
@ -89,11 +89,7 @@ func _serve_start(m *ice.Message) {
if cli.NodeInfo(m, SERVER, kit.Select(ice.Info.HostName, m.Option("nodename"))); m.Option(tcp.PORT) == tcp.RANDOM {
m.Option(tcp.PORT, m.Cmdx(tcp.PORT, aaa.RIGHT))
}
if m.Option("staffname") != "" {
m.Config("staffname", m.Option(aaa.USERNAME, m.Option("staffname")))
}
aaa.UserRoot(m, m.Option(aaa.PASSWORD), m.Option(aaa.USERNAME), m.Option(aaa.USERROLE), m.Option(aaa.USERNICK))
aaa.UserRoot(m, m.Option(aaa.PASSWORD), m.Option(aaa.USERNAME), m.Option(aaa.USERNICK))
m.Target().Start(m, m.OptionSimple(tcp.HOST, tcp.PORT)...)
m.Go(func() { m.Cmd(BROAD, SERVE) })
@ -364,7 +360,7 @@ func init() {
ctx.DisplayStorySpide(m, lex.PREFIX, m.ActionKey(), nfs.ROOT, MergeLink(m, ice.PS))
}
}},
cli.START: {Name: "start dev proto=http host port=9020 nodename password username userrole usernick staffname", Help: "启动", Hand: func(m *ice.Message, arg ...string) {
cli.START: {Name: "start dev proto=http host port=9020 nodename password username usernick", Help: "启动", Hand: func(m *ice.Message, arg ...string) {
_serve_start(m)
}},
}, mdb.HashAction())},
@ -396,7 +392,7 @@ func init() {
}},
PP(ice.HELP): {Name: "/help/", Help: "帮助", Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
arg = append(arg, ice.TUTOR_SHY)
arg = append(arg, "tutor.shy")
}
if len(arg) > 0 && arg[0] != ctx.ACTION {
arg[0] = path.Join(ice.SRC_HELP, arg[0])
@ -404,4 +400,13 @@ func init() {
m.Cmdy("web.chat./cmd/", arg)
}},
}})
ice.AddMerges(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) (ice.Handler, ice.Handler) {
if strings.HasPrefix(sub, ice.PS) {
if sub = kit.Select(sub, PP(key), sub == ice.PS); action.Hand == nil {
action.Hand = func(m *ice.Message, arg ...string) { m.Cmdy(key, arg) }
}
c.Commands[sub] = &ice.Command{Name: sub, Help: cmd.Help, Hand: action.Hand}
}
return nil, nil
})
}

195
conf.go
View File

@ -14,12 +14,12 @@ const (
OK = "ok"
TRUE = "true"
FALSE = "false"
SUCCESS = "success"
FAILURE = "failure"
PROCESS = "process"
FAILURE = "failure"
SUCCESS = "success"
AUTO = "auto"
HTTP = "http"
AUTO = "auto"
LIST = "list"
BACK = "back"
@ -28,6 +28,7 @@ const (
MISC = "misc"
SHY = "shy"
COM = "com"
DEV = "dev"
OPS = "ops"
ICE = "ice"
@ -49,16 +50,16 @@ const ( // MOD
MOD_TIME = "2006-01-02 15:04:05"
)
const ( // REPOS
VOLCANOS = "volcanos"
LEARNING = "learning"
ICEBERGS = "icebergs"
TOOLKITS = "toolkits"
INTSHELL = "intshell"
CONTEXTS = "contexts"
ICEBERGS = "icebergs"
TOOLKITS = "toolkits"
VOLCANOS = "volcanos"
LEARNING = "learning"
INSTALL = "install"
RELEASE = "release"
PUBLISH = "publish"
RELEASE = "release"
REQUIRE = "require"
DISPLAY = "display"
)
@ -69,12 +70,12 @@ const ( // DIR
VAR = "var"
USR = "usr"
SVG = "svg"
HTML = "html"
CSS = "css"
JS = "js"
GO = "go"
SH = "sh"
SVG = "svg"
CSV = "csv"
JSON = "json"
@ -89,45 +90,41 @@ const ( // DIR
FRAME_JS = "frame.js"
INDEX_JS = "index.js"
INDEX_SH = "index.sh"
INDEX_IML = "index.iml"
TUTOR_SHY = "tutor.shy"
PLUGIN_INPUT = "/plugin/input"
PLUGIN_STORY = "/plugin/story"
PLUGIN_LOCAL = "/plugin/local"
NODE_MODULES = "node_modules"
ISH_PLUGED = ".ish/pluged"
PLUGIN_INPUT = "/plugin/input/"
PLUGIN_STORY = "/plugin/story/"
PLUGIN_LOCAL = "/plugin/local/"
NODE_MODULES = "node_modules/"
ISH_PLUGED = ".ish/pluged/"
USR_VOLCANOS = "usr/volcanos"
USR_LEARNING = "usr/learning"
USR_ICEBERGS = "usr/icebergs"
USR_TOOLKITS = "usr/toolkits"
USR_INTSHELL = "usr/intshell"
USR_INSTALL = "usr/install"
USR_RELEASE = "usr/release"
USR_PUBLISH = "usr/publish"
USR_VOLCANOS = "usr/volcanos/"
USR_LEARNING = "usr/learning/"
USR_ICEBERGS = "usr/icebergs/"
USR_TOOLKITS = "usr/toolkits/"
USR_INTSHELL = "usr/intshell/"
USR_INSTALL = "usr/install/"
USR_PUBLISH = "usr/publish/"
USR_RELEASE = "usr/release/"
USR_LOCAL = "usr/local"
USR_LOCAL_GO = "usr/local/go"
USR_LOCAL_GO_BIN = "usr/local/go/bin"
USR_LOCAL_BIN = "usr/local/bin"
USR_LOCAL_LIB = "usr/local/lib"
USR_LOCAL_WORK = "usr/local/work"
USR_LOCAL_IMAGE = "usr/local/image"
USR_LOCAL_MEDIA = "usr/local/media"
USR_LOCAL_RIVER = "usr/local/river"
USR_LOCAL_DAEMON = "usr/local/daemon"
USR_LOCAL_EXPORT = "usr/local/export"
USR_LOCAL_REPOS = "usr/local/repos"
USR_LOCAL = "usr/local/"
USR_LOCAL_GO = "usr/local/go/"
USR_LOCAL_GO_BIN = "usr/local/go/bin/"
USR_LOCAL_BIN = "usr/local/bin/"
USR_LOCAL_LIB = "usr/local/lib/"
USR_LOCAL_WORK = "usr/local/work/"
USR_LOCAL_IMAGE = "usr/local/image/"
USR_LOCAL_DAEMON = "usr/local/daemon/"
USR_LOCAL_EXPORT = "usr/local/export/"
USR_LOCAL_REPOS = "usr/local/repos/"
VAR_RUN = "var/run"
VAR_TMP = "var/tmp"
VAR_LOG = "var/log"
VAR_CONF = "var/conf"
VAR_DATA = "var/data"
VAR_FILE = "var/file"
VAR_PROXY = "var/proxy"
VAR_TRASH = "var/trash"
VAR_RUN = "var/run/"
VAR_TMP = "var/tmp/"
VAR_LOG = "var/log/"
VAR_CONF = "var/conf/"
VAR_DATA = "var/data/"
VAR_FILE = "var/file/"
VAR_PROXY = "var/proxy/"
VAR_TRASH = "var/trash/"
BIN_ICE_BIN = "bin/ice.bin"
BIN_BOOT_LOG = "bin/boot.log"
ETC_INIT_SHY = "etc/init.shy"
@ -136,13 +133,13 @@ const ( // DIR
ETC_MISS_SH = "etc/miss.sh"
ETC_PATH = "etc/path"
SRC_HELP = "src/help"
SRC_DEBUG = "src/debug"
SRC_RELEASE = "src/release"
SRC_HELP = "src/help/"
SRC_DEBUG = "src/debug/"
SRC_RELEASE = "src/release/"
SRC_MAIN_SVG = "src/main.svg"
SRC_MAIN_SHY = "src/main.shy"
SRC_MAIN_JS = "src/main.js"
SRC_MAIN_GO = "src/main.go"
SRC_MAIN_SHY = "src/main.shy"
SRC_MAIN_SVG = "src/main.svg"
SRC_VERSION_GO = "src/version.go"
SRC_BINPACK_GO = "src/binpack.go"
SRC_RELAY_GO = "src/relay.go"
@ -167,8 +164,8 @@ const ( // MSG
MSG_SOURCE = "_source"
MSG_TARGET = "_target"
MSG_HANDLE = "_handle"
MSG_DAEMON = "_daemon"
MSG_UPLOAD = "_upload"
MSG_DAEMON = "_daemon"
MSG_ACTION = "_action"
MSG_STATUS = "_status"
@ -193,24 +190,25 @@ const ( // MSG
MSG_USERZONE = "user.zone"
MSG_LANGUAGE = "user.lang"
MSG_TITLE = "sess.title"
MSG_TOPIC = "sess.topic"
MSG_RIVER = "sess.river"
MSG_STORM = "sess.storm"
MSG_FILES = "file.system"
MSG_TITLE = "sess.title"
MSG_TOPIC = "sess.topic"
MSG_RIVER = "sess.river"
MSG_STORM = "sess.storm"
MSG_FILES = "file.system"
LOG_DISABLE = "log.disable"
FIELDS_DETAIL = "detail"
)
const ( // RENDER
RENDER_TEMPLATE = "_template"
RENDER_ANCHOR = "_anchor"
RENDER_BUTTON = "_button"
RENDER_IMAGES = "_images"
RENDER_VIDEOS = "_videos"
RENDER_IFRAME = "_iframe"
RENDER_QRCODE = "_qrcode"
RENDER_SCRIPT = "_script"
RENDER_BUTTON = "_button"
RENDER_ANCHOR = "_anchor"
RENDER_QRCODE = "_qrcode"
RENDER_IMAGES = "_images"
RENDER_VIDEOS = "_videos"
RENDER_IFRAME = "_iframe"
RENDER_SCRIPT = "_script"
RENDER_TEMPLATE = "_template"
RENDER_STATUS = "_status"
RENDER_REDIRECT = "_redirect"
RENDER_DOWNLOAD = "_download"
@ -227,9 +225,9 @@ const ( // PROCESS
PROCESS_REFRESH = "_refresh"
PROCESS_REWRITE = "_rewrite"
PROCESS_DISPLAY = "_display"
PROCESS_INNER = "_inner"
PROCESS_FIELD = "_field"
PROCESS_FLOAT = "_float"
PROCESS_INNER = "_inner"
PROCESS_AGAIN = "_again"
PROCESS_HOLD = "_hold"
@ -242,6 +240,9 @@ const ( // PROCESS
FIELD_PREFIX = "_prefix"
)
const ( // CTX
CTX_ARG = "ctx_arg"
CTX_DAEMON = "ctx_daemon"
CTX_FOLLOW = "follow"
CTX_STATUS = "status"
CTX_STREAM = "stream"
@ -253,50 +254,64 @@ const ( // CTX
CTX_INIT = "_init"
CTX_EXIT = "_exit"
CTX_ARG = "ctx_arg"
CTX_DAEMON = "ctx_daemon"
)
const ( // LOG
LOG_CMDS = "cmds"
LOG_AUTH = "auth"
LOG_COST = "cost"
LOG_INFO = "info"
LOG_WARN = "warn"
LOG_DEBUG = "debug"
LOG_ERROR = "error"
LOG_DEBUG = "debug"
)
const ( // Err
ErrWarn = "warn: "
ErrNotLogin = "not login: "
ErrNotRight = "not right: "
ErrNotFound = "not found: "
ErrNotValid = "not valid: "
ErrNotStart = "not start: "
ErrNotLogin = "not login: "
ErrNotRight = "not right: "
ErrNotFound = "not found: "
ErrNotValid = "not valid: "
ErrNotStart = "not start: "
ErrNotImplement = "not implement: "
)
const ( // ctx
COMMAND = "command"
ACTION = "action"
STYLE = "style"
INDEX = "index"
)
const ( // mdb
AAA = "aaa"
MDB = "mdb"
KEY = "key"
VALUE = "value"
FIELD = "field"
EXTRA = "extra"
SCRIPT = "script"
META = "meta"
HASH = "hash"
TIME = "time"
TYPE = "type"
NAME = "name"
TEXT = "text"
LINK = "link"
const ( // web
SERVE = "serve"
SPACE = "space"
TOPIC = "topic"
TITLE = "title"
WIDTH = "width"
HEIGHT = "height"
)
const ( // nfs
SOURCE = "source"
SCRIPT = "script"
)
const ( // mdb
SEARCH = "search"
SELECT = "select"
KEY = "key"
VALUE = "value"
EXTRA = "extra"
FIELD = "field"
META = "meta"
HASH = "hash"
TIME = "time"
TYPE = "type"
NAME = "name"
TEXT = "text"
LINK = "link"
)
const ( // ice
MDB = "mdb"
AAA = "aaa"
CLI = "cli"
)

View File

@ -89,7 +89,7 @@ func _website_parse(m *ice.Message, text string, args ...string) (ice.Map, bool)
case ctx.ARGS:
data[ls[i]] = kit.Split(ls[i+1])
case ctx.DISPLAY:
data[ls[i]] = ice.Display(ls[i+1])[ctx.DISPLAY]
// data[ls[i]] = ice.Display(ls[i+1])[ctx.DISPLAY]
case ctx.STYLE, ctx.ACTION, TITLE, MENUS:
data[ls[i]] = kit.UnMarshal(ls[i+1])
default:

View File

@ -86,7 +86,7 @@ func init() {
m.Cmd(ASSET, func(value ice.Maps) {
_asset_check(m, value[ACCOUNT])
})
m.ProcessRefresh30ms()
m.ProcessRefresh()
} else {
_asset_check(m, m.Option(ACCOUNT))
}

View File

@ -12,7 +12,7 @@ import (
)
func _word_show(m *ice.Message, name string, arg ...string) {
m.OptionMulti(ice.MSG_ALIAS, m.Configv(mdb.ALIAS), TITLE, map[string]int{}, MENU, kit.Dict(mdb.LIST, kit.List()))
m.Options(ice.MSG_ALIAS, m.Configv(mdb.ALIAS), TITLE, map[string]int{}, MENU, kit.Dict(mdb.LIST, kit.List()))
m.Cmdy(ssh.SOURCE, name, kit.Dict(nfs.DIR_ROOT, _wiki_path(m)))
}

View File

@ -7,13 +7,13 @@ import (
)
func (m *Message) ActionKey() string {
return strings.TrimSuffix(strings.TrimPrefix(m._sub, PS), PS)
return strings.TrimPrefix(strings.TrimSuffix(m._sub, PS), PS)
}
func (m *Message) CommandKey() string {
return strings.TrimSuffix(strings.TrimPrefix(m._key, PS), PS)
return strings.TrimPrefix(strings.TrimSuffix(m._key, PS), PS)
}
func (m *Message) PrefixKey(arg ...Any) string {
return kit.Keys(m.Prefix(m.CommandKey()), kit.Keys(arg))
return kit.Keys(m.Prefix(m.CommandKey()), kit.Keys(arg...))
}
func (m *Message) Prefix(arg ...string) string {
return m.Target().PrefixKey(arg...)

14
exec.go
View File

@ -7,23 +7,23 @@ import (
"time"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
"shylinux.com/x/toolkits/task"
)
func (m *Message) TryCatch(msg *Message, silent bool, hand ...func(msg *Message)) *Message {
defer func() {
switch e := recover(); e {
case io.EOF:
case nil:
case nil, io.EOF:
default:
fileline := m.FormatStack(2, 1)
fileline := m.FormatStack(2, 100)
m.Log(LOG_WARN, "catch: %s %s", e, fileline).Log("chain", msg.FormatChain())
m.Log(LOG_WARN, "catch: %s %s", e, fileline).Log("stack", msg.FormatStack(2, 100))
m.Log(LOG_WARN, "catch: %s %s", e, fileline).Result(ErrWarn, e, " ", fileline)
m.Log(LOG_WARN, "catch: %s %s", e, fileline).Result(ErrWarn, e, SP, fileline)
if len(hand) > 1 {
m.TryCatch(msg, silent, hand[1:]...)
} else if !silent {
m.Assert(e) // 抛出异常
m.Assert(e)
}
}
}()
@ -36,13 +36,13 @@ func (m *Message) Assert(expr Any) bool {
switch e := expr.(type) {
case nil:
return true
case error:
case bool:
if e == true {
return true
}
case error:
default:
expr = errors.New(kit.Format("error: %v", e))
expr = errors.New(kit.Format("error: %v %s", e, logs.FileLine(2, 3)))
}
m.Result(ErrWarn, expr)
panic(expr)

21
info.go
View File

@ -1,13 +1,13 @@
package ice
type MakeInfo struct {
Path string
Time string
Path string
Hash string
Domain string
Module string
Remote string
Branch string
Domain string
Version string
HostName string
UserName string
@ -21,19 +21,20 @@ var Info = struct {
UserName string
PassWord string
Colors bool
Domain string
NodeType string
NodeName string
CtxShare string
CtxRiver string
PidPath string
Colors bool
Help string
Route Maps // 路由命令
File Maps // 文件命令
names Map
File Maps
Route Maps
index Map
merges []MergeHandler
render map[string]func(*Message, string, ...Any) string
Save func(m *Message, key ...string) *Message
Load func(m *Message, key ...string) *Message
@ -47,12 +48,16 @@ report: shylinuxc@gmail.com
server: https://shylinux.com
source: https://shylinux.com/x/icebergs
`,
Route: Maps{},
File: Maps{},
names: Map{},
Route: Maps{},
index: Map{},
render: map[string]func(*Message, string, ...Any) string{},
Save: func(m *Message, key ...string) *Message { return m },
Load: func(m *Message, key ...string) *Message { return m },
Log: func(m *Message, p, l, s string) {},
}
type MergeHandler func(*Context, string, *Command, string, *Action) (Handler, Handler)
func AddMerges(h ...MergeHandler) { Info.merges = append(Info.merges, h...) }

63
init.go
View File

@ -12,10 +12,7 @@ import (
type Frame struct{}
func (f *Frame) Spawn(m *Message, c *Context, arg ...string) Server {
return &Frame{}
}
func (f *Frame) Begin(m *Message, arg ...string) Server {
func (s *Frame) Begin(m *Message, arg ...string) Server {
list := map[*Context]*Message{m.target: m}
m.Travel(func(p *Context, s *Context) {
s.root = m.target
@ -24,21 +21,20 @@ func (f *Frame) Begin(m *Message, arg ...string) Server {
s.Begin(list[s], arg...)
}
})
return f
return s
}
func (f *Frame) Start(m *Message, arg ...string) bool {
func (s *Frame) Start(m *Message, arg ...string) bool {
m.Cap(CTX_STREAM, strings.Split(m.Time(), SP)[1])
m.Cmd(kit.Keys(MDB, CTX_INIT))
m.Cmd("cli.runtime", CTX_INIT)
m.Cmd(kit.Keys(CLI, CTX_INIT))
m.Cmdy(INIT, arg)
for _, k := range kit.Split(kit.Select("ctx,log,gdb,ssh", os.Getenv(CTX_DAEMON))) {
m.Start(k)
}
m.Cmd(arg)
m.Cmdy(arg)
return true
}
func (f *Frame) Close(m *Message, arg ...string) bool {
func (s *Frame) Close(m *Message, arg ...string) bool {
list := map[*Context]*Message{m.target: m}
m.Travel(func(p *Context, s *Context) {
if msg, ok := list[p]; ok && msg != nil {
@ -47,9 +43,10 @@ func (f *Frame) Close(m *Message, arg ...string) bool {
}
})
conf.Close()
go func() { m.Sleep("1s"); os.Exit(kit.Int(Pulse.Option(EXIT))) }()
go func() { m.Sleep3s(); os.Exit(kit.Int(Pulse.Option(EXIT))) }()
return true
}
func (s *Frame) Spawn(m *Message, c *Context, arg ...string) Server { return &Frame{} }
const (
INIT = "init"
@ -58,9 +55,7 @@ const (
QUIT = "quit"
)
var Index = &Context{Name: ICE, Help: "冰山模块", Configs: Configs{
HELP: {Value: kit.Data(INDEX, Info.Help)},
}, Commands: Commands{
var Index = &Context{Name: ICE, Help: "冰山模块", Configs: Configs{HELP: {Value: kit.Data(INDEX, Info.Help)}}, Commands: Commands{
CTX_INIT: {Hand: func(m *Message, arg ...string) {
m.root.Travel(func(p *Context, c *Context) {
if cmd, ok := c.Commands[CTX_INIT]; ok && p != nil {
@ -68,23 +63,19 @@ var Index = &Context{Name: ICE, Help: "冰山模块", Configs: Configs{
}
})
}},
INIT: {Name: "init", Help: "启动", Hand: func(m *Message, arg ...string) {
INIT: {Hand: func(m *Message, arg ...string) {
m.root.Cmd(CTX_INIT)
m.Cmd("source", ETC_INIT_SHY)
m.Cmd(SOURCE, ETC_INIT_SHY)
}},
HELP: {Name: "help", Help: "帮助", Hand: func(m *Message, arg ...string) {
m.Echo(m.Config(INDEX))
}},
QUIT: {Name: "quit", Help: "结束", Hand: func(m *Message, arg ...string) {
os.Exit(0)
}},
EXIT: {Name: "exit", Help: "退出", Hand: func(m *Message, arg ...string) {
defer m.Target().Close(m.root.Spawn(), arg...)
HELP: {Hand: func(m *Message, arg ...string) { m.Echo(m.Config(INDEX)) }},
QUIT: {Hand: func(m *Message, arg ...string) { os.Exit(0) }},
EXIT: {Hand: func(m *Message, arg ...string) {
m.root.Option(EXIT, kit.Select("0", arg, 0))
m.Cmd("source", ETC_EXIT_SHY)
m.Cmd(SOURCE, ETC_EXIT_SHY)
m.root.Cmd(CTX_EXIT)
}},
CTX_EXIT: {Hand: func(m *Message, arg ...string) {
defer m.Target().Close(m.root.Spawn(), arg...)
m.root.Travel(func(p *Context, c *Context) {
if cmd, ok := c.Commands[CTX_EXIT]; ok && p != nil {
m.TryCatch(m.Spawn(c), true, func(msg *Message) {
@ -102,30 +93,26 @@ var Pulse = &Message{time: time.Now(), code: 0,
func init() { Index.root, Pulse.root = Index, Pulse }
func Run(arg ...string) string {
if len(arg) == 0 { // 进程参数
arg = kit.Simple(arg, os.Args[1:], kit.Split(os.Getenv(CTX_ARG)))
if len(arg) == 0 && len(os.Args) > 1 {
arg = kit.Simple(os.Args[1:], kit.Split(kit.Env(CTX_ARG)))
}
Pulse.meta[MSG_DETAIL] = arg
switch Index.Merge(Index).Begin(Pulse.Spawn(), arg...); kit.Select("", arg, 0) {
case "serve", "space": // 启动服务
switch Index.Merge(Index).Begin(Pulse, arg...); kit.Select("", arg, 0) {
case SERVE, SPACE:
if Index.Start(Pulse, arg...) {
conf.Wait()
println()
os.Exit(kit.Int(Pulse.Option(EXIT)))
}
default: // 执行命令
default:
if logs.Disable(true); len(arg) == 0 {
arg = append(arg, HELP)
}
Pulse.Cmd(INIT)
if Pulse.Cmdy(arg); strings.TrimSpace(Pulse.Result()) == "" {
if Pulse.Cmd(INIT).Cmdy(arg); strings.TrimSpace(Pulse.Result()) == "" {
Pulse.Table()
}
}
if !strings.HasSuffix(Pulse.Result(), NL) {
Pulse.Echo(NL)
if !strings.HasSuffix(Pulse.Result(), NL) {
Pulse.Echo(NL)
}
}
return Pulse.Result()
}

54
logs.go
View File

@ -29,27 +29,21 @@ func (m *Message) join(arg ...Any) (string, []Any) {
continue
}
switch v := arg[i+1].(type) {
case logs.Meta:
list = append(list, key)
meta = append(meta, v)
continue
case time.Time:
arg[i+1] = v.Format(MOD_TIME)
}
list = append(list, key+kit.Select("", DF, !strings.HasSuffix(key, DF)), kit.Format(kit.Select("", kit.Simple(arg[i+1]), 0)))
list = append(list, key+kit.Select("", DF, !strings.Contains(key, DF)), kit.Format(arg[i+1]))
}
return kit.Join(list, SP), meta
}
func (m *Message) log(level string, str string, arg ...Any) *Message {
_source := logs.FileLineMeta(logs.FileLine(3, 3))
if Info.Log != nil {
Info.Log(m, m.FormatPrefix(), level, logs.Format(str, append(arg, _source)...)) // 日志回调
Info.Log(m, m.FormatPrefix(), level, logs.Format(str, append(arg, _source)...))
}
if m.Option("log.disable") == TRUE {
if m.Option(LOG_DISABLE) == TRUE {
return m
}
// 日志颜色
prefix, suffix := "", ""
if Info.Colors {
switch level {
@ -57,20 +51,16 @@ func (m *Message) log(level string, str string, arg ...Any) *Message {
prefix, suffix = "\033[32m", "\033[0m"
case LOG_AUTH, LOG_COST:
prefix, suffix = "\033[33m", "\033[0m"
case LOG_WARN:
case LOG_WARN, LOG_ERROR:
prefix, suffix = "\033[31m", "\033[0m"
}
}
// 长度截断
switch level {
case LOG_INFO:
if len(str) > 4096 {
str = str[:4096]
}
}
// 输出日志
logs.Infof(str, append(arg, logs.PrefixMeta(kit.Format("%02d %4s->%-4s %s%s ", m.code, m.source.Name, m.target.Name, prefix, level)), logs.SuffixMeta(suffix), _source)...)
return m
}
@ -116,32 +106,26 @@ func (m *Message) Warn(err Any, arg ...Any) bool {
if !m.IsErr() {
if m.error(arg...); len(arg) > 0 {
switch kit.Format(arg[0]) {
case ErrNotValid:
m.RenderStatusBadRequest(str)
case ErrNotLogin:
m.RenderStatusUnauthorized(str)
case ErrNotRight:
m.RenderStatusForbidden(str)
case ErrNotFound:
m.RenderStatusNotFound(str)
case ErrNotValid:
m.RenderStatusBadRequest(str)
}
}
}
return true
}
func (m *Message) Debug(str string, arg ...Any) {
if str == "" {
str = m.FormatMeta()
}
m.log(LOG_DEBUG, str, arg...)
}
func (m *Message) Error(err bool, arg ...Any) bool {
if err {
m.error(arg...)
m.log(LOG_ERROR, m.FormatStack(1, 100))
str, meta := m.join(arg...)
m.log(LOG_ERROR, str, meta)
m.log(LOG_ERROR, m.FormatChain())
m.log(LOG_ERROR, str, meta)
m.log(LOG_ERROR, m.FormatStack(1, 100))
m.error(arg...)
return true
}
return false
@ -156,12 +140,19 @@ func (m *Message) error(arg ...Any) {
arg = append(arg, "")
}
str, meta := m.join(arg[2:]...)
m.meta[MSG_RESULT] = kit.Simple(ErrWarn, arg[0], arg[1], str, meta)
m.Resultv(ErrWarn, arg[0], arg[1], str, meta)
}
func (m *Message) IsErrNotFound() bool {
return m.IsErr(ErrNotFound)
}
func (m *Message) IsErrNotFound() bool { return m.IsErr(ErrNotFound) }
func (m *Message) IsErr(arg ...string) bool {
return len(arg) > 0 && m.Result(1) == arg[0] || len(arg) == 0 && m.Result(0) == ErrWarn
return len(arg) == 0 && m.Result(0) == ErrWarn || len(arg) > 0 && m.Result(1) == arg[0]
}
func (m *Message) Debug(str string, arg ...Any) {
if str == "" {
str = m.FormatMeta()
}
m.log(LOG_DEBUG, str, arg...)
}
func (m *Message) FormatPrefix() string {
@ -187,7 +178,6 @@ func (m *Message) FormatChain() string {
for msg := m; msg != nil; msg = msg.message {
ms = append(ms, msg)
}
meta := append([]string{}, NL)
for i := len(ms) - 1; i >= 0; i-- {
msg := ms[i]
@ -213,20 +203,16 @@ func (m *Message) FormatChain() string {
func (m *Message) FormatStack(s, n int) string {
pc := make([]uintptr, n+10)
frames := runtime.CallersFrames(pc[:runtime.Callers(s+1, pc)])
list := []string{}
for {
frame, more := frames.Next()
file := kit.Slice(kit.Split(frame.File, PS, PS), -1)[0]
name := kit.Slice(kit.Split(frame.Function, PS, PS), -1)[0]
switch ls := kit.Split(name, PT, PT); kit.Select("", ls, 0) {
// case "reflect", "runtime", "http", "task", "icebergs":
case "reflect", "runtime", "http":
default:
list = append(list, kit.Format("%s:%d\t%s", file, frame.Line, name))
}
if len(list) >= n {
break
}

424
meta.go
View File

@ -7,6 +7,24 @@ import (
kit "shylinux.com/x/toolkits"
)
func (m *Message) setDetail(key string, arg ...string) *Message {
for i := 0; i < len(m.meta[KEY]); i++ {
if m.meta[KEY][i] == key {
if len(arg) > 0 {
m.meta[VALUE][i] = arg[0]
break
}
for ; i < len(m.meta[KEY])-1; i++ {
m.meta[KEY][i] = m.meta[KEY][i+1]
m.meta[VALUE][i] = m.meta[VALUE][i+1]
}
m.meta[KEY] = kit.Slice(m.meta[KEY], 0, -1)
m.meta[VALUE] = kit.Slice(m.meta[VALUE], 0, -1)
break
}
}
return m
}
func (m *Message) Set(key string, arg ...string) *Message {
switch key {
case MSG_DETAIL, MSG_RESULT:
@ -14,61 +32,33 @@ func (m *Message) Set(key string, arg ...string) *Message {
case MSG_OPTION, MSG_APPEND:
if m.FieldsIsDetail() {
if len(arg) > 0 {
for i := 0; i < len(m.meta[KEY]); i++ {
if m.meta[KEY][i] == arg[0] {
if len(arg) > 1 {
m.meta[VALUE][i] = arg[1]
break
}
for ; i < len(m.meta[KEY])-1; i++ {
m.meta[KEY][i] = m.meta[KEY][i+1]
m.meta[VALUE][i] = m.meta[VALUE][i+1]
}
m.meta[KEY] = kit.Slice(m.meta[KEY], 0, -1)
m.meta[VALUE] = kit.Slice(m.meta[VALUE], 0, -1)
break
}
}
return m
m.setDetail(arg[0], arg[1:]...)
} else {
delete(m.meta, KEY)
delete(m.meta, VALUE)
delete(m.meta, MSG_APPEND)
}
delete(m.meta, KEY)
delete(m.meta, VALUE)
delete(m.meta, MSG_APPEND)
return m
}
if len(arg) > 0 {
if delete(m.meta, arg[0]); len(arg) == 1 {
return m
} else if len(arg) > 0 {
if delete(m.meta, arg[0]); len(arg) > 1 {
m.meta[arg[0]] = arg[1:]
}
} else {
for _, k := range m.meta[key] {
delete(m.meta, k)
}
delete(m.meta, key)
return m
}
return m
default:
if m.FieldsIsDetail() {
return m.setDetail(key, arg...)
}
for _, k := range kit.Split(key) {
delete(m.meta, k)
}
if m.FieldsIsDetail() {
for i := 0; i < len(m.meta[KEY]); i++ {
if m.meta[KEY][i] == key {
if len(arg) > 0 {
m.meta[VALUE][i] = arg[0]
break
}
for ; i < len(m.meta[KEY])-1; i++ {
m.meta[KEY][i] = m.meta[KEY][i+1]
m.meta[VALUE][i] = m.meta[VALUE][i+1]
}
m.meta[KEY] = kit.Slice(m.meta[KEY], 0, -1)
m.meta[VALUE] = kit.Slice(m.meta[VALUE], 0, -1)
break
}
}
return m
}
}
if len(arg) == 0 {
return m
}
return m.Add(key, arg...)
}
@ -76,21 +66,15 @@ 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 {
break
}
if key == MSG_APPEND {
if i := kit.IndexOf(m.meta[MSG_OPTION], arg[0]); i > -1 {
m.meta[MSG_OPTION][i] = ""
if index := 0; key == MSG_APPEND {
if m.meta[MSG_OPTION], index = kit.SliceRemove(m.meta[MSG_OPTION], arg[0]); index > -1 {
delete(m.meta, arg[0])
}
if kit.IndexOf(m.meta[key], arg[0]) == -1 {
m.meta[arg[0]] = []string{}
}
}
if kit.IndexOf(m.meta[key], arg[0]) == -1 {
m.meta[key] = append(m.meta[key], arg[0])
}
@ -116,20 +100,16 @@ func (m *Message) Push(key string, value Any, arg ...Any) *Message {
if len(head) == 0 && !m.FieldsIsDetail() {
head = kit.Split(m.OptionFields())
}
switch value := value.(type) {
case Map:
if len(head) == 0 { // 键值排序
head = kit.SortedKey(kit.KeyValue(Map{}, "", value))
if len(head) == 0 {
head = kit.SortedKey(kit.KeyValue(nil, "", value))
}
var val Map
if len(arg) > 1 {
val, _ = arg[1].(Map)
}
for _, k := range head {
// 查找数据
var v Any
switch k {
case KEY, HASH:
@ -158,40 +138,33 @@ func (m *Message) Push(key string, value Any, arg ...Any) *Message {
break
}
}
// 追加数据
switch v := kit.Format(v); key {
case FIELDS_DETAIL:
switch k {
case "_target":
continue
}
m.Add(MSG_APPEND, KEY, strings.TrimPrefix(k, "extra."))
m.Add(MSG_APPEND, KEY, strings.TrimPrefix(k, EXTRA+PT))
m.Add(MSG_APPEND, VALUE, v)
default:
m.Add(MSG_APPEND, k, v)
}
}
case Maps:
if len(head) == 0 { // 键值排序
if len(head) == 0 {
head = kit.SortedKey(value)
}
for _, k := range head {
m.Push(k, value[k])
}
default:
for _, v := range kit.Simple(value, arg) {
if m.FieldsIsDetail() {
if key != KEY || key != VALUE {
m.Add(MSG_APPEND, KEY, key)
m.Add(MSG_APPEND, VALUE, kit.Format(value))
continue
}
m.Add(MSG_APPEND, KEY, key)
m.Add(MSG_APPEND, VALUE, kit.Format(value))
} else {
m.Add(MSG_APPEND, key, v)
}
m.Add(MSG_APPEND, key, v)
}
}
return m
@ -200,8 +173,7 @@ func (m *Message) Echo(str string, arg ...Any) *Message {
if str == "" {
return m
}
m.meta[MSG_RESULT] = append(m.meta[MSG_RESULT], kit.Format(str, arg...))
return m
return m.Add(MSG_RESULT, kit.Format(str, arg...))
}
func (m *Message) Copy(msg *Message, arg ...string) *Message {
if m == nil || msg == nil || m == msg {
@ -213,12 +185,9 @@ func (m *Message) Copy(msg *Message, arg ...string) *Message {
}
return m
}
for _, k := range msg.meta[MSG_OPTION] {
switch k {
case MSG_CMDS:
case MSG_FIELDS:
case MSG_SESSID:
case MSG_CMDS, MSG_FIELDS, MSG_SESSID:
continue
}
if v, ok := msg.data[k]; ok {
@ -231,8 +200,7 @@ func (m *Message) Copy(msg *Message, arg ...string) *Message {
for _, k := range msg.meta[MSG_APPEND] {
m.Add(MSG_APPEND, kit.Simple(k, msg.meta[k])...)
}
m.meta[MSG_RESULT] = append(m.meta[MSG_RESULT], msg.meta[MSG_RESULT]...)
return m
return m.Add(MSG_RESULT, msg.meta[MSG_RESULT]...)
}
func (m *Message) Length() (max int) {
for _, k := range m.meta[MSG_APPEND] {
@ -245,49 +213,49 @@ func (m *Message) Length() (max int) {
func (m *Message) Tables(cbs ...func(value Maps)) *Message {
return m.Table(func(index int, value Maps, head []string) {
for _, cb := range cbs {
if cb != nil {
cb(value)
}
cb(value)
}
})
}
func (m *Message) Table(cbs ...func(index int, value Maps, head []string)) *Message {
if len(cbs) > 0 && cbs[0] != nil {
if m.FieldsIsDetail() {
if m.Length() == 0 {
return m
}
line := Maps{}
for i, k := range m.meta[KEY] {
line[k] = kit.Select("", m.meta[VALUE], i)
}
cbs[0](0, line, m.meta[KEY])
n := m.Length()
if n == 0 {
return m
}
n := m.Length()
for i := 0; i < n; i++ {
line := Maps{}
for _, k := range m.meta[MSG_APPEND] {
line[k] = kit.Select("", m.meta[k], i)
if m.FieldsIsDetail() {
value := Maps{}
for i, k := range m.meta[KEY] {
value[k] = kit.Select("", m.meta[VALUE], i)
}
for _, cb := range cbs {
cb(0, value, m.meta[KEY])
}
return m
}
for i := 0; i < n; i++ {
value := Maps{}
for _, k := range m.meta[MSG_APPEND] {
value[k] = kit.Select("", m.meta[k], i)
}
for _, cb := range cbs {
cb(i, value, m.meta[MSG_APPEND])
}
cbs[0](i, line, m.meta[MSG_APPEND])
}
return m
}
const (
TABLE_SPACE = "table.space"
TABLE_ROW_SEP = "table.row_sep"
TABLE_COL_SEP = "table.col_sep"
TABLE_COMPACT = "table.compact"
TABLE_ALIGN = "table.align"
)
//计算列宽
space := kit.Select(SP, m.Option(TABLE_SPACE))
depth, width := 0, map[string]int{}
length, width := 0, map[string]int{}
for _, k := range m.meta[MSG_APPEND] {
if len(m.meta[k]) > depth {
depth = len(m.meta[k])
if len(m.meta[k]) > length {
length = len(m.meta[k])
}
width[k] = kit.Width(k, len(space))
for _, v := range m.meta[k] {
@ -296,165 +264,128 @@ func (m *Message) Table(cbs ...func(index int, value Maps, head []string)) *Mess
}
}
}
// 回调函数
rows := kit.Select(NL, m.Option(TABLE_ROW_SEP))
cols := kit.Select(SP, m.Option(TABLE_COL_SEP))
compact := m.Option(TABLE_COMPACT) == TRUE
cb := func(value Maps, 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 {
show := func(value []string) {
for i, v := range value {
if m.Echo(v); i < len(value)-1 {
m.Echo(cols)
}
}
m.Echo(rows)
return true
}
// 输出表头
row, wor := Maps{}, []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, wor := Maps{}, []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))))
compact := m.Option(TABLE_COMPACT) == TRUE
_align := kit.Select("left", m.Option(TABLE_ALIGN))
align := func(value string, width int) string {
if compact {
return value + space
}
if !cb(row, wor, i) {
break
n := width - kit.Width(value, len(space))
switch _align {
case "left":
return value + strings.Repeat(space, n)
case "right":
return strings.Repeat(space, n) + value
case "center":
return strings.Repeat(space, n/2) + value + strings.Repeat(space, n-n/2)
}
return value + space
}
show(kit.Simple(m.meta[MSG_APPEND], func(k string) string { return align(k, width[k]) }))
for i := 0; i < length; i++ {
show(kit.Simple(m.meta[MSG_APPEND], func(k string) string { return align(kit.Select("", m.meta[k], i), width[k]) }))
}
return m
}
const (
INT = "int"
STR = "str"
// TIME = "time"
TIME_R = "time_r"
STR_R = "str_r"
INT_R = "int_r"
)
func (m *Message) Sort(key string, arg ...string) *Message {
ls := kit.Split(key)
if key = ls[0]; m.FieldsIsDetail() && key != KEY {
if m.FieldsIsDetail() {
return m
}
const (
STR = "str"
INT = "int"
TIME = "time"
TIME_R = "time_r"
INT_R = "int_r"
STR_R = "str_r"
GT = ">"
LT = "<"
)
// 排序方法
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
keys, cmps := kit.Split(key), kit.Simple()
for i, k := range keys {
cmp := kit.Select("", arg, i)
if cmp == "" {
cmp = INT
for _, v := range m.meta[k] {
if _, e := strconv.Atoi(v); e != nil {
cmp = STR
}
}
}
cmps = append(cmps, cmp)
}
// 排序因子
number := map[int]int64{}
table := []Maps{}
m.Table(func(index int, value Maps, head []string) {
switch table = append(table, value); cmp {
case INT:
number[index] = kit.Int64(value[key])
case INT_R:
number[index] = -kit.Int64(value[key])
case TIME:
number[index] = int64(kit.Time(value[key]))
case TIME_R:
number[index] = -int64(kit.Time(value[key]))
}
})
compare := func(i, j int, op string) bool {
for k := range ls {
if k == 0 {
list := []Maps{}
m.Tables(func(value Maps) { list = append(list, value) })
gt := func(i, j int) bool {
for s, k := range keys {
a, b := list[i][k], list[j][k]
if a == b {
continue
}
if table[i][ls[k]] == table[j][ls[k]] {
continue
switch cmp := cmps[s]; cmp {
case INT, INT_R:
if kit.Int(a) > kit.Int(b) {
return cmp == INT
}
if kit.Int(a) < kit.Int(b) {
return cmp == INT_R
}
case STR, STR_R:
if a > b {
return cmp == STR
}
if a < b {
return cmp == STR_R
}
case TIME, TIME_R:
if kit.Time(a) > kit.Time(b) {
return cmp == TIME
}
if kit.Time(a) < kit.Time(b) {
return cmp == TIME_R
}
}
if op == GT && table[i][ls[k]] > table[j][ls[k]] {
return true
}
if op == LT && table[i][ls[k]] < table[j][ls[k]] {
return true
}
return false
}
return false
}
// 排序数据
for i := 0; i < len(table)-1; i++ {
for j := i + 1; j < len(table); j++ {
swap := false
switch cmp {
case "", STR:
if table[i][key] > table[j][key] {
swap = true
} else if table[i][key] == table[j][key] && compare(i, j, GT) {
swap = true
}
case STR_R:
if table[i][key] < table[j][key] {
swap = true
} else if table[i][key] == table[j][key] && compare(i, j, LT) {
swap = true
}
default:
if number[i] > number[j] {
swap = true
} else if table[i][key] == table[j][key] && compare(i, j, GT) {
swap = true
}
}
if swap {
table[i], table[j] = table[j], table[i]
number[i], number[j] = number[j], number[i]
for i := 0; i < len(list)-1; i++ {
min := i
for j := i + 1; j < len(list); j++ {
if gt(min, j) {
min = j
}
}
if min != i {
list[i], list[min] = list[min], list[i]
}
}
// 输出数据
for _, k := range m.meta[MSG_APPEND] {
delete(m.meta, k)
}
for _, v := range table {
for _, v := range list {
for _, k := range m.meta[MSG_APPEND] {
m.Add(MSG_APPEND, k, v[k])
}
}
return m
}
func (m *Message) SortInt(key string) { m.Sort(key, "int") }
func (m *Message) SortIntR(key string) { m.Sort(key, "int_r") }
func (m *Message) SortStr(key string) { m.Sort(key, "str") }
func (m *Message) SortStrR(key string) { m.Sort(key, "str_r") }
func (m *Message) SortTime(key string) { m.Sort(key, "time") }
func (m *Message) SortTimeR(key string) { m.Sort(key, "time_r") }
func (m *Message) SortInt(key string) { m.Sort(key, INT) }
func (m *Message) SortStr(key string) { m.Sort(key, STR) }
func (m *Message) SortTime(key string) { m.Sort(key, TIME) }
func (m *Message) SortTimeR(key string) { m.Sort(key, TIME_R) }
func (m *Message) SortStrR(key string) { m.Sort(key, STR_R) }
func (m *Message) SortIntR(key string) { m.Sort(key, INT_R) }
func (m *Message) Detail(arg ...Any) string {
return kit.Select("", m.meta[MSG_DETAIL], 0)
@ -462,37 +393,38 @@ func (m *Message) Detail(arg ...Any) string {
func (m *Message) Detailv(arg ...Any) []string {
return m.meta[MSG_DETAIL]
}
func (m *Message) Options(arg ...Any) Any {
for i := 0; i < len(arg)-1; i += 2 {
m.Optionv(kit.Format(arg[i]), arg[i+1])
}
return m.Optionv(kit.Format(arg[0]))
}
func (m *Message) Optionv(key string, arg ...Any) Any {
if len(arg) > 0 {
if kit.IndexOf(m.meta[MSG_OPTION], key) == -1 { // 写数据
if kit.IndexOf(m.meta[MSG_OPTION], key) == -1 {
m.meta[MSG_OPTION] = append(m.meta[MSG_OPTION], key)
}
switch delete(m.data, key); str := arg[0].(type) {
switch delete(m.data, key); v := arg[0].(type) {
case nil:
delete(m.meta, key)
case string:
m.meta[key] = kit.Simple(arg...)
case []string:
m.meta[key] = str
m.meta[key] = v
default:
m.data[key] = str
m.data[key] = v
}
}
for msg := m; msg != nil; msg = msg.message {
if list, ok := msg.data[key]; ok {
return list // 读数据
if v, ok := msg.data[key]; ok {
return v
}
if list, ok := msg.meta[key]; ok {
return list // 读选项
if v, ok := msg.meta[key]; ok {
return v
}
}
return nil
}
func (m *Message) Message() *Message {
return m.message
}
func (m *Message) Option(key string, arg ...Any) string {
return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0)
}
@ -503,14 +435,7 @@ func (m *Message) Append(key string, arg ...Any) string {
return kit.Select("", m.Appendv(key, arg...), 0)
}
func (m *Message) Appendv(key string, arg ...Any) []string {
if key == MSG_APPEND {
if len(arg) > 0 {
m.meta[MSG_APPEND] = kit.Simple(arg)
}
return m.meta[key]
}
if m.FieldsIsDetail() && key != KEY {
if m.FieldsIsDetail() {
for i, k := range m.meta[KEY] {
if k == key || k == kit.Keys(EXTRA, key) {
if len(arg) > 0 {
@ -526,7 +451,12 @@ func (m *Message) Appendv(key string, arg ...Any) []string {
}
return nil
}
if key == MSG_APPEND {
if len(arg) > 0 {
m.meta[MSG_APPEND] = kit.Simple(arg)
}
return m.meta[key]
}
if len(arg) > 0 {
m.meta[key] = kit.Simple(arg...)
}

157
misc.go
View File

@ -8,7 +8,7 @@ import (
"shylinux.com/x/toolkits/logs"
)
func (m *Message) Split(str string, arg ...string) *Message { // field sp nl
func (m *Message) Split(str string, arg ...string) *Message {
m.Set(MSG_APPEND).Set(MSG_RESULT)
field := kit.Select("", arg, 0)
sp := kit.Select(SP, arg, 1)
@ -21,7 +21,7 @@ func (m *Message) Split(str string, arg ...string) *Message { // field sp nl
if strings.TrimSpace(l) == "" {
continue
}
if i == 0 && (field == "" || field == INDEX) { // 表头行
if i == 0 && (field == "" || field == INDEX) {
if fields = kit.Split(l, sp, sp); field == INDEX {
if strings.HasPrefix(l, SP) || strings.HasPrefix(l, TB) {
indexs = append(indexs, 0)
@ -37,8 +37,7 @@ func (m *Message) Split(str string, arg ...string) *Message { // field sp nl
}
continue
}
if len(indexs) > 0 { // 按位切分
if len(indexs) > 0 {
for i, v := range indexs {
if v >= len(l) {
m.Push(strings.TrimSpace(kit.Select(SP, fields, i)), "")
@ -52,7 +51,6 @@ func (m *Message) Split(str string, arg ...string) *Message { // field sp nl
}
continue
}
ls := kit.Split(l, sp, sp)
for i, v := range ls {
if i == len(fields)-1 {
@ -78,18 +76,6 @@ func (m *Message) PushDetail(value Any, arg ...string) *Message {
return m.Push(FIELDS_DETAIL, value, kit.Split(kit.Join(arg)))
}
func (m *Message) Options(arg ...Any) *Message {
for i := 0; i < len(arg); i += 2 {
m.Option(kit.Format(arg[i]), arg[i+1])
}
return m
}
func (m *Message) OptionMulti(arg ...Any) *Message {
for i := 0; i < len(arg); i += 2 {
m.Option(kit.Format(arg[i]), arg[i+1])
}
return m
}
func (m *Message) ToLowerAppend(arg ...string) *Message {
for _, k := range m.meta[MSG_APPEND] {
m.RenameAppend(k, strings.ToLower(k))
@ -101,7 +87,7 @@ func (m *Message) RenameOption(from, to string) *Message {
m.Option(from, "")
return m
}
func (m *Message) RenameAppend(arg ...string) *Message { // [from to]...
func (m *Message) RenameAppend(arg ...string) *Message {
for i := 0; i < len(arg)-1; i += 2 {
if arg[i] == arg[i+1] {
continue
@ -154,9 +140,6 @@ func (m *Message) SetResult(arg ...string) *Message {
return m.Set(MSG_RESULT, arg...)
}
func (m *Message) IsMobile() bool {
return strings.Contains(m.Option(MSG_USERUA), "Mobile")
}
func (m *Message) Design(action Any, help string, input ...Any) {
list := kit.List()
for _, input := range input {
@ -181,12 +164,27 @@ func (m *Message) Design(action Any, help string, input ...Any) {
kit.Value(m._cmd.Meta, kit.Keys("_trans", k), help)
}
}
func (m *Message) CmdHand(cmd *Command, key string, arg ...string) *Message {
if m._key, m._cmd = key, cmd; cmd == nil {
return m
}
if m._target = kit.FileLine(cmd.Hand, 3); cmd.RawHand != nil {
m._target = kit.Format(cmd.RawHand)
}
if fileline := kit.Select(m._target, m._source, m.target.Name == MDB); key == SELECT {
m.Log(LOG_CMDS, "%s.%s %d %v %v", m.Target().Name, key, len(arg), arg, m.Optionv(MSG_FIELDS), logs.FileLineMeta(fileline))
} else {
m.Log(LOG_CMDS, "%s.%s %d %v", m.Target().Name, key, len(arg), arg, logs.FileLineMeta(fileline))
}
if cmd.Hand != nil {
cmd.Hand(m, arg...)
} else if cmd.Actions != nil && cmd.Actions[SELECT] != nil {
cmd.Actions[SELECT].Hand(m, arg...)
}
return m
}
func (m *Message) _command(arg ...Any) *Message {
args, opts := []Any{}, Map{}
var cbs Any
// 解析参数
_source := logs.FileLine(3, 3)
args, opts, cbs, _source := []Any{}, Map{}, kit.Value(nil), logs.FileLine(3, 3)
for _, v := range arg {
switch val := v.(type) {
case string:
@ -203,12 +201,10 @@ func (m *Message) _command(arg ...Any) *Message {
opts[val.Name] = val.Value
case *Option:
opts[val.Name] = val.Value
case logs.Meta:
if val.Key == "fileline" {
_source = val.Value
}
case func(int, Maps, []string):
defer func() { m.Table(val) }()
case func(Maps):
@ -221,8 +217,6 @@ func (m *Message) _command(arg ...Any) *Message {
}
}
}
// 解析命令
list := kit.Simple(args...)
if len(list) == 0 && !m.Hand {
list = m.meta[MSG_DETAIL]
@ -230,25 +224,20 @@ func (m *Message) _command(arg ...Any) *Message {
if len(list) == 0 {
return m
}
ok := false
run := func(msg *Message, ctx *Context, cmd *Command, key string, arg ...string) {
key = kit.Slice(strings.Split(key, PT), -1)[0]
if ok = true; cbs != nil {
msg.OptionCB(kit.Slice(kit.Split(list[0], PT), -1)[0], cbs)
msg.OptionCB(key, cbs)
}
for k, v := range opts {
msg.Option(k, v)
}
// 执行命令
msg._source = _source
m.TryCatch(msg, true, func(msg *Message) { m = ctx._command(msg, cmd, key, arg...) })
}
// 查找命令
if list[0] == "" {
list[0] = m._key
run(m.Spawn(), m.target, m._cmd, list[0], list[1:]...)
run(m.Spawn(), m.target, m._cmd, m._key, list[1:]...)
} else if cmd, ok := m.target.Commands[strings.TrimPrefix(list[0], m.target.Cap(CTX_FOLLOW)+PT)]; ok {
run(m.Spawn(), m.target, cmd, list[0], list[1:]...)
} else if cmd, ok := m.source.Commands[strings.TrimPrefix(list[0], m.source.Cap(CTX_FOLLOW)+PT)]; ok {
@ -261,32 +250,11 @@ func (m *Message) _command(arg ...Any) *Message {
m.Warn(!ok, ErrNotFound, kit.Format(list))
return m
}
func (m *Message) CmdHand(cmd *Command, key string, arg ...string) *Message {
if m._key, m._cmd = key, cmd; cmd == nil {
return m
}
if m._target = kit.FileLine(cmd.Hand, 3); cmd.RawHand != nil {
m._target = kit.Format(cmd.RawHand)
}
if fileline := kit.Select(m._target, m._source, m.target.Name == MDB); key == "select" {
m.Log(LOG_CMDS, "%s.%s %d %v %v", m.Target().Name, key, len(arg), arg, m.Optionv(MSG_FIELDS), logs.FileLineMeta(fileline))
} else {
m.Log(LOG_CMDS, "%s.%s %d %v", m.Target().Name, key, len(arg), arg, logs.FileLineMeta(fileline))
}
if cmd.Hand != nil {
cmd.Hand(m, arg...)
} else if cmd.Actions != nil && cmd.Actions["select"] != nil {
cmd.Actions["select"].Hand(m, arg...)
}
return m
}
func (c *Context) _command(m *Message, cmd *Command, key string, arg ...string) *Message {
key = kit.Slice(strings.Split(key, PT), -1)[0]
if m._key, m._sub, m._cmd = key, "select", cmd; cmd == nil {
if m._key, m._sub, m._cmd = key, SELECT, cmd; cmd == nil {
return m
}
if m.Hand, m.meta[MSG_DETAIL] = true, kit.Simple(key, arg); cmd.Actions != nil {
if m.Hand, m.meta[MSG_DETAIL] = true, kit.Simple(m.PrefixKey(), arg); cmd.Actions != nil {
if len(arg) > 1 && arg[0] == ACTION {
if h, ok := cmd.Actions[arg[1]]; ok {
return c._action(m, cmd, key, arg[1], h, arg[2:]...)
@ -298,30 +266,14 @@ func (c *Context) _command(m *Message, cmd *Command, key string, arg ...string)
}
}
}
if m._target = kit.FileLine(cmd.Hand, 3); cmd.RawHand != nil {
m._target = kit.Format(cmd.RawHand)
}
if fileline := kit.Select(m._target, m._source, m.target.Name == MDB); key == "select" {
m.Log(LOG_CMDS, "%s.%s %d %v %v", c.Name, key, len(arg), arg, m.Optionv(MSG_FIELDS), logs.FileLineMeta(fileline))
} else {
m.Log(LOG_CMDS, "%s.%s %d %v", c.Name, key, len(arg), arg, logs.FileLineMeta(fileline))
}
if cmd.Hand != nil {
cmd.Hand(m, arg...)
} else if cmd.Actions != nil && cmd.Actions["select"] != nil {
cmd.Actions["select"].Hand(m, arg...)
}
return m
return m.CmdHand(cmd, key, arg...)
}
func (c *Context) _action(m *Message, cmd *Command, key string, sub string, h *Action, arg ...string) *Message {
if h.Hand == nil {
m.Cmdy(kit.Split(h.Name), arg)
return m
}
if m._sub = sub; len(h.List) > 0 && sub != "search" {
if m._sub = sub; len(h.List) > 0 && sub != SEARCH {
order := false
for i, v := range h.List {
name := kit.Format(kit.Value(v, NAME))
@ -331,8 +283,8 @@ func (c *Context) _action(m *Message, cmd *Command, key string, sub string, h *A
}
if order {
m.Option(name, kit.Select(value, arg, i))
} else if m.Option(name) == "" && value != "" {
m.Option(name, value)
} else {
m.OptionDefault(name, value)
}
}
if !order {
@ -341,7 +293,6 @@ func (c *Context) _action(m *Message, cmd *Command, key string, sub string, h *A
}
}
}
if m._target = kit.FileLine(h.Hand, 3); cmd.RawHand != nil {
m._target = kit.Format(cmd.RawHand)
}
@ -350,52 +301,51 @@ func (c *Context) _action(m *Message, cmd *Command, key string, sub string, h *A
h.Hand(m, arg...)
return m
}
func MergeActions(list ...Any) Actions {
if len(list) == 0 {
func MergeActions(arg ...Any) Actions {
if len(arg) == 0 {
return nil
}
base := list[0].(Actions)
for _, from := range list[1:] {
list := arg[0].(Actions)
for _, from := range arg[1:] {
switch from := from.(type) {
case Actions:
for k, v := range from {
if h, ok := base[k]; !ok {
base[k] = v
if h, ok := list[k]; !ok {
list[k] = v
} else if h.Hand == nil {
h.Hand = v.Hand
} else if k == CTX_INIT {
last := base[k].Hand
prev := v.Hand
base[k].Hand = func(m *Message, arg ...string) {
prev(m, arg...)
last := h.Hand
hand := v.Hand
h.Hand = func(m *Message, arg ...string) {
hand(m, arg...)
last(m, arg...)
}
}
}
case string:
base[CTX_INIT] = &Action{Hand: func(m *Message, arg ...string) {
h := list[CTX_INIT]
list[CTX_INIT] = &Action{Hand: func(m *Message, arg ...string) {
m.Search(from, func(p *Context, s *Context, key string, cmd *Command) {
for k, v := range cmd.Actions {
func(k string) {
if h, ok := base[k]; !ok {
base[k] = &Action{Name: v.Name, Help: v.Help, Hand: func(m *Message, arg ...string) {
m.Cmdy(from, k, arg)
}}
if h, ok := list[k]; !ok {
list[k] = &Action{Name: v.Name, Help: v.Help, Hand: func(m *Message, arg ...string) { m.Cmdy(from, k, arg) }}
} else if h.Hand == nil {
h.Hand = func(m *Message, arg ...string) {
m.Cmdy(from, k, arg)
}
h.Hand = func(m *Message, arg ...string) { m.Cmdy(from, k, arg) }
}
}(k)
}
m.target.Merge(m.target)
})
if h != nil {
h.Hand(m, arg...)
}
}}
default:
Pulse.ErrorNotImplement(from)
}
}
return base
return list
}
func SplitCmd(name string, actions Actions) (list []Any) {
const (
@ -414,7 +364,6 @@ func SplitCmd(name string, actions Actions) (list []Any) {
PAGE = "page"
ARGS = "args"
)
item, button := kit.Dict(), false
push := func(arg ...string) {
button = kit.Select("", arg, 0) == BUTTON
@ -432,7 +381,7 @@ func SplitCmd(name string, actions Actions) (list []Any) {
push(BUTTON, ls[i], AUTO)
case AUTO:
push(BUTTON, LIST, AUTO)
push(BUTTON, BACK, AUTO)
push(BUTTON, BACK)
case PAGE:
push(TEXT, "limit")
push(TEXT, "offend")

View File

@ -287,7 +287,7 @@ func init() {
}
_repos_cmd(m, m.Option(REPOS), TAG, m.Option(VERSION))
_repos_cmd(m, m.Option(REPOS), PUSH, "--tags")
m.ProcessRefresh30ms()
m.ProcessRefresh()
}},
BRANCH: {Name: "branch", Help: "分支", Hand: func(m *ice.Message, arg ...string) {
for _, line := range kit.Split(_repos_cmd(m.Spawn(), arg[0], BRANCH).Result(), ice.NL, ice.NL) {
@ -319,6 +319,9 @@ func init() {
m.Cmdy(code.VIMER, code.DEVPACK)
}},
web.DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
if m.Option(mdb.TYPE) != web.WORKER {
return
}
text := []string{}
for _, line := range kit.Split(m.Cmdx(web.SPACE, m.Option(mdb.NAME), cli.SYSTEM, "git", "diff", "--shortstat"), ice.FS, ice.FS) {
if list := kit.Split(line); strings.Contains(line, "file") {

View File

@ -11,7 +11,7 @@ func _group_list(m *ice.Message, appid string) {
_, data := _lark_get(m, appid, "/open-apis/chat/v4/list")
kit.Fetch(kit.Value(data, "data.groups"), func(index int, value ice.Map) {
m.Push(CHAT_ID, value[CHAT_ID])
m.PushImages(aaa.AVATAR, kit.Format(value[aaa.AVATAR]), "72")
m.PushImages(aaa.AVATAR, kit.Format(value[aaa.AVATAR]))
m.Push(mdb.NAME, value[mdb.NAME])
m.Push(mdb.TEXT, value["description"])
m.Push(OPEN_ID, value["owner_open_id"])

View File

@ -140,7 +140,7 @@ func init() {
}
m.Cmd(TAGS, mdb.INSERT, mdb.ZONE, value[mdb.ZONE], kit.Simple(value))
})
m.ProcessRefresh300ms()
m.ProcessRefresh()
}},
mdb.INSERT: {Name: "insert zone=core type name=hi text=hello path file line", Help: "添加"},
code.INNER: {Name: "inner", Help: "源码", Hand: func(m *ice.Message, arg ...string) {

View File

@ -38,10 +38,10 @@ func (m *Message) OptionSimple(key ...string) (res []string) {
if len(key) == 0 {
for _, k := range kit.Split(m.Config(FIELD)) {
switch k {
case "", TIME, HASH:
case TIME, HASH:
continue
}
if m.Option(k) == "" {
if k == "" || m.Option(k) == "" {
continue
}
res = append(res, k, m.Option(k))
@ -92,28 +92,26 @@ func (m *Message) Action(arg ...Any) *Message {
m.Option(MSG_ACTION, kit.Format(arg))
return m
}
func (m *Message) Status(arg ...Any) {
list := kit.List()
args := kit.Simple(arg)
func (m *Message) Status(arg ...Any) *Message {
list, args := kit.List(), kit.Simple(arg)
for i := 0; i < len(args)-1; i += 2 {
list = append(list, kit.Dict(NAME, args[i], VALUE, args[i+1]))
}
m.Option(MSG_STATUS, kit.Format(list))
return m
}
func (m *Message) StatusTime(arg ...Any) *Message {
m.Status(TIME, m.Time(), arg, kit.MDB_COST, m.FormatCost())
return m
return m.Status(TIME, m.Time(), arg, kit.MDB_COST, m.FormatCost())
}
func (m *Message) StatusTimeCount(arg ...Any) *Message {
m.Status(TIME, m.Time(), kit.MDB_COUNT, kit.Split(m.FormatSize())[0], arg, kit.MDB_COST, m.FormatCost())
return m
return m.Status(TIME, m.Time(), kit.MDB_COUNT, kit.Split(m.FormatSize())[0], arg, kit.MDB_COST, m.FormatCost())
}
func (m *Message) StatusTimeCountTotal(arg ...Any) {
m.Status(TIME, m.Time(), kit.MDB_COUNT, kit.Split(m.FormatSize())[0], kit.MDB_TOTAL, arg, kit.MDB_COST, m.FormatCost())
func (m *Message) StatusTimeCountTotal(arg ...Any) *Message {
return m.Status(TIME, m.Time(), kit.MDB_COUNT, kit.Split(m.FormatSize())[0], kit.MDB_TOTAL, arg, kit.MDB_COST, m.FormatCost())
}
func (m *Message) Process(action string, arg ...Any) {
m.Option(MSG_PROCESS, action)
func (m *Message) Process(cmd string, arg ...Any) {
m.Option(MSG_PROCESS, cmd)
m.Option(PROCESS_ARG, arg...)
}
func (m *Message) ProcessLocation(arg ...Any) {
@ -128,16 +126,12 @@ func (m *Message) ProcessHistory(arg ...Any) {
func (m *Message) ProcessConfirm(arg ...Any) {
m.Process(PROCESS_CONFIRM, arg...)
}
func (m *Message) ProcessRefresh(arg ...string) { // delay
if d, e := time.ParseDuration(kit.Select("300ms", arg, 0)); e == nil {
m.Option("_delay", int(d/time.Millisecond))
}
func (m *Message) ProcessRefresh(arg ...string) {
m.Process(PROCESS_REFRESH)
if d, e := time.ParseDuration(kit.Select("30ms", arg, 0)); e == nil {
m.Option(PROCESS_ARG, int(d/time.Millisecond))
}
}
func (m *Message) ProcessRefresh3ms() { m.ProcessRefresh("3ms") }
func (m *Message) ProcessRefresh30ms() { m.ProcessRefresh("30ms") }
func (m *Message) ProcessRefresh300ms() { m.ProcessRefresh("300ms") }
func (m *Message) ProcessRefresh3s() { m.ProcessRefresh("3s") }
func (m *Message) ProcessRewrite(arg ...Any) {
m.Process(PROCESS_REWRITE, arg...)
}
@ -146,11 +140,11 @@ func (m *Message) ProcessDisplay(arg ...Any) {
m.Option(MSG_DISPLAY, arg...)
}
func (m *Message) ProcessInner() { m.Process(PROCESS_INNER) }
func (m *Message) ProcessField(arg ...Any) {
m.Process(PROCESS_FIELD)
m.Option(FIELD_PREFIX, arg...)
}
func (m *Message) ProcessInner() { m.Process(PROCESS_INNER) }
func (m *Message) ProcessAgain() { m.Process(PROCESS_AGAIN) }
func (m *Message) ProcessHold(text ...Any) { m.Process(PROCESS_HOLD, text...) }
func (m *Message) ProcessBack() { m.Process(PROCESS_BACK) }
@ -158,40 +152,22 @@ func (m *Message) ProcessRich(arg ...Any) { m.Process(PROCESS_RICH, arg...) }
func (m *Message) ProcessGrow(arg ...Any) { m.Process(PROCESS_GROW, arg...) }
func (m *Message) ProcessOpen(url string) { m.Process(PROCESS_OPEN, url) }
func (m *Message) Display(file string, arg ...Any) *Message { // repos local file
func (m *Message) Display(file string, arg ...Any) *Message {
m.Option(MSG_DISPLAY, kit.MergeURL(displayRequire(2, file)[DISPLAY], arg...))
return m
}
func DisplayLocal(file string, arg ...string) Maps { // /plugin/local/file
if file == "" {
file = path.Join(kit.PathName(2), kit.Keys(kit.FileName(2), JS))
}
if !strings.HasPrefix(file, HTTP) && !strings.HasPrefix(file, PS) {
file = path.Join(PLUGIN_LOCAL, file)
}
return DisplayBase(file, arg...)
}
func DisplayStory(file string, arg ...string) Maps { // /plugin/story/file
if !strings.HasPrefix(file, HTTP) && !strings.HasPrefix(file, PS) {
file = path.Join(PLUGIN_STORY, file)
}
return DisplayBase(file, arg...)
}
func DisplayBase(file string, arg ...string) Maps {
return Maps{DISPLAY: file, STYLE: kit.Join(arg, SP)}
}
func Display(file string, arg ...string) Maps { // repos local file
return displayRequire(2, file, arg...)
}
func displayRequire(n int, file string, arg ...string) Maps {
if file == "" {
file = kit.Keys(kit.FileName(n+1), JS)
}
if !strings.HasPrefix(file, HTTP) && !strings.HasPrefix(file, PS) {
if !strings.HasPrefix(file, PS) && !strings.HasPrefix(file, HTTP) {
file = path.Join(PS, path.Join(path.Dir(FileRequire(n+2)), file))
}
return DisplayBase(file, arg...)
}
func DisplayBase(file string, arg ...string) Maps {
return Maps{DISPLAY: file, STYLE: kit.Join(arg, SP)}
}
func FileRequire(n int) string {
p := kit.Split(kit.FileLine(n, 100), DF)[0]
if strings.Contains(p, "go/pkg/mod") {

161
render.go
View File

@ -14,12 +14,7 @@ func Render(m *Message, cmd string, args ...Any) string {
if render, ok := Info.render[cmd]; ok {
return render(m, cmd, args...)
}
switch arg := kit.Simple(args...); cmd {
case RENDER_ANCHOR: // [name] link
p := kit.Select(arg[0], arg, 1)
return kit.Format(`<a href="%s" target="_blank">%s</a>`, p, arg[0])
case RENDER_BUTTON:
list := []string{}
for _, k := range args {
@ -44,47 +39,40 @@ func Render(m *Message, cmd string, args ...Any) string {
}
}
return strings.Join(list, "")
case RENDER_IMAGES: // src [height]
if m.Option("height") != "" && m.Option("width") != "" {
return kit.Format(`<img src="%s" style="max-height:%spx; max-width:%spx">`, arg[0], m.Option("height"), m.Option("width"))
}
if strings.Contains(m.Option(MSG_USERUA), "Mobile") {
return kit.Format(`<img src="%s" width=%d>`, arg[0], kit.Int(kit.Select(kit.Select("120", m.Option("width")), arg, 1))-24)
}
return kit.Format(`<img src="%s" height=%d>`, arg[0], kit.Int(kit.Select(kit.Select("240", m.Option("height")), arg, 1))/2-24)
case RENDER_VIDEOS: // src [height]
if m.Option("height") != "" && m.Option("width") != "" {
return kit.Format(`<video src="%s" controls style="max-height:%spx; max-width:%spx">`, arg[0], m.Option("height"), m.Option("width"))
}
return kit.Format(`<video src="%s" height=%s controls>`, arg[0], kit.Select("120", arg, 1))
case RENDER_ANCHOR:
return kit.Format(`<a href="%s" target="_blank">%s</a>`, kit.Select(arg[0], arg, 1), arg[0])
case RENDER_IMAGES:
return kit.Format(`<img src="%s" style="max-height:%spx; max-width:%spx">`, arg[0], m.Option(HEIGHT), m.Option(WIDTH))
case RENDER_VIDEOS:
return kit.Format(`<video src="%s" style="max-height:%spx; max-width:%spx" controls>`, arg[0], m.Option(HEIGHT), m.Option(WIDTH))
case RENDER_IFRAME:
return kit.Format(`<iframe src="%s"></iframe>`, arg[0])
case RENDER_SCRIPT:
return kit.Format(`<code>%s</code>`, arg[0])
default:
return arg[0]
if len(arg) == 1 {
return kit.Format(`<%s>%s</%s>`, cmd, arg[0], cmd)
}
return kit.Format(`<%s style="%s">%s</%s>`, cmd, kit.JoinKV(":", ";", arg[1:]...), arg[0], cmd)
}
return ""
}
func (m *Message) Render(cmd string, args ...Any) *Message {
func (m *Message) Render(cmd string, arg ...Any) *Message {
switch cmd {
case RENDER_TEMPLATE: // text [data]
if len(args) == 1 {
args = append(args, m)
case RENDER_TEMPLATE:
if len(arg) == 1 {
arg = append(arg, m)
}
if res, err := kit.Render(args[0].(string), args[1]); m.Assert(err) {
if res, err := kit.Render(arg[0].(string), arg[1]); m.Assert(err) {
m.Echo(string(res))
}
return m
}
m.Optionv(MSG_OUTPUT, cmd)
m.Optionv(MSG_ARGS, args)
m.Options(MSG_OUTPUT, cmd, MSG_ARGS, arg)
return m
}
func (m *Message) RenderTemplate(args ...Any) *Message {
return m.Render(RENDER_TEMPLATE, args...)
func (m *Message) RenderTemplate(arg ...Any) *Message {
return m.Render(RENDER_TEMPLATE, arg...)
}
func (m *Message) RenderStatus(status int, arg ...string) *Message {
return m.Render(RENDER_STATUS, status, arg)
@ -101,65 +89,61 @@ func (m *Message) RenderStatusForbidden(arg ...string) *Message {
func (m *Message) RenderStatusNotFound(arg ...string) *Message {
return m.Render(RENDER_STATUS, http.StatusNotFound, arg)
}
func (m *Message) RenderRedirect(args ...Any) *Message {
return m.Render(RENDER_REDIRECT, args...)
func (m *Message) RenderRedirect(arg ...Any) *Message {
return m.Render(RENDER_REDIRECT, arg...)
}
func (m *Message) RenderDownload(args ...Any) *Message {
return m.Render(RENDER_DOWNLOAD, args...)
func (m *Message) RenderDownload(arg ...Any) *Message {
return m.Render(RENDER_DOWNLOAD, arg...)
}
func (m *Message) RenderResult(args ...Any) *Message { // [fmt arg...]
return m.Render(RENDER_RESULT, args...)
func (m *Message) RenderResult(arg ...Any) *Message {
return m.Render(RENDER_RESULT, arg...)
}
func (m *Message) RenderJson(args ...Any) *Message { // [key value]...
return m.Render(RENDER_JSON, kit.Format(kit.Dict(args...)))
func (m *Message) RenderJson(arg ...Any) *Message {
return m.Render(RENDER_JSON, kit.Format(kit.Dict(arg...)))
}
func (m *Message) IsMobileUA() bool {
return strings.Contains(m.Option(MSG_USERUA), "Mobile")
}
func (m *Message) IsCliUA() bool {
if m.Option(MSG_USERUA) == "" || !strings.HasPrefix(m.Option(MSG_USERUA), "Mozilla") {
return true
}
return false
}
func (m *Message) PushAction(list ...Any) *Message {
if len(m.meta[MSG_APPEND]) == 0 {
return m
}
return m.Set(MSG_APPEND, ACTION).Tables(func(value Maps) { m.PushButton(list...) })
func (m *Message) IsMobileUA() bool {
return strings.Contains(m.Option(MSG_USERUA), "Mobile")
}
func (m *Message) PushSearch(args ...Any) {
data := kit.Dict(args...)
for i := 0; i < len(args); i += 2 {
switch k := args[i].(type) {
func (m *Message) PushSearch(arg ...Any) {
data := kit.Dict(arg...)
for i := 0; i < len(arg); i += 2 {
switch k := arg[i].(type) {
case string:
if i+1 < len(args) {
data[k] = args[i+1]
if i+1 < len(arg) {
data[k] = arg[i+1]
}
}
}
for _, k := range kit.Split(m.OptionFields()) {
switch k {
case TIME:
m.Push(k, kit.Select(m.Time(), data[k]))
case POD:
m.Push(k, kit.Select("", data[k]))
case CTX:
m.Push(k, kit.Select(m.Prefix(), data[k]))
case CMD:
m.Push(k, kit.Select(m.CommandKey(), data[k]))
case TIME:
m.Push(k, kit.Select(m.Time(), data[k]))
default:
m.Push(k, kit.Select("", data[k]))
}
}
}
func (m *Message) PushAnchor(arg ...Any) { // [name] link
if !m.IsCliUA() {
m.Push(LINK, Render(m, RENDER_ANCHOR, arg...))
func (m *Message) PushAction(arg ...Any) *Message {
if len(m.meta[MSG_APPEND]) == 0 {
return m
}
return m.Set(MSG_APPEND, ACTION).Tables(func(value Maps) { m.PushButton(arg...) })
}
func (m *Message) PushButton(arg ...Any) *Message { // name...
func (m *Message) PushButton(arg ...Any) *Message {
if !m.IsCliUA() {
if m.FieldsIsDetail() {
for i, k := range m.meta[KEY] {
@ -175,58 +159,63 @@ func (m *Message) PushButton(arg ...Any) *Message { // name...
}
return m
}
func (m *Message) PushImages(key, src string, arg ...string) { // key src [height]
func (m *Message) PushAnchor(arg ...string) {
if !m.IsCliUA() {
m.Push(key, Render(m, RENDER_IMAGES, src, arg))
m.Push(LINK, Render(m, RENDER_ANCHOR, arg))
}
}
func (m *Message) PushVideos(key, src string, arg ...string) { // key src [height]
func (m *Message) PushQRCode(key, src string) {
if !m.IsCliUA() {
m.Push(key, Render(m, RENDER_VIDEOS, src, arg))
m.Push(key, Render(m, RENDER_QRCODE, src))
}
}
func (m *Message) PushIFrame(key, src string, arg ...string) { // key src
func (m *Message) PushImages(key, src string) {
if !m.IsCliUA() {
m.Push(key, Render(m, RENDER_IFRAME, src, arg))
m.Push(key, Render(m, RENDER_IMAGES, src))
}
}
func (m *Message) PushQRCode(key string, src string, arg ...string) { // key src [height]
func (m *Message) PushVideos(key, src string) {
if !m.IsCliUA() {
m.Push(key, Render(m, RENDER_QRCODE, src, arg))
m.Push(key, Render(m, RENDER_VIDEOS, src))
}
}
func (m *Message) PushScript(arg ...string) { // [type] text...
func (m *Message) PushIFrame(key, src string) {
if !m.IsCliUA() {
m.Push(key, Render(m, RENDER_IFRAME, src))
}
}
func (m *Message) PushScript(arg ...string) {
if !m.IsCliUA() {
m.Push(SCRIPT, Render(m, RENDER_SCRIPT, arg))
}
}
func (m *Message) PushDownload(key string, arg ...Any) { // [name] file
func (m *Message) PushDownload(key string, arg ...string) {
if !m.IsCliUA() {
m.Push(key, Render(m, RENDER_DOWNLOAD, arg...))
m.Push(key, Render(m, RENDER_DOWNLOAD, arg))
}
}
func (m *Message) EchoAnchor(arg ...Any) *Message { // [name] link
return m.Echo(Render(m, RENDER_ANCHOR, arg...))
}
func (m *Message) EchoButton(arg ...Any) *Message { // name...
func (m *Message) EchoButton(arg ...Any) *Message {
return m.Echo(Render(m, RENDER_BUTTON, arg...))
}
func (m *Message) EchoImages(src string, arg ...string) *Message { // src [height]
return m.Echo(Render(m, RENDER_IMAGES, src, arg))
func (m *Message) EchoAnchor(arg ...string) *Message {
return m.Echo(Render(m, RENDER_ANCHOR, arg))
}
func (m *Message) EchoVideos(src string, arg ...string) *Message { // src [height]
return m.Echo(Render(m, RENDER_VIDEOS, src, arg))
func (m *Message) EchoQRCode(src string) *Message {
return m.Echo(Render(m, RENDER_QRCODE, src))
}
func (m *Message) EchoIFrame(src string, arg ...string) *Message { // src
return m.Echo(Render(m, RENDER_IFRAME, src, arg))
func (m *Message) EchoImages(src string) *Message {
return m.Echo(Render(m, RENDER_IMAGES, src))
}
func (m *Message) EchoQRCode(src string, arg ...string) *Message { // src [height]
return m.Echo(Render(m, RENDER_QRCODE, src, arg))
func (m *Message) EchoVideos(src string) *Message {
return m.Echo(Render(m, RENDER_VIDEOS, src))
}
func (m *Message) EchoScript(arg ...string) *Message { // [type] text...
func (m *Message) EchoIFrame(src string) *Message {
return m.Echo(Render(m, RENDER_IFRAME, src))
}
func (m *Message) EchoScript(arg ...string) *Message {
return m.Echo(Render(m, RENDER_SCRIPT, arg))
}
func (m *Message) EchoDownload(arg ...Any) *Message { // [name] file
return m.Echo(Render(m, RENDER_DOWNLOAD, arg...))
func (m *Message) EchoDownload(arg ...string) *Message {
return m.Echo(Render(m, RENDER_DOWNLOAD, arg))
}

288
type.go
View File

@ -5,7 +5,6 @@ import (
"fmt"
"io"
"net/http"
"path"
"strings"
"sync/atomic"
"time"
@ -63,21 +62,33 @@ type Context struct {
root *Context
server Server
begin *Message
start *Message
id int32
}
type Server interface {
Spawn(m *Message, c *Context, arg ...string) Server
Begin(m *Message, arg ...string) Server
Start(m *Message, arg ...string) bool
Close(m *Message, arg ...string) bool
Spawn(m *Message, c *Context, arg ...string) Server
}
func (c *Context) ID() int32 {
return atomic.AddInt32(&c.id, 1)
}
func (c *Context) Cap(key string, arg ...Any) string {
if len(arg) > 0 {
c.Caches[key].Value = kit.Format(arg[0])
}
return c.Caches[key].Value
}
func (c *Context) Cmd(m *Message, key string, arg ...string) *Message {
return c._command(m, c.Commands[key], key, arg...)
}
func (c *Context) Server() Server {
return c.server
}
func (c *Context) PrefixKey(arg ...string) string {
return kit.Keys(c.Cap(CTX_FOLLOW), arg)
}
func (c *Command) GetFileLine() string {
if c.RawHand != nil {
switch h := c.RawHand.(type) {
@ -92,25 +103,10 @@ func (c *Command) GetFileLine() string {
return ""
}
}
func (c *Context) Cap(key string, arg ...Any) string {
if len(arg) > 0 {
c.Caches[key].Value = kit.Format(arg[0])
}
return c.Caches[key].Value
}
func (c *Context) Cmd(m *Message, key string, arg ...string) *Message {
return c._command(m, c.Commands[key], key, arg...)
}
func (c *Context) Server() Server {
return c.server
}
func (c *Context) PrefixKey(arg ...string) string {
return kit.Keys(c.Cap(CTX_FOLLOW), arg)
}
func (c *Context) Register(s *Context, x Server, n ...string) *Context {
for _, n := range n {
if s, ok := Info.names[n]; ok {
if s, ok := Info.index[n]; ok {
last := ""
switch s := s.(type) {
case *Context:
@ -118,10 +114,9 @@ func (c *Context) Register(s *Context, x Server, n ...string) *Context {
}
panic(kit.Format("%s %s %v", ErrWarn, n, last))
}
Info.names[n] = s
Info.index[n] = s
}
if s.Merge(s); c.Contexts == nil {
if c.Contexts == nil {
c.Contexts = Contexts{}
}
c.Contexts[s.Name] = s
@ -147,14 +142,12 @@ func (c *Context) Merge(s *Context) *Context {
if c.Commands[CTX_EXIT] == nil {
c.Commands[CTX_EXIT] = &Command{Hand: func(m *Message, arg ...string) { Info.Save(m) }}
}
merge := func(pre *Command, before bool, key string, cmd *Command, cb ...Handler) {
merge := func(pre *Command, init bool, key string, cmd *Command, cb ...Handler) {
last := pre.Hand
pre.Hand = func(m *Message, arg ...string) {
if before {
if init {
last(m, arg...)
}
_key, _cmd := m._key, m._cmd
m._key, m._cmd = key, cmd
for _, cb := range cb {
@ -163,76 +156,60 @@ func (c *Context) Merge(s *Context) *Context {
}
}
m._key, m._cmd = _key, _cmd
if !before {
if !init {
last(m, arg...)
}
}
}
for key, cmd := range s.Commands {
if p, ok := c.Commands[key]; ok && s != c {
if pre, ok := c.Commands[key]; ok && s != c {
switch hand := cmd.Hand; key {
case CTX_INIT:
merge(p, true, key, cmd, hand)
merge(pre, true, key, cmd, hand)
continue
case CTX_EXIT:
merge(p, false, key, cmd, hand)
merge(pre, false, key, cmd, hand)
continue
}
}
if c.Commands[key] = cmd; cmd.List == nil {
cmd.List = SplitCmd(cmd.Name, cmd.Actions)
}
if cmd.Meta == nil {
cmd.Meta = kit.Dict()
}
for k, a := range cmd.Actions {
if p, ok := c.Commands[k]; ok {
switch h := a.Hand; k {
for sub, action := range cmd.Actions {
if pre, ok := c.Commands[sub]; ok && s == c {
switch h := action.Hand; sub {
case CTX_INIT:
merge(p, true, key, cmd, func(m *Message, arg ...string) { h(m, arg...) })
merge(pre, true, key, cmd, h)
case CTX_EXIT:
merge(p, false, key, cmd, func(m *Message, arg ...string) { h(m, arg...) })
merge(pre, false, key, cmd, h)
}
}
if strings.HasPrefix(k, PS) {
k = kit.Select(k, path.Join(PS, key)+PS, k == PS)
c.Commands[k] = &Command{Name: k, Help: cmd.Help, Hand: func(m *Message, arg ...string) { m.Cmdy(m.CommandKey(), arg) }}
if s == c {
for _, h := range Info.merges {
init, exit := h(c, key, cmd, sub, action)
merge(c.Commands[CTX_INIT], true, key, cmd, init)
merge(c.Commands[CTX_EXIT], false, key, cmd, exit)
}
}
if help := kit.Split(action.Help, " :"); len(help) > 0 {
if kit.Value(cmd.Meta, kit.Keys("_trans", strings.TrimPrefix(sub, "_")), help[0]); len(help) > 1 {
kit.Value(cmd.Meta, kit.Keys("_title", sub), help[1])
}
}
if action.Hand == nil {
continue
}
if s != c {
switch k {
case "search":
merge(c.Commands[CTX_INIT], true, key, cmd, func(m *Message, arg ...string) {
if m.CommandKey() != "search" {
m.Cmd("search", "create", m.CommandKey(), m.PrefixKey())
}
})
}
if action.List == nil {
action.List = SplitCmd(action.Name, nil)
}
help := strings.SplitN(a.Help, "", 2)
if len(help) == 1 || help[1] == "" {
help = strings.SplitN(help[0], ":", 2)
}
if kit.Value(cmd.Meta, kit.Keys("_trans", strings.TrimPrefix(k, "_")), help[0]); len(help) > 1 {
kit.Value(cmd.Meta, kit.Keys("title", k), help[1])
}
if a.Hand == nil {
continue // alias cmd
}
if a.List == nil {
a.List = SplitCmd(a.Name, nil)
}
if len(a.List) > 0 {
cmd.Meta[k] = a.List
if len(action.List) > 0 {
cmd.Meta[sub] = action.List
}
}
delete(cmd.Actions, CTX_INIT)
delete(cmd.Actions, CTX_EXIT)
}
if c.Configs == nil {
c.Configs = Configs{}
}
@ -247,6 +224,44 @@ func (c *Context) Merge(s *Context) *Context {
}
return c
}
func (c *Context) Begin(m *Message, arg ...string) *Context {
follow := c.Name
if c.context != nil && c.context != Index {
follow = kit.Keys(c.context.Cap(CTX_FOLLOW), c.Name)
}
if c.Caches == nil {
c.Caches = Caches{}
}
c.Caches[CTX_FOLLOW] = &Cache{Name: CTX_FOLLOW, Value: follow}
c.Caches[CTX_STATUS] = &Cache{Name: CTX_STATUS, Value: CTX_BEGIN}
c.Caches[CTX_STREAM] = &Cache{Name: CTX_STREAM, Value: ""}
if c.Merge(c); c.server != nil {
c.server.Begin(m, arg...)
}
return c
}
func (c *Context) Start(m *Message, arg ...string) bool {
wait := make(chan bool, 1)
defer func() { <-wait }()
m.Go(func() {
wait <- true
m.Log(CTX_START, c.Cap(CTX_FOLLOW))
c.Cap(CTX_STATUS, CTX_START)
if c.server != nil {
c.server.Start(m, arg...)
}
})
return true
}
func (c *Context) Close(m *Message, arg ...string) bool {
m.Log(CTX_CLOSE, c.Cap(CTX_FOLLOW))
c.Cap(CTX_STATUS, CTX_CLOSE)
if c.server != nil {
return c.server.Close(m, arg...)
}
return true
}
func (c *Context) Spawn(m *Message, name string, help string, arg ...string) *Context {
s := &Context{Name: name, Help: help}
if c.server != nil {
@ -257,44 +272,6 @@ func (c *Context) Spawn(m *Message, name string, help string, arg ...string) *Co
m.target = s
return s
}
func (c *Context) Begin(m *Message, arg ...string) *Context {
follow := c.Name
if c.context != nil && c.context != Index {
follow = kit.Keys(c.context.Cap(CTX_FOLLOW), c.Name)
}
c.Caches[CTX_FOLLOW] = &Cache{Name: CTX_FOLLOW, Value: follow}
c.Caches[CTX_STATUS] = &Cache{Name: CTX_STATUS, Value: CTX_BEGIN}
c.Caches[CTX_STREAM] = &Cache{Name: CTX_STREAM, Value: ""}
if c.begin = m; c.server != nil {
c.server.Begin(m, arg...)
}
return c
}
func (c *Context) Start(m *Message, arg ...string) bool {
wait := make(chan bool, 1)
defer func() { <-wait }()
m.Go(func() {
m.Log(CTX_START, c.Cap(CTX_FOLLOW))
c.Cap(CTX_STATUS, CTX_START)
wait <- true
if c.start = m; c.server != nil {
c.server.Start(m, arg...)
}
})
return true
}
func (c *Context) Close(m *Message, arg ...string) bool {
m.Log(CTX_CLOSE, c.Cap(CTX_FOLLOW))
c.Cap(CTX_STATUS, CTX_CLOSE)
if c.server != nil {
return c.server.Close(m, arg...)
}
return true
}
type Message struct {
time time.Time
@ -321,28 +298,11 @@ type Message struct {
I io.Reader
}
// func (m *Message) getMeta(key string) []string {
// defer m.lock.RLock()()
// return m.meta[key]
// }
// func (m *Message) setMeta(key string, value []string) {
// defer m.lock.Lock()()
// if value == nil {
// delete(m.meta, key)
// } else {
// m.meta[key] = value
// }
// }
// func (m *Message) getData(key string) Any {
// defer m.lock.RLock()()
// return m._data[key]
// }
//
func (m *Message) Time(args ...Any) string { // [duration] [format [args...]]
func (m *Message) Time(args ...Any) string {
t := m.time
if len(args) > 0 {
switch arg := args[0].(type) {
case string: // 时间偏移
case string:
if d, e := time.ParseDuration(arg); e == nil {
t, args = t.Add(d), args[1:]
}
@ -351,7 +311,7 @@ func (m *Message) Time(args ...Any) string { // [duration] [format [args...]]
f := MOD_TIME
if len(args) > 0 {
switch arg := args[0].(type) {
case string: // 时间格式
case string:
if f = arg; len(args) > 1 {
f = fmt.Sprintf(f, args[1:]...)
}
@ -365,6 +325,9 @@ func (m *Message) Target() *Context {
func (m *Message) Source() *Context {
return m.source
}
func (m *Message) Message() *Message {
return m.message
}
func (m *Message) Spawn(arg ...Any) *Message {
msg := &Message{
time: time.Now(), code: int(m.target.root.ID()),
@ -373,7 +336,6 @@ func (m *Message) Spawn(arg ...Any) *Message {
source: m.target, target: m.target, _cmd: m._cmd, _key: m._key, _sub: m._sub,
W: m.W, R: m.R, O: m.O, I: m.I,
}
for _, val := range arg {
switch val := val.(type) {
case []byte:
@ -401,27 +363,24 @@ func (m *Message) Spawn(arg ...Any) *Message {
return msg
}
func (m *Message) Start(key string, arg ...string) *Message {
m.Search(key+PT, func(p *Context, s *Context) { s.Start(m.Spawn(s), arg...) })
return m
return m.Search(key+PT, func(p *Context, s *Context) { s.Start(m.Spawn(s), arg...) })
}
func (m *Message) Travel(cb Any) *Message {
list := []*Context{m.root.target}
for i := 0; i < len(list); i++ {
switch cb := cb.(type) {
case func(*Context, *Context): // 遍历模块
case func(*Context, *Context):
cb(list[i].context, list[i])
case func(*Context, *Context, string, *Command):
target := m.target
for _, k := range kit.SortedKey(list[i].Commands) { // 命令列表
for _, k := range kit.SortedKey(list[i].Commands) {
m.target = list[i]
cb(list[i].context, list[i], k, list[i].Commands[k])
}
m.target = target
case func(*Context, *Context, string, *Config):
target := m.target
for _, k := range kit.SortedKey(list[i].Configs) { // 配置列表
for _, k := range kit.SortedKey(list[i].Configs) {
m.target = list[i]
cb(list[i].context, list[i], k, list[i].Configs[k])
}
@ -429,8 +388,7 @@ func (m *Message) Travel(cb Any) *Message {
default:
m.ErrorNotImplement(cb)
}
for _, k := range kit.SortedKey(list[i].Contexts) { // 遍历递进
for _, k := range kit.SortedKey(list[i].Contexts) {
list = append(list, list[i].Contexts[k])
}
}
@ -440,14 +398,12 @@ func (m *Message) Search(key string, cb Any) *Message {
if key == "" {
return m
}
// 查找模块
p := m.target.root
if key = strings.TrimPrefix(key, "ice."); key == PT {
p, key = m.target, ""
} else if key == ".." {
p, key = m.target.context, ""
} else if key == "ice." {
} else if key == "..." {
p, key = m.target.root, ""
} else if strings.Contains(key, PT) {
ls := strings.Split(key, PT)
@ -468,37 +424,33 @@ func (m *Message) Search(key string, cb Any) *Message {
return m
}
key = ls[len(ls)-1]
} else if ctx, ok := Info.names[key].(*Context); ok {
} else if ctx, ok := Info.index[key].(*Context); ok {
p = ctx
} else {
p = m.target
}
switch cb := cb.(type) {
case func(key string, cmd *Command):
if key == "" {
for k, v := range p.Commands {
cb(k, v) // 遍历命令
cb(k, v)
}
break
}
if cmd, ok := p.Commands[key]; ok {
cb(key, cmd) // 查找命令
cb(key, cmd)
}
case func(p *Context, s *Context, key string, cmd *Command):
if key == "" {
for k, v := range p.Commands {
cb(p.context, p, k, v) // 遍历命令
cb(p.context, p, k, v)
}
break
}
for _, p := range []*Context{p, m.target, m.source} {
for s := p; s != nil; s = s.context {
if cmd, ok := s.Commands[key]; ok {
cb(s.context, s, key, cmd) // 查找命令
cb(s.context, s, key, cmd)
return m
}
}
@ -506,23 +458,22 @@ func (m *Message) Search(key string, cb Any) *Message {
case func(p *Context, s *Context, key string, conf *Config):
if key == "" {
for k, v := range p.Configs {
cb(p.context, p, k, v) // 遍历命令
cb(p.context, p, k, v)
}
break
}
for _, p := range []*Context{p, m.target, m.source} {
for s := p; s != nil; s = s.context {
if cmd, ok := s.Configs[key]; ok {
cb(s.context, s, key, cmd) // 查找配置
cb(s.context, s, key, cmd)
return m
}
}
}
case func(p *Context, s *Context, key string):
cb(p.context, p, key) // 查找模块
cb(p.context, p, key)
case func(p *Context, s *Context):
cb(p.context, p) // 查找模块
cb(p.context, p)
default:
m.ErrorNotImplement(cb)
}
@ -542,9 +493,7 @@ func (m *Message) CmdAppend(arg ...Any) string {
}
func (m *Message) CmdMap(arg ...string) map[string]map[string]string {
field, list := kit.Slice(arg, -1)[0], map[string]map[string]string{}
m._command(kit.Slice(arg, 0, -1)).Tables(func(value Maps) {
list[value[field]] = value
})
m._command(kit.Slice(arg, 0, -1)).Tables(func(value Maps) { list[value[field]] = value })
return list
}
func (m *Message) Cmd(arg ...Any) *Message {
@ -563,23 +512,21 @@ func (m *Message) Cmdy(arg ...Any) *Message {
func (m *Message) Confi(key string, sub string) int {
return kit.Int(m.Conf(key, sub))
}
func (m *Message) Confv(arg ...Any) (val Any) { // key sub val
func (m *Message) Confv(arg ...Any) (val Any) {
run := func(conf *Config) {
if len(arg) == 1 {
val = conf.Value
return // 读配置
return
}
if len(arg) > 2 {
if arg[1] == nil || arg[1] == "" {
conf.Value = arg[2] // 写配置
conf.Value = arg[2]
} else {
kit.Value(conf.Value, arg[1:]...) // 写配置项
kit.Value(conf.Value, arg[1:]...)
}
}
val = kit.Value(conf.Value, arg[1]) // 读配置项
val = kit.Value(conf.Value, arg[1])
}
key := kit.Format(arg[0])
if key == "" {
key = m._key
@ -601,7 +548,7 @@ func (m *Message) Confm(key string, sub Any, cbs ...Any) Map {
value, _ := val.(Map)
return value
}
func (m *Message) Conf(arg ...Any) string { // key sub val
func (m *Message) Conf(arg ...Any) string {
return kit.Format(m.Confv(arg...))
}
func (m *Message) Capi(key string, val ...Any) int {
@ -616,14 +563,13 @@ func (m *Message) Capv(arg ...Any) Any {
case string:
key, arg = val, arg[1:]
}
for _, s := range []*Context{m.target} {
for c := s; c != nil; c = c.context {
if caps, ok := c.Caches[key]; ok {
if len(arg) > 0 { // 写数据
if len(arg) > 0 {
caps.Value = kit.Format(arg[0])
}
return caps.Value // 读数据
return caps.Value
}
}
}