1
0
mirror of https://shylinux.com/x/icebergs synced 2025-07-02 12:41:20 +08:00

Compare commits

..

No commits in common. "master" and "v1.0.4" have entirely different histories.

502 changed files with 16106 additions and 30438 deletions

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017-2025 shylinux Copyright (c) 2021 码神
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

128
README.md
View File

@ -1,3 +1,129 @@
# icebergs # icebergs
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/

View File

@ -2,15 +2,8 @@ package aaa
import ice "shylinux.com/x/icebergs" import ice "shylinux.com/x/icebergs"
const (
RSA = "rsa"
SIGN = "sign"
CERT = "cert"
VERIFY = "verify"
BASE64 = "base64"
)
const AAA = "aaa" const AAA = "aaa"
var Index = &ice.Context{Name: AAA, Help: "认证模块"} var Index = &ice.Context{Name: AAA, Help: "认证模块"}
func init() { ice.Index.Register(Index, nil, APPLY, OFFER, EMAIL, USER, TOTP, SESS, ROLE, CERT, RSA) } func init() { ice.Index.Register(Index, nil, ROLE, SESS, TOTP, USER) }

6
base/aaa/aaa.shy Normal file
View File

@ -0,0 +1,6 @@
chapter "aaa"
field "角色" role
field "会话" sess
field "令牌" totp
field "用户" user

View File

@ -1,77 +0,0 @@
package aaa
import (
"net/smtp"
"strings"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
const (
ADMIN = "admin"
SEND = "send"
DATE = "date"
FROM = "from"
TO = "to"
CC = "cc"
SUBJECT = "subject"
CONTENT = "content"
)
const EMAIL = "email"
func init() {
const (
ADMIN = "admin"
SERVICE = "service"
NL = "\r\n"
DF = ": "
)
Index.MergeCommands(ice.Commands{
EMAIL: {Help: "邮件", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create name*=admin service*='smtp.163.com:25' username* password*"},
SEND: {Name: "send from=admin to*='shy@shylinux.com' cc subject*=hi content*:textarea=hello", Help: "发送", Icon: "bi bi-send-plus", Hand: func(m *ice.Message, arg ...string) {
msg := mdb.HashSelects(m.Spawn(), m.OptionDefault(FROM, ADMIN))
if m.WarnNotFound(msg.Append(SERVICE) == "", m.Option(FROM)) {
return
}
m.ToastProcess()
content := []byte(kit.JoinKV(DF, NL, kit.Simple(FROM, msg.Append(USERNAME), m.OptionSimple(TO, CC, SUBJECT), DATE, time.Now().Format(time.RFC1123Z), html.ContentType, "text/html; charset=UTF-8")...) + NL + NL + m.Option(CONTENT))
auth := smtp.PlainAuth("", msg.Append(USERNAME), msg.Append(PASSWORD), kit.Split(msg.Append(SERVICE), ice.DF)[0])
m.Logs(EMAIL, SEND, string(content))
if !m.WarnNotValid(smtp.SendMail(msg.Append(SERVICE), auth, msg.Append(USERNAME), kit.Split(m.Option(TO)), content)) {
m.ToastSuccess()
}
}},
}, mdb.DevDataAction("name,service,username,password"), mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,service,username", ice.ACTION, SEND)), Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...); len(arg) == 0 && m.Length() == 0 {
m.EchoInfoButton(m.Trans("please add admin email", "请配置管理员邮箱"), mdb.CREATE, mdb.DEV_REQUEST)
} else if len(arg) == 0 {
m.Action(mdb.CREATE, mdb.DEV_REQUEST)
}
}},
})
ice.Info.Inputs = append(ice.Info.Inputs, func(m *ice.Message, arg ...string) {
switch kit.TrimPrefix(arg[0], "extra.") {
case TO:
if m.Option(ice.ACTION) != EMAIL {
break
}
fallthrough
case EMAIL:
m.Push(arg[0], "shy@shylinux.com", "shylinux@163.com")
case PASSWORD:
m.SetAppend()
}
})
}
func SendEmail(m *ice.Message, from, to, cc string, arg ...string) {
m.Option(ice.MSG_USERHOST, strings.Split(m.Option(ice.MSG_USERHOST), "://")[1])
m.Cmdy(EMAIL, SEND, kit.Select(mdb.Config(m, EMAIL), from), kit.Select(m.Option(EMAIL), to), cc,
strings.TrimSpace(kit.Select(ice.Render(m, ice.RENDER_TEMPLATE, SUBJECT_HTML), arg, 0)),
kit.Select(ice.Render(m, ice.RENDER_TEMPLATE, CONTENT_HTML), arg, 1),
)
}

View File

@ -1,71 +0,0 @@
package aaa
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func _offer_create(m *ice.Message, arg ...string) {
h := mdb.HashCreate(m.Spawn(), FROM, m.Option(ice.MSG_USERNAME), mdb.STATUS, INVITE, m.OptionSimple(EMAIL, SUBJECT, CONTENT))
SendEmail(m.Options("link", m.Cmdx("host", "publish", m.MergePodCmd("", "", mdb.HASH, h))), m.Option(FROM), "", "")
gdb.Event(m, OFFER_CREATE, mdb.HASH, h, EMAIL, m.Option(EMAIL))
}
func _offer_accept(m *ice.Message, arg ...string) {
msg := mdb.HashSelect(m.Spawn(), m.Option(mdb.HASH))
if ls := kit.Split(msg.Append(EMAIL), mdb.AT); !m.WarnNotFound(msg.Length() == 0 || len(ls) < 2, m.Option(mdb.HASH)) {
m.Spawn().AdminCmd(USER, mdb.CREATE, USERROLE, VOID, USERNAME, msg.Append(EMAIL), USERNICK, ls[0], USERZONE, ls[1])
mdb.HashModify(m, m.OptionSimple(mdb.HASH), mdb.STATUS, ACCEPT)
gdb.Event(m, OFFER_ACCEPT, mdb.HASH, m.Option(mdb.HASH), EMAIL, msg.Append(EMAIL))
m.ProcessLocation(m.MergePod("", ice.MSG_SESSID, SessValid(m.Options(ice.MSG_USERNAME, msg.Append(EMAIL)))))
}
}
const (
INVITE = "invite"
ACCEPT = "accept"
SUBJECT_HTML = "subject.html"
CONTENT_HTML = "content.html"
OFFER_CREATE = "offer.create"
OFFER_ACCEPT = "offer.accept"
)
const APPLY = "apply"
const OFFER = "offer"
func init() {
Index.MergeCommands(ice.Commands{
OFFER: {Help: "邀请", Role: VOID, Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict("from", "发自")),
), Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create from*=admin email*='shy@shylinux.com' subject content", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
_offer_create(m, arg...)
}},
ACCEPT: {Help: "接受", Role: VOID, Hand: func(m *ice.Message, arg ...string) {
if !m.WarnNotValid(m.Option(mdb.HASH), mdb.HASH) {
_offer_accept(m, arg...)
}
}},
}, mdb.ImportantHashAction(
mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,from,status,email,subject,content"), EMAIL, ADMIN,
), Hand: func(m *ice.Message, arg ...string) {
if m.WarnNotRight(len(arg) == 0 && !IsTechOrRoot(m)) {
return
} else if mdb.HashSelect(m, arg...).FieldsIsDetail() {
if m.Option(ice.MSG_USERNAME) == "" {
m.Option(ice.MSG_USERHOST, strings.Split(m.Option(ice.MSG_USERHOST), "://")[1])
m.SetAppend().EchoInfoButton(m.Template(SUBJECT_HTML), ACCEPT)
} else if strings.Contains(m.Option(ice.MSG_USERWEB), "/c/offer") {
m.ProcessLocation(m.MergePod(""))
}
}
}},
})
}
func OfferAction() ice.Actions {
return gdb.EventsAction(OFFER_CREATE, OFFER_ACCEPT, USER_CREATE, USER_REMOVE)
}

View File

@ -1,124 +0,0 @@
package portal
import (
"shylinux.com/x/ice"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web"
kit "shylinux.com/x/toolkits"
)
type apply struct {
ice.Hash
email string `data:"admin"`
checkbox string `data:"true"`
online string `data:"true"`
field string `data:"time,hash,status,email,userrole,username,usernick,icons,agent,system,ip,ua"`
apply string `name:"apply" help:"申请" role:"void"`
agree string `name:"agree userrole=tech,void" help:"同意" icon:"bi bi-check2-square"`
login string `name:"login" help:"登录" role:"void"`
list string `name:"list hash auto sso" help:"注册"`
}
func (s apply) Sso(m *ice.Message, arg ...string) {
m.AddHeaderLogin(cli.QRCODE, cli.QRCODE, "扫码登录", "10")
m.AddHeaderLogin(mdb.PLUGIN, aaa.EMAIL, "邮箱登录", "20", ctx.INDEX, m.ShortKey(), ctx.ARGS, kit.FuncName(s.Login))
m.AddHeaderLogin(mdb.PLUGIN, aaa.APPLY, "注册用户", "30", ctx.INDEX, m.ShortKey(), ctx.ARGS, kit.FuncName(s.Apply))
}
func (s apply) Apply(m *ice.Message, arg ...string) {
if m.IsGetMethod() {
if k := _cookie_key(m); m.Option(k) == "" || s.List(m, m.Option(k)).Length() == 0 && m.Result() == "" {
m.DisplayForm(m, "email*", aaa.USERNICK, s.Apply)
}
} else if !m.WarnAlreadyExists(m.Options(arg).Cmd(aaa.USER, m.Option(aaa.EMAIL)).Length() > 0, m.Option(aaa.EMAIL)) {
m.Options(ice.MSG_USERNAME, m.Option(aaa.EMAIL), ice.MSG_USERNICK, kit.Split(m.Option(aaa.EMAIL), "@")[0])
h := s.Hash.Create(m, kit.Simple(arg, mdb.STATUS, kit.FuncName(s.Apply), web.ParseUA(m.Message))...)
m.ProcessCookie(_cookie_key(m), h)
m.StreamPushRefreshConfirm()
m.ChatMessageInsertPlug(aaa.APPLY, "user.signup", "", m.PrefixKey(), h)
}
}
func (s apply) Agree(m *ice.Message, arg ...string) {
if m.WarnNotValid(m.Option(mdb.HASH) == "", mdb.HASH) {
return
}
msg := s.Hash.List(m.Spawn(), m.Option(mdb.HASH))
if m.WarnNotFound(msg.Length() == 0, m.Option(mdb.HASH)) {
return
}
s.Hash.Modify(m, kit.Simple(m.OptionSimple(mdb.HASH, aaa.USERROLE), mdb.STATUS, s.Agree)...)
// m.UserCreate(m.Option(aaa.USERROLE), msg.Append(aaa.USERNAME), msg.Append(aaa.USERNICK))
m.PushRefresh(msg.Append(cli.DAEMON))
}
func (s apply) Login(m *ice.Message, arg ...string) {
kit.If(m.Option(mdb.HASH) == kit.FuncName(s.Apply), func() { m.Options(mdb.HASH, "") })
if m.IsGetMethod() {
m.DisplayForm("email*", s.Login)
} else if m.Options(arg).Option(aaa.EMAIL) == "" {
if m.WarnNotValid(m.OptionDefault(mdb.HASH, m.Option(_cookie_key(m))) == "", mdb.HASH) {
m.ProcessCookie(_cookie_key(m), "")
return
}
msg := s.Hash.List(m.Spawn(), m.Option(mdb.HASH))
if m.WarnNotFound(msg.Length() == 0, m.Option(mdb.HASH)) {
m.ProcessCookie(_cookie_key(m), "")
return
}
m.UserCreate(m.Option(aaa.USERROLE), msg.Append(aaa.USERNAME), msg.Append(aaa.USERNICK))
web.RenderCookie(m.Message, m.Cmdx(aaa.SESS, mdb.CREATE, msg.Append(aaa.USERNAME)))
s.Hash.Modify(m, kit.Simple(m.OptionSimple(mdb.HASH), mdb.STATUS, s.Login)...)
m.ProcessLocation(nfs.PS)
m.StreamPushRefreshConfirm()
} else {
if m.WarnNotFound(m.Cmd(aaa.USER, m.Option(aaa.EMAIL)).Length() == 0, m.Option(aaa.EMAIL)) {
return
}
m.Options(ice.MSG_USERNAME, m.Option(aaa.EMAIL))
space := kit.Keys(kit.Slice(kit.Split(m.Option(ice.MSG_DAEMON), nfs.PT), 0, -1))
share := m.Cmd(web.SHARE, mdb.CREATE, mdb.TYPE, web.FIELD, mdb.NAME, web.CHAT_GRANT, mdb.TEXT, space, web.SPACE, ice.OPS).Append(mdb.LINK)
m.Options(web.LINK, share).SendEmail("", "", "")
// m.ProcessHold(m.Trans("please auth login in mailbox", "请注意查收邮件"))
m.Echo(m.Trans("please auth login in mailbox", "请注意查收邮件"))
m.ProcessInner()
}
}
func (s apply) List(m *ice.Message, arg ...string) *ice.Message {
kit.If(m.Option(_cookie_key(m)), func(p string) { arg = []string{p} })
kit.If(!m.IsTech(), func() { m.Option(ice.MSG_ONLINE, ice.FALSE) })
if m.IsTech() || (len(arg) > 0 && arg[0] != "") {
s.Hash.List(m, arg...).Table(func(value ice.Maps) {
switch value[mdb.STATUS] {
case kit.FuncName(s.Apply):
m.PushButton(s.Agree, s.Remove)
case kit.FuncName(s.Agree):
m.PushButton(s.Login, s.Remove)
default:
m.PushButton(s.Remove)
}
})
}
if m.Option(_cookie_key(m)) != "" || m.ActionKey() != "" {
switch m.Append(mdb.STATUS) {
case kit.FuncName(s.Login):
if m.ActionKey() == kit.FuncName(s.Apply) {
m.ProcessCookie(_cookie_key(m), "")
} else {
m.SetAppend().ProcessLocation(nfs.PS)
}
case kit.FuncName(s.Agree):
m.SetAppend().EchoInfoButton(m.Trans("please login", "请登录"), s.Login)
case kit.FuncName(s.Apply):
m.SetAppend().EchoInfoButton(m.Trans("please wait admin agree", "请等待管理员同意"), nil)
}
} else if len(arg) == 0 {
m.EchoQRCode(m.MergePodCmd("", "", ctx.ACTION, s.Apply))
}
return m
}
func init() { ice.Cmd("aaa.apply", apply{}) }
func _cookie_key(m *ice.Message) string { return kit.Keys(m.PrefixKey(), mdb.HASH) }

View File

@ -1,77 +0,0 @@
package portal
import (
"shylinux.com/x/ice"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
type asign struct {
ice.Hash
export string `data:"true"`
short string `data:"role"`
field string `data:"time,role"`
shorts string `data:"index"`
fields string `data:"time,index,operate"`
insert string `name:"insert index"`
deploy string `name:"deploy" help:"部署"`
list string `name:"list role auto" help:"分配"`
confer string `name:"confer username" help:"授权"`
}
func (s asign) Inputs(m *ice.Message, arg ...string) {
if arg[0] == "operate" {
m.Search(m.Option(ctx.INDEX), func(key string, cmd *ice.Command) {
for sub, action := range cmd.Actions {
if kit.HasPrefix(sub, "_", "/") {
continue
}
m.Push(arg[0], sub)
m.Push(mdb.NAME, action.Name)
m.Push(mdb.HELP, action.Help)
}
m.Sort(arg[0])
m.Option(ice.TABLE_CHECKBOX, ice.TRUE)
})
} else if arg[0] == aaa.USERNAME {
m.Cmdy(aaa.USER).Cut(aaa.USERNAME, aaa.USERNICK, aaa.USERROLE)
} else {
s.Hash.Inputs(m, arg...)
}
}
func (s asign) Modify(m *ice.Message, arg ...string) {
if m.Option(ctx.INDEX) != "" {
s.Update(m, arg...)
} else {
s.Modify(m, arg...)
}
}
func (s asign) Deploy(m *ice.Message, arg ...string) {
defer m.ToastProcess()()
s.List(m.Spawn()).Table(func(val ice.Maps) {
m.Cmd(aaa.ROLE, mdb.REMOVE, val[aaa.ROLE])
m.Cmd(aaa.ROLE, mdb.CREATE, val[aaa.ROLE])
s.List(m.Spawn(), val[aaa.ROLE]).Table(func(value ice.Maps) {
m.Cmd(aaa.ROLE, aaa.WHITE, val[aaa.ROLE], value[ctx.INDEX])
m.Cmd(aaa.ROLE, aaa.BLACK, val[aaa.ROLE], value[ctx.INDEX], ctx.ACTION)
kit.For(kit.Split(value["operate"]), func(p string) {
m.Cmd(aaa.ROLE, aaa.WHITE, val[aaa.ROLE], value[ctx.INDEX], ctx.ACTION, p)
})
})
})
}
func (s asign) List(m *ice.Message, arg ...string) *ice.Message {
if len(arg) == 0 {
s.Hash.List(m, arg...).Action(s.Create, s.Deploy).PushAction(s.Confer, s.Remove)
} else {
s.Hash.SubList(m, arg[0], arg[1:]...).Action(s.Insert, s.Deploy).PushAction(s.Delete)
}
return m
}
func (s asign) Confer(m *ice.Message, arg ...string) {
m.Cmd(aaa.USER, mdb.MODIFY, aaa.USERNAME, m.Option(aaa.USERNAME), aaa.USERROLE, m.Option(aaa.ROLE))
}
func init() { ice.Cmd("aaa.asign", asign{}) }

View File

@ -1,54 +1,81 @@
package aaa package aaa
import ( import (
"path"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
) )
func _role_keys(key ...string) string { func _role_list(m *ice.Message, userrole string) {
if _key := kit.Select("", strings.Split(key[0], ice.PT), -1); _key != "" { m.Richs(ROLE, nil, kit.Select(mdb.FOREACH, userrole), func(key string, value map[string]interface{}) {
if c, ok := ice.Info.Index[_key].(*ice.Context); ok && kit.Keys(c.Prefix(), _key) == key[0] { kit.Fetch(value[BLACK], func(k string, v interface{}) {
key[0] = _key m.Push(ROLE, kit.Value(value, mdb.NAME))
m.Push(mdb.ZONE, BLACK)
m.Push(mdb.KEY, k)
})
kit.Fetch(value[WHITE], func(k string, v interface{}) {
m.Push(ROLE, kit.Value(value, mdb.NAME))
m.Push(mdb.ZONE, WHITE)
m.Push(mdb.KEY, k)
})
})
}
func _role_chain(arg ...string) string {
return kit.ReplaceAll(kit.Keys(arg), ice.PS, ice.PT)
}
func _role_black(m *ice.Message, userrole, chain string) {
m.Richs(ROLE, nil, userrole, func(key string, value map[string]interface{}) {
list := value[BLACK].(map[string]interface{})
m.Log_CREATE(ROLE, userrole, BLACK, chain)
list[chain] = true
})
}
func _role_white(m *ice.Message, userrole, chain string) {
m.Richs(ROLE, nil, userrole, func(key string, value map[string]interface{}) {
list := value[WHITE].(map[string]interface{})
m.Log_CREATE(ROLE, userrole, WHITE, chain)
list[chain] = true
})
}
func _role_right(m *ice.Message, userrole string, keys ...string) (ok bool) {
if userrole == ROOT {
return true // 超级权限
}
m.Richs(ROLE, nil, kit.Select(VOID, userrole), func(key string, value map[string]interface{}) {
ok = true
list := value[BLACK].(map[string]interface{})
for i := 0; i < len(keys); i++ {
if v, o := list[kit.Join(keys[:i+1], ice.PT)]; o && v == true {
ok = false // 在黑名单
} }
} }
return strings.TrimPrefix(strings.TrimPrefix(strings.TrimSuffix(strings.ReplaceAll(path.Join(strings.ReplaceAll(kit.Keys(key), ice.PT, ice.PS)), ice.PS, ice.PT), ice.PT), ice.PT), "web.") if m.Warn(!ok, ice.ErrNotRight, keys, USERROLE, userrole) {
return // 没有权限
} }
func _role_set(m *ice.Message, role, zone, key string, status bool) { if userrole == TECH {
m.Logs(mdb.INSERT, mdb.KEY, ROLE, ROLE, role, zone, key) return // 管理权限
mdb.HashSelectUpdate(m, role, func(value ice.Map) { value[zone].(ice.Map)[key] = status })
} }
func _role_white(m *ice.Message, role, key string) { _role_set(m, role, WHITE, key, true) }
func _role_black(m *ice.Message, role, key string) { _role_set(m, role, BLACK, key, true) } ok = false
func _role_check(value ice.Map, key []string, ok bool) bool { list = value[WHITE].(map[string]interface{})
white, black := value[WHITE].(ice.Map), value[BLACK].(ice.Map) for i := 0; i < len(keys); i++ {
for i := 0; i < len(key); i++ { if v, o := list[kit.Join(keys[:i+1], ice.PT)]; o && v == true {
kit.If(white[kit.Join(key[:i+1], ice.PT)], func() { ok = true }) ok = true // 在白名单
kit.If(black[kit.Join(key[:i+1], ice.PT)], func() { ok = false })
} }
}
if m.Warn(!ok, ice.ErrNotRight, keys, USERROLE, userrole) {
return // 没有权限
}
if userrole == VOID {
return // 用户权限
}
})
return ok return ok
} }
func _role_right(m *ice.Message, role string, key ...string) (ok bool) {
return role == ROOT || len(mdb.HashSelectDetails(m, kit.Select(VOID, role), func(value ice.Map) bool { return _role_check(value, key, role == TECH) })) > 0 func RoleRight(m *ice.Message, userrole string, keys ...string) bool {
} return _role_right(m, userrole, kit.Split(kit.Keys(keys), ice.PT)...)
func _role_list(m *ice.Message, role string, arg ...string) *ice.Message {
mdb.HashSelectDetail(m, kit.Select(VOID, role), func(value ice.Map) {
kit.For(value[WHITE], func(k string, v ice.Any) {
if len(arg) == 0 || k == arg[0] {
m.Push(ROLE, kit.Value(value, mdb.NAME)).Push(mdb.ZONE, WHITE).Push(mdb.KEY, k).Push(mdb.STATUS, v)
}
})
kit.For(value[BLACK], func(k string, v ice.Any) {
if len(arg) == 0 || k == arg[0] {
m.Push(ROLE, kit.Value(value, mdb.NAME)).Push(mdb.ZONE, BLACK).Push(mdb.KEY, k).Push(mdb.STATUS, v)
}
})
})
return m.Sort(mdb.KEY)
} }
const ( const (
@ -57,116 +84,55 @@ const (
VOID = "void" VOID = "void"
) )
const ( const (
WHITE = "white"
BLACK = "black" BLACK = "black"
WHITE = "white"
RIGHT = "right" RIGHT = "right"
) )
const (
AUTH = "auth"
ACCESS = "access"
PUBLIC = "public"
PRIVATE = "private"
CONFIRM = "confirm"
)
const ROLE = "role" const ROLE = "role"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
ROLE: {Name: "role name key auto", Help: "角色", Actions: ice.MergeActions(ice.Actions{ ROLE: {Name: ROLE, Help: "角色", Value: kit.Data(mdb.SHORT, mdb.NAME)},
}, Commands: map[string]*ice.Command{
ROLE: {Name: "role role auto insert", Help: "角色", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(ROLE, mdb.CREATE, VOID, TECH) m.Rich(ROLE, nil, kit.Dict(mdb.NAME, TECH, BLACK, kit.Dict(), WHITE, kit.Dict()))
has := map[string]bool{VOID: true, TECH: true} m.Rich(ROLE, nil, kit.Dict(mdb.NAME, VOID, WHITE, kit.Dict(), BLACK, kit.Dict()))
m.Travel(func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) { m.Cmd(ROLE, WHITE, VOID, ice.SRC)
role := map[string][]string{} m.Cmd(ROLE, WHITE, VOID, ice.BIN)
kit.For(kit.Split(cmd.Role), func(k string) { role[k] = []string{} }) m.Cmd(ROLE, WHITE, VOID, ice.USR)
for sub, action := range cmd.Actions { m.Cmd(ROLE, BLACK, VOID, ice.USR_LOCAL)
kit.For(kit.Split(action.Role), func(k string) { role[k] = append(role[k], sub) }) m.Cmd(ROLE, WHITE, VOID, ice.USR_LOCAL_GO)
}
kit.For(role, func(role string, list []string) {
kit.If(!has[role], func() { m.Cmd(ROLE, mdb.CREATE, role); has[role] = true })
roleHandle(m, role, list...)
})
})
m.Cmd(ROLE, WHITE, VOID, ROLE, "action", RIGHT)
}}, }},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { mdb.INSERT: {Name: "insert role=void,tech zone=white,black key=", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
if arg[0] == mdb.KEY { m.Richs(ROLE, nil, m.Option(ROLE), func(key string, value map[string]interface{}) {
mdb.HashInputs(m, ice.INDEX).CutTo(ice.INDEX, arg[0]) m.Log_CREATE(ROLE, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY))
} list := value[m.Option(mdb.ZONE)].(map[string]interface{})
}}, list[m.Option(mdb.KEY)] = true
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) {
kit.For(arg, func(role string) {
mdb.Rich(m, ROLE, nil, kit.Dict(mdb.NAME, role, BLACK, kit.Dict(), WHITE, kit.Dict()))
}) })
}}, }},
mdb.INSERT: {Name: "insert role*=void zone*=white,black key*", Hand: func(m *ice.Message, arg ...string) { mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
_role_set(m, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY), true) m.Richs(ROLE, nil, m.Option(ROLE), func(key string, value map[string]interface{}) {
}}, m.Log_REMOVE(ROLE, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY))
mdb.DELETE: {Hand: func(m *ice.Message, arg ...string) { list := value[m.Option(mdb.ZONE)].(map[string]interface{})
_role_set(m, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY), false) delete(list, m.Option(mdb.KEY))
}},
WHITE: {Hand: func(m *ice.Message, arg ...string) { _role_white(m, arg[0], _role_keys(arg[1:]...)) }},
BLACK: {Hand: func(m *ice.Message, arg ...string) { _role_black(m, arg[0], _role_keys(arg[1:]...)) }},
RIGHT: {Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 2 {
m.Search(arg[1], func(key string, cmd *ice.Command) {
if _, ok := cmd.Actions[arg[2]]; ok {
arg = kit.Simple(arg[0], arg[1], ice.ACTION, arg[2:])
}
}) })
} }},
for _, role := range kit.AddUniq(kit.Split(arg[0]), VOID) {
if _role_right(m, role, kit.Split(_role_keys(arg[1:]...), ice.PT)...) { BLACK: {Name: "black role chain", Help: "黑名单", Hand: func(m *ice.Message, arg ...string) {
_role_black(m, arg[0], _role_chain(arg[1:]...))
}},
WHITE: {Name: "white role chain", Help: "白名单", Hand: func(m *ice.Message, arg ...string) {
_role_white(m, arg[0], _role_chain(arg[1:]...))
}},
RIGHT: {Name: "right role chain", Help: "查看权限", Hand: func(m *ice.Message, arg ...string) {
if _role_right(m, arg[0], kit.Split(_role_chain(arg[1:]...), ice.PT)...) {
m.Echo(ice.OK) m.Echo(ice.OK)
break
}
} }
}}, }},
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name")), Hand: func(m *ice.Message, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { _role_list(m, kit.Select("", arg, 0))
mdb.HashSelect(m, arg...) m.PushAction(mdb.DELETE)
} else {
_role_list(m, kit.Select("", arg, 0), kit.Slice(arg, 1)...)
}
}}, }},
}) }})
} }
func roleHandle(m *ice.Message, role string, key ...string) {
cmd := m.ShortKey()
role = kit.Select(VOID, role)
m.Cmd(ROLE, WHITE, role, cmd)
if cmd == "header" {
return
}
m.Cmd(ROLE, BLACK, role, cmd, ice.ACTION)
kit.For(key, func(key string) { m.Cmd(ROLE, WHITE, role, cmd, ice.ACTION, key) })
}
func WhiteAction(role string, key ...string) ice.Actions {
role = kit.Select(VOID, role)
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
cmd := m.CommandKey()
m.Cmd(ROLE, WHITE, role, cmd)
if cmd == "header" {
return
}
m.Cmd(ROLE, BLACK, role, cmd, ice.ACTION)
kit.For(key, func(key string) { m.Cmd(ROLE, WHITE, role, cmd, ice.ACTION, key) })
}}}
}
func White(m *ice.Message, key ...string) {
kit.For(key, func(key string) { m.Cmd(ROLE, WHITE, VOID, key) })
}
func Black(m *ice.Message, key ...string) {
kit.For(key, func(key string) { m.Cmd(ROLE, BLACK, VOID, key) })
}
func Right(m *ice.Message, key ...ice.Any) bool {
if key := kit.Simple(key); len(key) > 2 && key[1] == ice.ACTION && kit.IsIn(kit.Format(key[2]), ice.RUN, ice.COMMAND) {
return true
} else if len(key) > 0 && key[0] == ice.ETC_PATH {
return true
}
// m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD), m.CommandKey(), m.ActionKey())+" "+logs.FileLine(-2))
return !ice.Info.Important || m.Option(ice.MSG_USERROLE) == ROOT || !m.WarnNotRight(m.Cmdx(ROLE, RIGHT, m.Option(ice.MSG_USERROLE), key, logs.FileLineMeta(-1)) != ice.OK,
kit.Keys(key...), USERROLE, m.Option(ice.MSG_USERROLE))
}
func IsTechOrRoot(m *ice.Message) bool { return kit.IsIn(m.Option(ice.MSG_USERROLE), TECH, ROOT) }

View File

@ -4,22 +4,54 @@ import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
) )
func _sess_create(m *ice.Message, username string, arg ...string) { func _sess_check(m *ice.Message, sessid string) bool {
if msg := m.Cmd(USER, username); msg.Length() > 0 { m.Option(ice.MSG_USERROLE, VOID)
mdb.HashCreate(m, msg.AppendSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg) m.Option(ice.MSG_USERNAME, "")
} else { m.Option(ice.MSG_USERNICK, "")
mdb.HashCreate(m, m.OptionSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg) if sessid == "" {
return false
} }
m.Richs(SESS, nil, sessid, func(value map[string]interface{}) {
if value = kit.GetMeta(value); m.Warn(kit.Time(kit.Format(value[mdb.TIME])) < kit.Time(m.Time()), ice.ErrExpire) {
return // 会话超时
} }
func _sess_check(m *ice.Message, sessid string) { if m.Richs(USER, nil, value[USERNAME], func(value map[string]interface{}) {
if val := mdb.HashSelectDetails(m, sessid, func(value ice.Map) bool { m.Log_AUTH(
return kit.Format(value[mdb.TIME]) > m.Time() USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
}); len(val) > 0 { USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
SessAuth(m, val) USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]),
)
}) == nil {
m.Log_AUTH(
USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]),
)
} }
})
return m.Option(ice.MSG_USERNAME) != ""
}
func _sess_create(m *ice.Message, username string) string {
if username == "" {
return ""
}
h := m.Cmdx(mdb.INSERT, SESS, "", mdb.HASH, mdb.TIME, m.Time(m.Conf(SESS, kit.Keym(mdb.EXPIRE))),
USERROLE, UserRole(m, username), USERNAME, username, USERNICK, UserNick(m, username),
IP, m.Option(ice.MSG_USERIP), UA, m.Option(ice.MSG_USERUA),
)
m.Event(SESS_CREATE, SESS, h, USERNAME, username)
return h
}
func SessCreate(m *ice.Message, username string) string {
return m.Option(ice.MSG_SESSID, _sess_create(m, username))
}
func SessCheck(m *ice.Message, sessid string) bool {
return _sess_check(m, sessid)
} }
const ( const (
@ -27,46 +59,25 @@ const (
UA = "ua" UA = "ua"
) )
const ( const (
CHECK = "check" GRANT = "grant"
LOGIN = "login" LOGIN = "login"
LOGOUT = "logout" LOGOUT = "logout"
) )
const (
SESS_CREATE = "sess.create"
)
const SESS = "sess" const SESS = "sess"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SESS: {Name: "sess hash auto", Help: "会话", Actions: ice.MergeActions(ice.Actions{ SESS: {Name: SESS, Help: "会话", Value: kit.Data(
mdb.CREATE: {Name: "create username*", Hand: func(m *ice.Message, arg ...string) { mdb.SHORT, "uniq", mdb.FIELD, "time,hash,userrole,username,usernick,ip,ua", mdb.EXPIRE, "720h",
_sess_create(m, m.Option(USERNAME), UA, m.Option(ice.MSG_USERUA), IP, m.Option(ice.MSG_USERIP)) )},
}, Commands: map[string]*ice.Command{
SESS: {Name: "sess hash auto prunes", Help: "会话", Action: ice.MergeAction(map[string]*ice.Action{
mdb.CREATE: {Name: "create username", Help: "创建"},
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...)
}}, }},
CHECK: {Name: "check sessid*", Hand: func(m *ice.Message, arg ...string) { _sess_check(m, m.Option(ice.MSG_SESSID)) }}, }})
}, mdb.ImportantHashAction("checkbox", ice.TRUE, mdb.EXPIRE, mdb.MONTH, mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,userrole,username,usernick,avatar,ip,ua"))},
})
}
func SessCreate(m *ice.Message, username string) string {
return m.Option(ice.MSG_SESSID, m.Cmdx(SESS, mdb.CREATE, username))
}
func SessCheck(m *ice.Message, sessid string) bool {
m.Options(ice.MSG_USERNICK, "", ice.MSG_USERNAME, "", ice.MSG_USERROLE, VOID, ice.MSG_CHECKER, logs.FileLine(-1))
return sessid != "" && m.Cmdy(SESS, CHECK, sessid, logs.FileLineMeta(-1)).Option(ice.MSG_USERNAME) != ""
}
func SessValid(m *ice.Message) string {
if m.Option(ice.MSG_SESSID) == "" || m.Spawn().AdminCmd(SESS, m.Option(ice.MSG_SESSID)).Length() == 0 {
return m.Option(ice.MSG_SESSID, m.Spawn().AdminCmd(SESS, mdb.CREATE, m.Option(ice.MSG_USERNAME)).Result())
}
return m.Option(ice.MSG_SESSID)
}
func SessAuth(m *ice.Message, value ice.Any, arg ...string) *ice.Message {
return m.Auth(
USERROLE, m.Option(ice.MSG_USERROLE, kit.Format(kit.Value(value, USERROLE))),
USERNAME, m.Option(ice.MSG_USERNAME, kit.Format(kit.Value(value, USERNAME))),
USERNICK, m.Option(ice.MSG_USERNICK, kit.Format(kit.Value(value, USERNICK))),
LANGUAGE, m.OptionDefault(ice.MSG_LANGUAGE, kit.Format(kit.Value(value, LANGUAGE))),
AVATAR, m.Option(ice.MSG_AVATAR, kit.Format(kit.Value(value, AVATAR))),
arg, logs.FileLineMeta(kit.Select(logs.FileLine(-1), m.Option("aaa.checker"))),
)
}
func SessLogout(m *ice.Message, arg ...string) {
kit.If(m.Option(ice.MSG_SESSID), func(sessid string) { m.Cmd(SESS, mdb.REMOVE, mdb.HASH, sessid) })
} }

View File

@ -21,48 +21,68 @@ func _totp_gen(per int64) string {
b := hmac.New(sha1.New, buf.Bytes()).Sum(nil) b := hmac.New(sha1.New, buf.Bytes()).Sum(nil)
return strings.ToUpper(base32.StdEncoding.EncodeToString(b[:])) return strings.ToUpper(base32.StdEncoding.EncodeToString(b[:]))
} }
func _totp_get(key string, per int64, num int) string { func _totp_get(key string, num int, per int64) string {
buf, now := []byte{}, kit.Int64(time.Now().Unix()/per) now := kit.Int64(time.Now().Unix() / per)
kit.For(8, func(i int) { buf = append(buf, byte((uint64(now) >> uint64(((7 - i) * 8))))) })
kit.If(len(key)%8, func(l int) { key += strings.Repeat(mdb.EQ, 8-l) }) buf := []byte{}
for i := 0; i < 8; i++ {
buf = append(buf, byte((uint64(now) >> uint64(((7 - i) * 8)))))
}
if l := len(key) % 8; l != 0 {
key += strings.Repeat("=", 8-l)
}
s, _ := base32.StdEncoding.DecodeString(strings.ToUpper(key)) s, _ := base32.StdEncoding.DecodeString(strings.ToUpper(key))
hm := hmac.New(sha1.New, s) hm := hmac.New(sha1.New, s)
hm.Write(buf) hm.Write(buf)
b := hm.Sum(nil) b := hm.Sum(nil)
n := b[len(b)-1] & 0x0F n := b[len(b)-1] & 0x0F
res := int64(b[n]&0x7F)<<24 | int64(b[n+1]&0xFF)<<16 | int64(b[n+2]&0xFF)<<8 | int64(b[n+3]&0xFF) res := int64(b[n]&0x7F)<<24 | int64(b[n+1]&0xFF)<<16 | int64(b[n+2]&0xFF)<<8 | int64(b[n+3]&0xFF)
return kit.Format(kit.Format("%%0%dd", num), res%int64(math.Pow10(num))) return kit.Format(kit.Format("%%0%dd", num), res%int64(math.Pow10(num)))
} }
func TOTP_GET(key string, num int, per int64) string { return _totp_get(key, num, per) }
const (
SECRET = "secret"
PERIOD = "period"
NUMBER = "number"
)
const TOTP = "totp" const TOTP = "totp"
func init() { func init() {
const ( Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
NUMBER = "number" TOTP: {Name: TOTP, Help: "令牌", Value: kit.Data(
PERIOD = "period" mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,secret,period,number", mdb.LINK, "otpauth://totp/%s?secret=%s",
SECRET = "secret" )},
) }, Commands: map[string]*ice.Command{
Index.MergeCommands(ice.Commands{ TOTP: {Name: "totp name auto create", Help: "令牌", Action: ice.MergeAction(map[string]*ice.Action{
TOTP: {Help: "令牌", Actions: ice.MergeActions(ice.Actions{ mdb.CREATE: {Name: "create name secret period=30 number=6", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
mdb.CREATE: {Name: "create name*=hi number*=6 period*=30 secret", Hand: func(m *ice.Message, arg ...string) { if m.Option(SECRET) == "" { // 创建密钥
kit.If(m.Option(SECRET) == "", func() { m.Option(SECRET, _totp_gen(kit.Int64(m.Option(PERIOD)))) }) m.Option(SECRET, _totp_gen(kit.Int64(m.Option(PERIOD))))
mdb.HashCreate(m, m.OptionSimple(mdb.NAME, NUMBER, PERIOD, SECRET))
}},
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,number,period,secret", mdb.LINK, "otpauth://totp/%s?secret=%s")), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) {
kit.If(len(arg) > 0, func() { m.OptionFields(ice.FIELDS_DETAIL) })
m.Push(mdb.TIME, m.Time()).Push(mdb.NAME, value[mdb.NAME])
period := kit.Int64(value[PERIOD])
m.Push(mdb.EXPIRE, period-time.Now().Unix()%period)
m.Push(mdb.VALUE, _totp_get(value[SECRET], period, kit.Int(value[NUMBER])))
if len(arg) > 0 {
m.PushQRCode(mdb.SCAN, kit.Format(mdb.Config(m, mdb.LINK), value[mdb.NAME], value[SECRET]))
m.Echo(m.Append(mdb.VALUE))
}
})
kit.If(len(arg) == 0, func() { m.PushAction(mdb.REMOVE).Action(mdb.CREATE, mdb.PRUNES) })
}},
})
} }
func TOTP_GET(key string, per int64, num int) string { return _totp_get(key, per, num) } m.Cmd(mdb.INSERT, TOTP, "", mdb.HASH, m.OptionSimple(mdb.NAME, SECRET, PERIOD, NUMBER))
}},
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m.Spawn(c), arg...).Table(func(index int, value map[string]string, head []string) {
if len(arg) > 0 {
m.OptionFields(mdb.DETAIL)
}
m.Push(mdb.TIME, m.Time())
m.Push(mdb.NAME, value[mdb.NAME])
period := kit.Int64(value[PERIOD])
m.Push("rest", period-time.Now().Unix()%period)
m.Push("code", _totp_get(value[SECRET], kit.Int(value[NUMBER]), period))
if len(arg) > 0 {
m.PushQRCode(mdb.SCAN, kit.Format(m.Config(mdb.LINK), value[mdb.NAME], value[SECRET]))
m.Echo(_totp_get(value[SECRET], kit.Int(value[NUMBER]), kit.Int64(value[PERIOD])))
}
})
}},
}})
}

View File

@ -2,111 +2,138 @@ package aaa
import ( import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _user_create(m *ice.Message, name string, arg ...string) { func _user_exists(m *ice.Message, name string) bool {
mdb.HashCreate(m, USERNAME, name, arg) return m.Richs(USER, nil, name, nil) != nil
gdb.Event(m, USER_CREATE, USER, name)
} }
func _user_remove(m *ice.Message, name string, arg ...string) { func _user_login(m *ice.Message, name, word string) (ok bool) {
gdb.Event(m, USER_REMOVE, m.OptionSimple(USERNAME, USERNICK)) if !_user_exists(m, name) {
mdb.HashRemove(m, m.OptionSimple(USERNAME)) _user_create(m, VOID, name, word)
}
m.Richs(USER, nil, name, func(key string, value map[string]interface{}) {
if ok = !m.Warn(word != "" && word != value[PASSWORD], ice.ErrNotRight); ok {
m.Log_AUTH(
USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]),
)
}
})
return ok
}
func _user_create(m *ice.Message, role, name, word string) {
if name == "" {
return
}
if word == "" {
if m.Richs(USER, nil, name, func(key string, value map[string]interface{}) {
word = kit.Format(value[PASSWORD])
}) == nil {
word = kit.Hashs()
}
}
m.Rich(USER, nil, kit.Dict(USERROLE, role, USERNAME, name, PASSWORD, word))
m.Event(USER_CREATE, USER, name)
}
func _user_search(m *ice.Message, name, text string) {
m.Richs(USER, nil, mdb.FOREACH, func(key string, value map[string]interface{}) {
if value = kit.GetMeta(value); name == "" || name == value[USERNAME] {
m.PushSearch(kit.SimpleKV("", value[USERROLE], value[USERNAME], value[USERNICK]), value)
}
})
}
func UserRoot(m *ice.Message, arg ...string) { // password username userrole
username := m.Option(ice.MSG_USERNAME, kit.Select(ice.Info.UserName, arg, 1))
userrole := m.Option(ice.MSG_USERROLE, kit.Select(ROOT, arg, 2))
if len(arg) > 0 {
_user_create(m, userrole, username, kit.Select("", arg, 0))
}
}
func UserRole(m *ice.Message, username interface{}) (role string) {
if role = VOID; username == ice.Info.UserName {
return ROOT
}
if m.Richs(USER, nil, kit.Format(username), func(key string, value map[string]interface{}) {
role = kit.Format(kit.GetMeta(value)[USERROLE])
}) == nil && kit.Format(username) == m.Option(ice.MSG_USERNAME) {
return m.Option(ice.MSG_USERROLE)
}
return
}
func UserNick(m *ice.Message, username interface{}) (nick string) {
if m.Richs(USER, nil, kit.Format(username), func(key string, value map[string]interface{}) {
nick = kit.Format(kit.GetMeta(value)[USERNICK])
}) == nil && kit.Format(username) == m.Option(ice.MSG_USERNAME) {
return m.Option(ice.MSG_USERNICK)
}
return
}
func UserZone(m *ice.Message, username interface{}) (zone string) {
m.Richs(USER, nil, kit.Format(username), func(key string, value map[string]interface{}) {
zone = kit.Format(kit.GetMeta(value)[USERZONE])
})
return
}
func UserLogin(m *ice.Message, username, password string) bool {
return _user_login(m, username, password)
} }
const ( const (
BACKGROUND = "background" BACKGROUND = "background"
AVATAR_URL = "avatar_url"
AVATAR = "avatar" AVATAR = "avatar"
GENDER = "gender" GENDER = "gender"
MOBILE = "mobile" MOBILE = "mobile"
PHONE = "phone" EMAIL = "email"
SECRET = "secret"
THEME = "theme"
LANGUAGE = "language"
LOCATION = "location"
LONGITUDE = "longitude"
LATITUDE = "latitude"
COMPANY = "company"
PROVINCE = "province"
COUNTRY = "country"
CITY = "city" CITY = "city"
COUNTRY = "country"
LANGUAGE = "language"
PROVINCE = "province"
) )
const ( const (
USERNICK = "usernick" USERROLE = "userrole"
USERNAME = "username" USERNAME = "username"
PASSWORD = "password" PASSWORD = "password"
USERROLE = "userrole" USERNICK = "usernick"
USERZONE = "userzone" USERZONE = "userzone"
)
const (
USER_CREATE = "user.create" USER_CREATE = "user.create"
USER_REMOVE = "user.remove" )
const (
INVITE = "invite"
) )
const USER = "user" const USER = "user"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
USER: {Help: "用户", Icon: "Contacts.png", Actions: ice.MergeActions(ice.Actions{ USER: {Name: USER, Help: "用户", Value: kit.Data(
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { mdb.SHORT, USERNAME, mdb.FIELD, "time,userrole,username,usernick,userzone",
switch mdb.HashInputs(m, arg); arg[0] { )},
case USERNICK: }, Commands: map[string]*ice.Command{
m.Push(arg[0], m.Option(ice.MSG_USERNICK)) USER: {Name: "user username auto create", Help: "用户", Action: ice.MergeAction(map[string]*ice.Action{
case USERNAME: ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Push(arg[0], m.Option(ice.MSG_USERNAME)) m.Cmd(mdb.SEARCH, mdb.CREATE, m.CommandKey(), m.PrefixKey())
} UserRoot(ice.Pulse)
if arg[0] == USERROLE { }},
m.Option(ice.TABLE_CHECKBOX, ice.TRUE) mdb.SEARCH: {Name: "search type name text", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
if arg[0] == USER {
_user_search(m, arg[1], kit.Select("", arg, 2))
} }
}}, }},
mdb.CREATE: {Name: "create userrole=void,tech username* usernick language userzone email avatar", Hand: func(m *ice.Message, arg ...string) { mdb.CREATE: {Name: "create userrole=void,tech username password", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
_user_create(m, m.Option(USERNAME), m.OptionSimple(USERROLE, USERNICK, LANGUAGE, AVATAR, BACKGROUND, USERZONE, EMAIL)...) if !_user_exists(m, m.Option(USERNAME)) {
_user_create(m, m.Option(USERROLE), m.Option(USERNAME), m.Option(PASSWORD))
}
}}, }},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { _user_remove(m, m.Option(USERNAME)) }}, }, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}, mdb.ImportantHashAction(mdb.SHORT, USERNAME, mdb.FIELD, "time,userrole,username,usernick,language,avatar,background,userzone", html.CHECKBOX, ice.TRUE))}, mdb.HashSelect(m, arg...)
}) }},
} }})
func UserInfo(m *ice.Message, name ice.Any, key, meta string) (value string) {
if m.Cmd(USER, kit.Select(m.Option(ice.MSG_USERNAME), name), func(val ice.Maps) { value = val[key] }).Length() == 0 || value == "" {
return m.Option(meta)
}
return
}
func UserRole(m *ice.Message, username ice.Any) (role string) {
if username == "" {
return VOID
} else if role = VOID; username == ice.Info.UserName {
return ROOT
} else {
return UserInfo(m, username, USERROLE, ice.MSG_USERROLE)
}
}
func UserNick(m *ice.Message, username ice.Any) (nick string) {
return UserInfo(m, username, USERNICK, ice.MSG_USERNICK)
}
func UserLang(m *ice.Message, username ice.Any) (nick string) {
return UserInfo(m, username, LANGUAGE, ice.MSG_LANGUAGE)
}
func UserZone(m *ice.Message, username ice.Any) (zone string) {
return UserInfo(m, username, USERZONE, ice.MSG_USERZONE)
}
func UserEmail(m *ice.Message, username ice.Any) (nick string) {
return UserInfo(m, username, EMAIL, EMAIL)
}
func UserRoot(m *ice.Message, arg ...string) *ice.Message {
userrole := kit.Select(TECH, arg, 0)
username := kit.Select(ice.Info.UserName, arg, 1)
usernick := kit.Select(UserNick(m, username), arg, 2)
language := kit.Select(UserLang(m, username), arg, 3)
userzone := kit.Select(ice.OPS, arg, 4)
email := kit.Select(UserEmail(m, username), arg, 5)
if len(arg) > 0 {
kit.If(username != ROOT, func() { ice.Info.UserName = username })
m.Cmd(USER, mdb.CREATE, userrole, username, usernick, language, userzone, email)
}
return SessAuth(m, kit.Dict(USERROLE, userrole, USERNAME, username, USERNICK, usernick))
} }

View File

@ -1,18 +1,18 @@
package base package shy
import ( import (
_ "shylinux.com/x/icebergs/base/aaa" _ "shylinux.com/x/icebergs/base/aaa"
_ "shylinux.com/x/icebergs/base/cli"
_ "shylinux.com/x/icebergs/base/ctx" _ "shylinux.com/x/icebergs/base/ctx"
_ "shylinux.com/x/icebergs/base/mdb"
_ "shylinux.com/x/icebergs/base/web" _ "shylinux.com/x/icebergs/base/web"
_ "shylinux.com/x/icebergs/base/gdb" _ "shylinux.com/x/icebergs/base/gdb"
_ "shylinux.com/x/icebergs/base/lex" _ "shylinux.com/x/icebergs/base/lex"
_ "shylinux.com/x/icebergs/base/ssh" _ "shylinux.com/x/icebergs/base/log"
_ "shylinux.com/x/icebergs/base/yac" _ "shylinux.com/x/icebergs/base/yac"
_ "shylinux.com/x/icebergs/base/cli" _ "shylinux.com/x/icebergs/base/mdb"
_ "shylinux.com/x/icebergs/base/log"
_ "shylinux.com/x/icebergs/base/nfs" _ "shylinux.com/x/icebergs/base/nfs"
_ "shylinux.com/x/icebergs/base/ssh"
_ "shylinux.com/x/icebergs/base/tcp" _ "shylinux.com/x/icebergs/base/tcp"
) )

21
base/base.shy Normal file
View File

@ -0,0 +1,21 @@
label `
ctx cli web aaa
lex yac gdb log
tcp nfs ssh mdb
`
source ctx/ctx.shy
source cli/cli.shy
source web/web.shy
source aaa/aaa.shy
source lex/lex.shy
source yac/yac.shy
source gdb/gdb.shy
source log/log.shy
source tcp/tcp.shy
source nfs/nfs.shy
source ssh/ssh.shy
source mdb/mdb.shy

View File

@ -1,14 +1,9 @@
package cli package cli
import ( import ice "shylinux.com/x/icebergs"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const CLI = "cli" const CLI = "cli"
var Index = &ice.Context{Name: CLI, Help: "命令模块"} var Index = &ice.Context{Name: CLI, Help: "命令模块"}
func Prefix(arg ...string) string { return kit.Keys(CLI, arg) } func init() { ice.Index.Register(Index, nil, RUNTIME, QRCODE, SYSTEM, DAEMON, FOREVER) }
func init() { ice.Index.Register(Index, nil, RUNTIME, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE, SUDO) }

8
base/cli/cli.shy Normal file
View File

@ -0,0 +1,8 @@
chapter "cli"
field "环境" runtime
field "扫码" qrcode
field "命令" system
field "守护" daemon
field "启动" forever

View File

@ -1,92 +0,0 @@
package cli
import (
"fmt"
"image/color"
"math/rand"
"strconv"
"strings"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const (
_DARK = 255
_LIGHT = 127
)
var _color_map = map[string]color.Color{
BLACK: color.RGBA{0, 0, 0, _DARK},
RED: color.RGBA{_DARK, 0, 0, _DARK},
GREEN: color.RGBA{0, _DARK, 0, _DARK},
YELLOW: color.RGBA{_DARK, _DARK, 0, _DARK},
BLUE: color.RGBA{0, 0, _DARK, _DARK},
PURPLE: color.RGBA{_DARK, 0, _DARK, _DARK},
CYAN: color.RGBA{0, _DARK, _DARK, _DARK},
WHITE: color.RGBA{_DARK, _DARK, _DARK, _DARK},
SILVER: color.RGBA{0xC0, 0xC0, 0xC0, _DARK},
}
var _color_list = map[string]string{
"navy": "#000080",
"aliceblue": "#f0f8ff",
"firebrick": "#b22222",
}
func _parse_color(str string) color.Color {
if str == RANDOM {
list := kit.SortedKey(_color_map)
str = list[rand.Intn(len(list))]
}
str = kit.Select(str, _color_list[str])
if strings.HasPrefix(str, "#") {
kit.If(len(str) == 7, func() { str += "ff" })
if u, e := strconv.ParseUint(str[1:], 16, 64); e == nil {
return color.RGBA{uint8((u & 0xFF000000) >> 24), uint8((u & 0x00FF0000) >> 16), uint8((u & 0x0000FF00) >> 8), uint8((u & 0x000000FF) >> 0)}
}
}
if color, ok := _color_map[str]; ok {
return color
}
return _color_map[WHITE]
}
func _parse_cli_color(str string) string {
res := 0
r, g, b, _ := _parse_color(str).RGBA()
kit.If(r > _LIGHT, func() { res += 1 })
kit.If(g > _LIGHT, func() { res += 2 })
kit.If(b > _LIGHT, func() { res += 4 })
return kit.Format(res)
}
const (
BG = "bg"
FG = "fg"
COLOR = "color"
BLACK = "black"
WHITE = "white"
BLUE = "blue"
RED = "red"
GRAY = "gray"
CYAN = "cyan"
GREEN = "green"
SILVER = "silver"
PURPLE = "purple"
YELLOW = "yellow"
RANDOM = "random"
TRANS = "#0000"
LIGHT = "light"
DARK = "dark"
)
func Color(m *ice.Message, c string, str ice.Any) string {
wrap, color := `<span style="color:%s">%v</span>`, c
kit.If(m.IsCliUA(), func() { wrap, color = "\033[3%sm%v\033[0m", _parse_cli_color(c) })
return fmt.Sprintf(wrap, color, str)
}
func ColorRed(m *ice.Message, str ice.Any) string { return Color(m, RED, str) }
func ColorGreen(m *ice.Message, str ice.Any) string { return Color(m, GREEN, str) }
func ColorYellow(m *ice.Message, str ice.Any) string { return Color(m, YELLOW, str) }
func ParseCliColor(color string) string { return _parse_cli_color(color) }
func ParseColor(color string) color.Color { return _parse_color(color) }

View File

@ -1,62 +1,56 @@
package cli package cli
import ( import (
"bytes"
"io"
"os/exec" "os/exec"
"runtime"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _daemon_exec(m *ice.Message, cmd *exec.Cmd) { func _daemon_exec(m *ice.Message, cmd *exec.Cmd) {
if r, ok := m.Optionv(CMD_INPUT).(io.Reader); ok {
cmd.Stdin = r
}
err := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
cmd.Stderr = err
if w := _system_out(m, CMD_OUTPUT); w != nil { if w := _system_out(m, CMD_OUTPUT); w != nil {
cmd.Stdout, cmd.Stderr = w, w cmd.Stdout = w
cmd.Stderr = w
} }
if w := _system_out(m, CMD_ERRPUT); w != nil { if w := _system_out(m, CMD_ERRPUT); w != nil {
cmd.Stderr = w cmd.Stderr = w
} }
h := mdb.HashCreate(m.Spawn(), STATUS, START,
ice.CMD, strings.TrimPrefix(strings.TrimPrefix(kit.JoinWord(cmd.Args...), kit.Path("")+nfs.PS), cmd.Dir+nfs.PS), DIR, cmd.Dir, ENV, kit.Select("", cmd.Env), // 启动进程
m.OptionSimple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT, mdb.CACHE_CLEAR_ONEXIT), if e := cmd.Start(); m.Warn(e, ice.ErrNotStart, cmd.Args) {
return // 启动失败
}
m.Echo("%d", cmd.Process.Pid)
m.Go(func() {
h := m.Cmdx(mdb.INSERT, DAEMON, "", mdb.HASH,
STATUS, START, ice.CMD, kit.Join(cmd.Args, ice.SP),
PID, cmd.Process.Pid, DIR, cmd.Dir, ENV, kit.Select("", cmd.Env),
m.OptionSimple(CMD_OUTPUT, CMD_ERRPUT, mdb.CACHE_CLEAR_ON_EXIT),
) )
if e := cmd.Start(); m.WarnNotValid(e, cmd.Args, err.String()) {
mdb.HashModify(m, h, STATUS, ERROR, ERROR, e) if e := cmd.Wait(); m.Warn(e, ice.ErrNotStart, cmd.Args) {
return if m.Conf(DAEMON, kit.Keys(mdb.HASH, h, kit.Keym(STATUS))) == START {
m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, mdb.HASH, h, STATUS, ERROR, ERROR, e)
} }
mdb.HashSelectUpdate(m, h, func(value ice.Map) { value[PID] = cmd.Process.Pid })
m.Echo("%d", cmd.Process.Pid).Go(func() {
if e := cmd.Wait(); !m.WarnNotValid(e, cmd.Args, err.String()) && cmd.ProcessState != nil && cmd.ProcessState.Success() {
mdb.HashModify(m, mdb.HASH, h, STATUS, STOP)
m.Cost(CODE, "0", ctx.ARGS, cmd.Args)
} else { } else {
mdb.HashSelectUpdate(m, h, func(value ice.Map) { value[STATUS], value[ERROR] = ERROR, e }) m.Cost(CODE, cmd.ProcessState.ExitCode(), ctx.ARGS, cmd.Args)
m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, mdb.HASH, h, STATUS, STOP)
} }
switch status := mdb.HashSelectField(m.Sleep300ms(), h, STATUS); cb := m.OptionCB("").(type) {
case func(string) bool: switch m.Sleep300ms(); cb := m.OptionCB(DAEMON).(type) {
kit.If(!cb(status), func() { m.Cmdy(DAEMON, cmd.Path, cmd.Args) })
case func(string): case func(string):
cb(status) cb(m.Conf(DAEMON, kit.Keys(mdb.HASH, h, kit.Keym(STATUS))))
case func(): case func():
cb() cb()
case nil:
default:
m.ErrorNotImplement(cb)
} }
kit.For(kit.Simple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT), func(p string) { nfs.Close(m, m.Optionv(p)) })
for _, p := range kit.Simple(CMD_INPUT, CMD_OUTPUT, CMD_ERRPUT) {
kit.Close(m.Optionv(p))
}
}) })
} }
@ -64,10 +58,8 @@ const (
DIR = "dir" DIR = "dir"
ENV = "env" ENV = "env"
API = "api" API = "api"
MOD = "mod"
PWD = "pwd"
PID = "pid" PID = "pid"
PPID = "ppid" PWD = "pwd"
) )
const ( const (
BUILD = "build" BUILD = "build"
@ -76,129 +68,75 @@ const (
CHECK = "check" CHECK = "check"
BENCH = "bench" BENCH = "bench"
PPROF = "pprof" PPROF = "pprof"
CLEAR = "clear"
TIMEOUT = "timeout" TIMEOUT = "timeout"
STATUS = "status" STATUS = "status"
ERROR = "error" ERROR = "error"
CLEAR = "clear"
STASH = "stash"
DELAY = "delay"
RECORD = "record"
RELOAD = "reload"
REBOOT = "reboot"
RESTART = "restart"
INTERVAL = "interval"
OPTS = "opts"
ARGS = "args"
LOGS = "logs"
BEGIN = "begin"
END = "end"
START = "start" START = "start"
RESTART = "restart"
RELOAD = "reload"
STOP = "stop" STOP = "stop"
OPEN = "open"
CLOSE = "close"
PLAY = "play"
MAIN = "main"
CODE = "code" CODE = "code"
COST = "cost" COST = "cost"
FROM = "from"
BACK = "back" BACK = "back"
FROM = "from"
MAIN = "main"
KILL = "kill"
OPEN = "open"
CLOSE = "close"
BEGIN = "begin"
END = "end"
) )
const DAEMON = "daemon" const DAEMON = "daemon"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
DAEMON: {Name: "daemon hash auto", Help: "守护进程", Actions: ice.MergeActions(ice.Actions{ DAEMON: {Name: DAEMON, Help: "守护进程", Value: kit.Data(
nfs.PATH, ice.USR_LOCAL_DAEMON, mdb.FIELD, "time,hash,status,pid,cmd,dir,env",
)},
}, Commands: map[string]*ice.Command{
DAEMON: {Name: "daemon hash auto start prunes", Help: "守护进程", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashPrunesValue(m, mdb.CACHE_CLEAR_ONEXIT, ice.TRUE) m.Cmd(mdb.PRUNES, DAEMON, "", mdb.HASH, mdb.CACHE_CLEAR_ON_EXIT, ice.TRUE)
}}, }},
START: {Name: "start cmd* dir env", Hand: func(m *ice.Message, arg ...string) { mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.Options(CMD_DIR, m.Option(DIR), CMD_ENV, kit.Split(m.Option(ENV), " =")) m.OptionFields(m.Config(mdb.FIELD))
_daemon_exec(m, _system_cmd(m, kit.Split(m.Option(ice.CMD))...)) m.Cmdy(mdb.PRUNES, DAEMON, "", mdb.HASH, STATUS, STOP)
m.Cmdy(mdb.PRUNES, DAEMON, "", mdb.HASH, STATUS, ERROR)
}}, }},
RESTART: {Hand: func(m *ice.Message, arg ...string) { START: {Name: "start cmd env dir", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy("", STOP).Sleep3s().Cmdy("", START) m.Option(CMD_DIR, m.Option(DIR))
m.Option(CMD_ENV, kit.Split(m.Option(ENV), " ="))
m.Cmdy(DAEMON, kit.Split(m.Option(ice.CMD)))
}}, }},
STOP: {Hand: func(m *ice.Message, arg ...string) { RESTART: {Name: "restart", Help: "重启", Hand: func(m *ice.Message, arg ...string) {
h, pid := m.Option(mdb.HASH), m.Option(PID) m.Cmdy(DAEMON, STOP).Sleep3s().Cmdy(DAEMON, START)
mdb.HashSelects(m.Spawn(), h).Table(func(value ice.Maps) { }},
if h == "" && value[PID] != pid { STOP: {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
return m.OptionFields(m.Config(mdb.FIELD))
} m.Cmd(mdb.SELECT, DAEMON, "", mdb.HASH, m.OptionSimple(mdb.HASH)).Table(func(index int, value map[string]string, head []string) {
mdb.HashModify(m, mdb.HASH, kit.Select(h, value[mdb.HASH]), STATUS, STOP) m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, m.OptionSimple(mdb.HASH), STATUS, STOP)
kit.If(value[PID], func() { m.Cmd(gdb.SIGNAL, gdb.KILL, value[PID]) }) m.Cmdy(SYSTEM, KILL, value[PID])
}) })
}}, }},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { }, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
h, pid := m.Option(mdb.HASH), m.Option(PID) mdb.HashSelect(m, arg...).Set(ctx.ACTION).Table(func(index int, value map[string]string, head []string) {
mdb.HashSelects(m.Spawn(), h).Table(func(value ice.Maps) {
if h == "" && value[PID] != pid {
return
}
mdb.HashRemove(m, kit.Select(h, value[mdb.HASH]))
})
}},
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,pid,cmd,dir,env")), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m, arg...).Table(func(value ice.Maps) {
switch value[STATUS] { switch value[STATUS] {
case START: case START:
m.PushButton(RESTART, STOP) m.PushButton(RESTART, STOP)
default: default:
m.PushButton(START, mdb.REMOVE) m.PushButton(mdb.REMOVE)
} }
}) })
kit.If(len(arg) == 0, func() { m.Action(START, mdb.PRUNES) })
if len(arg) > 0 && m.Length() == 0 {
if runtime.GOOS == WINDOWS {
_daemon_exec(m, _system_cmd(m, arg...))
} else {
_daemon_exec(m, _system_cmd(m, arg...))
// _daemon_exec(m, _system_cmd(m, kit.Simple(kit.Split(arg[0]), arg[1:])...))
}
kit.If(IsSuccess(m) && m.Append(CMD_ERR) == "", func() { m.SetAppend() })
}
}},
})
}
func Opens(m *ice.Message, arg ...string) { if len(arg) == 0 || m.Length() > 0 {
if !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) { return
// return
} else if len(arg) == 0 || arg[0] == "" {
// return
} }
switch runtime.GOOS { _daemon_exec(m, _system_cmd(m, arg...))
case DARWIN: }},
if kit.Ext(arg[0]) == "app" { }})
m.Cmdy(SYSTEM, OPEN, "-a", arg[0])
} else {
m.Cmdy(SYSTEM, OPEN, arg[0])
} }
case WINDOWS:
if kit.Ext(arg[0]) == "exe" {
m.Cmdy(SYSTEM, arg[0])
} else {
m.Cmdy(SYSTEM, "explorer", arg[0])
}
}
}
func OpenCmds(m *ice.Message, arg ...string) *ice.Message {
if !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
return m
} else if len(arg) == 0 || arg[0] == "" {
return m
}
TellApp(m, "Terminal", kit.Format(`do script %q`, strings.Join(arg, "; ")), "activate")
return m
}
func TellApp(m *ice.Message, app string, arg ...string) {
OSAScript(m, kit.Format(`
tell application "%s"
%s
end tell
`, app, strings.Join(arg, lex.NL)))
}
func OSAScript(m *ice.Message, arg ...string) { m.Cmd(SYSTEM, "osascript", "-e", arg) }

View File

@ -2,72 +2,49 @@ package cli
import ( import (
"os" "os"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/gdb" "shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
) )
func _path_sep() string { return kit.Select(nfs.DF, ";", strings.Contains(os.Getenv(PATH), ";")) } func BinPath(arg ...string) string {
return kit.Join(kit.Simple(arg, kit.Path(ice.BIN), kit.Path(ice.USR_LOCAL_BIN), kit.Path(ice.USR_LOCAL_GO_BIN), kit.Env(PATH)), ice.DF)
}
const FOREVER = "forever" const FOREVER = "forever"
func init() { func init() {
Index.MergeCommands(ice.Commands{ const SERVE = "serve"
FOREVER: {Help: "启动", Actions: ice.Actions{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
START: {Hand: func(m *ice.Message, arg ...string) { FOREVER: {Name: "forever", Help: "启动", Action: map[string]*ice.Action{
env := []string{PATH, BinPath(""), HOME, kit.Select(kit.Path(""), os.Getenv(HOME))} SERVE: {Name: "serve", Help: "服务", Hand: func(m *ice.Message, arg ...string) {
kit.For(ENV_LIST, func(k string) { kit.If(kit.Env(k) != "", func() { env = append(env, k, kit.Env(k)) }) }) env := []string{PATH, BinPath(), HOME, kit.Select(kit.Path(""), os.Getenv(HOME))}
kit.For(os.Environ(), func(v string) { for _, k := range []string{TERM, SHELL, CTX_SHY, CTX_DEV, CTX_OPS, CTX_ARG, CTX_PID, CTX_USER, CTX_SHARE, CTX_RIVER} {
if ls := kit.Split(v, mdb.EQ, mdb.EQ); kit.IndexOf(env, ls[0]) == -1 && len(ls) > 1 { if kit.Env(k) != "" {
env = append(env, ls[0], ls[1]) env = append(env, k, kit.Env(k))
} }
})
m.Options(CMD_ENV, env, CMD_INPUT, os.Stdin, CMD_OUTPUT, os.Stdout, CMD_ERRPUT, os.Stderr)
kit.If(kit.Select("/dev/null", kit.Env(CTX_LOG)), func(p string) { m.Optionv(CMD_ERRPUT, p) })
m.Cmd(FOREVER, STOP)
if bin := kit.Select(os.Args[0], ice.BIN_ICE_BIN, nfs.Exists(m, ice.BIN_ICE_BIN)); len(arg) > 0 && arg[0] == ice.SPACE {
m.Cmdy(FOREVER, bin, ice.SPACE, START, ice.DEV, ice.OPS, arg[1:])
} else {
kit.If(len(arg) > 0 && arg[0] != ice.DEV, func() { arg = append([]string{ice.DEV, ""}, arg...) })
m.Cmdy(FOREVER, bin, ice.SERVE, START, arg)
} }
m.Option(CMD_ENV, env)
m.Optionv(CMD_INPUT, os.Stdin)
m.Optionv(CMD_OUTPUT, os.Stdout)
m.Optionv(CMD_ERRPUT, os.Stderr)
if p := kit.Env(CTX_LOG); p != "" {
m.Optionv(CMD_ERRPUT, p)
}
m.Cmdy(FOREVER, kit.Select(os.Args[0], nfs.PWD+ice.BIN_ICE_BIN, kit.FileExists(ice.BIN_ICE_BIN)),
SERVE, START, ice.DEV, "", aaa.USERNAME, aaa.ROOT, aaa.PASSWORD, aaa.ROOT, arg)
}}, }},
RESTART: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(gdb.SIGNAL, gdb.RESTART) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
STOP: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(gdb.SIGNAL, gdb.STOP) }}, for {
DELAY: {Hand: func(m *ice.Message, arg ...string) { m.Sleep(arg[0]).Cmdy(arg[1:]) }}, println(kit.Format("%s run %s", kit.Now(), kit.Join(arg, ice.SP)))
}, Hand: func(m *ice.Message, arg ...string) { if m.Sleep("1s"); IsSuccess(m.Cmd(SYSTEM, arg)) {
if len(arg) == 0 { println(kit.Format("%s exit", kit.Now()))
m.Cmdy(RUNTIME, BOOTINFO)
return return
} }
for {
if logs.Println("run %s", kit.Join(arg, lex.SP)); IsSuccess(m.Cmd(SYSTEM, arg)) {
logs.Println(ice.EXIT)
break
} }
logs.Println() }}},
}
}},
}) })
} }
func BinPath(arg ...string) string {
list := []string{}
push := func(p string) {
kit.If(kit.IndexOf(list, p) == -1, func() { list = append(list, kit.ReplaceAll(p, "\\", nfs.PS)) })
}
kit.For(arg, func(p string) {
list = append(list, kit.Path(p, ice.BIN), kit.Path(p, ice.USR_PUBLISH), kit.Path(p, ice.USR_LOCAL_BIN), kit.Path(p, ice.USR_LOCAL_GO_BIN))
kit.For(kit.Reverse(EtcPath(ice.Pulse)), func(l string) {
kit.If(strings.TrimSpace(l) != "" && !strings.HasPrefix(strings.TrimSpace(l), "#"), func() { push(kit.Path(p, l)) })
})
})
kit.For(strings.Split(kit.Env(PATH), _path_sep()), func(p string) { push(p) })
return kit.Join(list, _path_sep())
}

View File

@ -1,122 +0,0 @@
package cli
import (
"runtime"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
const (
CMD = "cmd"
ADD = "add"
OSID = "osid"
REPOS = "repos"
UBUNTU = "ubuntu"
CENTOS = "centos"
ALPINE = "alpine"
BUSYBOX = "busybox"
RELEASE = "release"
RHEL = "rhel"
ETC_OS_RELEASE = "/etc/os-release"
ETC_APK_REPOS = "/etc/apk/repositories"
)
const MIRRORS = "mirrors"
func init() {
Index.MergeCommands(ice.Commands{
MIRRORS: {Help: "软件镜像", Actions: ice.MergeActions(ice.Actions{
mdb.INSERT: {Name: "insert cli* osid cmd*"},
CMD: {Name: "cmd cli osid", Hand: func(m *ice.Message, arg ...string) {
osid := kit.Select(mdb.Conf(m, RUNTIME, kit.Keys(HOST, OSID)), m.Option(OSID))
mdb.ZoneSelectCB(m, m.Option(CLI), func(value ice.Map) {
kit.If(strings.Contains(osid, kit.Format(value[OSID])), func() {
m.Cmdy(kit.Split(kit.Format(value[CMD])))
})
})
}},
ADD: {Help: "安装", Hand: func(m *ice.Message, arg ...string) {
ice.Info.PushStream(m)
mdb.ZoneSelect(m, m.Option(CLI)).Table(func(value ice.Maps) {
m.ToastProcess()
if msg := m.Cmd(kit.Split(value[CMD])); IsSuccess(msg) {
m.ToastSuccess()
} else {
m.ToastFailure()
}
})
}},
REPOS: {Name: "repos proxy=mirrors.tencent.com", Help: "镜像", Hand: func(m *ice.Message, arg ...string) {
switch {
case strings.Contains(_release, ALPINE):
defer m.PushStream().ToastProcess()()
kit.If(m.Option("proxy"), func(p string) {
m.Cmd(nfs.SAVE, ETC_APK_REPOS, strings.ReplaceAll(m.Cmdx(nfs.CAT, ETC_APK_REPOS), "dl-cdn.alpinelinux.org", p))
})
m.Cmdy(SYSTEM, "apk", "update")
}
}},
ALPINE: {Name: "alpine cli cmd", Hand: func(m *ice.Message, arg ...string) { IsAlpine(m, arg...) }},
}, mdb.ZoneAction(mdb.SHORT, CLI, mdb.FIELDS, "time,id,osid,cmd"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
if mdb.ZoneSelect(m, arg...); len(arg) == 0 {
m.Table(func(value ice.Maps) {
p := SystemFind(m, value[CLI])
if m.Push(nfs.PATH, p); p == "" {
m.PushButton(ADD)
} else {
m.PushButton("")
}
}).Action(REPOS).StatusTimeCount("release", _release)
}
switch {
case strings.Contains(_release, ALPINE):
m.Cmdy(nfs.CAT, ETC_APK_REPOS)
}
// m.EchoScript(kit.Format("cd %s; %s", kit.Path(""), kit.JoinCmds(kit.Simple(kit.Path(os.Args[0]), os.Args[1:])...)))
}},
})
}
var _release = ""
func release(m *ice.Message) string {
list := []string{runtime.GOOS}
if list[0] != LINUX || !nfs.Exists(m, ETC_OS_RELEASE) {
return list[0]
}
m.Cmd(nfs.CAT, ETC_OS_RELEASE, kit.Dict(ice.MSG_USERROLE, aaa.ROOT), func(text string, _ int) string {
if ls := kit.Split(text, mdb.EQ); len(ls) > 1 {
kit.Switch(ls[0], []string{"ID", "ID_LIKE"}, func() { list = append(list, strings.TrimSpace(ls[1])) })
}
return text
})
_release = kit.JoinWord(list...)
return _release
}
func insert(m *ice.Message, sys, cmd string, arg ...string) bool {
if !strings.Contains(_release, sys) {
return false
}
if len(arg) > 0 {
m.GoSleep300ms(func() {
m.Cmd(mdb.INSERT, kit.Keys(CLI, MIRRORS), "", mdb.ZONE, arg[0], OSID, sys, CMD, cmd+lex.SP+kit.Select(arg[0], arg, 1))
})
}
return true
}
func IsAlpine(m *ice.Message, arg ...string) bool {
return insert(m, ALPINE, "system apk add", arg...)
}
func IsRedhat(m *ice.Message, arg ...string) bool {
return insert(m, RHEL, "system yum install -y", arg...)
}
func IsSystem(m *ice.Message, arg ...string) bool {
return IsAlpine(m, arg...) || IsRedhat(m, arg...)
}

View File

@ -2,22 +2,71 @@ package cli
import ( import (
"encoding/base64" "encoding/base64"
"fmt"
"image/color"
"math/rand"
"strconv"
"strings"
"shylinux.com/x/go-qrcode"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/tcp"
"shylinux.com/x/icebergs/base/web/html"
"shylinux.com/x/icebergs/misc/qrcode"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
var _trans_web = map[string]color.Color{
BLACK: color.RGBA{0, 0, 0, DARK},
RED: color.RGBA{DARK, 0, 0, DARK},
GREEN: color.RGBA{0, DARK, 0, DARK},
YELLOW: color.RGBA{DARK, DARK, 0, DARK},
BLUE: color.RGBA{0, 0, DARK, DARK},
PURPLE: color.RGBA{DARK, 0, DARK, DARK},
CYAN: color.RGBA{0, DARK, DARK, DARK},
WHITE: color.RGBA{DARK, DARK, DARK, DARK},
}
func _parse_color(str string) color.Color {
if str == RANDOM {
list := []string{}
for k := range _trans_web {
list = append(list, k)
}
str = list[rand.Intn(len(list))]
}
if strings.HasPrefix(str, "#") {
if len(str) == 7 {
str += "ff"
}
if u, e := strconv.ParseUint(str[1:], 16, 64); e == nil {
return color.RGBA{
uint8((u & 0xFF000000) >> 24),
uint8((u & 0x00FF0000) >> 16),
uint8((u & 0x0000FF00) >> 8),
uint8((u & 0x000000FF) >> 0),
}
}
}
return _trans_web[str]
}
func _parse_cli_color(str string) string {
res := 0
r, g, b, _ := _parse_color(str).RGBA()
if r > LIGHT {
res += 1
}
if g > LIGHT {
res += 2
}
if b > LIGHT {
res += 4
}
return kit.Format(res)
}
func _qrcode_cli(m *ice.Message, text string) { func _qrcode_cli(m *ice.Message, text string) {
sc := qrcode.New(text) qr, _ := qrcode.New(text, qrcode.Medium)
fg := ParseCliColor(m.Option(FG)) fg := _parse_cli_color(m.Option(FG))
bg := ParseCliColor(m.Option(BG)) bg := _parse_cli_color(m.Option(BG))
data := sc.Bitmap()
data := qr.Bitmap()
for i, row := range data { for i, row := range data {
if n := len(data); i < 3 || i >= n-3 { if n := len(data); i < 3 || i >= n-3 {
continue continue
@ -26,68 +75,76 @@ func _qrcode_cli(m *ice.Message, text string) {
if n := len(row); i < 3 || i >= n-3 { if n := len(row); i < 3 || i >= n-3 {
continue continue
} }
m.Echo("\033[4%sm \033[0m", kit.Select(bg, fg, col)) m.Echo("\033[4%sm \033[0m", kit.Select(bg, fg, col))
} }
m.Echo(lex.NL) m.Echo(ice.NL)
} }
m.Echo(text).Echo(lex.NL) m.Echo(text)
} }
func _qrcode_web(m *ice.Message, text string) string { func _qrcode_web(m *ice.Message, text string) {
sc := qrcode.New(text) qr, _ := qrcode.New(text, qrcode.Medium)
sc.ForegroundColor = ParseColor(m.Option(FG)) qr.ForegroundColor = _parse_color(m.Option(FG))
sc.BackgroundColor = ParseColor(m.Option(BG)) qr.BackgroundColor = _parse_color(m.Option(BG))
if data, err := sc.PNG(kit.Int(m.Option(SIZE))); m.Assert(err) {
m.Echo(`<img class="qrcode" src="data:image/png;base64,%s" title='%s'>`, base64.StdEncoding.EncodeToString(data), text) if data, err := qr.PNG(kit.Int(m.Option(SIZE))); m.Assert(err) {
m.Echo(`<img src="data:image/png;base64,%s" title='%s'>`, base64.StdEncoding.EncodeToString(data), text)
} }
return text
} }
func Color(m *ice.Message, c string, str interface{}) string {
wrap, color := `<span style="color:%s">%v</span>`, c
if m.IsCliUA() {
wrap, color = "\033[3%sm%v\033[0m", _parse_cli_color(c)
}
return fmt.Sprintf(wrap, color, str)
}
func ColorRed(m *ice.Message, str interface{}) string { return Color(m, RED, str) }
func ColorGreen(m *ice.Message, str interface{}) string { return Color(m, GREEN, str) }
func ColorYellow(m *ice.Message, str interface{}) string { return Color(m, YELLOW, str) }
const ( const (
FG = "fg"
BG = "bg"
SIZE = "size" SIZE = "size"
DARK = 255
LIGHT = 127
)
const (
COLOR = "color"
BLACK = "black"
RED = "red"
GREEN = "green"
YELLOW = "yellow"
BLUE = "blue"
PURPLE = "purple"
CYAN = "cyan"
WHITE = "white"
RANDOM = "random"
GLASS = "#0000"
GRAY = "gray"
) )
const QRCODE = "qrcode" const QRCODE = "qrcode"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
QRCODE: {Name: "qrcode text fg@key bg@key size auto", Help: "二维码", Icon: "Chess.png", Role: aaa.VOID, Meta: kit.Dict( QRCODE: {Name: "qrcode text fg bg size auto", Help: "二维码", Action: map[string]*ice.Action{
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(mdb.TEXT, "文本", BG, "背景色", FG, "字体色")),
), Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
ice.AddRender(ice.RENDER_QRCODE, func(m *ice.Message, args ...ice.Any) string { ice.AddRender(ice.RENDER_QRCODE, func(m *ice.Message, cmd string, args ...interface{}) string {
kit.If(m.IsMobileUA(), func() { m.Option(SIZE, "280") }) return m.Cmd(QRCODE, kit.Simple(args...)).Result()
return m.Cmd(Prefix(QRCODE), kit.Simple(args...)).Result()
}) })
}}, }},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[0] { m.Option(SIZE, kit.Select("240", arg, 3))
case FG, BG: m.Option(BG, kit.Select(WHITE, arg, 2))
m.Push(arg[0], kit.SortedKey(_color_map)) m.Option(FG, kit.Select(BLUE, arg, 1))
}
}},
"view": {Name: "view text icon link", Hand: func(m *ice.Message, arg ...string) {
defer m.Echo("<div class='code qrcode'>").Echo("</div>")
// m.Cmdy("", kit.MergeURL2(m.Option(ice.MSG_USERWEB), arg[2]))
m.Cmdy("", arg[2])
m.Echo("<img class='avatar' src='%s'></img>", arg[1])
m.Echo(arg[0])
}},
}), Hand: func(m *ice.Message, arg ...string) {
if m.IsCliUA() { if m.IsCliUA() {
m.OptionDefault(FG, BLACK, BG, WHITE) _qrcode_cli(m, kit.Select(ice.Info.Domain, arg, 0))
_qrcode_cli(m, kit.Select(kit.Select(ice.Info.Make.Domain, ice.Info.Domain), arg, 0))
} else { } else {
// m.OptionDefault(SIZE, kit.Select("360", "280", m.IsMobileUA())) _qrcode_web(m, kit.Select(m.Option(ice.MSG_USERWEB), arg, 0))
m.Option(FG, kit.Select(m.Option(ice.MSG_FG), arg, 1))
m.Option(BG, kit.Select(m.Option(ice.MSG_BG), arg, 2))
m.Option(SIZE, kit.Select(m.OptionDefault(SIZE, "320"), arg, 3))
switch m.Option(ice.MSG_THEME) {
case LIGHT, WHITE:
m.OptionDefault(FG, BLACK, BG, WHITE)
default:
m.OptionDefault(FG, WHITE, BG, BLACK)
}
m.StatusTime(mdb.LINK, _qrcode_web(m, tcp.PublishLocalhost(m, kit.Select(m.Option(ice.MSG_USERWEB), arg, 0))))
} }
}}, }},
}) }})
} }

View File

@ -2,306 +2,226 @@ package cli
import ( import (
"os" "os"
"os/user"
"path" "path"
"runtime" "runtime"
"strings" "strings"
"time"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _runtime_init(m *ice.Message) { func _runtime_init(m *ice.Message) {
count := kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT))) // 版本信息 make
defer m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT), count+1) kit.Fetch(kit.UnMarshal(kit.Format(ice.Info.Make)), func(key string, value interface{}) {
kit.For(kit.UnMarshal(kit.Format(ice.Info.Make)), func(k string, v ice.Any) { m.Conf(RUNTIME, kit.Keys(MAKE, strings.ToLower(k)), v) }) m.Conf(RUNTIME, kit.Keys(MAKE, strings.ToLower(key)), value)
})
// 主机信息 host
m.Conf(RUNTIME, kit.Keys(HOST, GOARCH), runtime.GOARCH) m.Conf(RUNTIME, kit.Keys(HOST, GOARCH), runtime.GOARCH)
m.Conf(RUNTIME, kit.Keys(HOST, GOOS), runtime.GOOS) m.Conf(RUNTIME, kit.Keys(HOST, GOOS), runtime.GOOS)
m.Conf(RUNTIME, kit.Keys(HOST, OSID), release(m))
m.Conf(RUNTIME, kit.Keys(HOST, PID), os.Getpid()) m.Conf(RUNTIME, kit.Keys(HOST, PID), os.Getpid())
m.Conf(RUNTIME, kit.Keys(HOST, PWD), kit.Path("")) m.Conf(RUNTIME, kit.Keys(HOST, HOME), kit.Env(HOME))
m.Conf(RUNTIME, kit.Keys(HOST, HOME), kit.HomePath("")) osid := ""
m.Conf(RUNTIME, kit.Keys(HOST, MAXPROCS), runtime.GOMAXPROCS(0)) m.Cmd(nfs.CAT, "/etc/os-release", func(text string) {
ice.Info.System = m.Conf(RUNTIME, kit.Keys(HOST, OSID)) if ls := kit.Split(text, "="); len(ls) > 1 {
kit.For(ENV_LIST, func(k string) { m.Conf(RUNTIME, kit.Keys(CONF, k), kit.Env(k)) }) switch ls[0] {
ice.Info.Lang = m.Conf(RUNTIME, kit.Keys(CONF, LANG)) case "ID", "ID_LIKE":
m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.UserName()) osid = strings.TrimSpace(ls[1] + ice.SP + osid)
m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), kit.Env("HOSTNAME")) }
m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME), path.Base(kit.Path(""))) }
if name, e := os.Hostname(); e == nil && name != "" { })
m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), name) m.Conf(RUNTIME, kit.Keys(HOST, OSID), osid)
// 启动信息 boot
if name, e := os.Hostname(); e == nil {
m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), kit.Select(name, kit.Env("HOSTNAME")))
}
if name, e := os.Getwd(); e == nil {
name = path.Base(kit.Select(name, kit.Env("PWD")))
name = kit.Slice(strings.Split(name, ice.PS), -1)[0]
name = kit.Slice(strings.Split(name, "\\"), -1)[0]
m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME), name)
}
if m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.Select(kit.Env(USER), kit.Env(CTX_USER))) == "" {
if user, e := user.Current(); e == nil && user.Name != "" {
m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.Select(user.Name, kit.Env(CTX_USER)))
} else {
m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), aaa.ROOT)
}
} }
ice.Info.UserName = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME))
ice.Info.HostName = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME)) ice.Info.HostName = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME))
ice.Info.PathName = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME)) ice.Info.PathName = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME))
kit.HashSeed = append(kit.HashSeed, ice.Info.UserName) ice.Info.UserName = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME))
kit.HashSeed = append(kit.HashSeed, ice.Info.HostName)
kit.HashSeed = append(kit.HashSeed, ice.Info.PathName) // 启动次数 boot
aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Author, "", "", ice.DEV, ice.Info.Make.Email) m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT), kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT)))+1)
aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Username, "", "", ice.DEV, ice.Info.Make.Email) m.Conf(RUNTIME, kit.Keys(BOOT, ice.BIN), _system_find(m, os.Args[0]))
aaa.UserRoot(ice.Pulse, aaa.ROOT, ice.Info.UserName)
aaa.UserRoot(ice.Pulse, aaa.ROOT, aaa.ROOT) // 环境变量 conf
ice.Info.Time = m.Time() for _, k := range []string{CTX_SHY, CTX_DEV, CTX_OPS, CTX_ARG, CTX_PID, CTX_USER, CTX_SHARE, CTX_RIVER} {
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.TIME), ice.Info.Time) m.Conf(RUNTIME, kit.Keys(CONF, k), kit.Env(k))
if runtime.GOARCH != MIPSLE {
msg := m.Cmd(nfs.DIR, _system_find(m, os.Args[0]), "time,path,size,hash")
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.HASH), msg.Append(mdb.HASH))
m.Conf(RUNTIME, kit.Keys(BOOT, nfs.SIZE), msg.Append(nfs.SIZE))
m.Conf(RUNTIME, kit.Keys(BOOT, ice.BIN), msg.Append(nfs.PATH))
ice.Info.Hash = msg.Append(mdb.HASH)
ice.Info.Size = msg.Append(nfs.SIZE)
} }
nfs.Exists(m, "/proc/meminfo", func(p string) {
kit.For(kit.SplitLine(m.Cmdx(nfs.CAT, p)), func(p string) {
switch ls := kit.Split(p, ": "); kit.Select("", ls, 0) {
case "MemTotal", "MemFree", "MemAvailable":
m.Conf(RUNTIME, kit.Keys(HOST, ls[0]), kit.FmtSize(kit.Int(ls[1])*1024))
}
})
})
m.Conf(m.PrefixKey(), mdb.META, "")
} }
func _runtime_hostinfo(m *ice.Message) { func _runtime_hostinfo(m *ice.Message) {
m.Push("time", ice.Info.Make.Time) m.Push("nCPU", strings.Count(m.Cmdx(nfs.CAT, "/proc/cpuinfo"), "processor"))
m.Push("nCPU", runtime.NumCPU()) for i, ls := range strings.Split(m.Cmdx(nfs.CAT, "/proc/meminfo"), ice.NL) {
m.Push("GOMAXPROCS", runtime.GOMAXPROCS(0)) vs := kit.Split(ls, ": ")
m.Push("NumGoroutine", runtime.NumGoroutine())
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
m.Push("Sys", kit.FmtSize(stats.Sys))
m.Push("Alloc", kit.FmtSize(stats.Alloc))
m.Push("TotalAlloc", kit.FmtSize(stats.TotalAlloc))
m.Push("StackSys", kit.FmtSize(stats.StackSys))
m.Push("StackInuse", kit.FmtSize(stats.StackInuse))
m.Push("HeapSys", kit.FmtSize(stats.HeapSys))
m.Push("HeapInuse", kit.FmtSize(stats.HeapInuse))
m.Push("HeapIdle", kit.FmtSize(stats.HeapIdle))
m.Push("HeapReleased", kit.FmtSize(stats.HeapReleased))
m.Push("NumGC", stats.NumGC)
m.Push("LastGC", time.Unix(int64(stats.LastGC)/int64(time.Second), int64(stats.LastGC)%int64(time.Second)))
m.Push("uptime", kit.Split(m.Cmdx(SYSTEM, "uptime"), mdb.FS)[0])
if runtime.GOOS == LINUX {
for i, ls := range strings.Split(m.Cmdx(nfs.CAT, "/proc/meminfo"), lex.NL) {
if vs := kit.Split(ls, ": "); len(vs) > 1 {
if m.Push(strings.TrimSpace(vs[0]), kit.FmtSize(kit.Int64(strings.TrimSpace(vs[1]))*1024)); i > 1 { if m.Push(strings.TrimSpace(vs[0]), kit.FmtSize(kit.Int64(strings.TrimSpace(vs[1]))*1024)); i > 1 {
break break
} }
} }
} m.Push("uptime", kit.Split(m.Cmdx(SYSTEM, "uptime"), ice.FS)[0])
} else {
m.Push("MemAvailable", "")
m.Push("MemTotal", "")
m.Push("MemFree", "")
}
} }
func _runtime_diskinfo(m *ice.Message) { func _runtime_diskinfo(m *ice.Message) {
m.Spawn().Split(kit.Replace(m.Cmdx(SYSTEM, "df", "-h"), "Mounted on", "Mountedon"), "", lex.SP, lex.NL).Table(func(value ice.Maps, index int, head []string) { m.Spawn().Split(m.Cmdx(SYSTEM, "df", "-h"), "", ice.SP, ice.NL).Table(func(index int, value map[string]string, head []string) {
kit.If(strings.HasPrefix(value["Filesystem"], "/dev"), func() { m.Push("", value, head) }) if strings.HasPrefix(value["Filesystem"], "/dev") {
m.Push("", value, head)
}
}) })
m.RenameAppend("%iused", "piused", "Use%", "Usep") m.RenameAppend("%iused", "piused", "Use%", "Usep")
ctx.DisplayStory(m, "pie.js?field=Size") m.DisplayStory("pie.js?field=Size")
}
func NodeInfo(m *ice.Message, kind, name string) {
m.Conf(RUNTIME, kit.Keys(NODE, mdb.TIME), m.Time())
ice.Info.NodeType = m.Conf(RUNTIME, kit.Keys(NODE, mdb.TYPE), kind)
ice.Info.NodeName = m.Conf(RUNTIME, kit.Keys(NODE, mdb.NAME), strings.ReplaceAll(name, ice.PT, "_"))
} }
const ( const (
MAKE = "make" MAKE = "make"
TEST = "test" TEST = "test"
HOST = "host" HOST = "host"
CONF = "conf"
BOOT = "boot" BOOT = "boot"
CONF = "conf"
NODE = "node" NODE = "node"
) )
const ( const (
GOARCH = "GOARCH" GOARCH = "GOARCH"
AMD64 = "amd64" AMD64 = "amd64"
X86 = "386" X386 = "386"
ARM = "arm" ARM = "arm"
ARM64 = "arm64" ARM64 = "arm64"
MIPSLE = "mipsle"
GOOS = "GOOS" GOOS = "GOOS"
LINUX = "linux" LINUX = "linux"
MACOS = "macos"
DARWIN = "darwin" DARWIN = "darwin"
WINDOWS = "windows" WINDOWS = "windows"
COMMIT_TIME = "commitTime" OSID = "OSID"
COMPILE_TIME = "compileTime" ALPINE = "alpine"
BOOT_TIME = "bootTime" CENTOS = "centos"
UBUNTU = "ubuntu"
KERNEL = "kernel"
ARCH = "arch"
CPU = "cpu"
OS = "os"
) )
const ( const (
PATH = "PATH"
HOME = "HOME"
USER = "USER"
TERM = "TERM"
SHELL = "SHELL" SHELL = "SHELL"
LANG = "LANG" TERM = "TERM"
TZ = "TZ" USER = "USER"
HOME = "HOME"
PATH = "PATH"
) )
const ( const (
CTX_SHY = "ctx_shy" CTX_SHY = "ctx_shy"
CTX_DEV = "ctx_dev" CTX_DEV = "ctx_dev"
CTX_DEV_IP = "ctx_dev_ip"
CTX_OPS = "ctx_ops" CTX_OPS = "ctx_ops"
CTX_REPOS = "ctx_repos" CTX_ARG = "ctx_arg"
CTX_NAME = "ctx_name"
CTX_DEMO = "ctx_demo"
CTX_MAIL = "ctx_mail"
CTX_ROOT = "ctx_root"
CTX_DOMAIN = "ctx_domain"
CTX_PID = "ctx_pid" CTX_PID = "ctx_pid"
CTX_LOG = "ctx_log" CTX_LOG = "ctx_log"
CTX_POD = "ctx_pod" CTX_USER = "ctx_user"
CTX_ENV = "ctx_env" CTX_SHARE = "ctx_share"
CTX_CLI = "ctx_cli" CTX_RIVER = "ctx_river"
CTX_ARG = "ctx_arg"
) )
var ENV_LIST = []string{TZ, LANG, TERM, SHELL, CTX_SHY, CTX_DEV, CTX_OPS, CTX_DEMO, CTX_MAIL, CTX_ROOT, CTX_PID}
const ( const (
USERNAME = "username"
HOSTNAME = "hostname" HOSTNAME = "hostname"
PATHNAME = "pathname" PATHNAME = "pathname"
USERNAME = "username"
) )
const ( const (
MAXPROCS = "maxprocs"
IFCONFIG = "ifconfig" IFCONFIG = "ifconfig"
DISKINFO = "diskinfo"
HOSTINFO = "hostinfo" HOSTINFO = "hostinfo"
USERINFO = "userinfo" USERINFO = "userinfo"
PROCINFO = "procinfo"
PROCKILL = "prockill"
BOOTINFO = "bootinfo" BOOTINFO = "bootinfo"
MAXPROCS = "maxprocs" DISKINFO = "diskinfo"
) )
const RUNTIME = "runtime" const RUNTIME = "runtime"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
RUNTIME: {Name: "runtime info=bootinfo,ifconfig,diskinfo,hostinfo,userinfo,bootinfo,role,api,cli,cmd,mod,env,path,chain auto upgrade reboot lock", Icon: "Infomation.png", Help: "环境", Actions: ice.MergeActions(ice.Actions{ RUNTIME: {Name: RUNTIME, Help: "运行环境", Value: kit.Dict()},
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { _runtime_init(m) }}, }, Commands: map[string]*ice.Command{
IFCONFIG: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(tcp.HOST) }}, RUNTIME: {Name: "runtime info=ifconfig,hostinfo,hostname,userinfo,procinfo,bootinfo,diskinfo,env,file,route auto", Help: "运行环境", Action: map[string]*ice.Action{
DISKINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_diskinfo(m) }}, ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
HOSTINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_hostinfo(m) }}, _runtime_init(m)
HOSTNAME: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(RUNTIME, MAXPROCS, "1")
}},
MAXPROCS: {Name: "maxprocs", Help: "最大并发", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 { if len(arg) > 0 {
ice.Info.HostName = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.NAME), mdb.Conf(m, RUNTIME, kit.Keys(BOOT, HOSTNAME), arg[0])) runtime.GOMAXPROCS(kit.Int(m.Conf(RUNTIME, kit.Keys(HOST, "GOMAXPROCS"), kit.Select("1", arg, 0))))
}
m.Echo("%d", runtime.GOMAXPROCS(0))
}},
IFCONFIG: {Name: "ifconfig", Help: "网卡配置", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy("tcp.host")
}},
HOSTINFO: {Name: "hostinfo", Help: "主机信息", Hand: func(m *ice.Message, arg ...string) {
_runtime_hostinfo(m)
}},
HOSTNAME: {Name: "hostname", Help: "主机域名", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 {
ice.Info.HostName = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), m.Conf(RUNTIME, kit.Keys(NODE, mdb.NAME), arg[0]))
} }
m.Echo(ice.Info.HostName) m.Echo(ice.Info.HostName)
}}, }},
MAXPROCS: {Hand: func(m *ice.Message, arg ...string) { USERINFO: {Name: "userinfo", Help: "用户信息", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) > 0, func() { runtime.GOMAXPROCS(kit.Int(mdb.Conf(m, RUNTIME, kit.Keys(HOST, MAXPROCS), arg[0]))) }) m.Split(m.Cmdx(SYSTEM, "who"), "user term time")
m.Echo("%d", runtime.GOMAXPROCS(0))
}}, }},
USERINFO: {Hand: func(m *ice.Message, arg ...string) { m.Split(m.Cmdx(SYSTEM, "who"), "user term time") }}, PROCINFO: {Name: "procinfo", Help: "进程信息", Hand: func(m *ice.Message, arg ...string) {
aaa.ROLE: {Hand: func(m *ice.Message, arg ...string) { m.Split(m.Cmdx(SYSTEM, "ps", "u")).PushAction(PROCKILL)
m.Cmd(aaa.ROLE, func(value ice.Maps) { m.Push(mdb.KEY, kit.Keys(value[aaa.ROLE], value[mdb.ZONE], value[mdb.KEY])) }) m.StatusTimeCount()
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, "ice."), mdb.FIELD, mdb.KEY, lex.SPLIT, nfs.PT)
}}, }},
API: {Hand: func(m *ice.Message, arg ...string) { PROCKILL: {Name: "prockill", Help: "结束进程", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 1 { m.Cmdy(SYSTEM, KILL, m.Option("PID"))
m.Cmdy(ctx.COMMAND, "inner").Push(ctx.ARGS, kit.Format(nfs.SplitPath(m, m.Option(nfs.FILE)))) m.ProcessRefresh30ms()
return }},
DISKINFO: {Name: "diskinfo", Help: "磁盘信息", Hand: func(m *ice.Message, arg ...string) {
_runtime_diskinfo(m)
}},
"env": {Name: "env", Help: "环境变量", Hand: func(m *ice.Message, arg ...string) {
for _, v := range os.Environ() {
ls := strings.SplitN(v, "=", 2)
m.Push(mdb.NAME, ls[0])
m.Push(mdb.VALUE, ls[1])
}
}},
"file": {Name: "file", Help: "模块文件", Hand: func(m *ice.Message, arg ...string) {
for k, v := range ice.Info.File {
m.Push(nfs.FILE, k)
m.Push(mdb.NAME, v)
}
m.Sort(nfs.FILE)
}},
"route": {Name: "route", Help: "接口命令", Hand: func(m *ice.Message, arg ...string) {
for k, v := range ice.Info.Route {
m.Push(nfs.PATH, k)
m.Push(nfs.FILE, v)
} }
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, nfs.PS), lex.PREFIX, kit.Fields(ctx.ACTION, m.ActionKey()))
kit.For(ice.Info.Route, func(k, v string) { m.Push(nfs.PATH, k).Push(nfs.FILE, v) })
m.Sort(nfs.PATH) m.Sort(nfs.PATH)
}}, }},
CLI: {Hand: func(m *ice.Message, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 1 { if len(arg) > 0 && arg[0] == BOOTINFO {
m.Cmdy(ctx.COMMAND, "inner").Push(ctx.ARGS, kit.Format(nfs.SplitPath(m, m.Option(nfs.FILE)))) arg = arg[1:]
return
} }
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, "ice."), lex.PREFIX, kit.Fields(ctx.ACTION, m.ActionKey()), mdb.FIELD, mdb.NAME, lex.SPLIT, nfs.PT) m.Cmdy(ctx.CONFIG, RUNTIME, arg)
kit.For(ice.Info.File, func(k, v string) { m.Push(nfs.FILE, k).Push(mdb.NAME, v) }) m.DisplayStory("json.js")
m.Sort(mdb.NAME)
}}, }},
CMD: {Hand: func(m *ice.Message, arg ...string) { }})
m.OptionFields(ctx.INDEX, mdb.NAME, mdb.HELP, nfs.FILE)
m.Cmdy(ctx.COMMAND, mdb.SEARCH, ctx.COMMAND)
}},
MOD: {Hand: func(m *ice.Message, arg ...string) {
kit.For(ice.Info.Gomod, func(k string, v string) { m.Push(nfs.MODULE, k).Push(nfs.VERSION, v) })
}},
ENV: {Hand: func(m *ice.Message, arg ...string) {
kit.For(os.Environ(), func(v string) { ls := strings.SplitN(v, mdb.EQ, 2); m.Push(mdb.NAME, ls[0]).Push(mdb.VALUE, ls[1]) })
m.Sort(mdb.NAME)
}},
nfs.PATH: {Hand: func(m *ice.Message, arg ...string) {
kit.For(_path_split(os.Getenv(PATH)), func(p string) { m.Push(nfs.PATH, p) })
}},
"chain": {Hand: func(m *ice.Message, arg ...string) { m.Echo(m.FormatChain()) }},
"upgrade": {Help: "升级", Hand: func(m *ice.Message, arg ...string) {
if nfs.Exists(m, ice.SRC_MAIN_GO) && nfs.Exists(m, ".git") && SystemFind(m, "go") != "" {
m.Cmdy("vimer", "compile")
} else if nfs.Exists(m, ice.BIN_ICE_BIN) {
m.Cmdy("upgrade")
} else {
m.Cmdy("", REBOOT)
}
}},
REBOOT: {Help: "重启", Hand: func(m *ice.Message, arg ...string) {
m.Go(func() { m.Sleep30ms(ice.EXIT, 1) })
}},
"lock": {Help: "锁屏", Icon: "bi bi-file-lock", Hand: func(m *ice.Message, arg ...string) {
switch runtime.GOOS {
case DARWIN:
TellApp(m, "System Events", `keystroke "q" using {control down, command down}`)
}
}},
}, ctx.ConfAction("")), Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) > 0 && arg[0] == BOOTINFO, func() { arg = arg[1:] })
m.Cmdy(ctx.CONFIG, RUNTIME, arg).StatusTime(mdb.TIME, ice.Info.Make.Time,
mdb.HASH, kit.Cut(ice.Info.Hash, 6), nfs.SIZE, ice.Info.Size,
mdb.NAME, ice.Info.NodeName, nfs.VERSION, ice.Info.Make.Versions(),
).Action()
ctx.DisplayStoryJSON(m)
}},
})
}
func NodeInfo(m *ice.Message, arg ...string) {
mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.TIME), m.Time())
ice.Info.NodeName = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.NAME), kit.Select(ice.Info.NodeName, arg, 0))
ice.Info.NodeType = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.TYPE), kit.Select(ice.Info.NodeType, arg, 1))
ice.Info.NodeIcon = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.ICON), kit.Select(ice.Info.NodeIcon, arg, 2))
}
func IsWindows() bool { return runtime.GOOS == WINDOWS }
func ParseMake(str string) []string {
res := kit.UnMarshal(str)
data := kit.Value(res, MAKE)
version := kit.Format(kit.Value(data, nfs.VERSION))
if kit.Format(kit.Value(data, "forword")) != "0" {
version = kit.Join(kit.TrimArg(kit.Simple(
kit.Select("v0.0.0", kit.Format(kit.Value(data, nfs.VERSION))),
kit.Select("0", kit.Format(kit.Value(data, "forword"))),
kit.Cut(kit.Format(kit.Value(data, mdb.HASH)), 6),
)...), "-")
}
return kit.Simple(
mdb.TIME, kit.Format(kit.Value(data, mdb.TIME)),
ice.SPACE, kit.Format(kit.Value(res, kit.Keys(NODE, mdb.NAME))),
nfs.MODULE, kit.Format(kit.Value(data, nfs.MODULE)),
nfs.VERSION, version,
COMMIT_TIME, kit.Format(kit.Value(data, "when")),
COMPILE_TIME, kit.Format(kit.Value(data, mdb.TIME)),
BOOT_TIME, kit.Format(kit.Value(res, kit.Keys(BOOT, mdb.TIME))),
SHELL, kit.Format(kit.Value(res, kit.Keys(CONF, SHELL))),
KERNEL, kit.Format(kit.Value(res, kit.Keys(HOST, GOOS))),
ARCH, kit.Format(kit.Value(res, kit.Keys(HOST, GOARCH))),
)
}
func SimpleMake() []string {
return []string{
nfs.MODULE, ice.Info.Make.Module, nfs.VERSION, ice.Info.Make.Versions(),
COMMIT_TIME, ice.Info.Make.When, COMPILE_TIME, ice.Info.Make.Time, BOOT_TIME, ice.Info.Time,
KERNEL, runtime.GOOS, ARCH, runtime.GOARCH,
}
} }

View File

@ -1,12 +0,0 @@
package cli
import (
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
)
func init() {
Index.MergeCommands(ice.Commands{
SUDO: {Actions: mdb.HashAction(mdb.SHORT, "cmd", mdb.FIELD, "time,cmd")},
})
}

View File

@ -3,87 +3,96 @@ package cli
import ( import (
"bytes" "bytes"
"io" "io"
"net/http"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/file"
) )
func _path_split(ps string) []string {
ps = kit.ReplaceAll(ps, "\\", nfs.PS)
return kit.Split(ps, lex.NL+kit.Select(nfs.DF, ";", strings.Contains(ps, ";")), lex.NL)
}
func _system_cmd(m *ice.Message, arg ...string) *exec.Cmd { func _system_cmd(m *ice.Message, arg ...string) *exec.Cmd {
bin, env := "", kit.Simple(m.Optionv(CMD_ENV))
kit.For(env, func(k, v string) {
if k == PATH {
if bin = _system_find(m, arg[0], _path_split(v)...); bin != "" {
m.Logs(FIND, "envpath cmd", bin)
}
}
})
if bin == "" {
if bin = _system_find(m, arg[0], EtcPath(m)...); bin != "" {
m.Logs(FIND, "etcpath cmd", bin)
}
}
if bin == "" {
if bin = _system_find(m, arg[0], m.Option(CMD_DIR), ice.BIN, nfs.PWD); bin != "" {
m.Logs(FIND, "contexts cmd", bin)
}
}
if bin == "" && !strings.Contains(arg[0], nfs.PS) {
if bin = _system_find(m, arg[0]); bin != "" {
m.Logs(FIND, "systems cmd", bin)
}
}
if bin == "" && !strings.Contains(arg[0], nfs.PS) {
m.Cmd(MIRRORS, CMD, arg[0])
if bin = _system_find(m, arg[0]); bin != "" {
m.Logs(FIND, "mirrors cmd", bin)
}
}
arg[0] = kit.Select(arg[0], bin)
if m.Cmd(SUDO, arg[0]).Length() > 0 {
m.Logs(FIND, "sudo cmd", arg[0])
arg = kit.Simple(SUDO, arg)
}
cmd := exec.Command(arg[0], arg[1:]...) cmd := exec.Command(arg[0], arg[1:]...)
if cmd.Dir = kit.TrimPath(m.Option(CMD_DIR)); len(cmd.Dir) > 0 {
if m.Logs(EXEC, CMD_DIR, cmd.Dir); !nfs.Exists(m, cmd.Dir) { // 运行目录
file.MkdirAll(cmd.Dir, ice.MOD_DIR) if cmd.Dir = m.Option(CMD_DIR); len(cmd.Dir) > 0 {
if m.Log_EXPORT(CMD_DIR, cmd.Dir); !kit.FileExists(cmd.Dir) {
nfs.MkdirAll(m, cmd.Dir)
} }
} }
kit.For(env, func(k, v string) { cmd.Env = append(cmd.Env, kit.Format("%s=%s", k, v)) })
kit.If(len(cmd.Env) > 0 && m.IsDebug(), func() { m.Logs(EXEC, CMD_ENV, kit.Format(cmd.Env)) }) // 环境变量
kit.If(len(cmd.Env) > 0, func() { m.Logs(EXEC, CMD_ENV, kit.Format(cmd.Env)) }) env := kit.Simple(m.Optionv(CMD_ENV))
_system_cmds(m, cmd, arg...) for i := 0; i < len(env)-1; i += 2 {
if cmd.Env = append(cmd.Env, kit.Format("%s=%s", env[i], env[i+1])); env[i] == PATH {
if file := _system_find(m, arg[0], strings.Split(env[i+1], ice.DF)...); file != "" {
m.Debug("cmd: %v", file)
cmd.Path = file
}
}
}
// 定制目录
if text := kit.ReadFile(ice.ETC_PATH); len(text) > 0 {
if file := _system_find(m, arg[0], strings.Split(text, ice.NL)...); file != "" {
m.Debug("cmd: %v", file)
cmd.Path = file
}
}
if _system_find(m, cmd.Path) == "" {
}
m.Debug("cmd: %v", cmd.Path)
if len(cmd.Env) > 0 {
m.Log_EXPORT(CMD_ENV, cmd.Env)
}
return cmd return cmd
} }
func _system_out(m *ice.Message, out string) io.Writer { func _system_out(m *ice.Message, out string) io.Writer {
defer func() { m.Warn(recover(), "output", out) }()
if w, ok := m.Optionv(out).(io.Writer); ok { if w, ok := m.Optionv(out).(io.Writer); ok {
return w return w
} else if m.Option(out) == "" { } else if m.Option(out) == "" {
return nil return nil
} else if f, p, e := file.CreateFile(m.Option(out)); m.Assert(e) { } else if f, p, e := kit.Create(m.Option(out)); m.Assert(e) {
m.Logs(nfs.SAVE, out, p).Optionv(out, f) m.Log_EXPORT(out, p)
m.Optionv(out, f)
return f return f
} }
return nil return nil
} }
func _system_find(m *ice.Message, bin string, dir ...string) string {
if strings.Contains(bin, ice.DF) {
return bin
}
if strings.HasPrefix(bin, ice.PS) {
return bin
}
if strings.HasPrefix(bin, nfs.PWD) {
return kit.Path(m.Option(CMD_DIR), bin)
}
if len(dir) == 0 {
dir = append(dir, strings.Split(kit.Env(PATH), ice.DF)...)
}
for _, p := range dir {
if _, err := os.Stat(path.Join(p, bin)); err == nil {
return kit.Path(path.Join(p, bin))
}
}
return ""
}
func _system_exec(m *ice.Message, cmd *exec.Cmd) { func _system_exec(m *ice.Message, cmd *exec.Cmd) {
// 输入流
if r, ok := m.Optionv(CMD_INPUT).(io.Reader); ok { if r, ok := m.Optionv(CMD_INPUT).(io.Reader); ok {
cmd.Stdin = r cmd.Stdin = r
} }
// 输出流
if w := _system_out(m, CMD_OUTPUT); w != nil { if w := _system_out(m, CMD_OUTPUT); w != nil {
cmd.Stdout, cmd.Stderr = w, w cmd.Stdout, cmd.Stderr = w, w
if w := _system_out(m, CMD_ERRPUT); w != nil { if w := _system_out(m, CMD_ERRPUT); w != nil {
@ -92,54 +101,29 @@ func _system_exec(m *ice.Message, cmd *exec.Cmd) {
} else { } else {
out := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS)) out := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
err := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS)) err := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
cmd.Stdout, cmd.Stderr = out, err
defer func() { defer func() {
m.Push(CMD_OUT, out.String()).Push(CMD_ERR, err.String()) m.Push(CMD_OUT, out.String())
if m.Echo(out.String()).Echo(err.String()); m.IsErr() { m.Push(CMD_ERR, err.String())
m.Option(ice.MSG_ARGS, kit.Simple(http.StatusBadRequest, cmd.Args, err.String())) m.Echo(strings.TrimSpace(kit.Select(out.String(), err.String())))
m.Echo(strings.TrimRight(err.String(), lex.NL))
m.Info("err: %v", err.String())
m.Info("out: %v", out.String())
}
}() }()
cmd.Stdout, cmd.Stderr = out, err
} }
if e := cmd.Run(); !m.WarnNotValid(e, cmd.Args) {
m.Cost(CODE, _system_code(cmd), EXEC, cmd.Args) // 执行命令
if e := cmd.Run(); !m.Warn(e, ice.ErrNotFound, cmd.Args) {
m.Cost(CODE, cmd.ProcessState.ExitCode(), ctx.ARGS, cmd.Args)
} }
m.Push(mdb.TIME, m.Time()).Push(CODE, _system_code(cmd)).StatusTime()
m.Push(mdb.TIME, m.Time()).Push(CODE, int(cmd.ProcessState.ExitCode()))
} }
func _system_code(cmd *exec.Cmd) string { func IsSuccess(m *ice.Message) bool {
return kit.Select("1", "0", cmd.ProcessState != nil && cmd.ProcessState.Success()) return m.Append(CODE) == "0" || m.Append(CODE) == ""
} }
func _system_find(m *ice.Message, bin string, dir ...string) string { func SystemFind(m *ice.Message, bin string, dir ...string) string {
if strings.Contains(bin, nfs.DF) { return _system_find(m, bin, dir...)
return bin
} else if strings.HasPrefix(bin, nfs.PS) {
return bin
} else if strings.HasPrefix(bin, nfs.PWD) {
return bin
}
kit.If(len(dir) == 0, func() { dir = append(dir, _path_split(kit.Env(PATH))...) })
for _, p := range dir {
if nfs.Exists(m, path.Join(p, bin)) {
return kit.Path(p, bin)
} else if IsWindows() && nfs.Exists(m, path.Join(p, bin)+".exe") {
return kit.Path(p, bin) + ".exe"
}
}
if nfs.Exists(m, bin) {
return kit.Path(bin)
}
return ""
} }
const ( const (
TIME_300ms = "300ms"
TIME_30ms = "30ms"
TIME_30s = "30s"
TIME_3s = "3s"
TIME_1s = "1s"
CMD_DIR = "cmd_dir" CMD_DIR = "cmd_dir"
CMD_ENV = "cmd_env" CMD_ENV = "cmd_env"
@ -147,103 +131,49 @@ const (
CMD_OUTPUT = "cmd_output" CMD_OUTPUT = "cmd_output"
CMD_ERRPUT = "cmd_errput" CMD_ERRPUT = "cmd_errput"
CMD_ERR = "cmd_err"
CMD_OUT = "cmd_out" CMD_OUT = "cmd_out"
CMD_ERR = "cmd_err"
RUN = "run"
REST = "rest"
PARAM = "param"
OPENS = "opens"
RELAY = "relay"
)
const (
SH = "sh"
LN = "ln"
CP = "cp"
MV = "mv"
RM = "rm"
CD = "cd"
CAT = "cat"
FIND = "find"
GREP = "grep"
TAIL = "tail"
WGET = "wget"
CURL = "curl"
SUDO = "sudo"
EXEC = "exec"
EXIT = "exit"
ECHO = "echo"
KILL = "kill"
GO = "go"
GOTAGS = "gotags"
GIT = "git"
MAN = "man"
YUM = "yum"
) )
const SYSTEM = "system" const SYSTEM = "system"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SYSTEM: {Name: "system cmd", Help: "系统命令", Actions: ice.MergeActions(ice.Actions{ SYSTEM: {Name: SYSTEM, Help: "系统命令", Value: kit.Data(mdb.FIELD, "time,id,cmd")},
nfs.PUSH: {Hand: func(m *ice.Message, arg ...string) { }, Commands: map[string]*ice.Command{
kit.For(arg, func(p string) { SYSTEM: {Name: "system cmd run", Help: "系统命令", Action: map[string]*ice.Action{
kit.If(!kit.IsIn(p, EtcPath(m)...), func() { nfs.FIND: {Name: "find", Help: "查找", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.PUSH, ice.ETC_PATH, strings.TrimSpace(p)+lex.NL) m.Echo(_system_find(m, arg[0], arg[1:]...))
})
})
m.Cmdy(nfs.CAT, ice.ETC_PATH)
}}, }},
FIND: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_system_find(m, arg[0], arg[1:]...)) }}, }, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
MAN: {Hand: func(m *ice.Message, arg ...string) { if len(arg) == 0 {
kit.If(len(arg) == 1, func() { arg = append(arg, "") }) mdb.ListSelect(m, arg...)
m.Echo(SystemCmds(m, "man %s %s|col -b", kit.Select("", arg[1], arg[1] != "1"), arg[0]))
}},
OPENS: {Hand: func(m *ice.Message, arg ...string) { Opens(m, arg...) }},
}), Hand: func(m *ice.Message, arg ...string) {
if _system_exec(m, _system_cmd(m, arg...)); IsSuccess(m) && m.Append(CMD_ERR) == "" {
m.SetAppend()
}
}},
})
ice.Info.SystemCmd = func(m *ice.Message, arg ...ice.Any) *ice.Message {
msg := m.Cmd(append([]ice.Any{SYSTEM}, arg...)...)
if m.Warn(!IsSuccess(msg), msg.Append(CMD_ERR)) {
}
return msg
}
}
func SystemFindGit(m *ice.Message) bool { return SystemFind(m, GIT) != "" }
func SystemFindGo(m *ice.Message) bool { return SystemFind(m, GO) != "" }
func SystemFind(m *ice.Message, bin string, dir ...string) string {
dir = append(dir, EtcPath(m)...)
return _system_find(m, bin, append(dir, _path_split(kit.Env(PATH))...)...)
}
func SystemExec(m *ice.Message, arg ...string) string { return strings.TrimSpace(m.Cmdx(SYSTEM, arg)) }
func SystemCmds(m *ice.Message, cmds string, args ...ice.Any) string {
return strings.TrimRight(m.Cmdx(SYSTEM, SH, "-c", kit.Format(cmds, args...), ice.Option{CMD_OUTPUT, ""}), lex.NL)
}
func IsSuccess(m *ice.Message) bool { return m.Append(CODE) == "" || m.Append(CODE) == "0" }
var _cache_path []string
func Shell(m *ice.Message) string { return kit.Select(SH, os.Getenv(SHELL)) }
func EtcPath(m *ice.Message) (res []string) {
if len(_cache_path) > 0 {
return _cache_path
}
nfs.Exists(m, ice.ETC_PATH, func(p string) {
kit.For(strings.Split(m.Cmdx(nfs.CAT, p, kit.Dict(aaa.UserRole, aaa.ROOT)), lex.NL), func(p string) {
kit.If(p != "" && !strings.HasPrefix(p, "# "), func() {
res = append(res, p)
})
})
})
_cache_path = res
return return
} }
m.Grow(SYSTEM, "", kit.Dict(mdb.TIME, m.Time(), ice.CMD, kit.Join(arg, ice.SP)))
if len(arg) == 1 {
arg = kit.Split(arg[0])
}
_system_exec(m, _system_cmd(m, arg...))
}},
}})
}
type buffer struct {
m *ice.Message
n string
}
func (b *buffer) Write(buf []byte) (int, error) {
if b.m.IsCliUA() {
print(string(buf))
} else {
b.m.PushNoticeGrow(string(buf))
}
return len(buf), nil
}
func (b *buffer) Close() error { return nil }
func PushStream(m *ice.Message) {
m.Option(CMD_OUTPUT, &buffer{m: m, n: m.Option(ice.MSG_DAEMON)})
}

View File

@ -1,11 +0,0 @@
package cli
import (
"os/exec"
ice "shylinux.com/x/icebergs"
)
func _system_cmds(m *ice.Message, cmd *exec.Cmd, arg ...string) *exec.Cmd {
return cmd
}

View File

@ -1,11 +0,0 @@
package cli
import (
"os/exec"
ice "shylinux.com/x/icebergs"
)
func _system_cmds(m *ice.Message, cmd *exec.Cmd, arg ...string) *exec.Cmd {
return cmd
}

View File

@ -1,11 +0,0 @@
package cli
import (
"os/exec"
ice "shylinux.com/x/icebergs"
)
func _system_cmds(m *ice.Message, cmd *exec.Cmd, arg ...string) *exec.Cmd {
return cmd
}

View File

@ -1,230 +1,100 @@
package ctx package ctx
import ( import (
"path"
"runtime"
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _command_list(m *ice.Message, name string) *ice.Message { func _command_list(m *ice.Message, name string) {
if strings.HasPrefix(name, "can.") { if strings.HasPrefix(name, "can.") {
return m.Push(mdb.INDEX, name).Push(mdb.NAME, name).Push(mdb.HELP, "").Push(mdb.META, "").Push(mdb.LIST, "") m.Push(mdb.INDEX, name)
return
} }
m.Option(ice.MSG_NODENAME, ice.Info.Titles) if name == "" { // 命令列表
m.Option(ice.MSG_NODEICON, m.Resource(ice.Info.NodeIcon)) for k, v := range m.Source().Commands {
if k[0] == '/' || k[0] == '_' {
continue // 内部命令
}
m.Push(mdb.KEY, k)
m.Push(mdb.NAME, v.Name)
m.Push(mdb.HELP, v.Help)
}
m.Sort(mdb.KEY)
return
}
// 命令详情
m.Spawn(m.Source()).Search(name, func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) { m.Spawn(m.Source()).Search(name, func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
icon := kit.Format(kit.Value(cmd.Meta, kit.Keys(ice.CTX_ICONS, key))) m.Push(mdb.INDEX, kit.Keys(s.Cap(ice.CTX_FOLLOW), key))
icons := kit.Select(cmd.Icon, icon, !kit.HasPrefix(icon, "bi ", "{")) m.Push(mdb.NAME, kit.Format(cmd.Name))
if icons != "" { m.Push(mdb.HELP, kit.Format(cmd.Help))
icons = m.Resource(icons) m.Push(mdb.META, kit.Format(cmd.Meta))
} m.Push(mdb.LIST, kit.Format(cmd.List))
m.Push(mdb.INDEX, kit.Keys(s.Prefix(), key))
m.Push(mdb.ICONS, icons)
m.Push(mdb.NAME, kit.Format(cmd.Name)).Push(mdb.HELP, kit.Format(cmd.Help))
m.Push(mdb.LIST, kit.Format(cmd.List)).Push(mdb.META, kit.Format(cmd.Meta))
m.Push("_command", ShortCmd(kit.Keys(s.Prefix(), key)))
if !nfs.Exists(m, kit.Split(cmd.FileLine(), nfs.DF)[0], func(p string) {
m.Push("_fileline", m.FileURI(p))
}) {
m.Push("_fileline", "")
}
m.Push("_role", kit.Select("", ice.OK, aaa.Right(m.Spawn(), name)))
m.Push("_help", GetCmdHelp(m, name))
}) })
return m
} }
func _command_search(m *ice.Message, kind, name, text string) { func _command_search(m *ice.Message, kind, name, text string) {
m.Travel(func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) { m.Travel(func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
if IsOrderCmd(key) || !strings.Contains(s.Prefix(key), name) { if key[0] == '/' || key[0] == '_' {
return // 内部命令
}
if name != "" && !strings.HasPrefix(key, name) && !strings.Contains(s.Name, name) {
return return
} }
m.PushSearch(ice.CTX, kit.PathName(1), ice.CMD, kit.FileName(1), m.PushSearch(ice.CTX, kit.PathName(1), ice.CMD, kit.FileName(1),
kit.SimpleKV("", s.Prefix(), kit.Select(key, cmd.Name), cmd.Help), kit.SimpleKV("", s.Cap(ice.CTX_FOLLOW), cmd.Name, cmd.Help),
INDEX, kit.Keys(s.Prefix(), key), mdb.HELP, cmd.Help) CONTEXT, s.Cap(ice.CTX_FOLLOW), COMMAND, key,
}).Sort(m.OptionFields()) INDEX, kit.Keys(s.Cap(ice.CTX_FOLLOW), key),
)
})
}
func CmdAction(fields ...string) map[string]*ice.Action {
return ice.SelectAction(map[string]*ice.Action{
COMMAND: {Name: "command", Help: "命令", Hand: func(m *ice.Message, arg ...string) {
if !m.PodCmd(COMMAND, arg) {
m.Cmdy(COMMAND, arg)
}
}},
ice.RUN: {Name: "run", Help: "执行", Hand: func(m *ice.Message, arg ...string) {
if m.Right(arg) && !m.PodCmd(arg) {
m.Cmdy(arg)
}
}},
}, fields...)
} }
const ( const (
ACTION = "action"
INDEX = "index" INDEX = "index"
CMDS = "cmds"
ARGS = "args" ARGS = "args"
OPTS = "opts"
STYLE = "style" STYLE = "style"
DISPLAY = "display" DISPLAY = "display"
PREVIEW = "preview"
ACTION = "action"
TOOLS = "tools"
RUN = "run"
SHIP = "ship"
ICONS = ice.CTX_ICONS
TRANS = ice.CTX_TRANS
TITLE = ice.CTX_TITLE
INPUT = html.INPUT
) )
const COMMAND = "command" const COMMAND = "command"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
COMMAND: {Name: "command key auto", Help: "命令", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{ COMMAND: {Name: "command key auto", Help: "命令", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
TravelCmd(m, func(key, file, line string) { AddFileCmd(file, key) }) m.Cmd(mdb.SEARCH, mdb.CREATE, m.CommandKey(), m.PrefixKey())
m.Travel(func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
kit.If(cmd.Actions == nil, func() { cmd.Actions = ice.Actions{} })
if _, ok := cmd.Actions[COMMAND]; !ok {
cmd.Actions[COMMAND] = &ice.Action{Hand: Command}
}
if _, ok := cmd.Actions[RUN]; !ok {
cmd.Actions[RUN] = &ice.Action{Hand: Run}
}
if _, ok := cmd.Actions[mdb.INPUTS]; !ok {
cmd.Actions[mdb.INPUTS] = &ice.Action{Hand: func(m *ice.Message, arg ...string) { mdb.HashInputs(m, arg) }}
}
})
}}, }},
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) { mdb.SEARCH: {Name: "search type name text", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
if arg[0] == m.CommandKey() || len(arg) > 1 && arg[1] != "" {
_command_search(m, arg[0], kit.Select("", arg, 1), kit.Select("", arg, 2)) _command_search(m, arg[0], kit.Select("", arg, 1), kit.Select("", arg, 2))
}
}}, }},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { INDEX: {Name: "index", Help: "索引", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 && arg[0] != "" && arg[0] != ice.EXIT {
m.Search(arg[0], func(key string, cmd *ice.Command) {
field := kit.Format(kit.Value(cmd.List, kit.Format("%d.name", len(arg)-1)))
if m.Cmdy(arg[0], mdb.INPUTS, field); m.Length() == 0 {
m.Cmdy(arg).Cut(field)
}
})
}
}}, }},
"default": {Hand: func(m *ice.Message, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Spawn(m.Source()).Search(arg[0], func(key string, cmd *ice.Command) {
if arg[1] == ACTION {
list := kit.Value(cmd.Meta, arg[2])
kit.For(arg[3:], func(k, v string) {
kit.For(list, func(value ice.Map) {
kit.If(value[mdb.NAME] == k, func() {
value[mdb.VALUE] = v
})
})
})
return
}
for i, v := range arg[1:] {
kit.Value(cmd.List, kit.Keys(i, mdb.VALUE), v)
}
})
}},
}), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
m.OptionFields(INDEX, mdb.HELP) arg = append(arg, "")
m.Cmdy("", mdb.SEARCH, COMMAND) }
} else { for _, key := range arg {
kit.For(arg, func(k string) { _command_list(m, k) }) _command_list(m, key)
} }
}}, }},
}) }})
}
var PodCmd = func(m *ice.Message, arg ...ice.Any) bool { return false }
func Run(m *ice.Message, arg ...string) {
kit.If(!PodCmd(m, arg) && aaa.Right(m, arg), func() { m.Cmdy(arg) })
}
func Command(m *ice.Message, arg ...string) {
kit.If(!PodCmd(m, COMMAND, arg), func() { m.Cmdy(COMMAND, arg) })
}
func FileCmd(dir string) string {
if strings.Index(dir, ":") == 1 {
return ice.Pulse.FileURI(kit.ExtChange(strings.Join(kit.Slice(strings.Split(dir, ":"), 0, 2), ":"), nfs.GO))
}
return ice.Pulse.FileURI(kit.ExtChange(strings.Split(dir, nfs.DF)[0], nfs.GO))
}
func AddFileCmd(dir, key string) {
if ls := strings.SplitN(path.Join(kit.Slice(kit.Split(FileCmd(dir), nfs.PS), 1, 4)...), mdb.AT, 2); len(ls) > 1 {
_ls := strings.Split(FileCmd(dir), mdb.AT+ls[1]+nfs.PS)
ice.Info.File[path.Join(nfs.P, nfs.USR, path.Base(_ls[0]), _ls[1])] = key
ice.Info.Gomod[ls[0]] = ls[1]
} else {
ice.Info.File[FileCmd(dir)] = key
}
}
func GetFileCmd(dir string) string {
if strings.HasPrefix(dir, ice.REQUIRE+nfs.PS) {
dir = nfs.PS + dir
} else if strings.HasPrefix(dir, ice.ISH_PLUGED) {
dir = path.Join(nfs.P, strings.TrimPrefix(dir, ice.ISH_PLUGED))
}
for _, dir := range []string{dir, path.Join(nfs.P, ice.Info.Make.Module, dir), path.Join(nfs.P, ice.Info.Make.Module, ice.SRC, dir)} {
if cmd, ok := ice.Info.File[FileCmd(dir)]; ok {
return cmd
}
p := path.Dir(dir)
if cmd, ok := ice.Info.File[FileCmd(path.Join(p, path.Base(p)+nfs.PT+nfs.GO))]; ok {
return cmd
}
}
return ""
}
func GetCmdHelp(m *ice.Message, cmds string) (file string) {
file = kit.TrimPrefix(m.FileURI(kit.ExtChange(GetCmdFile(m, cmds), nfs.SHY)), nfs.P, nfs.REQUIRE)
if !nfs.Exists(m, path.Join(nfs.USR_LEARNING_PORTAL, "commands", strings.TrimPrefix(file, nfs.USR_ICEBERGS)), func(p string) { file = p }) {
kit.If(!nfs.Exists(m, file), func() { file = "" })
}
return
}
func GetCmdFile(m *ice.Message, cmds string) (file string) {
m.Search(kit.Select(m.PrefixKey(), cmds), func(key string, cmd *ice.Command) {
if file = kit.TrimPrefix(m.FileURI(kit.Split(cmd.FileLine(), nfs.DF)[0]), nfs.P); !nfs.Exists(m, file) {
file = path.Join(nfs.P, file)
}
})
return
}
func TravelCmd(m *ice.Message, cb func(key, file, line string)) *ice.Message {
m.Travel(func(p *ice.Context, s *ice.Context, key string, cmd *ice.Command) {
if IsOrderCmd(key) {
return
}
if runtime.GOOS == ice.WINDOWS {
if ls := kit.Split(cmd.FileLine(), nfs.DF); len(ls) > 2 {
cb(kit.Keys(s.Prefix(), key), strings.TrimPrefix(strings.Join(kit.Slice(ls, 0, -1), nfs.DF), kit.Path("")+nfs.PS), kit.Select("1", ls, -1))
return
}
}
if ls := kit.Split(cmd.FileLine(), nfs.DF); len(ls) > 0 {
cb(kit.Keys(s.Prefix(), key), strings.TrimPrefix(ls[0], kit.Path("")+nfs.PS), kit.Select("1", ls, 1))
}
})
return m
}
func IsOrderCmd(key string) bool {
return key[0] == '/' || key[0] == '_'
}
func ShortCmd(key string) string {
_key := kit.Select("", kit.Split(key, nfs.PT), -1)
if _p, ok := ice.Info.Index[_key].(*ice.Context); ok && _p.Prefix(_key) == key {
return _key
}
return key
}
func ResourceFile(m *ice.Message, file string, arg ...string) string {
if strings.Contains(file, "bi ") {
return file
}
if kit.HasPrefix(file, nfs.PS, ice.HTTP) {
return file
} else if nfs.Exists(m, file) {
return file
} else {
return path.Join(path.Dir(GetCmdFile(m, m.PrefixKey())), file)
}
} }

View File

@ -2,75 +2,66 @@ package ctx
import ( import (
"encoding/json" "encoding/json"
"os"
"path" "path"
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/miss"
) )
func _config_only(v ice.Any, arg ...string) bool { func _config_list(m *ice.Message) {
switch v := v.(type) { for k, v := range m.Source().Configs {
case nil: if k[0] == '/' || k[0] == '_' {
return true continue // 内部配置
case ice.Map:
if len(v) > len(arg) {
return false
} }
for k, v := range v {
if v, ok := v.(ice.Map); ok && len(v) == 0 { m.Push(mdb.KEY, k)
continue m.Push(mdb.NAME, v.Name)
} else if kit.IndexOf(arg, k) == -1 { m.Push(mdb.VALUE, kit.Format(v.Value))
return false
} }
} m.Sort(mdb.KEY)
return true
}
return false
} }
func _config_save(m *ice.Message, name string, arg ...string) { func _config_save(m *ice.Message, name string, arg ...string) {
if !ice.HasVar() { name = path.Join(m.Config(nfs.PATH), name)
return if f, p, e := kit.Create(name); m.Assert(e) {
} defer f.Close()
data, msg := ice.Map{}, m.Spawn(m.Source())
msg := m.Spawn(m.Source())
data := map[string]interface{}{}
for _, k := range arg { for _, k := range arg {
if v := mdb.Confv(msg, k); _config_only(v, mdb.META) && _config_only(kit.Value(v, mdb.META), if v := msg.Confv(k); v != "" {
mdb.IMPORTANT, mdb.EXPIRE, mdb.VENDOR, nfs.SOURCE, nfs.SCRIPT, nfs.PATH, lex.REGEXP,
mdb.SHORT, mdb.FIELD, mdb.SHORTS, mdb.FIELDS,
mdb.ACTION, mdb.SORT, mdb.TOOLS,
"link", "linux", "darwin", "windows",
) {
continue
} else {
data[k] = v data[k] = v
} }
} }
if len(data) == 0 {
return // 保存配置
} if s, e := json.MarshalIndent(data, "", " "); m.Assert(e) {
if f, _, e := miss.CreateFile(path.Join(ice.VAR_CONF, name)); m.Assert(e) { if n, e := f.Write(s); m.Assert(e) {
defer f.Close() m.Log_EXPORT(CONFIG, name, nfs.FILE, p, nfs.SIZE, n)
if s, e := json.MarshalIndent(data, "", " "); !m.WarnNotValid(e) {
if _, e := f.Write(s); !m.WarnNotValid(e) {
} }
} }
m.Echo(p)
} }
} }
func _config_load(m *ice.Message, name string, arg ...string) { func _config_load(m *ice.Message, name string, arg ...string) {
if !ice.HasVar() { name = path.Join(m.Config(nfs.PATH), name)
return if f, e := os.Open(name); e == nil {
}
if f, e := miss.OpenFile(path.Join(ice.VAR_CONF, name)); e == nil {
defer f.Close() defer f.Close()
data, msg := ice.Map{}, m.Spawn(m.Source())
msg := m.Spawn(m.Source())
data := map[string]interface{}{}
json.NewDecoder(f).Decode(&data) json.NewDecoder(f).Decode(&data)
// 加载配置
for k, v := range data { for k, v := range data {
msg.Search(k, func(p *ice.Context, s *ice.Context, key string, conf *ice.Config) { msg.Search(k, func(p *ice.Context, s *ice.Context, key string) {
kit.If(s.Configs[key] == nil, func() { s.Configs[key] = &ice.Config{} }) m.Log_IMPORT(CONFIG, kit.Keys(s.Name, key), nfs.FILE, name)
if s.Configs[key] == nil {
s.Configs[key] = &ice.Config{}
}
s.Configs[key].Value = v s.Configs[key].Value = v
}) })
} }
@ -79,87 +70,68 @@ func _config_load(m *ice.Message, name string, arg ...string) {
func _config_make(m *ice.Message, key string, arg ...string) { func _config_make(m *ice.Message, key string, arg ...string) {
msg := m.Spawn(m.Source()) msg := m.Spawn(m.Source())
if len(arg) > 1 { if len(arg) > 1 {
kit.If(!kit.IsIn(strings.Split(arg[0], nfs.PT)[0], mdb.META, mdb.HASH, mdb.LIST), func() { arg[0] = kit.Keys(mdb.META, arg[0]) }) if strings.HasPrefix(arg[1], "@") {
kit.If(strings.HasPrefix(arg[1], mdb.AT), func() { arg[1] = msg.Cmdx(nfs.CAT, arg[1][1:]) }) arg[1] = msg.Cmdx(nfs.CAT, arg[1][1:])
mdb.Confv(msg, key, arg[0], kit.Parse(nil, "", arg[1:]...))
} }
if len(arg) > 0 { // 修改配置
m.Echo(kit.Formats(mdb.Confv(msg, key, arg[0]))) msg.Confv(key, arg[0], kit.Parse(nil, "", arg[1:]...))
} else {
m.Echo(kit.Formats(mdb.Confv(msg, key))).StatusTime(mdb.COUNT, kit.Length(mdb.Confv(msg, key, mdb.HASH)))
}
}
func _config_list(m *ice.Message) {
for k, v := range m.Source().Configs {
if !IsOrderCmd(k) {
m.Push(mdb.KEY, k).Push(mdb.NAME, v.Name).Push(mdb.VALUE, kit.Format(v.Value))
}
}
m.Sort(mdb.KEY)
} }
if len(arg) > 0 {
m.Echo(kit.Formats(msg.Confv(key, arg[0])))
} else {
m.Echo(kit.Formats(msg.Confv(key)))
}
}
func _config_rich(m *ice.Message, key string, sub string, arg ...string) {
m.Rich(key, sub, kit.Data(arg))
}
func _config_grow(m *ice.Message, key string, sub string, arg ...string) {
m.Grow(key, sub, kit.Dict(arg))
}
const (
SAVE = "save"
LOAD = "load"
RICH = "rich"
GROW = "grow"
)
const CONFIG = "config" const CONFIG = "config"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CONFIG: {Name: "config key auto", Help: "配置", Actions: ice.Actions{ CONFIG: {Name: CONFIG, Help: "配置", Value: kit.Data(nfs.PATH, ice.VAR_CONF)},
nfs.SAVE: {Hand: func(m *ice.Message, arg ...string) { _config_save(m, arg[0], arg[1:]...) }}, }, Commands: map[string]*ice.Command{
nfs.LOAD: {Hand: func(m *ice.Message, arg ...string) { _config_load(m, arg[0], arg[1:]...) }}, CONFIG: {Name: "config key auto", Help: "配置", Action: map[string]*ice.Action{
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], mdb.EXPORT) }}, SAVE: {Name: "save", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], mdb.IMPORT) }}, _config_save(m, arg[0], arg[1:]...)
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
nfs.Trash(m, path.Join(ice.VAR_DATA, arg[0]))
nfs.Trash(m, m.Cmdx(arg[0], mdb.EXPORT))
mdb.Conf(m, arg[0], mdb.HASH, "")
}}, }},
mdb.CREATE: {Name: "create name value", Hand: func(m *ice.Message, arg ...string) { LOAD: {Name: "load", Help: "加载", Hand: func(m *ice.Message, arg ...string) {
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), m.Option(mdb.VALUE)) _config_load(m, arg[0], arg[1:]...)
}}, }},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { RICH: {Name: "rich", Help: "富有", Hand: func(m *ice.Message, arg ...string) {
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), "") _config_rich(m, arg[0], arg[1], arg[2:]...)
}}, }},
mdb.MODIFY: {Hand: func(m *ice.Message, arg ...string) { GROW: {Name: "grow", Help: "成长", Hand: func(m *ice.Message, arg ...string) {
if arg[0] == mdb.VALUE { _config_grow(m, arg[0], arg[1], arg[2:]...)
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), arg[1]) }},
"list": {Name: "list", Help: "列表", Hand: func(m *ice.Message, arg ...string) {
list := []interface{}{}
for _, v := range arg[2:] {
list = append(list, v)
} }
m.Confv(arg[0], arg[1], kit.List(list...))
}}, }},
}, Hand: func(m *ice.Message, arg ...string) { "clear": {Name: "clear", Help: "清空", Hand: func(m *ice.Message, arg ...string) {
m.Conf(arg[0], "", "")
m.Cmd(ice.EXIT, 1)
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
_config_list(m) _config_list(m)
} else { return
}
_config_make(m, arg[0], arg[1:]...) _config_make(m, arg[0], arg[1:]...)
m.Action(mdb.CREATE, mdb.IMPORT, mdb.EXPORT, nfs.TRASH)
kit.For(mdb.Confv(m, arg[0], mdb.META), func(k, v string) {
m.Push(mdb.NAME, k).Push(mdb.VALUE, v).PushButton(mdb.REMOVE)
})
DisplayStoryJSON(m)
}
}}, }},
}) }})
}
func init() { ice.Info.Save = Save; ice.Info.Load = Load }
func Save(m *ice.Message, arg ...string) *ice.Message {
kit.If(len(arg) == 0, func() { arg = kit.SortedKey(m.Target().Configs) })
kit.For(arg, func(i int, k string) { arg[i] = strings.Replace(m.Prefix(k), nfs.PS, "", 1) })
return m.Cmd(prefix(CONFIG), nfs.SAVE, m.Prefix(nfs.JSON), arg)
}
func Load(m *ice.Message, arg ...string) *ice.Message {
kit.If(len(arg) == 0, func() { arg = kit.SortedKey(m.Target().Configs) })
kit.For(arg, func(i int, k string) { arg[i] = strings.Replace(m.Prefix(k), nfs.PS, "", 1) })
return m.Cmd(prefix(CONFIG), nfs.LOAD, m.Prefix(nfs.JSON), arg)
}
func ConfAction(arg ...ice.Any) ice.Actions {
return ice.Actions{ice.CTX_INIT: mdb.AutoConfig(arg...)}
}
func ConfigFromOption(m *ice.Message, arg ...string) {
if len(arg) == 0 {
kit.For(m.Target().Commands[m.CommandKey()].Actions[m.ActionKey()].List, func(value ice.Any) {
arg = append(arg, kit.Format(kit.Value(value, mdb.NAME)))
})
}
kit.For(arg, func(k string) { mdb.Config(m, k, kit.Select(mdb.Config(m, k), m.Option(k))) })
}
func OptionFromConfig(m *ice.Message, arg ...string) string {
kit.For(arg, func(k string) { m.Option(k, mdb.Config(m, k)) })
return m.Option(arg[0])
} }

View File

@ -5,28 +5,63 @@ import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _context_list(m *ice.Message, sub *ice.Context, name string) { func _context_list(m *ice.Message, sub *ice.Context, name string) {
m.Travel(func(p *ice.Context, s *ice.Context) { m.Travel(func(p *ice.Context, s *ice.Context) {
if name != "" && name != ice.ICE && !strings.HasPrefix(s.Prefix(), name+nfs.PT) { if name != "" && name != ice.ICE && !strings.HasPrefix(s.Cap(ice.CTX_FOLLOW), name+ice.PT) {
return return
} }
m.Push(mdb.NAME, s.Prefix()).Push(mdb.HELP, s.Help) m.Push(mdb.NAME, s.Cap(ice.CTX_FOLLOW))
m.Push(mdb.STATUS, s.Cap(ice.CTX_STATUS))
m.Push(mdb.STREAM, s.Cap(ice.CTX_STREAM))
m.Push(mdb.HELP, s.Help)
}) })
} }
func Inputs(m *ice.Message, field string) bool {
switch strings.TrimPrefix(field, "extra.") {
case ice.POD:
m.Cmdy("route")
case ice.CTX:
m.Cmdy(CONTEXT)
case ice.CMD:
m.Cmdy(CONTEXT, kit.Select(m.Option(ice.CTX), m.Option(kit.Keys(mdb.EXTRA, ice.CTX))), COMMAND)
case ice.ARG:
default:
return false
}
return true
}
const CONTEXT = "context" const CONTEXT = "context"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
CONTEXT: {Name: "context name=ice action=context,command,config key auto", Help: "模块", Hand: func(m *ice.Message, arg ...string) { CONTEXT: {Name: "context name=web action=context,command,config key auto spide", Help: "模块", Action: ice.MergeAction(map[string]*ice.Action{
kit.If(len(arg) == 0, func() { arg = append(arg, m.Source().Prefix()) }) "spide": {Name: "spide", Help: "架构图", Hand: func(m *ice.Message, arg ...string) {
m.Search(arg[0]+nfs.PT, func(p *ice.Context, s *ice.Context) { if len(arg) == 0 || arg[1] == CONTEXT { // 模块列表
m.Cmdy(CONTEXT, kit.Select(ice.ICE, arg, 0), CONTEXT)
m.Display("/plugin/story/spide.js?prefix=spide", "root", kit.Select(ice.ICE, arg, 0), "split", ice.PT)
} else if index := kit.Keys(arg[1]); strings.HasSuffix(index, arg[2]) { // 命令列表
m.Cmdy(CONTEXT, index, COMMAND).Table(func(i int, value map[string]string, head []string) {
m.Push("file", arg[1])
})
} else { // 命令详情
m.Cmdy(COMMAND, kit.Keys(index, strings.Split(arg[2], ice.SP)[0]))
}
}},
}, CmdAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
arg = append(arg, m.Source().Cap(ice.CTX_FOLLOW))
}
m.Search(arg[0]+ice.PT, func(p *ice.Context, s *ice.Context, key string) {
msg := m.Spawn(s) msg := m.Spawn(s)
defer m.Copy(msg) defer m.Copy(msg)
switch kit.Select(CONTEXT, arg, 1) { switch kit.Select(CONTEXT, arg, 1) {
case CONTEXT: case CONTEXT:
_context_list(msg, s, arg[0]) _context_list(msg, s, arg[0])
@ -37,5 +72,5 @@ func init() {
} }
}) })
}}, }},
}) }})
} }

View File

@ -1,14 +1,9 @@
package ctx package ctx
import ( import ice "shylinux.com/x/icebergs"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const CTX = "ctx" const CTX = "ctx"
var Index = &ice.Context{Name: CTX, Help: "标准模块"} var Index = &ice.Context{Name: CTX, Help: "标准模块"}
func init() { ice.Index.Register(Index, nil, CONTEXT, COMMAND, CONFIG) } func init() { ice.Index.Register(Index, nil, CONTEXT, COMMAND, CONFIG, MESSAGE) }
func prefix(arg ...string) string { return kit.Keys(CTX, arg) }

7
base/ctx/ctx.shy Normal file
View File

@ -0,0 +1,7 @@
chapter "ctx"
field "模块" context
field "命令" command
field "配置" config
field "消息" message

View File

@ -1,94 +0,0 @@
package ctx
import (
"path"
"reflect"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func isLocalFile(p string) bool {
return !strings.HasPrefix(p, nfs.PS) && !strings.HasPrefix(p, ice.HTTP)
}
func DisplayTable(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayBase(m, ice.PLUGIN_TABLE_JS, arg...)
}
func DisplayTableCard(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayTable(m, STYLE, "card")
}
func DisplayStory(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
kit.If(file == "", func() { file = kit.Keys(m.CommandKey(), nfs.JS) })
kit.If(isLocalFile(file), func() { file = path.Join(ice.PLUGIN_STORY, file) })
return DisplayBase(m, file, arg...)
}
func DisplayInput(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
kit.If(file == "", func() { file = kit.Keys(m.CommandKey(), nfs.JS) })
kit.If(isLocalFile(file), func() { file = path.Join(ice.PLUGIN_INPUT, file) })
return DisplayBase(m, file, arg...)
}
func DisplayStoryForm(m *ice.Message, arg ...ice.Any) *ice.Message {
args := kit.List()
for i := range arg {
switch v := arg[i].(type) {
case string:
args = append(args, ice.SplitCmd("list "+v, nil)...)
default:
trans := kit.Value(m.Commands(m.CommandKey()).Meta, ice.CTX_TRANS)
if t := reflect.TypeOf(v); t.Kind() == reflect.Func {
name := kit.FuncName(arg[i])
args = append(args, kit.Dict(mdb.TYPE, html.BUTTON, mdb.NAME, name, mdb.VALUE, kit.Select(name, kit.Value(trans, name), !m.IsEnglish())))
}
}
}
kit.For(args, func(v ice.Map) { m.Push("", v, kit.Split("type,name,value,values,need,action")) })
return DisplayStory(m, "form")
}
func DisplayInputKey(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayInput(m, "key", arg...)
}
func DisplayStoryWeight(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayStory(m, "weight", arg...)
}
func DisplayStoryPie(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayStory(m, "pie", arg...)
}
func DisplayStoryJSON(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayStory(m, "json", arg...)
}
func DisplayStorySpide(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayStory(m, "spide", arg...)
}
func DisplayStoryChina(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayStory(m, "china", arg...)
}
func DisplayStudio(m *ice.Message, cmd ...string) *ice.Message {
for i, k := range cmd {
kit.If(!strings.Contains(cmd[i], nfs.PT), func() { cmd[i] = m.Prefix(k) })
}
return DisplayStory(m.Cmdy(COMMAND, cmd), "studio")
}
func DisplayLocal(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
kit.If(file == "", func() { file = strings.ReplaceAll(strings.TrimPrefix(m.PrefixKey(), "web."), nfs.PT, nfs.PS) })
kit.If(isLocalFile(file), func() { file = path.Join(ice.PLUGIN_LOCAL, file) })
return DisplayBase(m, file, arg...)
}
func DisplayLocalInner(m *ice.Message, arg ...ice.Any) *ice.Message {
return DisplayLocal(m, "code/inner", arg...)
}
func DisplayBase(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
m.Option(ice.MSG_DISPLAY, kit.MergeURL(kit.Select(kit.ExtChange(file, nfs.JS), file, strings.Contains(file, mdb.QS)), arg...))
return Toolkit(m, "")
}
func DisplayBaseCSS(m *ice.Message, file string, arg ...ice.Any) *ice.Message {
m.Option(ice.MSG_DISPLAY_CSS, kit.MergeURL(kit.Select(kit.ExtChange(file, nfs.CSS), file, strings.Contains(file, mdb.QS)), arg...))
return m
}
func Toolkit(m *ice.Message, arg ...string) *ice.Message {
m.OptionDefault(ice.MSG_ONLINE, mdb.Config(m, "online"))
return m.Options(ice.MSG_TOOLKIT, kit.Select(mdb.Config(m, mdb.TOOLS), kit.Fields(arg)))
}

26
base/ctx/message.go Normal file
View File

@ -0,0 +1,26 @@
package ctx
import (
"reflect"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
const MESSAGE = "message"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
MESSAGE: {Name: "message", Help: "消息", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
t := reflect.TypeOf(m)
for i := 0; i < t.NumMethod(); i++ {
method := t.Method(i)
p := kit.FileLine(method.Func.Interface(), 4)
m.Push(mdb.NAME, method.Name)
m.Push(mdb.TEXT, strings.Split(p, ice.ICEBERGS+"/")[1])
}
}},
}})
}

View File

@ -1,61 +0,0 @@
package ctx
import (
"path"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func _process_args(m *ice.Message, args ice.Any) []string {
switch cb := args.(type) {
case []string:
return cb
case string:
return []string{cb}
case func() string:
return []string{cb()}
case func() []string:
return cb()
case func():
cb()
case nil:
default:
m.ErrorNotImplement(args)
}
return nil
}
func ProcessField(m *ice.Message, cmd string, args ice.Any, arg ...string) *ice.Message {
if cmd = kit.Select(m.ActionKey(), cmd); kit.HasPrefixList(arg, RUN) {
if !PodCmd(m, cmd, arg[1:]) && aaa.Right(m, cmd, arg[1:]) {
m.Cmdy(cmd, arg[1:])
}
return m
}
args = kit.Format(_process_args(m, args))
if PodCmd(m, COMMAND, cmd) {
m.Push(ice.SPACE, m.Option(ice.MSG_USERPOD))
} else {
m.Cmdy(COMMAND, cmd)
}
if m.Push(ARGS, args); m.IsMetaKey() {
m.Push(STYLE, html.FLOAT)
}
if m.ActionKey() == "" {
m.ProcessField(ACTION, RUN, cmd)
} else {
m.ProcessField(ACTION, m.ActionKey(), RUN)
}
return m
}
func ProcessFloat(m *ice.Message, cmd string, args ice.Any, arg ...string) *ice.Message {
if m.IsMetaKey() {
m.ProcessOpen(path.Join("/c/", cmd, path.Join(_process_args(m, args)...)))
return m
} else if !kit.HasPrefixList(arg, RUN) {
defer m.Push(STYLE, html.FLOAT)
}
return ProcessField(m, cmd, args, arg...)
}

View File

@ -1,75 +1,38 @@
package gdb package gdb
import ( import (
"sync"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
) )
const ( func _event_listen(m *ice.Message, event string, cmd string) {
LISTEN = "listen" m.Cmdy(mdb.INSERT, EVENT, "", mdb.HASH, EVENT, event)
HAPPEN = "happen" m.Cmdy(mdb.INSERT, EVENT, "", mdb.ZONE, event, ice.CMD, cmd)
) }
func _event_action(m *ice.Message, event string, arg ...string) {
mdb.ZoneSelect(m, event).Table(func(index int, value map[string]string, head []string) {
m.Cmd(kit.Split(value[ice.CMD]), event, arg).Cost(EVENT, event, ice.ARG, arg)
})
}
const EVENT = "event" const EVENT = "event"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
EVENT: {Name: "event event id auto listen happen", Help: "事件流", Actions: ice.MergeActions(ice.Actions{ EVENT: {Name: EVENT, Help: "事件流", Value: kit.Data(mdb.SHORT, EVENT, mdb.FIELD, "time,id,cmd")},
LISTEN: {Name: "listen event* cmd*", Help: "监听", Hand: func(m *ice.Message, arg ...string) { }, Commands: map[string]*ice.Command{
mdb.ZoneInsert(m, m.OptionSimple(EVENT, ice.CMD)) EVENT: {Name: "event event id auto listen", Help: "事件流", Action: ice.MergeAction(map[string]*ice.Action{
list[m.Option(EVENT)]++ LISTEN: {Name: "listen event cmd", Help: "监听", Hand: func(m *ice.Message, arg ...string) {
_event_listen(m, m.Option(EVENT), m.Option(ice.CMD))
}}, }},
HAPPEN: {Name: "happen event*", Help: "触发", Hand: func(m *ice.Message, arg ...string) { ACTION: {Name: "action event arg", Help: "触发", Hand: func(m *ice.Message, arg ...string) {
defer m.Cost() _event_action(m, m.Option(EVENT), arg[2:]...)
m.OptionCB(mdb.SELECT, "")
mdb.ZoneSelectAll(m.Spawn(ice.OptionFields("")), arg[1]).Table(func(value ice.Maps) {
m.Cmdy(kit.Split(value[ice.CMD]), arg[1], arg[2:], ice.OptionFields(""))
})
_waitMap.Range(func(key, cb ice.Any) bool { cb.(func(*ice.Message, ...string))(m, arg...); return true })
}}, }},
}, mdb.ZoneAction(mdb.SHORT, EVENT, mdb.FIELDS, "time,id,cmd"), mdb.ClearOnExitHashAction())}, }, mdb.ZoneAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}) if mdb.ZoneSelect(m, arg...); len(arg) == 0 {
m.PushAction(ACTION, mdb.REMOVE)
} }
}},
func EventsAction(arg ...string) ice.Actions { }})
list := kit.DictList(arg...)
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
for sub := range m.Target().Commands[m.CommandKey()].Actions {
kit.If(list[sub] == ice.TRUE, func() { Watch(m, sub) })
}
}}}
}
var list map[string]int = map[string]int{}
func Watch(m *ice.Message, key string, arg ...string) *ice.Message {
kit.If(len(arg) == 0, func() { arg = append(arg, m.ShortKey()) })
return m.Cmd(Prefix(EVENT), LISTEN, EVENT, key, ice.CMD, kit.Join(arg, ice.SP))
}
func Event(m *ice.Message, key string, arg ...ice.Any) *ice.Message {
if key = kit.Select(kit.Keys(m.CommandKey(), m.ActionKey()), key); list[key] == 0 {
return m
}
return m.Cmdy(Prefix(EVENT), HAPPEN, EVENT, key, arg, logs.FileLineMeta(-1))
}
func EventDeferEvent(m *ice.Message, key string, arg ...ice.Any) func(string, ...ice.Any) {
Event(m, key, arg...)
return func(key string, args ...ice.Any) { Event(m, key, args...) }
}
var _waitMap = sync.Map{}
func WaitEvent(m *ice.Message, key string, cb func(*ice.Message, ...string) bool) {
wg := sync.WaitGroup{}
h := kit.HashsUniq()
defer _waitMap.Delete(h)
_waitMap.Store(h, func(m *ice.Message, arg ...string) {
m.Info("WaitEvent %v %v", key, kit.FileLine(cb, 3))
kit.If((key == "" || m.Option(EVENT) == key) && cb(m, arg...), func() { wg.Done() })
})
wg.Add(1)
defer wg.Wait()
} }

View File

@ -1,56 +1,57 @@
package gdb package gdb
import ( import (
"fmt"
"os" "os"
"os/signal"
"syscall"
"time" "time"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
) )
type Frame struct{ s chan os.Signal } type Frame struct {
s chan os.Signal
t time.Duration
e chan bool
}
func (f *Frame) Begin(m *ice.Message, arg ...string) { func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
f.s = make(chan os.Signal, 10) return &Frame{}
} }
func (f *Frame) Start(m *ice.Message, arg ...string) { func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
if ice.HasVar() { f.s = make(chan os.Signal, ice.MOD_CHAN)
if f, p, e := logs.CreateFile(ice.VAR_LOG_ICE_PID); e == nil { f.e = make(chan bool, 1)
m.Logs("save", "file", p, PID, os.Getpid()) return f
fmt.Fprint(f, os.Getpid())
f.Close()
} }
} func (f *Frame) Start(m *ice.Message, arg ...string) bool {
t := time.NewTicker(kit.Duration(mdb.Conf(m, TIMER, kit.Keym(TICK)))) f.t = kit.Duration(m.Conf(TIMER, kit.Keym(TICK)))
for { for {
select { select {
case <-t.C: case <-f.e:
m.Options(ice.LOG_DISABLE, ice.TRUE).Cmd(TIMER, HAPPEN) return true
case s, ok := <-f.s:
if !ok { // case <-time.Tick(f.t):
return // // m.Cmd(TIMER, ACTION)
}
m.Cmd(SIGNAL, HAPPEN, SIGNAL, s) case s := <-f.s:
m.Cmd(SIGNAL, ACTION, ACTION, SIGNAL, s)
} }
} }
return true
} }
func (f *Frame) Close(m *ice.Message, arg ...string) { func (f *Frame) Close(m *ice.Message, arg ...string) bool {
close(f.s) f.e <- true
} return true
func (f *Frame) listen(m *ice.Message, s int, arg ...string) {
signal.Notify(f.s, syscall.Signal(s))
mdb.HashCreate(m, SIGNAL, s, arg)
} }
const GDB = "gdb" const GDB = "gdb"
var Index = &ice.Context{Name: GDB, Help: "事件模块"} var Index = &ice.Context{Name: GDB, Help: "事件模块", Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Load(TIMER)
}},
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Save(TIMER)
}},
}}
func Prefix(arg ...string) string { return kit.Keys(GDB, arg) } func init() { ice.Index.Register(Index, &Frame{}, ROUTINE, SIGNAL, EVENT, TIMER) }
func init() { ice.Index.Register(Index, &Frame{}, SIGNAL, EVENT, TIMER, ROUTINE) }

6
base/gdb/gdb.shy Normal file
View File

@ -0,0 +1,6 @@
chapter "gdb"
field "协程池" routine
field "信号量" signal
field "事件流" event
field "定时器" timer

View File

@ -1,46 +1,34 @@
package gdb package gdb
import ( import (
"path"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
) )
const ROUTINE = "routine" const ROUTINE = "routine"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
ROUTINE: {Help: "协程池", Actions: ice.MergeActions(ice.Actions{ ROUTINE: {Name: ROUTINE, Help: "协程池", Value: kit.Data(mdb.SHORT, "time,hash,status,fileline")},
mdb.CREATE: {Name: "create name cmd", Hand: func(m *ice.Message, arg ...string) { }, Commands: map[string]*ice.Command{
m.Go(func() { ROUTINE: {Name: "routine hash auto prunes", Help: "协程池", Action: ice.MergeAction(map[string]*ice.Action{
cb := m.OptionCB("") mdb.CREATE: {Name: "create fileline status", Help: "创建"},
m.OptionDefault(ice.CMD, logs.FileLine(cb)) mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
h := mdb.HashCreate(m, m.OptionSimple(mdb.NAME, ice.CMD), mdb.STATUS, START) m.OptionFields(m.Config(mdb.SHORT))
defer func() { m.Cmdy(mdb.PRUNES, ROUTINE, "", mdb.HASH, cli.STATUS, cli.STOP)
if e := recover(); e == nil { m.Cmdy(mdb.PRUNES, ROUTINE, "", mdb.HASH, cli.STATUS, cli.ERROR)
mdb.HashRemove(m, mdb.HASH, h)
} else {
mdb.HashModify(m, mdb.HASH, h, mdb.STATUS, ERROR, ERROR, e)
}
}()
switch cb := cb.(type) {
case string:
m.Cmd(kit.Split(cb))
case []string:
m.Cmd(kit.Split(kit.Join(cb)))
case func(*ice.Message):
cb(m.Spawn(m.Source()))
case func():
cb()
default:
m.ErrorNotImplement(cb)
}
}, m.Option(mdb.NAME))
}}, }},
}, mdb.StatusHashAction(mdb.LIMIT, 1000, mdb.LEAST, 500, mdb.FIELD, "time,hash,status,name,cmd"), mdb.ClearOnExitHashAction())}, "inner": {Name: "inner", Help: "源码", Hand: func(m *ice.Message, arg ...string) {
}) ls := kit.Split(m.Option("fileline"), ":")
} m.ProcessCommand("inner", []string{path.Dir(ls[0]), path.Base(ls[0]), ls[1]}, arg...)
func Go(m *ice.Message, cb ice.Any, arg ...string) { }},
m.Cmd(ROUTINE, mdb.CREATE, kit.Select(m.ShortKey(), arg, 0), logs.FileLine(cb), cb) }, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...)
m.PushAction("inner", mdb.REMOVE)
}},
}})
} }

View File

@ -3,71 +3,32 @@ package gdb
import ( import (
"os" "os"
"os/signal" "os/signal"
"path"
"syscall" "syscall"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/file" log "shylinux.com/x/toolkits/logs"
) )
func _signal_listen(m *ice.Message, s int, arg ...string) { func _signal_listen(m *ice.Message, s int, arg ...string) {
if f, ok := m.Target().Server().(*Frame); ok { if f, ok := m.Target().Server().(*Frame); ok {
f.listen(m, s, arg...) m.Cmdy(mdb.INSERT, SIGNAL, "", mdb.HASH, arg)
signal.Notify(f.s, syscall.Signal(s))
} }
} }
func _signal_action(m *ice.Message, arg ...string) { func _signal_action(m *ice.Message, arg ...string) {
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) { m.Cmdy(kit.Split(value[ice.CMD])) }) mdb.HashSelect(m.Spawn(), arg...).Table(func(index int, value map[string]string, head []string) {
} m.Cmdy(kit.Split(value[ice.CMD]))
func _signal_process(m *ice.Message, p string, s os.Signal) {
kit.If(p == "", func() { b, _ := file.ReadFile(ice.VAR_LOG_ICE_PID); p = string(b) })
if p, e := os.FindProcess(kit.Int(kit.Select(kit.Format(os.Getpid()), p))); e == nil {
p.Signal(s)
}
}
const (
PID = "pid"
)
const (
DEBUG = "debug"
ERROR = "error"
START = "start"
RESTART = "restart"
STOP = "stop"
KILL = "kill"
)
const SIGNAL = "signal"
func init() {
Index.MergeCommands(ice.Commands{
SIGNAL: {Help: "信号量", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { _signal_init(m, arg...) }},
LISTEN: {Name: "listen signal name cmd", Help: "监听", Hand: func(m *ice.Message, arg ...string) {
_signal_listen(m, kit.Int(m.Option(SIGNAL)), arg...)
}},
HAPPEN: {Name: "happen signal", Help: "触发", Hand: func(m *ice.Message, arg ...string) {
_signal_action(m, m.Option(SIGNAL))
}},
RESTART: {Name: "restart pid", Hand: func(m *ice.Message, arg ...string) {
_signal_process(m, m.Option(PID), syscall.SIGINT)
}},
STOP: {Name: "stop pid", Hand: func(m *ice.Message, arg ...string) {
_signal_process(m, m.Option(PID), syscall.SIGQUIT)
}},
KILL: {Name: "kill pid signal", Hand: func(m *ice.Message, arg ...string) {
_signal_process(m, m.Option(PID), syscall.Signal(kit.Int(kit.Select("9", m.Option(SIGNAL)))))
}},
}, mdb.HashAction(mdb.SHORT, SIGNAL, mdb.FIELD, "time,signal,name,cmd", mdb.ACTION, HAPPEN), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
defer kit.If(len(arg) == 0, func() { m.Action(LISTEN) })
mdb.HashSelect(m, arg...)
}},
}) })
} }
func SignalNotify(m *ice.Message, sig syscall.Signal, cb func()) { func SignalNotify(m *ice.Message, sig int, cb func()) {
ch := make(chan os.Signal) ch := make(chan os.Signal)
signal.Notify(ch, sig) signal.Notify(ch, syscall.Signal(sig))
m.Go(func() { m.Go(func() {
for { for {
if _, ok := <-ch; ok { if _, ok := <-ch; ok {
@ -76,3 +37,39 @@ func SignalNotify(m *ice.Message, sig syscall.Signal, cb func()) {
} }
}) })
} }
const (
LISTEN = "listen"
ACTION = "action"
)
const SIGNAL = "signal"
func init() {
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SIGNAL: {Name: SIGNAL, Help: "信号器", Value: kit.Data(
mdb.SHORT, SIGNAL, mdb.FIELD, "time,signal,name,cmd", nfs.PATH, path.Join(ice.VAR_RUN, "ice.pid"),
)},
}, Commands: map[string]*ice.Command{
SIGNAL: {Name: "signal signal auto listen", Help: "信号器", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
if log.LogDisable {
return // 禁用日志
}
m.Cmd(nfs.SAVE, kit.Select(m.Config(nfs.PATH), m.Conf(cli.RUNTIME, kit.Keys(cli.CONF, cli.CTX_PID))),
m.Conf(cli.RUNTIME, kit.Keys(cli.HOST, cli.PID)))
m.Cmd(SIGNAL, LISTEN, SIGNAL, "3", mdb.NAME, "退出", ice.CMD, "exit 0")
m.Cmd(SIGNAL, LISTEN, SIGNAL, "2", mdb.NAME, "重启", ice.CMD, "exit 1")
}},
LISTEN: {Name: "listen signal name cmd", Help: "监听", Hand: func(m *ice.Message, arg ...string) {
_signal_listen(m, kit.Int(m.Option(SIGNAL)), arg...)
}},
ACTION: {Name: "action signal", Help: "触发", Hand: func(m *ice.Message, arg ...string) {
_signal_action(m, m.Option(SIGNAL))
}},
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...).Sort(SIGNAL)
m.PushAction(ACTION, mdb.REMOVE)
}},
}})
}

View File

@ -1,24 +0,0 @@
package gdb
import (
"os"
"syscall"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
func _signal_init(m *ice.Message, arg ...string) {
_signal_listen(m, 1, mdb.NAME, START, ice.CMD, "runtime")
_signal_listen(m, 2, mdb.NAME, RESTART, ice.CMD, "exit 1")
_signal_listen(m, 3, mdb.NAME, STOP, ice.CMD, "exit 0")
_signal_listen(m, int(syscall.SIGUSR1), mdb.NAME, "info", ice.CMD, "runtime")
}
func SignalProcess(m *ice.Message, pid string) bool {
if proc, err := os.FindProcess(kit.Int(pid)); err == nil && proc.Signal(syscall.SIGUSR1) == nil {
return true
}
return false
}

View File

@ -1,23 +0,0 @@
package gdb
import (
"os"
"syscall"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
func _signal_init(m *ice.Message, arg ...string) {
_signal_listen(m, 1, mdb.NAME, START, ice.CMD, "runtime")
_signal_listen(m, 2, mdb.NAME, RESTART, ice.CMD, "exit 1")
_signal_listen(m, 3, mdb.NAME, STOP, ice.CMD, "exit 0")
_signal_listen(m, int(syscall.SIGUSR1), mdb.NAME, "info", ice.CMD, "runtime")
}
func SignalProcess(m *ice.Message, pid string) bool {
if proc, err := os.FindProcess(kit.Int(pid)); err == nil && proc.Signal(syscall.SIGUSR1) == nil {
return true
}
return false
}

View File

@ -1,15 +0,0 @@
package gdb
import (
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
)
func _signal_init(m *ice.Message, arg ...string) {
_signal_listen(m, 1, mdb.NAME, START, ice.CMD, "runtime")
_signal_listen(m, 2, mdb.NAME, RESTART, ice.CMD, "exit 1")
_signal_listen(m, 3, mdb.NAME, STOP, ice.CMD, "exit 0")
}
func SignalProcess(m *ice.Message, pid string) bool {
return false
}

View File

@ -4,49 +4,62 @@ import (
"time" "time"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _timer_action(m *ice.Message, now time.Time, arg ...string) { func _timer_action(m *ice.Message, arg ...string) {
mdb.HashSelects(m).Table(func(value ice.Maps) { now := time.Now().UnixNano()
count := kit.Int(value[mdb.COUNT]) m.OptionFields(m.Config(mdb.FIELD))
if count == 0 || value[mdb.TIME] > now.Format(ice.MOD_TIME) {
m.Richs(TIMER, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
if value = kit.GetMeta(value); value[cli.STATUS] == cli.STOP {
return return
} }
m.Options(ice.LOG_DISABLE, ice.FALSE)
m.Cmd(kit.Split(value[ice.CMD])).Cost() order := kit.Int(value[ORDER])
kit.If(count < 0, func() { count++ }) if n := kit.Time(kit.Format(value[NEXT])); now > n && order > 0 {
mdb.HashModify(m, mdb.NAME, value[mdb.NAME], mdb.COUNT, count-1, mdb.TIME, m.Time(value[INTERVAL])) m.Logs(TIMER, mdb.KEY, key, ORDER, order)
msg := m.Cmd(value[ice.CMD])
m.Grow(TIMER, kit.Keys(mdb.HASH, key), kit.Dict(ice.RES, msg.Result()))
if value[ORDER] = kit.Format(order - 1); order > 1 {
value[NEXT] = msg.Time(value[INTERVAL])
}
}
}) })
} }
const ( const (
DELAY = "delay" DELAY = "delay"
INTERVAL = "interval" INTERVAL = "interval"
ORDER = "order"
NEXT = "next"
TICK = "tick" TICK = "tick"
) )
const TIMER = "timer" const TIMER = "timer"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
TIMER: {Help: "定时器", Meta: kit.Dict( TIMER: {Name: TIMER, Help: "定时器", Value: kit.Data(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(DELAY, "延时", INTERVAL, "间隔", TICK, "周期")), mdb.FIELD, "time,hash,delay,interval,order,next,cmd", TICK, "1s",
), Actions: ice.MergeActions(ice.Actions{ )},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { }, Commands: map[string]*ice.Command{
switch mdb.HashInputs(m, arg); arg[0] { TIMER: {Name: "timer hash id auto create action prunes", Help: "定时器", Action: ice.MergeAction(map[string]*ice.Action{
case mdb.COUNT: mdb.CREATE: {Name: "create delay=10ms interval=10s order=3 cmd=runtime", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
m.Push(arg[0], "-1") m.Cmdy(mdb.INSERT, TIMER, "", mdb.HASH, DELAY, "10ms", INTERVAL, "10m", ORDER, 1, NEXT, m.Time(m.Option(DELAY)), arg)
case ice.CMD:
m.Push(arg[0], "cli.procstat insert")
}
}}, }},
mdb.CREATE: {Name: "create name*=hi delay=10ms interval=10s count=3 cmd*=runtime"}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
mdb.PRUNES: {Hand: func(m *ice.Message, arg ...string) { mdb.HashPrunesValue(m, mdb.COUNT, "0") }}, m.OptionFields(m.Config(mdb.FIELD))
HAPPEN: {Hand: func(m *ice.Message, arg ...string) { _timer_action(m, time.Now(), arg...) }}, m.Cmdy(mdb.PRUNES, TIMER, "", mdb.HASH, ORDER, 0)
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,delay,interval,count,cmd", TICK, "10s")), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m, arg...).StatusTimeCount(mdb.ConfigSimple(m, TICK))
}}, }},
}) ACTION: {Name: "action", Help: "执行", Hand: func(m *ice.Message, arg ...string) {
_timer_action(m, arg...)
}},
}, mdb.ZoneAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Fields(len(arg), m.Config(mdb.FIELD), "time,id,res")
mdb.ZoneSelect(m, arg...)
}},
}})
} }

4
base/lex/lex.shy Normal file
View File

@ -0,0 +1,4 @@
chapter "lex"
field "分词" lex.split

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
@ -345,10 +346,10 @@ func (mat *Matrix) show(m *ice.Message) {
value = append(value, "*") value = append(value, "*")
} }
if node.next > 0 { if node.next > 0 {
// value = append(value, cli.ColorGreen(m, node.next)) value = append(value, cli.ColorGreen(m, node.next))
} }
if node.hash > 0 { if node.hash > 0 {
// value = append(value, cli.ColorRed(m, kit.Select(kit.Format("%d", node.hash), mat.word[node.hash]))) value = append(value, cli.ColorRed(m, kit.Select(kit.Format("%d", node.hash), mat.word[node.hash])))
} }
} }
m.Push(key, strings.Join(value, ",")) m.Push(key, strings.Join(value, ","))
@ -358,11 +359,11 @@ func (mat *Matrix) show(m *ice.Message) {
m.Status(NLANG, mat.nlang, NCELL, mat.ncell, NPAGE, len(mat.page), NHASH, len(mat.hash)) m.Status(NLANG, mat.nlang, NCELL, mat.ncell, NPAGE, len(mat.page), NHASH, len(mat.hash))
} }
func _lex_load(m *ice.Message) { func _lex_load(m *ice.Message) {
mdb.Richs(m, m.PrefixKey(), "", mdb.FOREACH, func(key string, value ice.Map) { m.Richs(m.PrefixKey(), "", mdb.FOREACH, func(key string, value map[string]interface{}) {
value = kit.GetMeta(value) value = kit.GetMeta(value)
mat := NewMatrix(m, kit.Int(kit.Select("32", value[NLANG])), kit.Int(kit.Select("256", value[NCELL]))) mat := NewMatrix(m, kit.Int(kit.Select("32", value[NLANG])), kit.Int(kit.Select("256", value[NCELL])))
mdb.Grows(m, m.PrefixKey(), kit.Keys(mdb.HASH, key), "", "", func(index int, value ice.Map) { m.Grows(m.PrefixKey(), kit.Keys(mdb.HASH, key), "", "", func(index int, value map[string]interface{}) {
mat.Train(m, kit.Format(value[NPAGE]), kit.Format(value[NHASH]), kit.Format(value[mdb.TEXT])) mat.Train(m, kit.Format(value[NPAGE]), kit.Format(value[NHASH]), kit.Format(value[mdb.TEXT]))
}) })
value[MATRIX] = mat value[MATRIX] = mat
@ -384,29 +385,29 @@ const (
const MATRIX = "matrix" const MATRIX = "matrix"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
MATRIX: {Name: "matrix hash npage text auto", Help: "魔方矩阵", Actions: ice.Actions{ MATRIX: {Name: MATRIX, Help: "魔方矩阵", Value: kit.Data()},
}, Commands: map[string]*ice.Command{
MATRIX: {Name: "matrix hash npage text auto", Help: "魔方矩阵", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
// _lex_load(m.Load()) // _lex_load(m.Load())
}}, }},
mdb.CREATE: {Name: "create nlang=32 ncell=128", Help: "创建", Hand: func(m *ice.Message, arg ...string) { mdb.CREATE: {Name: "create nlang=32 ncell=128", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
mat := NewMatrix(m, kit.Int(kit.Select("32", m.Option(NLANG))), kit.Int(kit.Select("128", m.Option(NCELL)))) mat := NewMatrix(m, kit.Int(kit.Select("32", m.Option(NLANG))), kit.Int(kit.Select("128", m.Option(NCELL))))
h := mdb.Rich(m, m.PrefixKey(), "", kit.Data(mdb.TIME, m.Time(), MATRIX, mat, NLANG, mat.nlang, NCELL, mat.ncell)) h := m.Rich(m.PrefixKey(), "", kit.Data(mdb.TIME, m.Time(), MATRIX, mat, NLANG, mat.nlang, NCELL, mat.ncell))
switch cb := m.OptionCB(MATRIX).(type) { switch cb := m.OptionCB(MATRIX).(type) {
case func(string, *Matrix): case func(string, *Matrix):
cb(h, mat) cb(h, mat)
default:
m.ErrorNotImplement(cb)
} }
m.Echo(h) m.Echo(h)
}}, }},
mdb.INSERT: {Name: "insert hash npage=num nhash=num text=123", Help: "添加", Hand: func(m *ice.Message, arg ...string) { mdb.INSERT: {Name: "insert hash npage=num nhash=num text=123", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, m.PrefixKey(), "", m.Option(mdb.HASH), func(key string, value ice.Map) { m.Richs(m.PrefixKey(), "", m.Option(mdb.HASH), func(key string, value map[string]interface{}) {
value = kit.GetMeta(value) value = kit.GetMeta(value)
mat, _ := value[MATRIX].(*Matrix) mat, _ := value[MATRIX].(*Matrix)
m.Echo("%d", mat.Train(m, m.Option(NPAGE), m.Option(NHASH), m.Option(mdb.TEXT))) m.Echo("%d", mat.Train(m, m.Option(NPAGE), m.Option(NHASH), m.Option(mdb.TEXT)))
mdb.Grow(m, m.PrefixKey(), kit.Keys(mdb.HASH, key), kit.Dict( m.Grow(m.PrefixKey(), kit.Keys(mdb.HASH, key), kit.Dict(
mdb.TIME, m.Time(), NPAGE, m.Option(NPAGE), NHASH, m.Option(NHASH), mdb.TEXT, m.Option(mdb.TEXT), mdb.TIME, m.Time(), NPAGE, m.Option(NPAGE), NHASH, m.Option(NHASH), mdb.TEXT, m.Option(mdb.TEXT),
)) ))
@ -418,7 +419,7 @@ func init() {
m.Cmdy(mdb.DELETE, m.PrefixKey(), "", mdb.HASH, mdb.HASH, m.Option(mdb.HASH)) m.Cmdy(mdb.DELETE, m.PrefixKey(), "", mdb.HASH, mdb.HASH, m.Option(mdb.HASH))
}}, }},
PARSE: {Name: "parse hash npage text=123", Help: "解析", Hand: func(m *ice.Message, arg ...string) { PARSE: {Name: "parse hash npage text=123", Help: "解析", Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, m.PrefixKey(), "", m.Option(mdb.HASH), func(key string, value ice.Map) { m.Richs(m.PrefixKey(), "", m.Option(mdb.HASH), func(key string, value map[string]interface{}) {
value = kit.GetMeta(value) value = kit.GetMeta(value)
mat, _ := value[MATRIX].(*Matrix) mat, _ := value[MATRIX].(*Matrix)
@ -431,13 +432,13 @@ func init() {
m.ProcessInner() m.ProcessInner()
}}, }},
"show": {Name: "show", Help: "矩阵", Hand: func(m *ice.Message, arg ...string) { "show": {Name: "show", Help: "矩阵", Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, m.PrefixKey(), "", kit.Select(m.Option(mdb.HASH), arg, 0), func(key string, value ice.Map) { m.Richs(m.PrefixKey(), "", kit.Select(m.Option(mdb.HASH), arg, 0), func(key string, value map[string]interface{}) {
value = kit.GetMeta(value) value = kit.GetMeta(value)
value[MATRIX].(*Matrix).show(m) value[MATRIX].(*Matrix).show(m)
}) })
m.ProcessInner() m.ProcessInner()
}}, }},
}, Hand: func(m *ice.Message, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if m.Action(mdb.CREATE); len(arg) == 0 { // 矩阵列表 if m.Action(mdb.CREATE); len(arg) == 0 { // 矩阵列表
m.Fields(len(arg), "time,hash,npage,nhash") m.Fields(len(arg), "time,hash,npage,nhash")
m.Cmdy(mdb.SELECT, m.PrefixKey(), "", mdb.HASH) m.Cmdy(mdb.SELECT, m.PrefixKey(), "", mdb.HASH)
@ -452,7 +453,7 @@ func init() {
return return
} }
mdb.Richs(m, m.PrefixKey(), "", arg[0], func(key string, value ice.Map) { m.Richs(m.PrefixKey(), "", arg[0], func(key string, value map[string]interface{}) {
value = kit.GetMeta(value) value = kit.GetMeta(value)
mat, _ := value[MATRIX].(*Matrix) mat, _ := value[MATRIX].(*Matrix)
@ -467,5 +468,5 @@ func init() {
m.Push("word", string(word)) m.Push("word", string(word))
}) })
}}, }},
}) }})
} }

View File

@ -1,12 +1,3 @@
package lex package lex
const ( const REGEXP = "regexp"
PATTERN = "pattern"
EXTREG = "extreg"
REGEXP = "regexp"
PREFIX = "prefix"
SUFFIX = "suffix"
SPACE = "space"
OPERATOR = "operator"
)

View File

@ -4,7 +4,6 @@ import (
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
@ -25,65 +24,57 @@ func _split_tab(text string) (tab int) {
func _split_deep(stack []int, text string) ([]int, int) { func _split_deep(stack []int, text string) ([]int, int) {
tab := _split_tab(text) tab := _split_tab(text)
for i := len(stack) - 1; i >= 0; i-- { for i := len(stack) - 1; i >= 0; i-- {
kit.If(tab <= stack[i], func() { stack = stack[:len(stack)-1] }) if tab <= stack[i] {
stack = stack[:len(stack)-1]
}
} }
stack = append(stack, tab) stack = append(stack, tab)
return stack, len(stack) return stack, len(stack)
} }
func _split_list(m *ice.Message, file string, arg ...string) ice.Map { func _split_list(m *ice.Message, file string, arg ...string) map[string]interface{} {
const INDENT = "_indent" const DEEP = "_deep"
stack, indent := []int{}, 0 stack, deep := []int{}, 0
list, line := kit.List(kit.Data(INDENT, -1)), "" list := kit.List(kit.Data(DEEP, -1))
err := false line := ""
m.Cmd(nfs.CAT, file, func(text string) { m.Cmd(nfs.CAT, file, func(text string) {
if strings.HasPrefix(strings.TrimSpace(text), "# ") {
return // 注释
}
if strings.TrimSpace(text) == "" { if strings.TrimSpace(text) == "" {
return return // 空行
} }
if line += text; strings.Count(text, "`")%2 == 1 { if line += text; strings.Count(text, "`")%2 == 1 {
return return // 多行
} }
if strings.HasPrefix(strings.TrimSpace(text), "# ") {
return stack, deep = _split_deep(stack, text)
} data := kit.Data(DEEP, deep)
stack, indent = _split_deep(stack, text)
data := kit.Data(INDENT, indent) // 回调函数
ls := kit.Split(text, m.Option(SPLIT_SPACE), m.Option(SPLIT_BLOCK), m.Option(SPLIT_QUOTE), m.Option(SPLIT_TRANS)) ls := kit.Split(text, m.Option(SPLIT_SPACE), m.Option(SPLIT_BLOCK), m.Option(SPLIT_QUOTE), m.Option(SPLIT_TRANS))
if err {
return
}
switch cb := m.OptionCB(SPLIT).(type) { switch cb := m.OptionCB(SPLIT).(type) {
case func(int, []string): case func(int, []string, map[string]interface{}) []string:
cb(indent, ls) ls = cb(deep, ls, data)
case func(int, []string) []string: case func([]string, map[string]interface{}) []string:
ls = cb(indent, ls)
case func(int, []string, ice.Map, ice.Map):
root, _ := kit.Value(list[0], "list.0").(ice.Map)
cb(indent, ls, data, root)
case func(int, []string, ice.Map) []string:
ls = cb(indent, ls, data)
case func([]string, ice.Map) []string:
ls = cb(ls, data) ls = cb(ls, data)
case func([]string) []string:
ls = cb(ls)
case func([]string):
cb(ls)
case func(string, []string):
cb(text, ls)
case func(int, string, []string):
cb(indent, text, ls)
case nil:
default:
err = true
m.ErrorNotImplement(cb)
} }
kit.For(arg, func(k string) {
kit.Value(data, kit.Keym(k), kit.Select("", ls, 0)) // 参数字段
kit.If(len(ls) > 0, func() { ls = ls[1:] }) for _, k := range arg {
}) if kit.Value(data, kit.Keym(k), kit.Select("", ls, 0)); len(ls) > 0 {
kit.For(ls, func(k, v string) { kit.Value(data, kit.Keym(k), v) }) ls = ls[1:]
}
}
// 属性字段
for i := 0; i < len(ls)-1; i += 2 {
kit.Value(data, kit.Keym(ls[i]), ls[i+1])
}
// 查找节点
for i := len(list) - 1; i >= 0; i-- { for i := len(list) - 1; i >= 0; i-- {
if indent > kit.Int(kit.Value(list[i], kit.Keym(INDENT))) { if deep > kit.Int(kit.Value(list[i], kit.Keym(DEEP))) {
kit.Value(list[i], kit.Keys(mdb.LIST, "-2"), data) kit.Value(list[i], "list.-2", data)
list = append(list, data) list = append(list, data)
break break
} }
@ -91,31 +82,32 @@ func _split_list(m *ice.Message, file string, arg ...string) ice.Map {
} }
line = "" line = ""
}) })
return list[0].(ice.Map) return list[0].(map[string]interface{})
}
func Split(m *ice.Message, arg ...string) map[string]interface{} {
return kit.Value(_split_list(m, arg[0], arg[1:]...), "list.0").(map[string]interface{})
} }
const (
TB = ice.TB
SP = ice.SP
NL = ice.NL
)
const ( const (
SPLIT_SPACE = "split.space" SPLIT_SPACE = "split.space"
SPLIT_BLOCK = "split.block" SPLIT_BLOCK = "split.block"
SPLIT_QUOTE = "split.quote" SPLIT_QUOTE = "split.quote"
SPLIT_TRANS = "split.trans" SPLIT_TRANS = "split.trans"
) )
const PARSE = "parse"
const SPLIT = "split" const SPLIT = "split"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SPLIT: {Name: "split path key auto", Help: "分词", Hand: func(m *ice.Message, arg ...string) { SPLIT: {Name: "split", Help: "解析", Value: kit.Data()},
if len(arg) == 0 || strings.HasSuffix(arg[0], nfs.PS) { }, Commands: map[string]*ice.Command{
SPLIT: {Name: "split path key auto", Help: "解析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 || strings.HasSuffix(arg[0], ice.PS) {
m.Cmdy(nfs.DIR, arg) m.Cmdy(nfs.DIR, arg)
} else { return
}
m.Echo(kit.Format(_split_list(m, arg[0], kit.Split(kit.Join(arg[1:]))...))) m.Echo(kit.Format(_split_list(m, arg[0], kit.Split(kit.Join(arg[1:]))...)))
} m.DisplayStory("json.js")
}}, }},
}) }})
} }

View File

@ -1,13 +0,0 @@
package log
import (
ice "shylinux.com/x/icebergs"
)
const BENCH = "bench"
func init() {
Index.MergeCommands(ice.Commands{
BENCH: {Help: "记录", Hand: func(m *ice.Message, arg ...string) {}},
})
}

View File

@ -1,94 +0,0 @@
package log
import (
"regexp"
"strings"
"time"
"unicode"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
func _debug_file(k string) string { return ice.VAR_LOG + k + ".log" }
const DEBUG = "debug"
func init() {
const (
LEVEL = "level"
)
Index.MergeCommands(ice.Commands{
DEBUG: {Name: "debug level=error,bench,debug,error,watch offset limit auto reset app doc", Help: "日志", Actions: ice.Actions{
"doc": {Help: "文档", Hand: func(m *ice.Message, arg ...string) { m.ProcessOpen("https://pkg.go.dev/std") }},
"reset": {Help: "重置", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.CAT, _debug_file(arg[0]), func(line string, index int) { m.ProcessRewrite(mdb.OFFSET, index+2, mdb.LIMIT, 1000) })
}},
"app": {Hand: func(m *ice.Message, arg ...string) {
cli.OpenCmds(m, kit.Format("cd %s", kit.Path("")), "tail -f var/log/bench.log")
}},
}, Hand: func(m *ice.Message, arg ...string) {
r := regexp.MustCompile("{.*}")
offset, limit := kit.Int(kit.Select("0", arg, 1)), kit.Int(kit.Select("100", arg, 2))
switch arg[0] {
case BENCH, ERROR, DEBUG:
m.Cmd(nfs.CAT, _debug_file(arg[0]), func(text string, index int) {
if index < offset || index >= offset+limit || !strings.Contains(text, kit.Select("", arg, 3)) {
return
}
ls := strings.SplitN(strings.ReplaceAll(strings.ReplaceAll(text, " ", " "), " ", " "), lex.SP, 8)
if _, e := time.Parse(kit.Split(ice.MOD_TIMES)[0], ls[0]); e != nil || len(ls) < 8 {
m.Push(mdb.TIME, "").Push(ice.LOG_TRACEID, "").Push(mdb.ID, "")
m.Push(nfs.PATH, "").Push(nfs.FILE, "").Push(nfs.LINE, "")
m.Push(ctx.SHIP, "").Push(LEVEL, "").Push(nfs.CONTENT, text)
return
}
m.Push(mdb.TIME, ls[0]+lex.SP+ls[1]).Push(ice.LOG_TRACEID, ls[3]).Push(mdb.ID, ls[4])
m.Push(nfs.PATH, ice.USR_ICEBERGS)
if i := strings.LastIndex(ls[7], lex.SP); strings.HasPrefix(ls[7][i+1:], ice.BASE) || strings.HasPrefix(ls[7][i+1:], ice.CORE) || strings.HasPrefix(ls[7][i+1:], ice.MISC) {
m.Push(nfs.FILE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[0]))
m.Push(nfs.LINE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[1]))
ls[7] = ls[7][:i]
} else if strings.HasPrefix(ls[7][i+1:], ice.USR_ICEBERGS) {
m.Push(nfs.FILE, strings.TrimPrefix(strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[0]), ice.USR_ICEBERGS))
m.Push(nfs.LINE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[1]))
ls[7] = ls[7][:i]
} else {
m.Push(nfs.FILE, "base/web/serve.go").Push(nfs.LINE, "62")
}
if ls[6] == ice.LOG_CMDS {
_ls := strings.SplitN(ls[5], lex.SP, 2)
if ls[6], ls[7] = _ls[0], _ls[1]; !unicode.IsDigit(rune(ls[7][0])) {
_ls := strings.SplitN(ls[7], lex.SP, 2)
ls[6], ls[7] = ls[6]+lex.SP+_ls[0], _ls[1]
}
}
switch ls[6] {
case "recv", "done", "send", "echo":
ls[7] += "\n" + kit.Formats(kit.UnMarshal(r.FindString(ls[7])))
}
m.Push(ctx.SHIP, ls[5]).Push(LEVEL, ls[6]).Push(nfs.CONTENT, ls[7])
})
case WATCH:
m.Cmd(nfs.CAT, ice.VAR_LOG+arg[0]+".log", func(text string, index int) {
if index < offset || index >= offset+limit || !strings.Contains(text, kit.Select("", arg, 3)) {
return
}
ls := strings.SplitN(strings.ReplaceAll(strings.ReplaceAll(text, " ", " "), " ", " "), lex.SP, 8)
m.Push(mdb.TIME, ls[0]+lex.SP+ls[1]).Push(ice.LOG_TRACEID, ls[3]).Push(mdb.ID, ls[4])
i := strings.LastIndex(ls[7], lex.SP)
m.Push(nfs.PATH, ice.USR_ICEBERGS)
m.Push(nfs.FILE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[0]))
m.Push(nfs.LINE, strings.TrimSpace(strings.Split(ls[7][i:], nfs.DF)[1]))
m.Push(ctx.SHIP, ls[5]).Push(LEVEL, ls[6]).Push(nfs.CONTENT, ls[7][:i])
})
}
m.StatusTimeCountStats(LEVEL)
}},
})
}

View File

@ -1,18 +0,0 @@
package log
import (
"path"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/nfs"
)
const ERROR = "error"
func init() {
Index.MergeCommands(ice.Commands{
ERROR: {Help: "错误", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(nfs.CAT, path.Join(ice.VAR_LOG, "error.log"))
}},
})
}

View File

@ -2,152 +2,148 @@ package log
import ( import (
"bufio" "bufio"
"fmt"
"path" "path"
"strings"
"sync/atomic"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs" log "shylinux.com/x/toolkits/logs"
) )
type Log struct { type Log struct {
c bool m *ice.Message
p, l, s string p string
l string
s string
} }
type Frame struct{ p chan *Log } type Frame struct{ p chan *Log }
func (f *Frame) Begin(m *ice.Message, arg ...string) { func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
return &Frame{}
} }
func (f *Frame) Start(m *ice.Message, arg ...string) { func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
if !ice.HasVar() {
return
}
mdb.Confm(m, FILE, nil, func(k string, v ice.Map) {
if mdb.Conf(m, k, kit.Keym(mdb.DISABLE)) == ice.TRUE {
return
}
if f, p, e := logs.CreateFile(kit.Format(v[nfs.PATH])); e == nil {
m.Logs(nfs.SAVE, nfs.FILE, p)
v[FILE] = bufio.NewWriter(f)
}
})
f.p = make(chan *Log, ice.MOD_BUFS) f.p = make(chan *Log, ice.MOD_BUFS)
ice.Info.Log = func(m *ice.Message, p, l, s string) { ice.Info.Log = func(msg *ice.Message, p, l, s string) {
f.p <- &Log{c: m.Option(ice.LOG_DEBUG) == ice.TRUE, p: p, l: l, s: s} f.p <- &Log{m: msg, p: p, l: l, s: s}
} }
return f
}
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
for { for {
select { select {
case l, ok := <-f.p: case l, ok := <-f.p:
if !ok { if !ok {
return break
} }
kit.For([]string{m.Conf(SHOW, kit.Keys(l.l, FILE)), BENCH}, func(file string) {
if file == "" { file := kit.Select(BENCH, m.Conf(SHOW, kit.Keys(l.l, FILE)))
return view := m.Confm(VIEW, m.Conf(SHOW, kit.Keys(l.l, VIEW)))
} bio := m.Confv(FILE, kit.Keys(file, FILE)).(*bufio.Writer)
conf := m.Confv(FILE, file)
bio := kit.Value(conf, FILE).(*bufio.Writer)
if bio == nil { if bio == nil {
return continue
} }
defer bio.Flush()
defer fmt.Fprintln(bio) bio.WriteString(l.p)
fmt.Fprint(bio, l.p, lex.SP) bio.WriteString(ice.SP)
view := mdb.Confm(m, VIEW, m.Conf(SHOW, kit.Keys(l.l, VIEW))) if ice.Info.Colors == true {
kit.If(ice.Info.Colors || l.c, func() { bio.WriteString(kit.Format(view[PREFIX])) }) if p, ok := view[PREFIX].(string); ok {
defer kit.If(ice.Info.Colors || l.c, func() { bio.WriteString(kit.Format(view[SUFFIX])) }) bio.WriteString(p)
fmt.Fprint(bio, l.l, lex.SP, l.s)
})
} }
} }
bio.WriteString(l.l)
bio.WriteString(ice.SP)
bio.WriteString(l.s)
if ice.Info.Colors == true {
if p, ok := view[SUFFIX].(string); ok {
bio.WriteString(p)
}
}
bio.WriteString(ice.NL)
bio.Flush()
}
}
return true
}
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
ice.Info.Log = nil
close(f.p)
return true
} }
func (f *Frame) Close(m *ice.Message, arg ...string) { ice.Info.Log = nil; close(f.p) }
const ( const (
PREFIX = "prefix" PREFIX = "prefix"
SUFFIX = "suffix" SUFFIX = "suffix"
TRACEID = "traceid"
) )
const ( const (
GREEN = "green" GREEN = "green"
YELLOW = "yellow" YELLOW = "yellow"
RED = "red" RED = "red"
) )
const (
BENCH = "bench"
WATCH = "watch"
ERROR = "error"
TRACE = "trace"
)
const ( const (
FILE = "file" FILE = "file"
VIEW = "view" VIEW = "view"
SHOW = "show" SHOW = "show"
) )
const (
BENCH_LOG = "bench.log"
DEBUG_LOG = "debug.log"
ERROR_LOG = "error.log"
WATCH_LOG = "watch.log"
)
const LOG = "log"
var Index = &ice.Context{Name: LOG, Help: "日志模块", Configs: ice.Configs{ var Index = &ice.Context{Name: "log", Help: "日志模块", Configs: map[string]*ice.Config{
FILE: {Name: FILE, Help: "日志文件", Value: kit.Dict( FILE: {Name: FILE, Help: "日志文件", Value: kit.Dict(
BENCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, BENCH_LOG), mdb.LIST, []string{}), BENCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "bench.log"), mdb.LIST, []string{}),
DEBUG, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, DEBUG_LOG), mdb.LIST, []string{ice.LOG_DEBUG}), WATCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "watch.log"), mdb.LIST, []string{
ERROR, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, ERROR_LOG), mdb.LIST, []string{ice.LOG_WARN, ice.LOG_ERROR}), ice.LOG_CREATE, ice.LOG_REMOVE,
WATCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, WATCH_LOG), mdb.LIST, []string{mdb.CREATE, mdb.REMOVE, mdb.INSERT, mdb.DELETE, mdb.MODIFY, mdb.EXPORT, mdb.IMPORT}), ice.LOG_INSERT, ice.LOG_DELETE,
ice.LOG_MODIFY, ice.LOG_SELECT,
ice.LOG_EXPORT, ice.LOG_IMPORT,
}),
ERROR, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "error.log"), mdb.LIST, []string{
ice.LOG_WARN, ice.LOG_ERROR,
}),
TRACE, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "trace.log"), mdb.LIST, []string{
ice.LOG_DEBUG,
}),
)}, )},
VIEW: {Name: VIEW, Help: "日志格式", Value: kit.Dict( VIEW: {Name: VIEW, Help: "日志格式", Value: kit.Dict(
GREEN, kit.Dict(PREFIX, "\033[32m", SUFFIX, "\033[0m", mdb.LIST, []string{ice.CTX_START, ice.LOG_CMDS}), GREEN, kit.Dict(PREFIX, "\033[32m", SUFFIX, "\033[0m", mdb.LIST, []string{
YELLOW, kit.Dict(PREFIX, "\033[33m", SUFFIX, "\033[0m", mdb.LIST, []string{ice.LOG_AUTH, ice.LOG_COST}), ice.LOG_START, ice.LOG_SERVE, ice.LOG_CMDS,
RED, kit.Dict(PREFIX, "\033[31m", SUFFIX, "\033[0m", mdb.LIST, []string{ice.CTX_CLOSE, ice.LOG_WARN}), }),
YELLOW, kit.Dict(PREFIX, "\033[33m", SUFFIX, "\033[0m", mdb.LIST, []string{
ice.LOG_AUTH, ice.LOG_COST,
}),
RED, kit.Dict(PREFIX, "\033[31m", SUFFIX, "\033[0m", mdb.LIST, []string{
ice.LOG_CLOSE, ice.LOG_WARN,
}),
)}, )},
SHOW: {Name: SHOW, Help: "日志分流", Value: kit.Dict()}, SHOW: {Name: SHOW, Help: "日志分流", Value: kit.Dict()},
}, Commands: ice.Commands{ }, Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
ice.Info.Load(m) if log.LogDisable {
mdb.Confm(m, FILE, nil, func(key string, value ice.Map) { return // 禁用日志
kit.For(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, FILE), key) }) }
m.Confm(VIEW, nil, func(key string, value map[string]interface{}) {
kit.Fetch(value[mdb.LIST], func(index int, k string) {
m.Conf(SHOW, kit.Keys(k, VIEW), key)
}) })
mdb.Confm(m, VIEW, nil, func(key string, value ice.Map) { })
kit.For(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, VIEW), key) }) m.Confm(FILE, nil, func(key string, value map[string]interface{}) {
kit.Fetch(value[mdb.LIST], func(index int, k string) {
m.Conf(SHOW, kit.Keys(k, FILE), key)
})
// 日志文件
if f, p, e := kit.Create(kit.Format(value[nfs.PATH])); m.Assert(e) {
m.Cap(ice.CTX_STREAM, path.Base(p))
value[FILE] = bufio.NewWriter(f)
m.Log_CREATE(nfs.FILE, p)
}
}) })
}}, }},
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
ice.Info.Save(m)
}},
}} }}
func init() { ice.Index.Register(Index, &Frame{}, TAIL) } func init() { ice.Index.Register(Index, &Frame{}) }
func init() {
ice.Info.Traceid = "short"
ice.Pulse.Option("work.id", "0")
ice.Pulse.Option("task.id", "0")
ice.Pulse.Option(ice.LOG_TRACEID, Traceid(ice.Pulse))
}
var _trace_count int64
func Traceid(m *ice.Message) (traceid string) {
ls := []string{}
kit.For(kit.Split(ice.Info.Traceid), func(key string) {
switch key {
case "short":
if len(ls) == 0 {
ls = append(ls, kit.Hashs(mdb.UNIQ)[:6])
}
case "long":
if len(ls) == 0 {
ls = append(ls, kit.Hashs(mdb.UNIQ))
}
case "node":
ls = append(ls, ice.Info.NodeName)
case "hide":
ls = ls[:0]
}
})
kit.If(len(ls) > 0, func() { ls = append(ls, kit.Format(atomic.AddInt64(&_trace_count, 1))) })
return strings.Join(ls, "-")
}

1
base/log/log.shy Normal file
View File

@ -0,0 +1 @@
chapter "log"

View File

@ -1,40 +0,0 @@
package log
import (
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
func _tail_create(m *ice.Message, arg ...string) {
h := mdb.HashCreate(m, arg)
kit.For(kit.Split(m.Option(nfs.FILE)), func(file string) {
m.Options(cli.CMD_OUTPUT, nfs.Pipe(m, func(text string) { mdb.ZoneInsert(m, h, nfs.FILE, file, nfs.SIZE, len(text), mdb.TEXT, text) }), mdb.CACHE_CLEAR_ONEXIT, ice.TRUE)
m.Cmd(cli.DAEMON, TAIL, "-n", "0", "-f", file)
})
}
const TAIL = "tail"
func init() {
Index.MergeCommands(ice.Commands{
TAIL: {Name: "tail name id auto page", Help: "日志流", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m.Spawn(ice.OptionFields("name,file"))).Table(func(value ice.Maps) {
m.Cmd("", mdb.CREATE, kit.SimpleKV("name,file", value))
})
}},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case mdb.NAME:
m.Push(arg[0], kit.Split(m.Option(FILE), nfs.PS))
case nfs.FILE:
m.Cmdy(nfs.DIR, kit.Select(nfs.PWD, arg, 1), nfs.PATH).RenameAppend(nfs.PATH, nfs.FILE).ProcessAgain()
}
}},
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) { _tail_create(m, arg...) }},
}, mdb.PageZoneAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,file,count", mdb.FIELDS, "time,id,file,size,text"))},
})
}

View File

@ -1,29 +0,0 @@
package log
import (
"path"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
const WATCH = "watch"
func init() {
Index.MergeCommands(ice.Commands{
WATCH: {Help: "记录", Hand: func(m *ice.Message, arg ...string) {
stats := map[string]int{}
m.Cmd(nfs.CAT, path.Join(ice.VAR_LOG, "watch.log"), func(text string) {
ls := kit.Split(text)
m.Push(mdb.TIME, ls[0]+lex.SP+ls[1]).Push(mdb.ID, ls[2]).Push(nfs.SOURCE, kit.Slice(ls, -1)[0])
m.Push(ctx.SHIP, ls[3]).Push("operate", ls[4]).Push(nfs.CONTENT, kit.Join(kit.Slice(ls, 5, -1), lex.SP))
stats[ls[4]]++
})
m.StatusTimeCount(stats)
}},
})
}

View File

@ -1,7 +1,32 @@
package mdb package mdb
import ice "shylinux.com/x/icebergs" import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const ENGINE = "engine" const ENGINE = "engine"
func init() { Index.MergeCommands(ice.Commands{ENGINE: {Help: "引擎", Actions: RenderAction()}}) } func init() {
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
ENGINE: {Name: ENGINE, Help: "引擎", Value: kit.Data(SHORT, TYPE, FIELD, "time,type,name,text")},
}, Commands: map[string]*ice.Command{
ENGINE: {Name: "engine type name text auto", Help: "引擎", Action: ice.MergeAction(map[string]*ice.Action{
CREATE: {Name: "create type name text", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
m.Option(NAME, kit.Select(m.Option(TYPE), m.Option(NAME)))
m.Option(TYPE, kit.Ext(m.Option(TYPE)))
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, m.OptionSimple("type,name,text"))
}},
}, HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 1 {
m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg, func(value map[string]interface{}) {
m.Cmdy(kit.Keys(value[TEXT], value[NAME]), m.CommandKey(), arg[0], arg[1], kit.Select("", arg, 2), kit.Slice(arg, 3))
})
return
}
if HashSelect(m, arg...); len(arg) == 0 {
m.Sort(TYPE)
}
}},
}})
}

View File

@ -2,421 +2,224 @@ package mdb
import ( import (
"encoding/json" "encoding/json"
"io" "os"
"net/http"
"path" "path"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
"shylinux.com/x/toolkits/miss"
) )
func _hash_fields(m *ice.Message) []string { func _hash_fields(m *ice.Message) []string {
return kit.Split(kit.Select(HASH_FIELD, m.OptionFields())) return kit.Split(kit.Select("time,hash,type,name,text", m.OptionFields()))
} }
func _hash_inputs(m *ice.Message, prefix, chain string, field, value string) { func _hash_inputs(m *ice.Message, prefix, chain string, field, value string) {
list := map[string]int{} list := map[string]int{}
defer func() { m.Richs(prefix, chain, FOREACH, func(key string, val map[string]interface{}) {
delete(list, "") if val = kit.GetMeta(val); kit.Format(val[COUNT]) != "" {
kit.For(list, func(k string, i int) { m.Push(field, k).Push(COUNT, i) }) list[kit.Format(val[field])] = kit.Int(val[COUNT])
m.SortIntR(COUNT) } else {
}() list[kit.Format(val[field])]++
defer RLock(m, prefix)() }
Richs(m, prefix, chain, FOREACH, func(key string, value Map) {
value = kit.GetMeta(value)
list[kit.Format(value[field])] += kit.Int(kit.Select("1", value[COUNT]))
}) })
for k, i := range list {
m.Push(field, k)
m.Push(COUNT, i)
} }
func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) string { m.SortIntR(COUNT)
m.Logs(INSERT, KEY, path.Join(prefix, chain), arg)
defer Lock(m, prefix)()
if expire := m.Conf(prefix, kit.Keys(chain, kit.Keym(EXPIRE))); expire != "" && arg[0] != HASH {
arg = kit.Simple(TIME, m.Time(expire), arg)
} }
if arg[0] == HASH { func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) {
m.Echo(arg[1]).Conf(prefix, kit.Keys(chain, HASH, arg[1]), kit.Data(arg[2:])) if m.Option(ice.MSG_DOMAIN) != "" {
} else { m.Conf(prefix, kit.Keys(chain, kit.Keym(SHORT)), m.Conf(prefix, kit.Keym(SHORT)))
if target, ok := m.Optionv(TARGET).([]string); ok && len(target) == 0 {
m.Echo(Rich(m, prefix, chain, kit.Data(arg)))
} else {
m.Echo(Rich(m, prefix, chain, kit.Data(arg, TARGET, m.Optionv(TARGET))))
} }
} m.Log_INSERT(KEY, path.Join(prefix, chain), arg[0], arg[1])
saveImportant(m, prefix, chain, kit.Simple(INSERT, prefix, chain, HASH, HASH, m.Result(), TIME, m.Time(), arg)...) m.Echo(m.Rich(prefix, chain, kit.Data(arg)))
return m.Result()
} }
func _hash_delete(m *ice.Message, prefix, chain, field, value string) { func _hash_delete(m *ice.Message, prefix, chain, field, value string) {
defer Lock(m, prefix)() if field != HASH {
Richs(m, prefix, chain, value, func(key string, val Map) { field, value = HASH, kit.Select(kit.Hashs(value), m.Option(HASH))
if target, ok := kit.GetMeta(val)[TARGET].(io.Closer); ok {
target.Close()
} }
m.Logs(DELETE, KEY, path.Join(prefix, chain), field, value, VALUE, kit.Format(val)) m.Richs(prefix, chain, value, func(key string, val map[string]interface{}) {
m.Log_DELETE(KEY, path.Join(prefix, chain), field, value, VALUE, kit.Format(val))
m.Conf(prefix, kit.Keys(chain, HASH, key), "") m.Conf(prefix, kit.Keys(chain, HASH, key), "")
saveImportant(m, prefix, chain, kit.Simple(DELETE, prefix, chain, HASH, HASH, key)...)
}) })
} }
func _hash_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) { func _hash_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) {
m.Logs(MODIFY, KEY, path.Join(prefix, chain), field, value, arg) m.Richs(prefix, chain, value, func(key string, val map[string]interface{}) {
defer Lock(m, prefix)() val = kit.GetMeta(val)
Richs(m, prefix, chain, value, func(key string, val Map) { m.Log_MODIFY(KEY, path.Join(prefix, chain), field, value, arg)
_mdb_modify(m, val, field, arg...) for i := 0; i < len(arg); i += 2 {
saveImportant(m, prefix, chain, kit.Simple(MODIFY, prefix, chain, HASH, HASH, key, arg)...) if arg[i] == field {
continue
}
kit.Value(val, arg[i], kit.Select("", arg, i+1))
}
}) })
} }
func _hash_select(m *ice.Message, prefix, chain, field, value string) { func _hash_select(m *ice.Message, prefix, chain, field, value string) {
kit.If(field == HASH && value == RANDOM, func() { value = RANDOMS }) if field == HASH && value == RANDOM {
defer m.SortStrR(TIME) value = RANDOMS
}
fields := _hash_fields(m) fields := _hash_fields(m)
defer RLock(m, prefix)() m.Richs(prefix, chain, value, func(key string, val map[string]interface{}) {
if strings.Contains(value, ",") { switch val = kit.GetMeta(val); cb := m.OptionCB(SELECT).(type) {
kit.For(kit.Split(value), func(value string) { case func(fields []string, value map[string]interface{}):
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) }) cb(fields, val)
}) case func(value map[string]interface{}):
cb(val)
default:
if m.OptionFields() == DETAIL {
m.Push(DETAIL, val)
} else { } else {
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) }) m.Push(key, val, fields)
} }
} }
func _hash_select_field(m *ice.Message, prefix, chain string, key string, field string) (value string) { })
defer RLock(m, prefix)() if !m.FieldsIsDetail() {
Richs(m, prefix, chain, key, func(key string, val Map) { value = kit.Select(kit.Format(val[field]), key, field == HASH) }) m.SortTimeR(TIME)
return }
}
func _hash_export(m *ice.Message, prefix, chain, file string) {
f, p, e := kit.Create(kit.Keys(file, JSON))
m.Assert(e)
defer f.Close()
en := json.NewEncoder(f)
en.SetIndent("", " ")
m.Assert(en.Encode(m.Confv(prefix, kit.Keys(chain, HASH))))
m.Log_EXPORT(KEY, path.Join(prefix, chain), FILE, p)
m.Conf(prefix, kit.Keys(chain, HASH), "")
m.Echo(p)
}
func _hash_import(m *ice.Message, prefix, chain, file string) {
f, e := os.Open(kit.Keys(file, JSON))
m.Assert(e)
defer f.Close()
list := map[string]interface{}{}
m.Assert(json.NewDecoder(f).Decode(&list))
count := 0
if m.Conf(prefix, kit.Keys(chain, META, SHORT)) == "" {
for k, data := range list {
m.Conf(prefix, kit.Keys(chain, HASH, k), data)
count++
}
} else {
for _, data := range list {
m.Rich(prefix, chain, data)
count++
}
}
m.Log_IMPORT(KEY, path.Join(prefix, chain), COUNT, count)
m.Echo("%d", count)
} }
func _hash_prunes(m *ice.Message, prefix, chain string, arg ...string) { func _hash_prunes(m *ice.Message, prefix, chain string, arg ...string) {
fields := _hash_fields(m) fields := _hash_fields(m)
kit.If(kit.IndexOf(fields, HASH) == -1, func() { fields = append(fields, HASH) }) m.Richs(prefix, chain, FOREACH, func(key string, val map[string]interface{}) {
defer RLock(m, prefix)() switch val = kit.GetMeta(val); cb := m.OptionCB(PRUNES).(type) {
Richs(m, prefix, chain, FOREACH, func(key string, value Map) { case func(string, map[string]interface{}) bool:
switch value = kit.GetMeta(value); cb := m.OptionCB("").(type) { if !cb(key, val) {
case func(string, Map) bool: return
kit.If(cb(key, value), func() { m.Push(key, value, fields) }) }
default: default:
kit.For(arg, func(k, v string) { for i := 0; i < len(arg)-1; i += 2 {
kit.If(value[k] == v || kit.Value(value, k) == v, func() { m.Push(key, value, fields) }) if val[arg[i]] != arg[i+1] && kit.Value(val, arg[i]) != arg[i+1] {
return
}
}
}
m.Push(key, val, fields)
})
m.Table(func(index int, value map[string]string, head []string) {
_hash_delete(m, prefix, chain, HASH, value[HASH])
}) })
} }
})
}
func _hash_export(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() {
return
}
defer Lock(m, prefix)()
if len(Confm(m, prefix, kit.Keys(chain, HASH))) == 0 {
return
}
f, p, e := miss.CreateFile(kit.Keys(file, JSON))
m.Assert(e)
defer f.Close()
defer m.Echo(p)
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p)
en := json.NewEncoder(f)
if en.SetIndent("", " "); !m.WarnNotValid(en.Encode(m.Confv(prefix, kit.Keys(chain, HASH))), EXPORT, prefix) {
// m.Conf(prefix, kit.Keys(chain, HASH), "")
}
}
func _hash_import(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() {
return
}
defer Lock(m, prefix)()
f, e := miss.OpenFile(kit.Keys(file, JSON))
if e != nil && !ice.Info.Important {
return
} else if m.WarnNotFound(e) {
return
}
defer f.Close()
data := Map{}
m.Warn(json.NewDecoder(f).Decode(&data))
m.Logs(IMPORT, KEY, path.Join(prefix, chain), FILE, kit.Keys(file, JSON), COUNT, len(data))
kit.If(m.Confv(prefix, kit.Keys(chain, HASH)) == nil, func() { m.Confv(prefix, kit.Keys(chain, HASH), ice.Map{}) })
kit.For(data, func(k string, v Any) { m.Confv(prefix, kit.Keys(chain, HASH, k), v) })
m.Echo("%d", len(data))
}
const (
MONTH = "720h"
DAYS = "72h"
HOUR = "1h"
CACHE_CLEAR_ONEXIT = "cache.clear.onexit"
)
const (
HASH_FIELD = "time,hash,type,name,text"
)
const HASH = "hash" const HASH = "hash"
func HashAction(arg ...Any) ice.Actions { func AutoConfig(args ...interface{}) *ice.Action {
return ice.Actions{ return &ice.Action{Hand: func(m *ice.Message, arg ...string) {
ice.CTX_INIT: AutoConfig(append(kit.List(FIELD, HASH_FIELD), arg...)...), if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { HashSelectClose(m) }}, cs[m.CommandKey()] = &ice.Config{Value: kit.Data(args...)}
m.Load(m.CommandKey())
INPUTS: {Hand: func(m *ice.Message, arg ...string) { HashInputs(m, arg) }},
CREATE: {Hand: func(m *ice.Message, arg ...string) { HashCreate(m, arg) }},
REMOVE: {Hand: func(m *ice.Message, arg ...string) { HashRemove(m, arg) }},
MODIFY: {Hand: func(m *ice.Message, arg ...string) { HashModify(m, arg) }},
SELECT: {Hand: func(m *ice.Message, arg ...string) { HashSelect(m, arg...) }},
PRUNES: {Name: "prunes before@date", Hand: func(m *ice.Message, arg ...string) { HashPrunes(m, nil) }},
EXPORT: {Hand: func(m *ice.Message, arg ...string) { HashExport(m, arg) }},
IMPORT: {Hand: func(m *ice.Message, arg ...string) { HashImport(m, arg) }},
} }
}}
} }
func StatusHashAction(arg ...Any) ice.Actions { func HashAction(args ...interface{}) map[string]*ice.Action {
return ice.MergeActions(ice.Actions{ _key := func(m *ice.Message) string {
PRUNES: &ice.Action{Name: "prunes status", Hand: func(m *ice.Message, arg ...string) { if m.Config(HASH) == "uniq" {
args := []string{}
kit.For(kit.Split(m.OptionDefault(STATUS, "error,close,stop,end")), func(s string) { args = append(args, STATUS, s) })
m.Cmdy(PRUNES, m.PrefixKey(), m.Option(SUBKEY), HASH, args, ice.OptionFields(HashField(m)))
}},
}, HashAction(arg...))
}
func ClearOnExitHashAction() ice.Actions {
return ice.Actions{ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { Conf(m, m.PrefixKey(), HASH, "") }}}
}
func ExportHashAction(arg ...Any) ice.Actions {
return ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE); HashImport(m, arg) }},
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { HashExport(m, arg) }},
}, HashAction(arg...))
}
const (
DEV_REQUEST = "devRequest"
DEV_CHOOSE = "devChoose"
DEV_RESPONSE = "devResponse"
DEV_CONFIRM = "devConfirm"
DEV_CREATE = "devCreate"
)
func DevDataAction(fields ...string) ice.Actions {
const (
DAEMON = "daemon"
ORIGIN = "origin"
BACK = "back"
)
return ice.Actions{
DEV_REQUEST: {Name: "request origin*", Help: "请求", Icon: "bi bi-cloud-download", Hand: func(m *ice.Message, arg ...string) {
back := m.Options(ice.MSG_USERWEB, m.Option(ice.MSG_USERHOST)).MergePod("")
m.ProcessOpen(m.Options(ice.MSG_USERWEB, m.Option(ORIGIN), ice.MSG_USERPOD, "").MergePodCmd("", m.PrefixKey(), ACTION, DEV_CHOOSE, BACK, back, DAEMON, m.Option(ice.MSG_DAEMON)))
}},
DEV_CHOOSE: {Hand: func(m *ice.Message, arg ...string) {
HashSelect(m.Options(ice.MSG_FIELDS, kit.Join(fields))).PushAction(DEV_RESPONSE).Options(ice.MSG_ACTION, "")
}},
DEV_RESPONSE: {Help: "选择", Hand: func(m *ice.Message, arg ...string) {
if !m.WarnNotAllow(m.Option(ice.MSG_METHOD) != http.MethodPost) {
m.ProcessReplace(m.ParseLink(m.Option(BACK)).MergePodCmd("", m.PrefixKey(), ACTION, DEV_CONFIRM, m.OptionSimple(DAEMON), m.OptionSimple(fields...)))
}
}},
DEV_CONFIRM: {Hand: func(m *ice.Message, arg ...string) {
m.EchoInfoButton(kit.JoinWord(m.PrefixKey(), m.Cmdx("nfs.cat", "src/template/mdb.hash/savefrom.html"), m.Option(kit.Split(fields[0])[0])), DEV_CREATE)
}},
DEV_CREATE: {Help: "创建", Hand: func(m *ice.Message, arg ...string) {
if !m.WarnNotAllow(m.Option(ice.MSG_METHOD) != http.MethodPost) {
defer kit.If(m.Option(DAEMON), func(p string) { m.Cmd("space", p, "refresh") })
HashCreate(m.ProcessClose(), m.OptionSimple(fields...))
}
}},
}
}
func HashKey(m *ice.Message) string {
if m.Option(HASH) != "" {
return HASH return HASH
} }
return HashShort(m) if m.Config(SHORT) == "uniq" {
return HASH
} }
func HashShort(m *ice.Message) string { return kit.Select(HASH, m.Config(SHORT))
if m.Option(SHORT) != "" {
return m.Option(SHORT)
} }
short := "" return ice.SelectAction(map[string]*ice.Action{ice.CTX_INIT: AutoConfig(args...),
if m.Option(SUBKEY) != "" { INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
if short = Conf(m, m.PrefixKey(), kit.Keys(m.Option(SUBKEY), META, SHORT)); short == "" { m.Cmdy(INPUTS, m.PrefixKey(), "", HASH, arg)
short = Config(m, SHORTS) }},
} CREATE: {Name: "create type name text", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
} else { m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg)
short = Config(m, SHORT) }},
} REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
return kit.Select(HASH, short, short != UNIQ) m.OptionFields(m.Config(FIELD))
} m.Cmdy(DELETE, m.PrefixKey(), "", HASH, m.OptionSimple(_key(m)), arg)
func HashField(m *ice.Message) string { m.Event(kit.Keys(m.CommandKey(), REMOVE), m.CommandKey(), m.Option(m.Config(SHORT)))
if m.Option(FIELD) != "" { }},
return m.Option(FIELD) MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
} m.Cmdy(MODIFY, m.PrefixKey(), "", HASH, m.OptionSimple(_key(m)), arg)
field := "" }},
if m.Option(SUBKEY) != "" { EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
if field = Conf(m, m.PrefixKey(), kit.Keys(m.Option(SUBKEY), META, FIELDS)); field == "" { m.OptionFields(m.Config(FIELD))
field = Config(m, FIELDS) m.Cmdy(EXPORT, m.PrefixKey(), "", HASH, arg)
} }},
} else { IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
field = Config(m, FIELD) m.Cmdy(IMPORT, m.PrefixKey(), "", HASH, arg)
} }},
return kit.Select(HASH_FIELD, field) PRUNES: &ice.Action{Name: "prunes before@date", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
} HashPrunes(m, nil)
func HashInputs(m *ice.Message, arg ...Any) *ice.Message { }},
return m.Cmdy(INPUTS, m.PrefixKey(), m.Option(SUBKEY), HASH, arg) SELECT: &ice.Action{Name: "select hash auto", Help: "列表", Hand: func(m *ice.Message, arg ...string) {
} HashSelect(m, arg...)
func HashCreate(m *ice.Message, arg ...Any) string { }},
kit.If(len(arg) == 0 || len(kit.Simple(arg...)) == 0, func() {
arg = append(arg, m.OptionSimple(kit.Filters(kit.Split(HashField(m)), TIME, HASH)...))
}) })
kit.If(m.Option(SUBKEY) == "", func() { kit.If(Config(m, SHORTS), func(p string) { arg = append([]ice.Any{SHORT, p}, arg) }) })
return m.Echo(m.Cmdx(append(kit.List(INSERT, m.PrefixKey(), m.Option(SUBKEY), HASH, logs.FileLineMeta(-1)), arg...)...)).Result()
} }
func HashRemove(m *ice.Message, arg ...Any) *ice.Message { func HashActionStatus(args ...interface{}) map[string]*ice.Action {
if args := kit.Simple(arg...); len(args) == 0 { list := HashAction(args...)
arg = append(arg, m.OptionSimple(HashKey(m))) list[PRUNES] = &ice.Action{Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
} else if len(args) == 1 { m.OptionFields(m.Config(FIELD))
arg = kit.List(HashKey(m), args[0]) m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, STATUS, "error")
} m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, STATUS, "close")
return m.Cmdy(DELETE, m.PrefixKey(), m.Option(SUBKEY), HASH, arg) }}
} return list
func HashModify(m *ice.Message, arg ...Any) *ice.Message {
if args := kit.Simple(arg...); args[0] != HASH && args[0] != HashShort(m) {
arg = append(kit.List(m.OptionSimple(HashKey(m))), arg...)
}
return m.Cmd(MODIFY, m.PrefixKey(), m.Option(SUBKEY), HASH, arg)
} }
func HashSelect(m *ice.Message, arg ...string) *ice.Message { func HashSelect(m *ice.Message, arg ...string) *ice.Message {
if len(arg) > 0 && (arg[0] == FOREACH || strings.Contains(arg[0], ",")) { m.Fields(len(arg), m.Config(FIELD))
m.Fields(0, HashField(m)) m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg)
} else { m.PushAction(m.Config("action"), REMOVE)
m.Fields(len(kit.Slice(arg, 0, 1)), HashField(m)) m.StatusTimeCount()
}
m.Cmdy(SELECT, m.PrefixKey(), m.Option(SUBKEY), HASH, HashShort(m), arg, logs.FileLineMeta(-1))
kit.If(kit.Select(Config(m, SHORT), Config(m, SORT)), func(sort string) { kit.If(sort != UNIQ, func() { m.Sort(sort) }) })
if m.PushAction(Config(m, ACTION), REMOVE); !m.FieldsIsDetail() {
m.Options(ice.TABLE_CHECKBOX, Config(m, html.CHECKBOX))
return m.Action(CREATE)
}
return sortByField(m, HashField(m), arg...)
}
func HashPrunes(m *ice.Message, cb func(Map) bool) *ice.Message {
expire := kit.Select(m.Time("-"+kit.Select(DAYS, Config(m, EXPIRE))), m.Option("before"))
m.OptionCB(PRUNES, func(key string, value Map) bool { return kit.Format(value[TIME]) < expire && (cb == nil || cb(value)) })
return m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, ice.OptionFields(HashField(m)))
}
func HashExport(m *ice.Message, arg ...Any) *ice.Message {
return m.Cmdy(EXPORT, m.PrefixKey(), "", HASH, arg)
}
func HashImport(m *ice.Message, arg ...Any) *ice.Message {
return m.Cmdy(IMPORT, m.PrefixKey(), "", HASH, arg)
}
func HashSelects(m *ice.Message, arg ...string) *ice.Message {
m.OptionFields(HashField(m))
return HashSelect(m, arg...)
}
func HashSelectValue(m *ice.Message, cb Any) *ice.Message {
m.OptionFields(Config(m, FIELD))
defer RLock(m, m.PrefixKey())()
Richs(m, m.PrefixKey(), nil, FOREACH, func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil) })
return m return m
} }
func HashSelectUpdate(m *ice.Message, key string, cb Any) *ice.Message { func HashPrunes(m *ice.Message, cb func(map[string]string) bool) *ice.Message {
defer Lock(m, m.PrefixKey())() _key := func(m *ice.Message) string {
Richs(m, m.PrefixKey(), nil, kit.Select(FOREACH, key), func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil) }) if m.Config(HASH) == "uniq" {
return m return HASH
} }
func HashSelectDetail(m *ice.Message, key string, cb Any) (has bool) { return kit.Select(HASH, m.Config(SHORT))
defer RLock(m, m.PrefixKey())() }
Richs(m, m.PrefixKey(), nil, key, func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil); has = true }) expire := kit.Time(kit.Select(m.Time("-72h"), m.Option(EXPIRE)))
m.Cmd(m.CommandKey()).Table(func(index int, value map[string]string, head []string) {
if kit.Time(value[TIME]) > expire {
return return
} }
func HashSelectDetails(m *ice.Message, key string, cb func(Map) bool) Map { if cb != nil && cb(value) {
val := kit.Dict()
HashSelectDetail(m, key, func(value Map) { kit.If(cb(value), func() { kit.For(value, func(k string, v Any) { val[k] = v }) }) })
return val
}
func HashSelectField(m *ice.Message, key string, field string) (value string) {
HashSelectDetail(m, key, func(key string, val Map) { value = kit.Select(kit.Format(kit.Value(val, field)), key, field == HASH) })
return return
} }
func HashSelectTarget(m *ice.Message, key string, create Any) (target Any) { m.OptionFields(m.Config(FIELD))
HashSelectUpdate(m, key, func(value Map) { m.Cmdy(DELETE, m.PrefixKey(), "", HASH, _key(m), value[_key(m)])
target = value[TARGET]
if _target, ok := target.([]string); ok && len(_target) == 0 {
target = nil
}
if _target, ok := target.(List); ok && len(_target) == 0 {
target = nil
}
if _target, ok := target.(Map); ok && len(_target) == 0 {
target = nil
}
if target != nil || create == nil {
return
}
switch create := create.(type) {
case func(Maps) Any:
target = create(kit.ToMaps(value))
case func(Map) Any:
target = create(value)
case func() Any:
target = create()
default:
m.ErrorNotImplement(create)
}
value[TARGET] = target
})
return
}
func HashSelectClose(m *ice.Message) *ice.Message {
HashSelectValue(m, func(value Map) {
if c, ok := value[TARGET].(io.Closer); ok {
m.WarnNotValid(c.Close())
}
delete(value, TARGET)
}) })
return m return m
} }
func HashPrunesValue(m *ice.Message, field, value string) {
m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, field, value, ice.OptionFields(HashField(m)))
}
func HashCreateDeferRemove(m *ice.Message, arg ...Any) func() {
h := HashCreate(m, arg...)
return func() { HashRemove(m.SetResult(), HASH, h) }
}
func HashModifyDeferRemove(m *ice.Message, arg ...Any) func() {
HashModify(m, arg...)
return func() { HashRemove(m, arg...) }
}
func Richs(m *ice.Message, prefix string, chain Any, raw Any, cb Any) (res Map) {
cache := Confm(m, prefix, chain)
if cache == nil {
return nil
}
if value := kit.Format(raw); strings.Contains(value, ",") {
kit.For(kit.Split(value), func(value string) {
res = miss.Richs(path.Join(prefix, kit.Keys(chain)), cache, value, cb)
})
return
}
return miss.Richs(path.Join(prefix, kit.Keys(chain)), cache, raw, cb)
}
func Rich(m *ice.Message, prefix string, chain Any, data Any) string {
cache := Confm(m, prefix, chain)
kit.If(cache == nil, func() { cache = kit.Data(); m.Confv(prefix, chain, cache) })
return miss.Rich(path.Join(prefix, kit.Keys(chain)), cache, data)
}
func sortByField(m *ice.Message, fields string, arg ...string) *ice.Message {
return m.Table(func(value ice.Maps) {
m.SetAppend().FieldsSetDetail()
kit.For(kit.Split(fields), func(key string) {
key = strings.TrimSuffix(key, "*")
if key == HASH {
m.Push(key, kit.Select(value[key], arg, 0))
} else {
m.Push(key, value[key])
}
delete(value, key)
})
kit.For(kit.SortedKey(value), func(k string) { m.Push(k, value[k]) })
})
}

View File

@ -4,94 +4,114 @@ import (
"encoding/csv" "encoding/csv"
"os" "os"
"path" "path"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/miss"
) )
func _list_fields(m *ice.Message) []string { func _list_fields(m *ice.Message) []string {
return kit.Split(kit.Select(LIST_FIELD, m.OptionFields())) return kit.Split(kit.Select("time,id,type,name,text", m.OptionFields()))
} }
func _list_inputs(m *ice.Message, prefix, chain string, field, value string) { func _list_inputs(m *ice.Message, prefix, chain string, field, value string) {
list := map[string]int{} list := map[string]int{}
defer func() { m.Grows(prefix, chain, "", "", func(index int, val map[string]interface{}) {
delete(list, "") if val = kit.GetMeta(val); kit.Format(val[COUNT]) != "" {
kit.For(list, func(k string, i int) { m.Push(field, k).Push(COUNT, i) }) list[kit.Format(val[field])] = kit.Int(val[COUNT])
m.SortIntR(COUNT) } else {
}() list[kit.Format(val[field])]++
defer RLock(m, prefix)() }
Grows(m, prefix, chain, "", "", func(value ice.Map) {
value = kit.GetMeta(value)
list[kit.Format(value[field])] += kit.Int(kit.Select("1", value[COUNT]))
}) })
for k, i := range list {
m.Push(field, k)
m.Push(COUNT, i)
}
m.SortIntR(COUNT)
} }
func _list_insert(m *ice.Message, prefix, chain string, arg ...string) { func _list_insert(m *ice.Message, prefix, chain string, arg ...string) {
m.Logs(INSERT, KEY, path.Join(prefix, chain), arg) m.Log_INSERT(KEY, path.Join(prefix, chain), arg[0], arg[1])
defer Lock(m, prefix)() m.Echo("%d", m.Grow(prefix, chain, kit.Dict(arg)))
m.Echo("%d", Grow(m, prefix, chain, kit.Dict(arg, TARGET, m.Optionv(TARGET)))) }
saveImportant(m, prefix, chain, kit.Simple(INSERT, prefix, chain, LIST, TIME, m.Time(), arg)...) func _list_delete(m *ice.Message, prefix, chain, field, value string) {
} }
func _list_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) { func _list_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) {
m.Logs(MODIFY, KEY, path.Join(prefix, chain), field, value, arg) m.Grows(prefix, chain, field, value, func(index int, val map[string]interface{}) {
defer Lock(m, prefix)() val = kit.GetMeta(val)
Grows(m, prefix, chain, field, value, func(index int, val ice.Map) { _mdb_modify(m, val, field, arg...) }) m.Log_MODIFY(KEY, path.Join(prefix, chain), field, value, arg)
saveImportant(m, prefix, chain, kit.Simple(MODIFY, prefix, chain, LIST, field, value, arg)...) for i := 0; i < len(arg); i += 2 {
if arg[i] == field {
continue
}
kit.Value(val, arg[i], kit.Select("", arg, i+1))
}
})
} }
func _list_select(m *ice.Message, prefix, chain, field, value string) { func _list_select(m *ice.Message, prefix, chain, field, value string) {
defer m.SortIntR(ID) if value == "" {
field = ""
}
fields := _list_fields(m) fields := _list_fields(m)
defer RLock(m, prefix)() m.Grows(prefix, chain, kit.Select(m.Option(ice.CACHE_FIELD), field), kit.Select(m.Option(ice.CACHE_VALUE), value), func(index int, val map[string]interface{}) {
Grows(m, prefix, chain, kit.Select(m.Option(CACHE_FIELD), field), kit.Select(m.Option(CACHE_VALUE), value), func(value ice.Map) { switch val = kit.GetMeta(val); cb := m.OptionCB(SELECT).(type) {
_mdb_select(m, m.OptionCB(""), "", value, fields, nil) case func(fields []string, value map[string]interface{}):
cb(fields, val)
default:
if m.OptionFields() == DETAIL {
m.Push(DETAIL, val)
} else {
m.Push("", val, fields)
}
}
}) })
} }
func _list_export(m *ice.Message, prefix, chain, file string) { func _list_export(m *ice.Message, prefix, chain, file string) {
defer Lock(m, prefix)() f, p, e := kit.Create(kit.Keys(file, CSV))
p := kit.Keys(file, CSV)
count := kit.Int(Conf(m, prefix, kit.Keys(chain, META, COUNT)))
if count == 0 {
if s, e := os.Stat(p); e == nil && !s.IsDir() {
os.Remove(p)
}
return
}
f, p, e := miss.CreateFile(p)
m.Assert(e) m.Assert(e)
defer f.Close() defer f.Close()
defer m.Echo(p)
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
w := csv.NewWriter(f) w := csv.NewWriter(f)
defer w.Flush() defer w.Flush()
head := kit.Split(ListField(m))
Grows(m, prefix, chain, "", "", func(index int, value ice.Map) { count := 0
if value = kit.GetMeta(value); index == 0 { head := kit.Split(m.OptionFields())
kit.If(len(head) == 0 || head[0] == ice.FIELDS_DETAIL, func() { head = kit.SortedKey(value) }) m.Grows(prefix, chain, "", "", func(index int, val map[string]interface{}) {
w.Write(head) if val = kit.GetMeta(val); index == 0 {
if len(head) == 0 || head[0] == "detail" { // 默认表头
for k := range val {
head = append(head, k)
} }
w.Write(kit.Simple(head, func(k string) string { return kit.Format(value[k]) })) kit.Sort(head)
}
w.Write(head) // 输出表头
}
data := []string{}
for _, k := range head {
data = append(data, kit.Format(val[k]))
}
w.Write(data) // 输出数据
count++
}) })
m.Log_EXPORT(KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
m.Conf(prefix, kit.Keys(chain, kit.Keym(COUNT)), 0) m.Conf(prefix, kit.Keys(chain, kit.Keym(COUNT)), 0)
m.Conf(prefix, kit.Keys(chain, LIST), "") m.Conf(prefix, kit.Keys(chain, LIST), "")
m.Echo(p)
} }
func _list_import(m *ice.Message, prefix, chain, file string) { func _list_import(m *ice.Message, prefix, chain, file string) {
defer Lock(m, prefix)() f, e := os.Open(kit.Keys(file, CSV))
f, e := miss.OpenFile(kit.Keys(file, CSV)) m.Assert(e)
if e != nil && !ice.Info.Important {
return
} else if m.WarnNotFound(e) {
return
}
defer f.Close() defer f.Close()
r := csv.NewReader(f) r := csv.NewReader(f)
head, _ := r.Read()
count := 0 count := 0
head, _ := r.Read()
for { for {
line, e := r.Read() line, e := r.Read()
if e != nil { if e != nil {
break break
} }
data := kit.Dict() data := kit.Dict()
for i, k := range head { for i, k := range head {
if k == EXTRA { if k == EXTRA {
@ -100,134 +120,63 @@ func _list_import(m *ice.Message, prefix, chain, file string) {
kit.Value(data, k, line[i]) kit.Value(data, k, line[i])
} }
} }
Grow(m, prefix, chain, data)
m.Grow(prefix, chain, data)
count++ count++
} }
m.Logs(IMPORT, KEY, kit.Keys(prefix, chain), FILE, kit.Keys(file, CSV), COUNT, count)
m.Log_IMPORT(KEY, kit.Keys(prefix, chain), COUNT, count)
m.Echo("%d", count) m.Echo("%d", count)
} }
func _list_prunes(m *ice.Message, prefix, chain string, arg ...string) {
}
const (
LIST_FIELD = "time,id,type,name,text"
)
const LIST = "list" const LIST = "list"
func ListAction(arg ...ice.Any) ice.Actions { func ListAction(fields ...string) map[string]*ice.Action {
return ice.Actions{ice.CTX_INIT: AutoConfig(append(kit.List(FIELD, LIST_FIELD), arg...)...), return ice.SelectAction(map[string]*ice.Action{
INPUTS: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(INPUTS, m.PrefixKey(), "", LIST, arg) }}, INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
INSERT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(INSERT, m.PrefixKey(), "", LIST, arg) }}, m.Cmdy(INPUTS, m.PrefixKey(), "", LIST, arg)
DELETE: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(DELETE, m.PrefixKey(), "", LIST, m.OptionSimple(ID), arg) }},
MODIFY: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(MODIFY, m.PrefixKey(), "", LIST, m.OptionSimple(ID), arg) }},
SELECT: {Name: "select id auto insert", Hand: func(m *ice.Message, arg ...string) { ListSelect(m, arg...) }},
PRUNES: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(PRUNES, m.PrefixKey(), "", LIST, arg) }},
EXPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(EXPORT, m.PrefixKey(), "", LIST, arg) }},
IMPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(IMPORT, m.PrefixKey(), "", LIST, arg) }},
}
}
func PageListAction(arg ...ice.Any) ice.Actions {
return ice.MergeActions(ice.Actions{
SELECT: {Name: "select id auto insert page", Hand: func(m *ice.Message, arg ...string) { PageListSelect(m, arg...) }},
NEXT: {Hand: func(m *ice.Message, arg ...string) {
NextPage(m, kit.Select(Config(m, COUNT), arg, 0), kit.Slice(arg, 1)...)
}}, }},
PREV: {Hand: func(m *ice.Message, arg ...string) { INSERT: {Name: "insert type=go name=hi text=hello", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
PrevPageLimit(m, kit.Select(Config(m, COUNT), arg, 0), kit.Slice(arg, 1)...) m.Cmdy(INSERT, m.PrefixKey(), "", LIST, arg)
}}, }},
}, ListAction(arg...)) DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(DELETE, m.PrefixKey(), "", LIST, m.OptionSimple(ID), arg)
}},
MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(MODIFY, m.PrefixKey(), "", LIST, m.OptionSimple(ID), arg)
}},
EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
m.Option(ice.CACHE_LIMIT, "-1")
m.OptionFields(m.Config(FIELD))
m.Cmdy(EXPORT, m.PrefixKey(), "", LIST)
m.Conf(m.PrefixKey(), LIST, "")
m.Config(COUNT, 0)
}},
IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(IMPORT, m.PrefixKey(), "", LIST, arg)
}},
PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(PRUNES, m.PrefixKey(), "", LIST, arg)
}},
PREV: {Name: "prev", Help: "上一页", Hand: func(m *ice.Message, arg ...string) {
PrevPage(m, m.Config(COUNT), kit.Slice(arg, 1)...)
}},
NEXT: {Name: "next", Help: "下一页", Hand: func(m *ice.Message, arg ...string) {
NextPage(m, m.Config(COUNT), kit.Slice(arg, 1)...)
}},
SELECT: {Name: "select", Help: "列表", Hand: func(m *ice.Message, arg ...string) {
ListSelect(m, arg...)
}},
}, fields...)
} }
func ListField(m *ice.Message) string { return kit.Select(LIST_FIELD, Config(m, FIELD)) }
func ListSelect(m *ice.Message, arg ...string) *ice.Message { func ListSelect(m *ice.Message, arg ...string) *ice.Message {
m.Fields(len(kit.Slice(arg, 0, 1)), ListField(m)) m.OptionPage(kit.Slice(arg, 1)...)
if m.Cmdy(SELECT, m.PrefixKey(), "", LIST, ID, arg); !m.FieldsIsDetail() { m.Fields(len(kit.Slice(arg, 0, 1)), m.Config(FIELD))
return m.StatusTimeCountTotal(Config(m, COUNT)) m.Cmdy(SELECT, m.PrefixKey(), "", LIST, ID, arg)
if !m.FieldsIsDetail() {
m.StatusTimeCountTotal(m.Config(COUNT))
} }
return m.StatusTime() return m
}
func PageListSelect(m *ice.Message, arg ...string) *ice.Message {
OptionPage(m, kit.Slice(arg, 1)...)
return ListSelect(m, arg...)
}
func NextPageLimit(m *ice.Message, total string, arg ...string) {
if kit.Int(kit.Select("0", arg, 1)) > 0 {
NextPage(m, total, arg...)
} else {
m.ProcessHold("已经是最后一页啦!")
}
}
func NextPage(m *ice.Message, total string, arg ...string) {
limit, offend := kit.Select("10", arg, 0), kit.Select("0", arg, 1)
if offends := kit.Int(offend) - kit.Int(limit); total != "0" && (offends <= -kit.Int(total) || offends >= kit.Int(total)) {
m.ProcessHold("已经是最后一页啦!")
} else if offends == 0 {
m.ProcessRewrite("offend", "")
} else {
m.ProcessRewrite("offend", offends)
}
}
func PrevPage(m *ice.Message, total string, arg ...string) {
limit, offend := kit.Select("10", arg, 0), kit.Select("0", arg, 1)
if offends := kit.Int(offend) + kit.Int(limit); total != "0" && (offends <= -kit.Int(total) || offends >= kit.Int(total)) {
m.ProcessHold("已经是最前一页啦!")
} else if offends == 0 {
m.ProcessRewrite("offend", "")
} else {
m.ProcessRewrite("offend", offends)
}
}
func PrevPageLimit(m *ice.Message, total string, arg ...string) {
if kit.Int(kit.Select("0", arg, 1)) < 0 {
PrevPage(m, total, arg...)
} else {
m.ProcessHold("已经是最前一页啦!")
}
}
func OptionPages(m *ice.Message, arg ...string) (page int, size int) {
m.Option(CACHE_OFFEND, kit.Select(m.Option(CACHE_OFFEND), arg, 0))
m.Option(CACHE_LIMIT, kit.Select(m.Option(CACHE_LIMIT), arg, 1))
m.Option(CACHE_FILTER, kit.Select(m.Option(CACHE_FILTER), arg, 2))
m.Option(OFFEND, kit.Select(m.Option(OFFEND), arg, 0))
m.Option(LIMIT, kit.Select(m.Option(LIMIT), arg, 1))
size = kit.Int(kit.Select("10", m.Option(LIMIT)))
page = kit.Int(m.Option(OFFEND))/size + 1
return
}
func OptionPage(m *ice.Message, arg ...string) int {
page, _ := OptionPages(m, arg...)
return page
}
const (
CACHE_LIMIT = "cache.limit"
CACHE_BEGIN = "cache.begin"
CACHE_COUNT = "cache.count"
CACHE_OFFEND = "cache.offend"
CACHE_FILTER = "cache.filter"
CACHE_VALUE = "cache.value"
CACHE_FIELD = "cache.field"
)
func Grows(m *ice.Message, prefix string, chain Any, match string, value string, cb Any) Map {
cache, ok := m.Confv(prefix, chain).(ice.Map)
if cache == nil || !ok {
return nil
} else if begin, limit := kit.Int(m.Option(CACHE_BEGIN)), kit.Int(m.Option(CACHE_LIMIT)); begin != 0 && limit > 0 {
if count := kit.Int(m.Option(CACHE_COUNT, kit.Int(kit.Value(cache, kit.Keym(COUNT))))); count-begin < limit {
m.Option(CACHE_OFFEND, 0)
m.Option(CACHE_LIMIT, count-begin+1)
} else {
m.Option(CACHE_OFFEND, count-begin-limit+1)
}
}
return miss.Grows(path.Join(prefix, kit.Keys(chain)), cache,
kit.Int(kit.Select("0", strings.TrimPrefix(m.Option(CACHE_OFFEND), "-"))),
kit.Int(kit.Select("10", m.Option(CACHE_LIMIT))), match, value, cb)
}
func Grow(m *ice.Message, prefix string, chain Any, data Any) int {
cache, ok := m.Confv(prefix, chain).(ice.Map)
if cache == nil || !ok {
cache = kit.Data()
m.Confv(prefix, chain, cache)
}
return miss.Grow(path.Join(prefix, kit.Keys(chain)), cache, data)
} }

View File

@ -1,75 +0,0 @@
package mdb
import (
"sync"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/task"
)
var _lock = task.Lock{}
var _locks = map[string]*task.Lock{}
func getLock(m *ice.Message, arg ...string) *task.Lock {
key := kit.Select(m.PrefixKey(), kit.Keys(arg))
defer _lock.Lock()()
l, ok := _locks[key]
kit.If(!ok, func() { l = &task.Lock{}; _locks[key] = l })
return l
}
func Lock(m *ice.Message, arg ...string) func() {
return getLock(m, arg...).Lock()
}
func RLock(m *ice.Message, arg ...string) func() {
return getLock(m, arg...).RLock()
}
func ConfigSimple(m *ice.Message, key ...string) (res []string) {
for _, key := range key {
res = append(res, key, kit.Format(Configv(m, key)))
}
return
}
func Config(m *ice.Message, key string, arg ...Any) string {
return kit.Format(Configv(m, key, arg...))
}
func Configv(m *ice.Message, key string, arg ...Any) Any {
kit.If(len(arg) > 0, func() { Confv(m, m.PrefixKey(), kit.Keym(key), arg[0]) })
return Confv(m, m.PrefixKey(), kit.Keym(key))
}
func Confv(m *ice.Message, arg ...Any) Any {
key := kit.Select(m.PrefixKey(), kit.Format(arg[0]))
if ctx, ok := ice.Info.Index[key].(*ice.Context); ok {
key = ctx.Prefix(key)
}
if len(arg) > 2 {
defer Lock(m, key)()
} else {
defer RLock(m, key)()
}
return m.Confv(arg...)
}
func Conf(m *ice.Message, arg ...Any) string { return kit.Format(Confv(m, arg...)) }
func Confm(m *ice.Message, key string, sub Any, cbs ...Any) Map {
val := m.Confv(key, sub)
kit.If(len(cbs) > 0, func() { kit.For(val, cbs[0]) })
value, _ := val.(Map)
return value
}
var cache = sync.Map{}
func Cache(m *ice.Message, key string, add func() Any) Any {
if key = kit.Keys(m.PrefixKey(), key); add == nil {
cache.Delete(key)
return nil
} else if val, ok := cache.Load(key); ok {
return val
} else if val := add(); val != nil {
cache.Store(key, val)
return val
} else {
return nil
}
}

View File

@ -8,318 +8,221 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
type Any = ice.Any func _file_name(m *ice.Message, arg ...string) string {
type List = ice.List
type Maps = ice.Maps
type Map = ice.Map
func _mdb_modify(m *ice.Message, value Map, field string, arg ...string) {
value = kit.GetMeta(value)
kit.For(arg, func(k, v string) { kit.If(k != field, func() { kit.Value(value, k, v) }) })
}
func _mdb_select(m *ice.Message, cb Any, key string, value Map, fields []string, val Map) {
switch value, val = kit.GetMeta(value), kit.GetMeta(val); cb := cb.(type) {
case func([]string, Map):
cb(fields, value)
case func(string, []string, Map, Map):
cb(key, fields, value, val)
case func(string, Map, Map):
cb(key, value, val)
case func(string, Map):
cb(key, value)
case func(Map):
cb(value)
case func(Any):
cb(value[TARGET])
case func(Maps):
cb(kit.ToMaps(value))
case string, []string, []Any, nil:
if m.FieldsIsDetail() {
// m.Push(ice.FIELDS_DETAIL, value, nil, kit.Dict(HASH, key))
m.Push(ice.FIELDS_DETAIL, value)
} else {
m.Push(key, value, fields, val)
}
default:
m.ErrorNotImplement(cb)
}
}
func _mdb_export_file(m *ice.Message, arg ...string) string {
if len(arg) > 3 && strings.Contains(arg[3], ice.PS) { if len(arg) > 3 && strings.Contains(arg[3], ice.PS) {
return arg[3] return arg[3]
} }
return path.Join(ice.USR_LOCAL_EXPORT, path.Join(arg[:2]...), arg[2]) return path.Join(ice.USR_LOCAL_EXPORT, m.Option(ice.MSG_DOMAIN), path.Join(arg[:2]...), arg[2])
return kit.Select(path.Join(ice.USR_LOCAL_EXPORT, m.Option(ice.MSG_DOMAIN), path.Join(arg[:2]...), arg[2]), arg, 3)
}
func _domain_chain(m *ice.Message, chain string) string {
return kit.Keys(m.Option(ice.MSG_DOMAIN), chain)
} }
const ( const (
DICT = kit.MDB_DICT CSV = "csv"
META = kit.MDB_META JSON = "json"
)
const (
DICT = "dict"
META = "meta"
)
const (
ID = kit.MDB_ID
KEY = kit.MDB_KEY
TIME = kit.MDB_TIME
// ZONE = kit.MDB_ZONE
TYPE = kit.MDB_TYPE
NAME = kit.MDB_NAME
TEXT = kit.MDB_TEXT
LINK = kit.MDB_LINK
SCAN = kit.MDB_SCAN
SHOW = kit.MDB_SHOW
HELP = kit.MDB_HELP
DATA = kit.MDB_DATA
FILE = kit.MDB_FILE
SHORT = kit.MDB_SHORT SHORT = kit.MDB_SHORT
FIELD = kit.MDB_FIELD FIELD = kit.MDB_FIELD
COUNT = kit.MDB_COUNT
TOTAL = kit.MDB_TOTAL TOTAL = kit.MDB_TOTAL
COUNT = kit.MDB_COUNT
LIMIT = kit.MDB_LIMIT LIMIT = kit.MDB_LIMIT
LEAST = kit.MDB_LEAST LEAST = kit.MDB_LEAST
STORE = kit.MDB_STORE STORE = kit.MDB_STORE
FSIZE = kit.MDB_FSIZE FSIZE = kit.MDB_FSIZE
UNIQ = kit.MDB_UNIQ
FOREACH = kit.MDB_FOREACH
RANDOMS = kit.MDB_RANDOMS
)
const (
ID = kit.MDB_ID
TIME = kit.MDB_TIME
TYPE = kit.MDB_TYPE
NAME = kit.MDB_NAME
TEXT = kit.MDB_TEXT
ICON = kit.MDB_ICON
SCAN = kit.MDB_SCAN
LINK = kit.MDB_LINK
HELP = kit.MDB_HELP
FILE = kit.MDB_FILE
DATA = kit.MDB_DATA
VIEW = kit.MDB_VIEW
SHOW = kit.MDB_SHOW
KEY = kit.MDB_KEY
VALUE = kit.MDB_VALUE
INDEX = kit.MDB_INDEX INDEX = kit.MDB_INDEX
VALUE = kit.MDB_VALUE
EXTRA = kit.MDB_EXTRA EXTRA = kit.MDB_EXTRA
ALIAS = kit.MDB_ALIAS ALIAS = kit.MDB_ALIAS
EXPIRE = kit.MDB_EXPIRE EXPIRE = kit.MDB_EXPIRE
STATUS = kit.MDB_STATUS STATUS = kit.MDB_STATUS
STREAM = kit.MDB_STREAM STREAM = kit.MDB_STREAM
TOOLS = "tools" FOREACH = "*"
ICONS = "icons" RANDOMS = "%"
UNITS = "units"
ORDER = "order"
SCORE = "score"
GROUP = "group"
VALID = "valid"
ENABLE = "enable"
MEMBER = "member"
DISABLE = "disable"
EXPIRED = "expired"
INVALID = "invalid"
SOURCE = "_source"
TARGET = "_target"
IMPORTANT = "important"
) )
const ( const (
INPUTS = "inputs" DETAIL = "detail"
RANDOM = "random"
CREATE = "create" CREATE = "create"
REMOVE = "remove" REMOVE = "remove"
UPDATE = "update"
INSERT = "insert" INSERT = "insert"
DELETE = "delete" DELETE = "delete"
MODIFY = "modify" MODIFY = "modify"
SELECT = "select" SELECT = "select"
INPUTS = "inputs"
PRUNES = "prunes" PRUNES = "prunes"
EXPORT = "export" EXPORT = "export"
IMPORT = "import" IMPORT = "import"
DETAIL = "detail"
FIELDS = "fields"
SHORTS = "shorts"
PARAMS = "params"
OFFEND = "offend"
OFFSET = "offset"
RANDOM = "random"
WEIGHT = "weight"
SUBKEY = "mdb.sub"
ACTION = "action"
UPLOAD = "upload" UPLOAD = "upload"
RECENT = "recent"
REPEAT = "repeat"
REVERT = "revert" REVERT = "revert"
RENAME = "rename" REPEAT = "repeat"
VENDOR = "vendor"
PRUNE = "prune"
TABLE = "table"
CLASS = "class"
DATABASE = "database"
PAGE = "page"
NEXT = "next" NEXT = "next"
PREV = "prev" PREV = "prev"
PLAY = "play" PAGE = "page"
SORT = "sort"
JSON = "json"
CSV = "csv"
SUB = "sub"
QS = ice.QS
EQ = ice.EQ
AT = ice.AT
FS = ice.FS
) )
const (
CACHE_CLEAR_ON_EXIT = "cache.clear.on.exit"
)
func PrevPageLimit(m *ice.Message, total string, arg ...string) {
if kit.Int(kit.Select("0", arg, 1)) > 0 {
PrevPage(m, total, arg...)
} else {
m.Toast("已经是最前一页啦!")
m.ProcessHold()
}
}
func PrevPage(m *ice.Message, total string, arg ...string) {
limit, offend := kit.Select("10", arg, 0), kit.Select("0", arg, 1)
offends := kit.Int(offend) - kit.Int(limit)
if offends <= -kit.Int(total) || offends >= kit.Int(total) {
m.Toast("已经是最前一页啦!")
m.ProcessHold()
return
}
m.ProcessRewrite("offend", offends)
}
func NextPage(m *ice.Message, total string, arg ...string) {
limit, offend := kit.Select("10", arg, 0), kit.Select("0", arg, 1)
offends := kit.Int(offend) + kit.Int(limit)
if offends <= -kit.Int(total) || offends >= kit.Int(total) {
m.Toast("已经是最后一页啦!")
m.ProcessHold()
return
}
m.ProcessRewrite("offend", offends)
}
func NextPageLimit(m *ice.Message, total string, arg ...string) {
if kit.Int(kit.Select("0", arg, 1)) < 0 {
NextPage(m, total, arg...)
} else {
m.Toast("已经是最后一页啦!")
m.ProcessHold()
}
}
const MDB = "mdb" const MDB = "mdb"
var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands{ var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {}}, ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {}}, ice.Pulse.Option(ice.CACHE_LIMIT, "10")
INPUTS: {Name: "inputs key sub type field value", Hand: func(m *ice.Message, arg ...string) { }},
kit.Switch(arg[2], ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
HASH, func() { _hash_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4)) }, }},
ZONE, func() { _zone_inputs(m, arg[0], arg[1], arg[3], kit.Select(NAME, arg, 4), kit.Select("", arg, 5)) }, INSERT: {Name: "insert key sub type arg...", Help: "添加", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
LIST, func() { _list_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4)) }, switch arg[2] {
) case ZONE: // insert key sub type zone arg...
for _, inputs := range ice.Info.Inputs { _list_insert(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...)
if arg[2] == ZONE { case HASH:
inputs(m, arg[4]) _hash_insert(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...)
} else { case LIST:
inputs(m, arg[3]) _list_insert(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...)
}
} }
}}, }},
INSERT: {Name: "insert key sub type arg...", Hand: func(m *ice.Message, arg ...string) { DELETE: {Name: "delete key sub type field value", Help: "删除", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
kit.Switch(arg[2], switch arg[2] {
HASH, func() { _hash_insert(m, arg[0], arg[1], arg[3:]...) }, case ZONE: // delete key sub type zone field value
ZONE, func() { _list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5])
if arg[3] == ZONE { case HASH:
_zone_insert(m, arg[0], arg[1], arg[4], arg[5:]...) _hash_delete(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4])
} else { case LIST:
_zone_insert(m, arg[0], arg[1], arg[3], arg[4:]...) _list_delete(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4])
} }
},
LIST, func() { _list_insert(m, arg[0], arg[1], arg[3:]...) },
)
}}, }},
DELETE: {Name: "delete key sub type field value", Hand: func(m *ice.Message, arg ...string) { MODIFY: {Name: "modify key sub type field value arg...", Help: "编辑", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
kit.Switch(arg[2], switch arg[2] {
HASH, func() { _hash_delete(m, arg[0], arg[1], arg[3], arg[4]) }, case ZONE: // modify key sub type zone id field value
// ZONE, func() { _list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5]) }, _list_modify(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), ID, arg[4], arg[5:]...)
// LIST, func() { _list_delete(m, arg[0], arg[1], arg[3], arg[4]) }, case HASH:
) _hash_modify(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4], arg[5:]...)
}}, case LIST:
MODIFY: {Name: "modify key sub type field value arg...", Hand: func(m *ice.Message, arg ...string) { _list_modify(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4], arg[5:]...)
kit.Switch(arg[2],
HASH, func() { _hash_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...) },
ZONE, func() { _zone_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...) },
LIST, func() { _list_modify(m, arg[0], arg[1], arg[3], arg[4], arg[5:]...) },
)
}},
SELECT: {Name: "select key sub type field value", Hand: func(m *ice.Message, arg ...string) {
kit.Switch(arg[2],
HASH, func() { _hash_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select(FOREACH, arg, 4)) },
ZONE, func() { _zone_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select("", arg, 4)) },
LIST, func() { _list_select(m, arg[0], arg[1], kit.Select("", arg, 3), kit.Select("", arg, 4)) },
)
}},
PRUNES: {Name: "prunes key sub type [field value]...", Hand: func(m *ice.Message, arg ...string) {
kit.Switch(arg[2],
HASH, func() {
_hash_prunes(m, arg[0], arg[1], arg[3:]...)
m.Table(func(value Maps) { _hash_delete(m, arg[0], arg[1], HASH, value[HASH]) })
},
// ZONE, func() { _list_prunes(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...) },
// LIST, func() { _list_prunes(m, arg[0], arg[1], arg[3:]...) },
)
}},
EXPORT: {Name: "export index auto", Help: "导出数据", Actions: ice.MergeActions(ice.Actions{
IMPORT: {Hand: func(m *ice.Message, arg ...string) {
HashSelect(m).Table(func(value ice.Maps) {
if value[ENABLE] != ice.FALSE {
m.Cmd(IMPORT, value[INDEX], "", value[TYPE])
} }
})
}}, }},
EXPORT: {Hand: func(m *ice.Message, arg ...string) { SELECT: {Name: "select key sub type field value", Help: "查询", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
HashSelect(m).Table(func(value ice.Maps) { switch arg[2] {
if value[ENABLE] != ice.FALSE { case ZONE:
m.Cmd(EXPORT, value[INDEX], "", value[TYPE]) _zone_select(m, arg[0], _domain_chain(m, arg[1]), kit.Select("", arg, 3), kit.Select("", arg, 4))
case HASH:
_hash_select(m, arg[0], _domain_chain(m, arg[1]), kit.Select("", arg, 3), kit.Select(FOREACH, arg, 4))
case LIST:
_list_select(m, arg[0], _domain_chain(m, arg[1]), kit.Select("", arg, 3), kit.Select("", arg, 4))
} }
})
}}, }},
}, ExportHashAction(SHORT, INDEX, FIELD, "time,index,type,enable")), Hand: func(m *ice.Message, arg ...string) { INPUTS: {Name: "inputs key sub type field value", Help: "补全", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) < 2 { switch arg[2] {
HashSelect(m, arg...).PushAction(REMOVE) case ZONE: // inputs key sub type zone field value
return _list_inputs(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), kit.Select(NAME, arg, 4), kit.Select("", arg, 5))
case HASH:
_hash_inputs(m, arg[0], _domain_chain(m, arg[1]), kit.Select(NAME, arg, 3), kit.Select("", arg, 4))
case LIST:
_list_inputs(m, arg[0], _domain_chain(m, arg[1]), kit.Select(NAME, arg, 3), kit.Select("", arg, 4))
} }
m.OptionDefault(CACHE_LIMIT, "-1")
file := _mdb_export_file(m, arg...)
kit.Switch(arg[2],
HASH, func() { _hash_export(m, arg[0], arg[1], file) },
ZONE, func() { _zone_export(m, arg[0], arg[1], file); _hash_export(m, arg[0], arg[1], file) },
LIST, func() { _list_export(m, arg[0], arg[1], file) },
)
}}, }},
IMPORT: {Name: "import key sub type file", Hand: func(m *ice.Message, arg ...string) { PRUNES: {Name: "prunes key sub type [field value]...", Help: "清理", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
file := _mdb_export_file(m, arg...) switch arg[2] {
kit.Switch(arg[2], case ZONE: // prunes key sub type zone field value
HASH, func() { _hash_import(m, arg[0], arg[1], file) }, _list_prunes(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...)
ZONE, func() { _hash_import(m, arg[0], arg[1], file); _zone_import(m, arg[0], arg[1], file) }, case HASH:
LIST, func() { _list_import(m, arg[0], arg[1], file) }, _hash_prunes(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...)
) case LIST:
_list_prunes(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...)
}
}},
EXPORT: {Name: "export key sub type file", Help: "导出", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch file := _file_name(m, arg...); arg[2] {
case ZONE:
_zone_export(m, arg[0], _domain_chain(m, arg[1]), file)
case HASH:
_hash_export(m, arg[0], _domain_chain(m, arg[1]), file)
case LIST:
_list_export(m, arg[0], _domain_chain(m, arg[1]), file)
}
}},
IMPORT: {Name: "import key sub type file", Help: "导入", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch file := _file_name(m, arg...); arg[2] {
case ZONE:
_zone_import(m, arg[0], _domain_chain(m, arg[1]), file)
case HASH:
_hash_import(m, arg[0], _domain_chain(m, arg[1]), file)
case LIST:
_list_import(m, arg[0], _domain_chain(m, arg[1]), file)
}
}}, }},
}} }}
func init() { func init() {
ice.Index.Register(Index, nil, INPUTS, INSERT, DELETE, MODIFY, SELECT, PRUNES, EXPORT, IMPORT, PLUGIN, RENDER, ENGINE, SEARCH) ice.Index.Register(Index, nil,
} INSERT, DELETE, MODIFY, SELECT,
func init() { INPUTS, PRUNES, EXPORT, IMPORT,
ice.Module(MDB, SEARCH, ENGINE, PLUGIN, RENDER,
HashInputs, HashCreate, HashRemove, func(m *ice.Message) { HashPrunes(m, nil) }, HashModify, HashSelect,
ZoneInputs, ZoneCreate, ZoneRemove, ZoneInsert, ZoneModify, ZoneSelect,
) )
} }
func AutoConfig(arg ...Any) *ice.Action {
return &ice.Action{Hand: func(m *ice.Message, args ...string) {
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(arg...)}
} else {
kit.For(kit.Dict(arg...), func(k string, v Any) { Config(m, k, v) })
}
if cmd := m.Target().Commands[m.CommandKey()]; cmd == nil {
return
} else {
s := Config(m, SHORT)
kit.If(s == "" || s == UNIQ || strings.Contains(s, ","), func() { s = HASH })
if cmd.Name == "" {
cmd.Name = kit.Format("%s %s auto", m.CommandKey(), s)
cmd.List = ice.SplitCmd(cmd.Name, cmd.Actions)
}
add := func(list []string) (inputs []Any) {
kit.For(list, func(k string) {
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID, ENABLE, DISABLE), func() {
inputs = append(inputs, k+kit.Select("", FOREACH, strings.Contains(s, k)))
})
})
return
}
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(HashField(m)))...) })
return
if cmd.Actions[INSERT] != nil {
kit.If(cmd.Meta[INSERT] == nil, func() { m.Design(INSERT, "", add(kit.Simple(Config(m, SHORT), kit.Split(ListField(m))))...) })
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(Config(m, SHORT)))...) })
} else if cmd.Actions[CREATE] != nil {
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(HashField(m)))...) })
}
}
}}
}
func ImportantZoneAction(arg ...Any) ice.Actions {
return ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE) }},
}, ZoneAction(arg...))
}
func ImportantHashAction(arg ...Any) ice.Actions {
return ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE) }},
}, HashAction(arg...))
}
func saveImportant(m *ice.Message, key, sub string, arg ...string) {
if m.Option("skip.important") == ice.TRUE {
return
}
kit.If(m.Conf(key, kit.Keys(META, IMPORTANT)) == ice.TRUE, func() { ice.SaveImportant(m, arg...) })
}

7
base/mdb/mdb.shy Normal file
View File

@ -0,0 +1,7 @@
chapter "mdb"
field "插件" mdb.plugin
field "渲染" mdb.render
field "引擎" mdb.engine
field "搜索" mdb.search

View File

@ -1,7 +1,35 @@
package mdb package mdb
import ice "shylinux.com/x/icebergs" import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const PLUGIN = "plugin" const PLUGIN = "plugin"
func init() { Index.MergeCommands(ice.Commands{PLUGIN: {Help: "插件", Actions: RenderAction()}}) } func init() {
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
PLUGIN: {Name: PLUGIN, Help: "插件", Value: kit.Data(SHORT, TYPE, FIELD, "time,type,name,text")},
}, Commands: map[string]*ice.Command{
PLUGIN: {Name: "plugin type name text auto", Help: "插件", Action: map[string]*ice.Action{
CREATE: {Name: "create type name text", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
m.Option(NAME, kit.Select(m.Option(TYPE), m.Option(NAME)))
m.Option(TYPE, kit.Ext(m.Option(TYPE)))
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, m.OptionSimple("type,name,text"))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 1 {
m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg, func(value map[string]interface{}) {
m.Cmdy(kit.Keys(value[TEXT], value[NAME]), m.CommandKey(), arg[0], arg[1], kit.Select("", arg, 2), kit.Slice(arg, 3))
})
return
}
if HashSelect(m, arg...); len(arg) == 0 {
m.Sort(TYPE)
} else if len(arg) == 1 {
m.DisplayStory("json.js")
m.Echo(kit.Formats(m.Confv(m.Append(NAME), "meta.plug")))
}
}},
}})
}

View File

@ -7,23 +7,29 @@ import (
const RENDER = "render" const RENDER = "render"
func init() { Index.MergeCommands(ice.Commands{RENDER: {Help: "渲染", Actions: RenderAction()}}) } func init() {
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
func RenderAction(arg ...ice.Any) ice.Actions { RENDER: {Name: RENDER, Help: "渲染", Value: kit.Data(SHORT, TYPE, FIELD, "time,type,name,text")},
return ice.MergeActions(ice.Actions{ice.CTX_INIT: AutoConfig(SHORT, TYPE, FIELD, "time,type,name,text", arg), }, Commands: map[string]*ice.Command{
CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) { Config(m, SHORT, TYPE); HashCreate(m) }}, RENDER: {Name: "render type name text auto", Help: "渲染", Action: map[string]*ice.Action{
SELECT: {Name: "select type name text auto create", Hand: func(m *ice.Message, arg ...string) { CREATE: {Name: "create type name text", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
if len(arg) < 2 || arg[0] == "" { m.Option(NAME, kit.Select(m.Option(TYPE), m.Option(NAME)))
HashSelect(m, arg...) m.Option(TYPE, kit.Ext(m.Option(TYPE)))
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, m.OptionSimple("type,name,text"))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 1 {
m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg, func(value map[string]interface{}) {
m.Cmdy(kit.Keys(value[TEXT], value[NAME]), m.CommandKey(), arg[0], arg[1], kit.Select("", arg, 2), kit.Slice(arg, 3))
})
return return
} }
m.OptionDefault(ice.MSG_FIELDS, kit.Select("type,name,text", arg, 2)) if HashSelect(m, arg...); len(arg) == 0 {
kit.For(kit.Split(arg[0]), func(k string) { m.Sort(TYPE)
HashSelects(m.Spawn(), k).Table(func(value ice.Maps) { } else if len(arg) == 1 {
m.Cmdy(kit.Keys(value[TEXT], value[NAME]), m.CommandKey(), k, arg[1], kit.Select("", arg, 2), kit.Slice(arg, 3)) m.DisplayStory("json.js")
}) m.Echo(kit.Formats(m.Confv(m.Append(NAME), "meta.plug")))
}) }
m.Sort(m.OptionFields()) }},
}}, }})
}, ClearOnExitHashAction())
} }

View File

@ -8,24 +8,26 @@ import (
const SEARCH = "search" const SEARCH = "search"
func init() { func init() {
Index.MergeCommands(ice.Commands{SEARCH: {Help: "搜索", Actions: RenderAction()}}) Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) ice.Handler { SEARCH: {Name: SEARCH, Help: "搜索", Value: kit.Data(SHORT, TYPE, FIELD, "time,type,name,text")},
if sub == SEARCH { }, Commands: map[string]*ice.Command{
return func(m *ice.Message, arg ...string) { m.Cmd(sub, CREATE, m.CommandKey(), m.PrefixKey()) } SEARCH: {Name: "search type name text auto", Help: "搜索", Action: map[string]*ice.Action{
} CREATE: {Name: "create type name text", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
return nil m.Option(NAME, kit.Select(m.Option(TYPE), m.Option(NAME)))
m.Option(TYPE, kit.Ext(m.Option(TYPE)))
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, m.OptionSimple("type,name,text"))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 1 {
m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg, func(value map[string]interface{}) {
m.OptionFields(kit.Select("ctx,cmd,type,name,text", kit.Select(m.OptionFields())))
m.Cmdy(kit.Keys(value[TEXT], value[NAME]), m.CommandKey(), arg[0], arg[1], kit.Select("", arg, 2), kit.Slice(arg, 3))
}) })
return
} }
func IsSearchPreview(m *ice.Message, arg []string, cb ...func() []string) bool { if HashSelect(m, arg...); len(arg) == 0 {
if arg[0] == FOREACH && arg[1] == "" { m.Sort(TYPE)
for _, cb := range cb {
if cb != nil {
if args := cb(); len(args) > 0 {
m.PushSearch(TYPE, kit.Select("", args, 0), NAME, kit.Select("", args, 1), TEXT, kit.Select("", args, 2))
} }
} }},
} }})
return true
}
return false
} }

View File

@ -8,118 +8,106 @@ import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
"shylinux.com/x/toolkits/miss"
) )
func _zone_meta(m *ice.Message, prefix, chain, key string) string {
defer RLock(m, prefix)()
return m.Conf(prefix, kit.Keys(chain, kit.Keym(key)))
}
func _zone_fields(m *ice.Message) []string { func _zone_fields(m *ice.Message) []string {
return kit.Split(kit.Select(ZONE_FIELD, m.OptionFields())) return kit.Split(kit.Select("zone,id,time,type,name,text", m.OptionFields()))
}
func _zone_inputs(m *ice.Message, prefix, chain, zone string, field, value string) {
if field == _zone_meta(m, prefix, chain, SHORT) {
_hash_inputs(m, prefix, chain, field, value)
return
}
h := _hash_select_field(m, prefix, chain, zone, HASH)
_list_inputs(m, prefix, kit.Keys(chain, HASH, h), field, value)
}
func _zone_insert(m *ice.Message, prefix, chain, zone string, arg ...string) {
h := _hash_select_field(m, prefix, chain, zone, HASH)
if h == "" {
h = _hash_insert(m, prefix, chain, kit.Select(ZONE, _zone_meta(m, prefix, chain, SHORT)), zone)
}
m.Assert(h != "")
_list_insert(m, prefix, kit.Keys(chain, HASH, h), arg...)
}
func _zone_modify(m *ice.Message, prefix, chain, zone, id string, arg ...string) {
h := _hash_select_field(m, prefix, chain, zone, HASH)
m.Assert(h != "")
_list_modify(m, prefix, kit.Keys(chain, HASH, h), ID, id, arg...)
} }
func _zone_select(m *ice.Message, prefix, chain, zone string, id string) { func _zone_select(m *ice.Message, prefix, chain, zone string, id string) {
if zone == "" { if zone == RANDOM {
_hash_select(m, prefix, chain, HASH, FOREACH)
return
} else if zone == RANDOM {
zone = RANDOMS zone = RANDOMS
} }
defer m.SortIntR(ID)
fields := _zone_fields(m) fields := _zone_fields(m)
defer RLock(m, prefix)() cb := m.OptionCB(SELECT)
Richs(m, prefix, chain, kit.Select(FOREACH, zone), func(key string, val Map) { m.Richs(prefix, chain, kit.Select(FOREACH, zone), func(key string, val map[string]interface{}) {
chain := kit.Keys(chain, HASH, key) if val = kit.GetMeta(val); zone == "" {
Grows(m, prefix, chain, ID, id, func(value ice.Map) { if m.OptionFields() == DETAIL {
_mdb_select(m, m.OptionCB(""), key, value, fields, val) m.Push(DETAIL, val)
} else {
m.Push(key, val, fields)
}
return
}
m.Grows(prefix, kit.Keys(chain, HASH, key), ID, id, func(index int, value map[string]interface{}) {
switch value = kit.GetMeta(value); cb := cb.(type) {
case func(string, []string, map[string]interface{}, map[string]interface{}):
cb(key, fields, value, val)
case func(string, map[string]interface{}, map[string]interface{}):
cb(key, value, val)
case func(string, map[string]interface{}):
cb(key, value)
case func(map[string]interface{}):
cb(value)
case func(map[string]string):
res := map[string]string{}
for k, v := range value {
res[k] = kit.Format(v)
}
cb(res)
default:
if m.FieldsIsDetail() {
m.Push(DETAIL, value)
} else {
m.Push(key, value, fields, val)
}
}
}) })
m.StatusTimeCountTotal(kit.Value(val, "meta.count"), "step", "0")
}) })
} }
func _zone_export(m *ice.Message, prefix, chain, file string) { func _zone_export(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() { f, p, e := kit.Create(kit.Keys(file, CSV))
return
}
defer Lock(m, prefix)()
if len(Confm(m, prefix, kit.Keys(chain, HASH))) == 0 {
return
}
f, p, e := miss.CreateFile(kit.Keys(file, CSV))
m.Assert(e) m.Assert(e)
defer f.Close() defer f.Close()
defer m.Echo(p)
w := csv.NewWriter(f) w := csv.NewWriter(f)
defer w.Flush() defer w.Flush()
head := kit.AddUniq(_zone_fields(m), EXTRA)
w.Write(head) fields := _zone_fields(m)
fields = append(fields, EXTRA)
w.Write(fields)
count := 0 count := 0
for _, key := range kit.SortedKey(m.Confv(prefix, kit.Keys(chain, HASH))) { m.Richs(prefix, chain, FOREACH, func(key string, val map[string]interface{}) {
Richs(m, prefix, chain, key, func(key string, val ice.Map) {
val = kit.GetMeta(val) val = kit.GetMeta(val)
chain := kit.Keys(chain, HASH, key)
Grows(m, prefix, chain, "", "", func(value ice.Map) { m.Grows(prefix, kit.Keys(chain, HASH, key), "", "", func(index int, value map[string]interface{}) {
value = kit.GetMeta(value) value = kit.GetMeta(value)
w.Write(kit.Simple(head, func(k string) string {
return kit.Select(kit.Format(kit.Value(val, k)), kit.Format(kit.Value(value, k))) list := []string{}
})) for _, k := range fields {
list = append(list, kit.Select(kit.Format(kit.Value(val, k)), kit.Format(kit.Value(value, k))))
}
w.Write(list)
count++ count++
}) })
}) })
m.Conf(prefix, kit.Keys(chain, HASH, key, LIST), "")
m.Conf(prefix, kit.Keys(chain, HASH, key, META, COUNT), "") m.Log_EXPORT(KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
} m.Conf(prefix, kit.Keys(chain, HASH), "")
kit.If(count == 0, func() { os.Remove(p) }) m.Echo(p)
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
} }
func _zone_import(m *ice.Message, prefix, chain, file string) { func _zone_import(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() { f, e := os.Open(kit.Keys(file, CSV))
return m.Assert(e)
}
defer Lock(m, prefix)()
f, e := miss.OpenFile(kit.Keys(file, CSV))
if e != nil && !ice.Info.Important {
return
} else if m.WarnNotFound(e) {
return
}
defer f.Close() defer f.Close()
r := csv.NewReader(f) r := csv.NewReader(f)
head, _ := r.Read() head, _ := r.Read()
zkey := kit.Select(head[0], m.OptionFields())
list := ice.Maps{}
times := ice.Maps{}
kit.For(m.Confv(prefix, kit.Keys(chain, HASH)), func(key string, value ice.Any) {
times[key] = kit.Format(kit.Value(value, kit.Keys(META, TIME)))
})
count := 0 count := 0
list := map[string]string{}
zkey := kit.Select(head[0], m.OptionFields())
for { for {
line, e := r.Read() line, e := r.Read()
if e != nil { if e != nil {
break break
} }
zone, data := "", kit.Dict()
zone := ""
data := kit.Dict()
for i, k := range head { for i, k := range head {
switch k { switch k {
case zkey: case zkey:
@ -127,163 +115,105 @@ func _zone_import(m *ice.Message, prefix, chain, file string) {
case ID: case ID:
continue continue
case EXTRA: case EXTRA:
if line[i] != "" {
kit.Value(data, k, kit.UnMarshal(line[i])) kit.Value(data, k, kit.UnMarshal(line[i]))
}
default: default:
kit.Value(data, k, line[i]) kit.Value(data, k, line[i])
} }
} }
if list[zone] == "" { if list[zone] == "" {
list[zone] = Rich(m, prefix, chain, kit.Data(zkey, zone)) list[zone] = m.Rich(prefix, chain, kit.Data(zkey, zone))
kit.If(times[list[zone]], func(t string) { m.Confv(prefix, kit.Keys(chain, HASH, list[zone], META, TIME), t) })
} }
func() { chain := kit.Keys(chain, HASH, list[zone]); Grow(m, prefix, chain, data) }()
m.Grow(prefix, kit.Keys(chain, HASH, list[zone]), data)
count++ count++
} }
m.Logs(IMPORT, KEY, path.Join(prefix, chain), FILE, kit.Keys(file, CSV), COUNT, count)
m.Log_IMPORT(KEY, path.Join(prefix, chain), COUNT, count)
m.Echo("%d", count) m.Echo("%d", count)
} }
const (
ZONE_FIELD = "time,id,type,name,text"
)
const ZONE = "zone" const ZONE = "zone"
func ZoneConfig(arg ...Any) *ice.Action { func ZoneAction(args ...interface{}) map[string]*ice.Action {
return &ice.Action{Hand: func(m *ice.Message, args ...string) { _zone := func(m *ice.Message) string { return kit.Select(ZONE, m.Config(SHORT)) }
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(arg...)} return ice.SelectAction(map[string]*ice.Action{ice.CTX_INIT: AutoConfig(args...),
} else { INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
kit.For(kit.Dict(arg...), func(k string, v Any) { Config(m, k, v) }) arg[0] = strings.TrimPrefix(arg[0], "extra.")
arg[0] = kit.Select(arg[0], m.Config(kit.Keys(ALIAS, arg[0])))
switch arg[0] {
case ice.POD:
m.Cmdy("route")
case ice.CTX:
m.Cmdy("context")
case ice.CMD:
m.Cmdy("context", kit.Select(m.Option(ice.CTX), m.Option(kit.Keys(EXTRA, ice.CTX))), "command")
case ice.ARG:
case "index":
m.OptionFields(arg[0])
m.Cmdy("command", SEARCH, "command", kit.Select("", arg, 1))
case _zone(m):
m.Cmdy(INPUTS, m.PrefixKey(), "", HASH, arg)
default:
m.Cmdy(INPUTS, m.PrefixKey(), "", ZONE, m.Option(_zone(m)), arg)
} }
if cmd := m.Target().Commands[m.CommandKey()]; cmd == nil { }},
return CREATE: {Name: "create zone", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
} else { m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg)
s := kit.Select(ZONE, Config(m, SHORT)) }},
kit.If(s == UNIQ || strings.Contains(s, ","), func() { s = HASH }) REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
if cmd.Name == "" { m.Cmdy(DELETE, m.PrefixKey(), "", HASH, m.OptionSimple(_zone(m)), arg)
cmd.Name = kit.Format("%s %s id auto", m.CommandKey(), s) }},
cmd.List = ice.SplitCmd(cmd.Name, cmd.Actions) INSERT: {Name: "insert zone type=go name=hi text=hello", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
arg = m.OptionSimple(_zone(m), m.Config(FIELD))
} }
add := func(list []string) (inputs []Any) { m.Cmdy(INSERT, m.PrefixKey(), "", HASH, _zone(m), arg[1])
kit.For(list, func(k string) { m.Cmdy(INSERT, m.PrefixKey(), "", ZONE, m.Option(_zone(m)), arg[2:])
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID), func() { }},
inputs = append(inputs, k+kit.Select("", FOREACH, strings.Contains(s, k))) MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, m.Option(_zone(m)), m.Option(ID), arg)
}},
PLUGIN: {Name: "plugin extra.pod extra.ctx extra.cmd extra.arg", Help: "插件", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, m.Option(_zone(m)), m.Option(ID), arg)
}},
EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
m.Option(ice.CACHE_LIMIT, "-1")
m.OptionFields(_zone(m), m.Config(FIELD))
m.Cmdy(EXPORT, m.PrefixKey(), "", ZONE)
}},
IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(_zone(m))
m.Cmdy(IMPORT, m.PrefixKey(), "", ZONE)
}},
PREV: {Name: "prev", Help: "上一页", Hand: func(m *ice.Message, arg ...string) {
PrevPage(m, arg[0], arg[1:]...)
}},
NEXT: {Name: "next", Help: "下一页", Hand: func(m *ice.Message, arg ...string) {
NextPageLimit(m, arg[0], arg[1:]...)
}},
SELECT: {Name: "select", Help: "列表", Hand: func(m *ice.Message, arg ...string) {
ZoneSelect(m, arg...)
}},
}) })
})
return
}
kit.If(cmd.Meta[INSERT] == nil, func() { m.Design(INSERT, "", add(kit.Simple(kit.Split(s), kit.Split(ZoneField(m))))...) })
kit.If(cmd.Meta[CREATE] == nil, func() { m.Design(CREATE, "", add(kit.Split(kit.Select(s, Config(m, FIELD))))...) })
}
}}
}
func ZoneAction(arg ...ice.Any) ice.Actions {
return ice.Actions{ice.CTX_INIT: ZoneConfig(append(kit.List(SHORT, ZONE, FIELDS, ZONE_FIELD), arg...)...),
INPUTS: {Hand: func(m *ice.Message, arg ...string) { ZoneInputs(m, arg) }},
CREATE: {Hand: func(m *ice.Message, arg ...string) { ZoneCreate(m, arg) }},
REMOVE: {Hand: func(m *ice.Message, arg ...string) { ZoneRemove(m, arg) }},
INSERT: {Hand: func(m *ice.Message, arg ...string) { ZoneInsert(m, arg) }},
MODIFY: {Hand: func(m *ice.Message, arg ...string) { ZoneModify(m, arg) }},
SELECT: {Hand: func(m *ice.Message, arg ...string) { ZoneSelect(m, arg...) }},
EXPORT: {Hand: func(m *ice.Message, arg ...string) { ZoneExport(m, arg) }},
IMPORT: {Hand: func(m *ice.Message, arg ...string) { ZoneImport(m, arg) }},
}
}
func ExportZoneAction(arg ...ice.Any) ice.Actions {
return ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { Config(m, IMPORTANT, ice.TRUE); ZoneImport(m, arg) }},
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.OptionFields(""); ZoneExport(m, arg) }},
}, ZoneAction(arg...))
}
func PageZoneAction(arg ...ice.Any) ice.Actions {
return ice.MergeActions(ice.Actions{
SELECT: {Hand: func(m *ice.Message, arg ...string) { PageZoneSelect(m, arg...) }},
PREV: {Hand: func(m *ice.Message, arg ...string) { PrevPageLimit(m, arg[0], arg[1:]...) }},
NEXT: {Hand: func(m *ice.Message, arg ...string) { NextPage(m, arg[0], arg[1:]...) }},
}, ZoneAction(arg...))
}
func ZoneKey(m *ice.Message) string {
if m.Option(HASH) != "" {
return HASH
}
return ZoneShort(m)
}
func ZoneShort(m *ice.Message) string {
return kit.Select(ZONE, Config(m, SHORT), Config(m, SHORT) != UNIQ)
}
func ZoneField(m *ice.Message) string { return kit.Select(ZONE_FIELD, Config(m, FIELDS)) }
func ZoneInputs(m *ice.Message, arg ...Any) {
m.Cmdy(INPUTS, m.PrefixKey(), "", ZONE, m.Option(ZoneKey(m)), arg)
}
func ZoneCreate(m *ice.Message, arg ...Any) { m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg) }
func ZoneRemove(m *ice.Message, arg ...Any) {
if args := kit.Simple(arg...); len(args) == 0 {
arg = append(arg, m.OptionSimple(ZoneKey(m)))
} else if len(args) == 1 {
arg = kit.List(ZoneKey(m), args[0])
}
m.Cmdy(DELETE, m.PrefixKey(), "", HASH, arg)
}
func ZoneInsert(m *ice.Message, arg ...Any) {
if args := kit.Simple(arg...); len(args) == 0 {
m.Cmdy(INSERT, m.PrefixKey(), "", ZONE, m.Option(ZoneShort(m)), m.OptionSimple(ZoneField(m)))
} else if args[0] == ZoneKey(m) {
m.Cmdy(INSERT, m.PrefixKey(), "", ZONE, args[1:])
} else {
m.Cmdy(INSERT, m.PrefixKey(), "", ZONE, arg)
}
}
func ZoneModify(m *ice.Message, arg ...Any) {
if args := kit.Simple(arg...); m.Option(ID) == "" {
HashModify(m, arg...)
} else if args[0] == HASH || args[0] == ZoneShort(m) {
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, args[1], args[3], args[4:])
} else {
m.Cmdy(MODIFY, m.PrefixKey(), "", ZONE, m.Option(ZoneKey(m)), m.Option(ID), arg)
}
} }
func ZoneSelect(m *ice.Message, arg ...string) *ice.Message { func ZoneSelect(m *ice.Message, arg ...string) *ice.Message {
arg = kit.Slice(arg, 0, 2) m.Fields(len(arg), kit.Fields(TIME, m.Config(SHORT), COUNT), m.Config(FIELD))
short, field, fields := Config(m, SHORT), Config(m, FIELD), ZoneField(m) if m.Cmdy(SELECT, m.PrefixKey(), "", ZONE, arg); kit.Select("", arg, 0) == "" {
m.Fields(len(arg), kit.Select(kit.Fields(TIME, short, COUNT), field), fields) m.Sort(m.Config(SHORT))
if m.Cmdy(SELECT, m.PrefixKey(), "", ZONE, arg, logs.FileLineMeta(-1)); len(arg) == 0 { m.PushAction(REMOVE)
m.Sort(short).PushAction(REMOVE).Action(CREATE)
} else if len(arg) == 1 {
m.Action(INSERT)
} else {
sortByField(m, fields)
} }
m.StatusTimeCount()
return m return m
} }
func ZoneExport(m *ice.Message, arg ...Any) {
kit.If(m.OptionFields() == "", func() { m.OptionFields(Config(m, SHORT), ZoneField(m)) })
m.Cmdy(EXPORT, m.PrefixKey(), "", ZONE, arg)
}
func ZoneImport(m *ice.Message, arg ...Any) {
m.Cmdy(IMPORT, m.PrefixKey(), "", ZONE, arg)
}
func ZoneSelects(m *ice.Message, arg ...string) *ice.Message {
m.OptionFields(ZoneField(m))
return ZoneSelect(m, arg...)
}
func ZoneSelectAll(m *ice.Message, arg ...string) *ice.Message { func ZoneSelectAll(m *ice.Message, arg ...string) *ice.Message {
m.Option(CACHE_LIMIT, "-1") m.Option(ice.CACHE_LIMIT, "-1")
return ZoneSelect(m, arg...) return ZoneSelect(m, arg...)
} }
func ZoneSelectCB(m *ice.Message, zone string, cb Any) *ice.Message { func ZoneSelectCB(m *ice.Message, zone string, cb interface{}) *ice.Message {
m.OptionCB(SELECT, cb) m.OptionCB(SELECT, cb)
m.Option(CACHE_LIMIT, "-1") m.Option(ice.CACHE_LIMIT, "-1")
return ZoneSelect(m, zone) return ZoneSelect(m, zone)
} }
func PageZoneSelect(m *ice.Message, arg ...string) *ice.Message {
OptionPages(m, kit.Slice(arg, 2)...)
arg = kit.Slice(arg, 0, 2)
if ZoneSelect(m, arg...); len(arg) == 0 {
m.Action(CREATE)
} else if len(arg) == 1 {
m.Action(INSERT, PAGE)
}
return m
}

View File

@ -1,11 +1,9 @@
package nfs package nfs
import ( import (
"bufio"
"bytes" "bytes"
"encoding/csv"
"encoding/json"
"io" "io"
"io/ioutil"
"os" "os"
"path" "path"
"strings" "strings"
@ -16,221 +14,173 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _cat_find(m *ice.Message, p string) (io.ReadCloser, error) { type ReadCloser struct {
r io.Reader
}
func (r *ReadCloser) Read(buf []byte) (int, error) {
return r.r.Read(buf)
}
func (r *ReadCloser) Close() error {
if c, ok := r.r.(io.Closer); ok {
return c.Close()
}
return nil
}
func NewReadCloser(r io.Reader) *ReadCloser {
return &ReadCloser{r: r}
}
var rewriteList = []interface{}{}
func AddRewrite(cb interface{}) { rewriteList = append(rewriteList, cb) }
func _cat_right(m *ice.Message, name string) bool {
return aaa.RoleRight(m, m.Option(ice.MSG_USERROLE), strings.Split(name, ice.PS)...)
}
func _cat_find(m *ice.Message, name string) io.ReadCloser {
if m.Option(CAT_CONTENT) != "" { if m.Option(CAT_CONTENT) != "" {
return NewReadCloser(bytes.NewBufferString(m.Option(CAT_CONTENT))), nil return NewReadCloser(bytes.NewBufferString(m.Option(CAT_CONTENT)))
} }
return OpenFile(m, path.Join(m.Option(DIR_ROOT), p))
// 模块回调
for _, h := range rewriteList {
switch h := h.(type) {
case func(m *ice.Message, name string) io.ReadCloser:
if r := h(m, name); r != nil {
return r
} }
func _cat_hash(m *ice.Message, p string) (h string) { case func(m *ice.Message, name string) []byte:
Open(m, p, func(r io.Reader) { h = kit.Hashs(r) }) if b := h(m, name); b != nil {
return return NewReadCloser(bytes.NewBuffer(b))
} }
func _cat_line(m *ice.Message, p string) (n int) { case func(m *ice.Message, name string) string:
Open(m, p, func(r io.Reader) { kit.For(r, func(s string) { n++ }) }) if s := h(m, name); s != "" {
return return NewReadCloser(bytes.NewBufferString(s))
} }
func _cat_list(m *ice.Message, p string) {
if m.Option(CAT_CONTENT) == "" && !kit.IsIn(kit.Ext(p), "css", "js") && !aaa.Right(m, path.Join(m.Option(DIR_ROOT), p)) {
return
} }
f, e := _cat_find(m, p) }
if m.WarnNotFound(e, FILE, p) {
return // 本地文件
if f, e := os.Open(path.Join(m.Option(DIR_ROOT), name)); e == nil {
return f
}
return nil
}
func _cat_list(m *ice.Message, name string) {
if m.Warn(!_cat_right(m, name), ice.ErrNotRight) {
return // 没有权限
}
f := _cat_find(m, name)
if m.Warn(f == nil, ice.ErrNotFound, name) {
return // 没有文件
} }
defer f.Close() defer f.Close()
switch cb := m.OptionCB("").(type) {
switch cb := m.OptionCB(CAT).(type) {
case func(string, int) string: case func(string, int) string:
list := []string{} list := []string{}
kit.For(f, func(s string, i int) { list = append(list, cb(s, i)) }) for bio, i := bufio.NewScanner(f), 0; bio.Scan(); i++ {
m.Echo(strings.Join(list, ice.NL) + ice.NL) list = append(list, cb(bio.Text(), i))
case func([]string, string) string:
list := []string{}
kit.For(f, func(s string, i int) { list = append(list, cb(kit.Split(s), s)) })
m.Echo(strings.Join(list, ice.NL) + ice.NL)
case func(string, int):
kit.For(f, cb)
case func(string):
kit.For(f, cb)
case func([]string, string):
kit.For(f, cb)
case func([]string):
kit.For(f, cb)
case nil:
if b, e := ioutil.ReadAll(f); !m.WarnNotFound(e) {
m.Echo(string(b)).StatusTime(FILE, p, SIZE, len(b))
} }
m.Echo(strings.Join(list, ice.NL) + ice.NL)
case func(string, int):
for bio, i := bufio.NewScanner(f), 0; bio.Scan(); i++ {
cb(bio.Text(), i)
}
case func(string):
for bio := bufio.NewScanner(f); bio.Scan(); {
cb(bio.Text())
}
case func([]string, string):
for bio := bufio.NewScanner(f); bio.Scan(); {
cb(kit.Split(bio.Text()), bio.Text())
}
default: default:
m.ErrorNotImplement(cb) buf := make([]byte, ice.MOD_BUFS)
for begin := 0; true; {
if n, e := f.Read(buf[begin:]); !m.Warn(e, ice.ErrNotFound, name) {
m.Log_IMPORT(FILE, name, SIZE, n)
if begin += n; begin < len(buf) {
buf = buf[:begin]
break
}
buf = append(buf, make([]byte, ice.MOD_BUFS)...)
}
}
m.Echo(string(buf))
} }
} }
const ( const (
CAT_CONTENT = "cat_content" CAT_CONTENT = "cat_content"
CONFIGURE = "configure" TEMPLATE = "template"
STDIO = "stdio"
TAGS = "tags"
MODULE = "module"
SOURCE = "source" SOURCE = "source"
TARGET = "target"
BINARY = "binary" BINARY = "binary"
SCRIPT = "script" TARGET = "target"
FORMAT = "format"
TRANS = "trans"
CLONE = "clone"
REPOS = "repos"
REMOTE = "remote"
ORIGIN = "origin"
COMMIT = "commit"
BRANCH = "branch"
MASTER = "master" MASTER = "master"
VERSION = "version" BRANCH = "branch"
COMPILE = "compile" REPOS = "repos"
LOAD = "load"
TAGS = "tags"
) )
const ( const (
HTML = ice.HTML HTML = ice.HTML
CSS = ice.CSS CSS = ice.CSS
SVG = ice.SVG
JS = ice.JS JS = ice.JS
GO = ice.GO GO = ice.GO
SH = ice.SH SH = ice.SH
SHY = ice.SHY
CSV = ice.CSV CSV = ice.CSV
JSON = ice.JSON JSON = ice.JSON
MOD = "mod"
PROTO = "proto"
YAML = "yaml"
CONF = "conf"
XML = "xml"
YML = "yml"
TXT = "txt" TXT = "txt"
MD = "md" SHY = "shy"
PY = "py" SVG = "svg"
IMAGE = "image" PWD = "./"
JPEG = "jpeg"
JPG = "jpg"
PNG = "png"
MP4 = "mp4"
MOV = "mov"
PDF = "pdf"
DF = ice.DF
PS = ice.PS
PT = ice.PT
) )
const (
PATH = "path"
FILE = "file"
LINE = "line"
SIZE = "size"
)
const CAT = "cat" const CAT = "cat"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CAT: {Name: "cat path auto", Help: "文件", Actions: ice.MergeActions(ice.Actions{ CAT: {Name: CAT, Help: "文件", Value: kit.Data(
ice.CTX_INIT: mdb.AutoConfig(SOURCE, kit.DictList( SOURCE, kit.Dict(
HTML, CSS, JS, GO, SH, PY, SHY, CSV, JSON, CONFIGURE, PROTO, YAML, CONF, XML, YML, TXT, MD, strings.ToLower(ice.LICENSE), strings.ToLower(ice.MAKEFILE), HTML, ice.TRUE, CSS, ice.TRUE, JS, ice.TRUE, GO, ice.TRUE, SH, ice.TRUE, CSV, ice.TRUE, JSON, ice.TRUE,
)), "md", ice.TRUE, "shy", ice.TRUE, "makefile", ice.TRUE, "license", ice.TRUE,
}, DIR), Hand: func(m *ice.Message, arg ...string) { "conf", ice.TRUE, "yaml", ice.TRUE, "yml", ice.TRUE,
if !DirList(m, arg...) { "py", ice.TRUE, "txt", ice.TRUE,
if arg[0] != "" { ),
m.Logs(FIND, m.OptionSimple(DIR_ROOT), FILE, arg[0]) )},
}, Commands: map[string]*ice.Command{
CAT: {Name: "cat path auto", Help: "文件", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(mdb.RENDER, mdb.CREATE, m.CommandKey(), m.PrefixKey())
}},
mdb.RENDER: {Name: "render type name text", Help: "渲染", Hand: func(m *ice.Message, arg ...string) {
_cat_list(m, path.Join(arg[2], arg[1]))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 || strings.HasSuffix(arg[0], ice.PS) {
m.Cmdy(DIR, arg)
return
}
if m.Option(DIR_ROOT) != "" {
m.Info("dir_root: %v", m.Option(DIR_ROOT))
} }
_cat_list(m, arg[0]) _cat_list(m, arg[0])
}
}}, }},
}) }})
}
func DirList(m *ice.Message, arg ...string) bool {
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) {
m.Cmdy(DIR, kit.Slice(arg, 0, 1))
return true
} else {
return false
}
}
func IsSourceFile(m *ice.Message, ext string) bool {
return mdb.Conf(m, Prefix(CAT), kit.Keym(SOURCE, ext)) == ice.TRUE
}
func OptionLoad(m *ice.Message, p string) *ice.Message {
Open(m, p, func(r io.Reader) {
var data ice.Any
m.Assert(json.NewDecoder(r).Decode(&data))
kit.For(data, func(k string, v ice.Any) { m.Optionv(k, v) })
})
return m
}
func Open(m *ice.Message, p string, cb ice.Any) {
if p == "" {
return
} else if strings.HasSuffix(p, PS) {
kit.If(p == PS, func() { p = "" })
if ls, e := ReadDir(m, p); !m.WarnNotFound(e) {
switch cb := cb.(type) {
case func([]os.FileInfo):
cb(ls)
case func(os.FileInfo):
kit.For(ls, cb)
case func(io.Reader, string):
kit.For(ls, func(s os.FileInfo) { kit.If(!s.IsDir(), func() { Open(m, path.Join(p, s.Name()), cb) }) })
default:
m.ErrorNotImplement(cb)
}
}
} else if f, e := OpenFile(m, p); !m.WarnNotFound(e, p) {
defer f.Close()
switch cb := cb.(type) {
case func(io.Reader, os.FileInfo):
s, _ := StatFile(m, p)
cb(f, s)
case func(io.Reader, string):
cb(f, p)
case func(io.Reader):
cb(f)
case func(string):
if b, e := ioutil.ReadAll(f); !m.WarnNotFound(e) {
cb(string(b))
}
default:
m.ErrorNotImplement(cb)
}
}
}
func ReadAll(m *ice.Message, r io.Reader) []byte {
if b, e := ioutil.ReadAll(r); !m.WarnNotFound(e) {
return b
}
return nil
}
func ReadFile(m *ice.Message, p string) (b []byte, e error) {
Open(m, p, func(r io.Reader) { b, e = ioutil.ReadAll(r) })
return
}
func Rewrite(m *ice.Message, p string, cb func(string) string) {
m.Cmd(SAVE, p, m.Cmdx(CAT, p, func(s string, i int) string { return cb(s) }))
}
func ScanCSV(m *ice.Message, file string, cb func([]string), arg ...string) {
f, e := OpenFile(m, file)
if m.Warn(e) {
return
}
r := csv.NewReader(f)
head, err := r.Read()
if err != nil {
return
}
index := []int{}
kit.If(len(arg) == 0, func() { arg = append(arg, head...) })
kit.For(arg, func(h string) { index = append(index, kit.IndexOf(head, h)) })
for {
data, err := r.Read()
if err != nil {
break
}
res := []string{}
kit.For(index, func(i int) { res = append(res, data[i]) })
cb(res)
}
} }

View File

@ -1,12 +1,13 @@
package nfs package nfs
import ( import (
"bufio"
"crypto/sha1"
"io/ioutil"
"os" "os"
"path" "path"
"regexp" "regexp"
"runtime"
"strings" "strings"
"time"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/aaa"
@ -14,314 +15,253 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _dir_size(m *ice.Message, p string) (n int) { func _dir_list(m *ice.Message, root string, name string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string) *ice.Message {
Open(m, p+PS, func(ls []os.FileInfo) { n = len(ls) }) if !_cat_right(m, path.Join(root, name)) {
return return m // 没有权限
} }
func _dir_hash(m *ice.Message, p string) (h string) {
list := []string{} if len(ice.Info.Pack) > 0 && m.Option(DIR_PACK) == ice.TRUE {
Open(m, p+PS, func(s os.FileInfo) { list = append(list, kit.Format("%s%d%s", s.Name(), s.Size(), s.ModTime())) }) for k, b := range ice.Info.Pack {
kit.If(len(list) > 0, func() { h = kit.Hashs(list) }) p := strings.TrimPrefix(k, root)
return "" if !strings.HasPrefix(p, name) {
} if p = strings.TrimPrefix(k, root+ice.PS); !strings.HasPrefix(p, name) {
func _dir_list(m *ice.Message, root string, dir string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string) (total int64, last time.Time) { if p = strings.TrimPrefix(k, ice.PS); !strings.HasPrefix(p, name) {
ls, _ := ReadDir(m, path.Join(root, dir))
if len(ls) == 0 {
if s, e := StatFile(m, path.Join(root, dir)); e == nil && !s.IsDir() {
Open(m, path.Dir(path.Join(root, dir))+PS, func(s os.FileInfo) { kit.If(s.Name() == path.Base(dir), func() { ls = append(ls, s) }) })
dir, deep = path.Dir(dir), false
}
}
for _, s := range ls {
if s.Name() == PT || s.Name() == ".." || strings.HasPrefix(s.Name(), PT) && dir_type != TYPE_ALL {
continue continue
} }
p, pp := path.Join(root, dir, s.Name()), path.Join(dir, s.Name()) }
isDir := s.IsDir() || kit.IsDir(p) && deep == false }
isBin := s.Mode().String()[3] == 'x' || kit.Ext(s.Name()) == "exe"
if !(dir_type == TYPE_BIN && (!isBin || isDir) || dir_type == TYPE_CAT && isDir || dir_type == TYPE_DIR && !isDir) && (dir_reg == nil || dir_reg.MatchString(s.Name())) { m.Debug("dir binpack %s", p)
switch cb := m.OptionCB("").(type) { for _, field := range fields {
case func(os.FileInfo, string): switch field {
cb(s, p) case PATH:
m.Push(field, p)
case SIZE:
m.Push(field, len(b))
default:
m.Push(field, "")
}
}
}
return m
}
list, e := ioutil.ReadDir(path.Join(root, name))
if e != nil { // 单个文件
ls, _ := ioutil.ReadDir(path.Dir(path.Join(root, name)))
for _, k := range ls {
if k.Name() == path.Base(name) {
list = append(list, k)
}
}
name = path.Dir(name)
}
// 文件排序
for i := 0; i < len(list)-1; i++ {
for j := i + 1; j < len(list); j++ {
if list[i].Name() > list[j].Name() {
list[i], list[j] = list[j], list[i]
}
}
}
for _, f := range list {
if f.Name() == ice.PT || f.Name() == ".." {
continue continue
case func(string): }
if strings.HasPrefix(f.Name(), ice.PT) && dir_type != TYPE_ALL {
continue
}
p := path.Join(root, name, f.Name())
if !(dir_type == TYPE_CAT && f.IsDir() || dir_type == TYPE_DIR && !f.IsDir()) && (dir_reg == nil || dir_reg.MatchString(f.Name())) {
switch cb := m.OptionCB(DIR).(type) {
case func(f os.FileInfo, p string):
cb(f, p)
continue
case func(p string):
cb(p) cb(p)
continue continue
case nil:
default:
m.ErrorNotImplement(cb)
} }
kit.If(s.ModTime().After(last), func() { last = s.ModTime() })
for _, field := range fields { for _, field := range fields {
switch field { switch field {
case mdb.TIME: case mdb.TIME:
m.Push(field, s.ModTime().Format(ice.MOD_TIME)) m.Push(field, f.ModTime().Format(ice.MOD_TIME))
case mdb.TYPE: case mdb.TYPE:
m.Push(field, kit.Select(CAT, DIR, isDir)) m.Push(field, kit.Select(CAT, DIR, f.IsDir()))
case TREE:
case "tree":
if level == 0 { if level == 0 {
m.Push(field, s.Name()) m.Push(field, f.Name())
} else { } else {
m.Push(field, strings.Repeat("| ", level-1)+"|-"+s.Name()) m.Push(field, strings.Repeat("| ", level-1)+"|-"+f.Name())
} }
case FULL: case "full":
m.Push(field, p+kit.Select("", PS, isDir)) m.Push(field, path.Join(root, name, f.Name())+kit.Select("", ice.PS, f.IsDir()))
case PATH: case PATH:
m.Push(field, pp+kit.Select("", PS, isDir)) m.Push(field, path.Join(name, f.Name())+kit.Select("", ice.PS, f.IsDir()))
case FILE: case FILE:
m.Push(field, s.Name()+kit.Select("", PS, isDir)) m.Push(field, f.Name()+kit.Select("", ice.PS, f.IsDir()))
case NAME: case mdb.NAME:
m.Push(field, s.Name()) m.Push(field, f.Name())
case SIZE: case SIZE:
if isDir { if f.IsDir() {
m.Push(field, _dir_size(m, p)) if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil {
m.Push(field, len(ls))
} else { } else {
m.Push(field, kit.FmtSize(s.Size())) m.Push(field, 0)
total += s.Size() }
} else {
m.Push(field, kit.FmtSize(f.Size()))
} }
case LINE: case LINE:
if isDir { if f.IsDir() {
m.Push(field, _dir_size(m, p)) if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil {
m.Push(field, len(ls))
} else { } else {
m.Push(field, _cat_line(m, p)) m.Push(field, 0)
}
} else {
nline := 0
if f, e := os.Open(p); m.Assert(e) {
defer f.Close()
for bio := bufio.NewScanner(f); bio.Scan(); nline++ {
bio.Text()
}
}
m.Push(field, nline)
} }
case mdb.HASH, "hashs": case mdb.HASH, "hashs":
h := "" var h [20]byte
if isDir { if f.IsDir() {
h = _dir_hash(m, p) if d, e := ioutil.ReadDir(p); m.Assert(e) {
} else { meta := []string{}
h = _cat_hash(m, p) for _, v := range d {
meta = append(meta, kit.Format("%s%d%s", v.Name(), v.Size(), v.ModTime()))
} }
m.Push(mdb.HASH, kit.Select(h[:6], h[:], field == mdb.HASH)) kit.Sort(meta)
h = sha1.Sum([]byte(strings.Join(meta, "")))
}
} else {
if f, e := ioutil.ReadFile(path.Join(name, f.Name())); m.Assert(e) {
h = sha1.Sum(f)
}
}
m.Push(mdb.HASH, kit.Select(kit.Format(h[:6]), kit.Format(h[:]), field == mdb.HASH))
case mdb.LINK: case mdb.LINK:
if isDir { m.PushDownload(mdb.LINK, kit.Select("", f.Name(), !f.IsDir()), path.Join(root, name, f.Name()))
m.Push(mdb.LINK, "")
} else {
if strings.Contains(p, "ice.windows") {
m.PushDownload(mdb.LINK, "ice.exe", p)
} else {
m.PushDownload(mdb.LINK, p)
}
}
case mdb.SHOW: case mdb.SHOW:
switch p := m.MergeLink(SHARE_LOCAL+p, ice.POD, m.Option(ice.MSG_USERPOD)); kit.Ext(s.Name()) { switch p := m.MergeURL2("/share/local/"+path.Join(name, f.Name()), ice.POD, m.Option(ice.MSG_USERPOD)); kit.Ext(f.Name()) {
case PNG, JPG: case "png", "jpg":
m.PushImages(field, p) m.PushImages(field, p)
case MP4: case "mp4":
m.PushVideos(field, p) m.PushVideos(field, p)
default: default:
m.Push(field, "") m.Push(field, "")
} }
case mdb.ACTION: case "action":
if m.IsCliUA() || m.Option(ice.MSG_USERROLE) == aaa.VOID { if m.IsCliUA() || m.Option(ice.MSG_USERROLE) == aaa.VOID {
break break
} }
m.PushButton(mdb.SHOW, "rename", TRASH) m.PushButton(kit.Select("", TRASH, !f.IsDir()))
default: default:
m.Push(field, "") m.Push(field, "")
} }
} }
} }
if deep && isDir {
switch s.Name() { if f.IsDir() && deep {
case "pluged", "node_modules": _dir_list(m, root, path.Join(name, f.Name()), level+1, deep, dir_type, dir_reg, fields)
continue
}
_total, _last := _dir_list(m, root, pp, level+1, deep, dir_type, dir_reg, fields)
if total += _total; _last.After(last) {
last = _last
} }
} }
return m
} }
func _dir_search(m *ice.Message, kind, name string) {
msg := _dir_list(m.Spawn(), PWD, "", 0, true, TYPE_BOTH, nil, kit.Split("time,type,name"))
msg.Table(func(index int, value map[string]string, head []string) {
if !strings.Contains(value[mdb.NAME], name) {
return return
} }
if value[mdb.TYPE] == CAT {
value[mdb.TYPE] = kit.Ext(value[mdb.NAME])
}
m.PushSearch(value)
})
}
func Dir(m *ice.Message, sort string) *ice.Message {
m.Option(DIR_TYPE, TYPE_DIR)
m.Copy(m.Cmd(DIR, PWD).Sort(sort))
m.Option(DIR_TYPE, TYPE_CAT)
m.Copy(m.Cmd(DIR, PWD).Sort(sort))
return m
}
func MkdirAll(m *ice.Message, p string) error {
m.Log_EXPORT("mkdir", "dir", p)
return os.MkdirAll(p, ice.MOD_DIR)
}
const ( const (
PWD = "./"
SRC = "src/"
ETC = "etc/"
BIN = "bin/"
VAR = "var/"
USR = "usr/"
SCAN = "scan"
GOWORK = "gowork"
PORTAL_GO = "portal.go"
PORTAL_JSON = "portal.json"
ETC_LOCAL_SH = "etc/local.sh"
ETC_CERT_KEY = "etc/cert/cert.key"
ETC_CERT_PEM = "etc/cert/cert.pem"
SRC_DOCUMENT = "src/document/"
SRC_PRIVATE = "src/private/"
SRC_MAIN_PNG = "src/main.png"
SRC_OPTION_GO = "src/option.go"
SRC_TEMPLATE = ice.SRC_TEMPLATE
USR_TOOLKITS = ice.USR_TOOLKITS
USR_ICEBERGS = ice.USR_ICEBERGS
USR_RELEASE = ice.USR_RELEASE
USR_PUBLISH = ice.USR_PUBLISH
USR_LOCAL = ice.USR_LOCAL
USR_LOCAL_WORK = ice.USR_LOCAL_WORK
USR_IMAGE = "usr/image/"
USR_MATERIAL = "usr/material/"
USR_LOCAL_IMAGE = "usr/local/image/"
USR_LEARNING_PORTAL = "usr/learning/portal/"
USR_MODULES = "usr/node_modules/"
USR_PACKAGE = "usr/package.json"
VAR_LOG_BENCH_LOG = "var/log/bench.log"
USR_ICONS_AVATAR = "usr/icons/avatar.jpg"
USR_ICONS_CONTEXTS = "usr/icons/contexts.jpg"
USR_ICONS_ICEBERGS = "usr/icons/icebergs.png"
USR_ICONS_VOLCANOS = "usr/icons/volcanos.png"
USR_ICONS = "usr/icons/"
V = "/v/"
M = "/m/"
P = "/p/"
X = "/x/"
S = "/s/"
C = "/c/"
INTSHELL = "/intshell/"
VOLCANOS = "/volcanos/"
VOLCANOS_PLUGIN = "/volcanos/plugin/"
REQUIRE_MODULES = "/require/modules/"
REQUIRE_USR = "/require/usr/"
REQUIRE_SRC = "/require/src/"
REQUIRE = "/require/"
PLUGIN = "/plugin/"
SHARE_LOCAL = "/share/local/"
PATHNAME = "pathname"
FILENAME = "filename"
CONTEXTS = "contexts"
TYPE_ALL = "all" TYPE_ALL = "all"
TYPE_BIN = "bin"
TYPE_CAT = "cat" TYPE_CAT = "cat"
TYPE_DIR = "dir" TYPE_DIR = "dir"
TYPE_BOTH = "both" TYPE_BOTH = "both"
)
const (
DIR_PACK = "dir_pack"
DIR_ROOT = "dir_root" DIR_ROOT = "dir_root"
DIR_DEEP = "dir_deep"
DIR_TYPE = "dir_type" DIR_TYPE = "dir_type"
DIR_DEEP = "dir_deep"
DIR_REG = "dir_reg" DIR_REG = "dir_reg"
DIR_DEF_FIELDS = "time,path,size,action" DIR_DEF_FIELDS = "time,path,size,action"
DIR_WEB_FIELDS = "time,path,size,link,action" DIR_WEB_FIELDS = "time,size,path,action,link"
DIR_CLI_FIELDS = "path,size,time" DIR_CLI_FIELDS = "path,size,time"
ROOT = "root"
TREE = "tree"
FULL = "full"
PATH = "path"
FILE = "file"
NAME = "name"
SIZE = "size"
LINE = "line"
) )
const DIR = "dir" const DIR = "dir"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
DIR: {Name: "dir path auto upload app", Icon: "dir.png", Help: "文件夹", Actions: ice.Actions{ DIR: {Name: DIR, Help: "目录", Value: kit.Data()},
}, Commands: map[string]*ice.Command{
DIR: {Name: "dir path field... auto upload", Help: "目录", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
aaa.White(m, ice.MAKEFILE, ice.README_MD, ice.LICENSE) m.Cmd(mdb.SEARCH, mdb.CREATE, m.CommandKey(), m.PrefixKey())
aaa.White(m, ice.SRC, ice.BIN, ice.USR) m.Cmd(mdb.RENDER, mdb.CREATE, m.CommandKey(), m.PrefixKey())
aaa.Black(m, ice.SRC_PRIVATE)
aaa.Black(m, ice.USR_LOCAL)
}}, }},
ice.APP: {Help: "本机", Hand: func(m *ice.Message, arg ...string) { mdb.SEARCH: {Name: "search type name", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
switch runtime.GOOS { if arg[0] == mdb.FOREACH {
case "darwin":
m.System("open", kit.Path(m.Option(PATH)))
}
}},
mdb.SHOW: {Help: "预览", Hand: func(m *ice.Message, arg ...string) {
Show(m.ProcessInner(), path.Join(m.Option(DIR_ROOT), m.Option(PATH)))
}}, mdb.UPLOAD: {},
SIZE: {Hand: func(m *ice.Message, arg ...string) {
m.Echo(kit.Select("", kit.Split(m.System("du", "-sh").Result()), 0))
}},
"rename": {Name: "rename to", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(MOVE, path.Join(path.Dir(m.Option(PATH)), m.Option(TO)), m.Option(PATH))
}},
TRASH: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(TRASH, mdb.CREATE, m.Option(PATH))
}},
}, Hand: func(m *ice.Message, arg ...string) {
root, dir := kit.Select(PWD, m.Option(DIR_ROOT)), kit.Select(PWD, arg, 0)
kit.If(strings.HasPrefix(dir, PS), func() { root = "" })
if !aaa.Right(m, path.Join(root, dir)) {
return return
} }
m.Logs(FIND, DIR_ROOT, root, PATH, dir, m.OptionSimple(DIR_TYPE, DIR_REG)) _dir_search(m, arg[0], arg[1])
fields := kit.Split(kit.Select(kit.Select(DIR_DEF_FIELDS, m.OptionFields()), kit.Join(kit.Slice(arg, 1))))
size, last := _dir_list(m, root, dir, 0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), regexp.MustCompile(m.Option(DIR_REG)), fields)
kit.If(m.Option(DIR_ROOT), func() { m.Option(DIR_ROOT, path.Join(m.Option(DIR_ROOT))+PS) })
m.StatusTimeCount(mdb.TIME, last, SIZE, kit.FmtSize(size), m.OptionSimple(DIR_ROOT))
}}, }},
}) mdb.RENDER: {Name: "render type name text", Help: "渲染", Hand: func(m *ice.Message, arg ...string) {
_dir_list(m, arg[2], arg[1], 0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)),
nil, kit.Split(kit.Select("time,size,type,path", m.OptionFields())))
}},
mdb.UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) {
m.Upload(m.Option(PATH))
}},
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
os.Remove(m.Option(PATH))
}},
TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(TRASH, m.Option(PATH))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if m.Option(DIR_ROOT) != "" {
m.Info("dir_root: %v", m.Option(DIR_ROOT))
} }
_dir_list(m, kit.Select(PWD, m.Option(DIR_ROOT)), kit.Select(PWD, arg, 0),
func Relative(m *ice.Message, p string) string { 0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), kit.Regexp(m.Option(DIR_REG)),
if _p := kit.ExtChange(p, JS); Exists(m, _p) { kit.Split(kit.Select(kit.Select(DIR_DEF_FIELDS, m.OptionFields()), kit.Join(kit.Slice(arg, 1)))))
return _p m.SortTimeR(mdb.TIME)
} else if _p := kit.ExtChange(path.Join(ice.USR_VOLCANOS, ice.PLUGIN_LOCAL, path.Join(kit.Slice(kit.Split(p, PS), -2)...)), JS); Exists(m, kit.Split(_p, "?")[0]) { m.StatusTimeCount()
return _p }},
} else { }})
return p
}
}
func SplitPath(m *ice.Message, p string) []string {
if kit.HasPrefix(p, REQUIRE_SRC, REQUIRE_USR) {
p = strings.TrimPrefix(p, REQUIRE)
} else if kit.HasPrefix(p, REQUIRE) {
ls := kit.Split(p, PS)
return []string{ice.USR_REQUIRE + path.Join(ls[1:4]...) + PS, path.Join(ls[4:]...)}
} else if kit.HasPrefix(p, P) {
p = strings.TrimPrefix(p, P)
}
line := kit.Select("1", strings.Split(p, DF), 1)
p = strings.Split(p, DF)[0]
p = strings.Split(p, "?")[0]
if ls := kit.Split(kit.Select(ice.SRC_MAIN_GO, p), PS); len(ls) == 1 {
return []string{PWD, ls[0], line}
} else if ls[0] == ice.USR {
return []string{strings.Join(ls[:2], PS) + PS, strings.Join(ls[2:], PS), line}
} else {
return []string{strings.Join(ls[:1], PS) + PS, strings.Join(ls[1:], PS), line}
}
}
func Dir(m *ice.Message, field string) *ice.Message {
m.Copy(m.Cmd(DIR, PWD, kit.Dict(DIR_TYPE, TYPE_DIR)).Sort(field))
m.Copy(m.Cmd(DIR, PWD, kit.Dict(DIR_TYPE, TYPE_CAT)).Sort(field))
return m
}
func DirDeepAll(m *ice.Message, root, dir string, cb func(ice.Maps), arg ...string) *ice.Message {
m.Options(DIR_TYPE, CAT, DIR_ROOT, root, DIR_DEEP, ice.TRUE)
defer m.Options(DIR_TYPE, "", DIR_ROOT, "", DIR_DEEP, "")
if msg := m.Cmd(DIR, dir, arg); cb == nil {
return m.Copy(msg)
} else {
return msg.Table(cb)
}
}
func Show(m *ice.Message, file string) bool {
p := SHARE_LOCAL + file
kit.If(m.Option(ice.MSG_USERPOD), func(pod string) { p = kit.MergeURL(p, ice.POD, pod) })
switch strings.ToLower(kit.Ext(file)) {
case PNG, JPG, JPEG, "gif":
m.EchoImages(p)
case MP4, MOV:
m.EchoVideos(p)
default:
if IsSourceFile(m, kit.Ext(file)) {
m.Cmdy(CAT, file)
} else {
m.ProcessOpen(p)
return false
}
}
return true
} }

View File

@ -1,40 +0,0 @@
package nfs
import (
"path"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const DOCUMENT = "document"
func init() {
Index.MergeCommands(ice.Commands{
DOCUMENT: {Name: "document index path auto", Help: "文档", Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
m.Cmdy(ice.COMMAND).Option(ice.MSG_DISPLAY, "")
return
}
m.Search(arg[0], func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
if p := DocumentPath(m); p != "" {
if len(kit.Slice(arg, 0, 2)) == 1 {
m.Cmdy(DIR, p)
} else {
m.Cmdy(CAT, arg[1])
}
}
})
}},
})
}
func Document(m *ice.Message, p string, arg ...ice.Any) string {
return kit.Renders(kit.Format(DocumentText(m, p), arg...), m)
}
var DocumentText = func(m *ice.Message, p string) string {
return m.Cmdx(CAT, DocumentPath(m, path.Base(p)))
}
var DocumentPath = func(m *ice.Message, arg ...string) string {
return path.Join(USR_LEARNING_PORTAL, m.PrefixKey(), path.Join(arg...))
}

View File

@ -4,22 +4,16 @@ import (
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
) )
const FIND = "find" const FIND = "find"
func init() { func init() {
const CMD_DIR = "cmd_dir" Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
Index.MergeCommands(ice.Commands{ FIND: {Name: "find path word auto", Help: "搜索", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
FIND: {Name: "find word file auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { for _, file := range strings.Split(m.Cmdx("cli.system", FIND, PWD, "-name", arg[1]), ice.NL) {
kit.If(len(arg) == 0, func() { arg = append(arg, "main.go") }) m.Push(FILE, strings.TrimPrefix(file, PWD))
m.Options(mdb.VALUE, arg[0], CMD_DIR, kit.Select("", arg, 2)) }
msg := m.System(FIND, kit.Select(SRC, arg, 1), "-name", arg[0]) }},
m.Echo(msg.FormatsMeta(nil)) }})
kit.For(strings.Split(msg.Result(), ice.NL), func(s string) { m.Push(FILE, s) })
m.StatusTimeCount(kit.Dict(PATH, m.Option(CMD_DIR)))
}},
})
} }

View File

@ -1,33 +1,14 @@
package nfs package nfs
import ( import ice "shylinux.com/x/icebergs"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
const (
OPENS = "opens"
)
const GREP = "grep" const GREP = "grep"
func init() { func init() {
const CMD_DIR = "cmd_dir" Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
Index.MergeCommands(ice.Commands{ GREP: {Name: "grep path word auto", Help: "搜索", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
GREP: {Name: "grep word file auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { m.Option("cmd_dir", arg[0])
kit.If(len(arg) == 0, func() { arg = append(arg, ice.MAIN) }) m.Split(m.Cmdx("cli.system", GREP, "--exclude=.[a-z]*", "--exclude-dir=.[a-z]*", "-rni", arg[1]), "file:line:text", ":")
kit.If(len(arg) == 1, func() { arg = append(arg, ice.SRC) })
m.Options(mdb.VALUE, arg[0])
kit.For(kit.SplitLine(m.System(GREP, "--exclude=.[a-z]*", "--exclude-dir=.[a-z]*", "-rni", arg[0], kit.AddUniq([]string{}, arg[1:]...)).Result()), func(s string) {
if ls := strings.SplitN(s, DF, 3); len(ls) > 2 {
_ls := SplitPath(m, ls[0])
m.Push(PATH, _ls[0]).Push(FILE, _ls[1]).Push(LINE, ls[1]).Push(mdb.TEXT, ls[2])
}
})
m.Sort("path,file,line")
}}, }},
}) }})
} }

View File

@ -1,43 +0,0 @@
package nfs
import (
"compress/gzip"
"compress/zlib"
"encoding/hex"
"io"
"os"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
const HEX = "hex"
func init() {
Index.MergeCommands(ice.Commands{HEX: {Name: "hex path compress=raw,gzip,zlib size auto", Help: "二进制", Hand: func(m *ice.Message, arg ...string) {
if DirList(m, arg...) {
return
}
Open(m, arg[0], func(r io.Reader, s os.FileInfo) {
switch arg[1] {
case "gzip":
if g, e := gzip.NewReader(r); !m.WarnNotFound(e) {
r = g
}
case "zlib":
if z, e := zlib.NewReader(r); !m.WarnNotFound(e) {
r = z
}
}
buf := make([]byte, kit.Int(kit.Select("1024", arg, 2)))
n, _ := r.Read(buf)
kit.For(n, func(i int) {
kit.If(i%8 == 0, func() { m.Push(OFFSET, kit.Format("%04d", i)) })
m.Push(kit.Format(i%8), hex.EncodeToString(buf[i:i+1]))
kit.If(i%8 == 7, func() { m.Push(mdb.TEXT, string(buf[i-7:i+1])) })
})
m.StatusTime(mdb.TIME, s.ModTime().Format(ice.MOD_TIME), FILE, arg[0], SIZE, kit.FmtSize(s.Size()))
})
}}})
}

View File

@ -1,15 +1,9 @@
package nfs package nfs
import ( import ice "shylinux.com/x/icebergs"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const NFS = "nfs" var Index = &ice.Context{Name: "nfs", Help: "存储模块"}
var Index = &ice.Context{Name: NFS, Help: "存储模块"}
func init() { func init() {
ice.Index.Register(Index, nil, ZIP, TAR, CAT, DIR, PACK, DEFS, SAVE, PUSH, COPY, LINK, GREP, FIND, MOVE, MOVETO, TRASH) ice.Index.Register(Index, nil, TAR, CAT, DIR, DEFS, SAVE, PUSH, COPY, LINK, TAIL, TRASH, GREP)
} }
func Prefix(arg ...string) string { return kit.Keys(NFS, arg) }

7
base/nfs/nfs.shy Normal file
View File

@ -0,0 +1,7 @@
chapter "nfs"
field "文件" nfs.cat
field "目录" nfs.dir
field "跟踪" nfs.tail
field "删除" nfs.trash

View File

@ -1,134 +0,0 @@
package nfs
import (
"io"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/file"
)
const PACK = "pack"
func init() {
Index.MergeCommands(ice.Commands{
PACK: {Name: "pack path auto create upload", Help: "文件系统", Actions: ice.Actions{
mdb.CREATE: {Name: "create path*=src/hi/hi.txt text*=hello", Hand: func(m *ice.Message, arg ...string) {
OptionFiles(m, PackFile)
Create(m, m.Option(PATH), func(w io.Writer, p string) {
Save(m, w, m.Option(mdb.TEXT), func(n int) { m.Logs(LOAD, FILE, p, SIZE, n) })
})
}},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { PackFile.Remove(path.Clean(m.Option(PATH))) }},
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) {
OptionFiles(m, PackFile)
Open(m, path.Join(m.Option(PATH), m.Option(FILE)), func(r io.Reader, p string) {
OptionFiles(m, DiskFile)
Create(m, p, func(w io.Writer) { Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, p, SIZE, n) }) })
})
}},
mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) {
OptionFiles(m, DiskFile)
Open(m, path.Join(m.Option(PATH), m.Option(FILE)), func(r io.Reader, p string) {
OptionFiles(m, PackFile)
Create(m, p, func(w io.Writer) { Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, p, SIZE, n) }) })
})
}},
}, Hand: func(m *ice.Message, arg ...string) {
OptionFiles(m, PackFile)
if p := kit.Select("", arg, 0); p != "" && !strings.HasSuffix(p, PS) {
Open(m, p, func(r io.Reader) { m.Echo(string(ReadAll(m, r))) })
} else {
Open(m, path.Join(p)+PS, func(s os.FileInfo) {
m.Push(mdb.TIME, s.ModTime().Format(ice.MOD_TIME))
m.Push(PATH, path.Join(p, s.Name())+kit.Select("", PS, s.IsDir()))
m.Push(SIZE, kit.FmtSize(s.Size()))
})
m.PushAction(mdb.REMOVE)
}
}},
})
}
var DiskFile = file.NewDiskFile()
var PackFile = file.NewPackFile()
func init() { file.Init(OptionFiles(ice.Pulse, DiskFile, PackFile)) }
func OptionFiles(m *ice.Message, f ...file.File) file.File {
if len(f) > 1 {
m.Optionv(ice.MSG_FILES, file.NewMultiFile(f...))
} else if len(f) > 0 {
m.Optionv(ice.MSG_FILES, f[0])
}
return m.Optionv(ice.MSG_FILES).(file.File)
}
func StatFile(m *ice.Message, p string) (os.FileInfo, error) { return OptionFiles(m).StatFile(p) }
func OpenFile(m *ice.Message, p string) (io.ReadCloser, error) { return OptionFiles(m).OpenFile(p) }
func CreateFile(m *ice.Message, p string) (io.WriteCloser, string, error) {
return OptionFiles(m).CreateFile(p)
}
func AppendFile(m *ice.Message, p string) (io.ReadWriteCloser, string, error) {
w, e := OptionFiles(m).AppendFile(p)
return w, p, e
}
func WriteFile(m *ice.Message, p string, b []byte) error { return OptionFiles(m).WriteFile(p, b) }
func ReadDir(m *ice.Message, p string) ([]os.FileInfo, error) {
list, e := OptionFiles(m).ReadDir(p)
for i := 0; i < len(list)-1; i++ {
for j := i + 1; j < len(list); j++ {
if list[i].IsDir() && !list[j].IsDir() {
continue
} else if !list[i].IsDir() && list[j].IsDir() || list[i].Name() > list[j].Name() {
list[i], list[j] = list[j], list[i]
}
}
}
return list, e
}
func MkdirAll(m *ice.Message, p string) string {
OptionFiles(m).MkdirAll(p, ice.MOD_DIR)
return p
}
func RemoveAll(m *ice.Message, p string) error { return OptionFiles(m).RemoveAll(p) }
func Remove(m *ice.Message, p string) error { return OptionFiles(m).Remove(p) }
func Rename(m *ice.Message, oldname string, newname string) error {
MkdirAll(m, path.Dir(newname))
return OptionFiles(m).Rename(oldname, newname)
}
func Symlink(m *ice.Message, oldname string, newname string) error {
return OptionFiles(m).Symlink(oldname, newname)
}
func Link(m *ice.Message, oldname string, newname string) error {
return OptionFiles(m).Link(oldname, newname)
}
func Exists(m *ice.Message, p string, cb ...func(string)) bool {
if _, e := OptionFiles(m).StatFile(p); e == nil {
for _, cb := range cb {
cb(p)
}
return true
}
return false
}
func ExistsFile(m *ice.Message, p string) bool {
if s, e := OptionFiles(m).StatFile(p); e == nil && !s.IsDir() {
return true
}
return false
}
func NewReadCloser(r io.Reader) io.ReadCloser { return file.NewReadCloser(r) }
func NewWriteCloser(w func([]byte) (int, error), c func() error) io.WriteCloser {
return file.NewWriteCloser(w, c)
}
func Close(m *ice.Message, p ice.Any) {
if w, ok := p.(io.Closer); ok {
w.Close()
}
}

View File

@ -1,228 +1,118 @@
package nfs package nfs
import ( import (
"fmt"
"io" "io"
"os" "os"
"path" "path"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _defs_file(m *ice.Message, name string, text ...string) { func _defs_file(m *ice.Message, name string, text ...string) {
if s, e := os.Stat(path.Join(m.Option(DIR_ROOT), name)); e == nil && s.Size() > 0 { if _, e := os.Stat(path.Join(m.Option(DIR_ROOT), name)); os.IsNotExist(e) {
return
}
for i, v := range text { for i, v := range text {
if b, e := kit.Render(v, m); !m.WarnNotValid(e) { b, _ := kit.Render(v, m)
text[i] = string(b) text[i] = string(b)
} }
}
_save_file(m, name, text...) _save_file(m, name, text...)
} }
}
func _save_file(m *ice.Message, name string, text ...string) { func _save_file(m *ice.Message, name string, text ...string) {
Create(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) { if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
defer m.Echo(p) defer f.Close()
kit.For(text, func(s string) { Save(m, w, s, func(n int) { m.Logs(SAVE, FILE, p, SIZE, n) }) })
}) for _, v := range text {
if n, e := f.WriteString(v); m.Assert(e) {
m.Log_EXPORT(FILE, p, SIZE, n)
}
}
m.Echo(p)
}
} }
func _push_file(m *ice.Message, name string, text ...string) { func _push_file(m *ice.Message, name string, text ...string) {
Append(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) { p := path.Join(m.Option(DIR_ROOT), name)
defer m.Echo(p) if strings.Contains(p, ice.PS) {
kit.For(text, func(s string) { Save(m, w, s, func(n int) { m.Logs(SAVE, FILE, p, SIZE, n) }) }) MkdirAll(m, path.Dir(p))
}) }
if f, e := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, ice.MOD_FILE); m.Assert(e) {
defer f.Close()
for _, k := range text {
if n, e := f.WriteString(k); m.Assert(e) {
m.Log_EXPORT(FILE, p, SIZE, n)
}
}
m.Echo(p)
}
} }
func _copy_file(m *ice.Message, name string, from ...string) { func _copy_file(m *ice.Message, name string, from ...string) {
Create(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) { if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
defer m.Echo(p) defer f.Close()
kit.For(from, func(f string) {
Open(m, path.Join(m.Option(DIR_ROOT), f), func(r io.Reader) { for _, v := range from {
Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, f, SIZE, n).Logs(SAVE, FILE, p, SIZE, n) }) if s, e := os.Open(v); !m.Warn(e, ice.ErrNotFound, name) {
}) defer s.Close()
})
}) if n, e := io.Copy(f, s); !m.Warn(e, ice.ErrNotFound, name) {
m.Log_IMPORT(FILE, v, SIZE, n)
m.Log_EXPORT(FILE, p, SIZE, n)
}
}
}
m.Echo(p)
}
} }
func _link_file(m *ice.Message, name string, from string) { func _link_file(m *ice.Message, name string, from string) {
if m.WarnNotValid(from == "", FROM) { if from == "" {
return return
} }
name = path.Join(m.Option(DIR_ROOT), name) os.Remove(name)
from = path.Join(m.Option(DIR_ROOT), from) MkdirAll(m, path.Dir(name))
if m.WarnNotFound(!Exists(m, from), from) { if e := os.Link(from, name); e != nil {
return m.Warn(os.Symlink(from, name), ice.ErrFailure, from)
} }
Remove(m, name) m.Echo(name)
if MkdirAll(m, path.Dir(name)); m.WarnNotValid(Link(m, from, name)) && m.WarnNotValid(Symlink(m, from, name), from) {
return
}
m.Logs(SAVE, FILE, name, FROM, from).Echo(name)
} }
const ( const (
CONTENT = "content" CONTENT = "content"
OFFSET = "offset"
ALIAS = "alias"
FROM = "from"
TO = "to"
) )
const DEFS = "defs" const DEFS = "defs"
const SAVE = "save" const SAVE = "save"
const PUSH = "push" const PUSH = "push"
const COPY = "copy" const COPY = "copy"
const LINK = "link" const LINK = "link"
const LOAD = "load"
const MOVE = "move"
const MOVETO = "moveto"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
DEFS: {Name: "defs file text run", Help: "默认", Hand: func(m *ice.Message, arg ...string) { DEFS: {Name: "defs file text...", Help: "默认", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
OptionFiles(m, DiskFile)
_defs_file(m, arg[0], arg[1:]...) _defs_file(m, arg[0], arg[1:]...)
}}, }},
SAVE: {Name: "save file text run", Help: "保存", Hand: func(m *ice.Message, arg ...string) { SAVE: {Name: "save file text...", Help: "保存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
kit.If(len(arg) == 1, func() { arg = append(arg, m.Option(CONTENT)) }) if len(arg) == 1 {
arg = append(arg, m.Option(CONTENT))
}
_save_file(m, arg[0], arg[1:]...) _save_file(m, arg[0], arg[1:]...)
}}, }},
PUSH: {Name: "push file text run", Help: "追加", Hand: func(m *ice.Message, arg ...string) { PUSH: {Name: "push file text...", Help: "追加", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
kit.If(len(arg) == 1, func() { arg = append(arg, m.Option(CONTENT)) }) if len(arg) == 1 {
arg = append(arg, m.Option(CONTENT))
}
_push_file(m, arg[0], arg[1:]...) _push_file(m, arg[0], arg[1:]...)
}}, }},
COPY: {Name: "copy file from run", Help: "复制", Hand: func(m *ice.Message, arg ...string) { COPY: {Name: "copy file from...", Help: "复制", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
kit.If(len(arg) > 1 && Exists(m, arg[1]), func() { _copy_file(m, arg[0], arg[1:]...) }) for _, file := range arg[1:] {
}}, if _, e := os.Stat(file); e == nil {
LINK: {Name: "link file from run", Help: "链接", Hand: func(m *ice.Message, arg ...string) { _copy_file(m, arg[0], arg[1:]...)
_link_file(m, arg[0], arg[1])
}},
MOVE: {Name: "move file from run", Help: "移动", Hand: func(m *ice.Message, arg ...string) {
arg[1] = path.Join(m.Option(DIR_ROOT), arg[1])
arg[0] = path.Join(m.Option(DIR_ROOT), arg[0])
Rename(m, arg[1], arg[0])
}},
MOVETO: {Name: "moveto path from run", Help: "移动到", Hand: func(m *ice.Message, arg ...string) {
kit.For(arg[1:], func(from string) { m.Cmd(MOVE, path.Join(arg[0], path.Base(from)), from) })
}},
})
}
func Create(m *ice.Message, p string, cb ice.Any) string {
if f, p, e := CreateFile(m, p); !m.WarnNotValid(e) {
defer f.Close()
switch cb := cb.(type) {
case func(io.Writer, string):
cb(f, p)
case func(io.Writer):
cb(f)
default:
m.ErrorNotImplement(cb)
}
}
return p
}
func Append(m *ice.Message, p string, cb ice.Any) {
if f, p, e := AppendFile(m, p); !m.WarnNotValid(e) {
defer f.Close()
switch cb := cb.(type) {
case func(io.Writer, string):
cb(f, p)
case func(io.Writer):
cb(f)
default:
m.ErrorNotImplement(cb)
}
}
}
func Save(m *ice.Message, w io.Writer, s string, cb ice.Any) {
switch content := m.Optionv(CONTENT).(type) {
case io.Reader:
io.Copy(w, content)
return return
} }
if n, e := fmt.Fprint(w, s); !m.WarnNotValid(e) {
switch cb := cb.(type) {
case func(int):
cb(n)
default:
m.ErrorNotImplement(cb)
} }
}},
LINK: {Name: "link file from", Help: "链接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_link_file(m, arg[0], arg[1])
}},
}})
} }
}
func Copy(m *ice.Message, w io.Writer, r io.Reader, cb ice.Any) {
if n, e := io.Copy(w, r); !m.WarnNotValid(e) {
switch cb := cb.(type) {
case func(int):
cb(int(n))
default:
m.ErrorNotImplement(cb)
}
}
}
func CopyStream(m *ice.Message, to io.Writer, from io.Reader, cache, total int, cb ice.Any) {
kit.If(total == 0, func() { total = 1 })
count, buf := 0, make([]byte, cache)
for {
n, e := from.Read(buf)
to.Write(buf[0:n])
if count += n; count > total {
total = count
}
switch value := count * 100 / total; cb := cb.(type) {
case func(int, int, int):
cb(count, total, value)
case func(int, int):
cb(count, total)
case nil:
default:
m.ErrorNotImplement(cb)
}
if e == io.EOF || m.WarnNotValid(e) {
break
}
}
}
func CopyFile(m *ice.Message, to, from string, cb func([]byte, int) []byte) {
Open(m, from, func(r io.Reader) {
Create(m, to, func(w io.Writer) {
offset, buf := 0, make([]byte, 1024*1024)
for {
n, _ := r.Read(buf)
if n, _ = w.Write(cb(buf[:n], offset)); n == 0 {
break
}
offset += n
}
m.Logs(SAVE, FILE, to, FROM, from, SIZE, offset)
})
})
}
func Pipe(m *ice.Message, cb ice.Any) io.WriteCloser {
r, w := io.Pipe()
switch cb := cb.(type) {
case func(string):
m.Go(func() { kit.For(r, cb) })
case func([]byte):
m.Go(func() {
buf := make([]byte, ice.MOD_BUFS)
for {
n, e := r.Read(buf)
if cb(buf[:n]); e != nil {
break
}
}
})
default:
}
return w
}
func TempName(m *ice.Message) string {
return m.Cmdx(SAVE, path.Join(ice.VAR_TMP, kit.Hashs(mdb.UNIQ)), "")
}
func Temp(m *ice.Message, cb func(p string)) {
p := TempName(m)
defer os.Remove(p)
cb(p)
}
var ImageResize = func(m *ice.Message, p string, height, width uint) bool { return false }

80
base/nfs/tail.go Normal file
View File

@ -0,0 +1,80 @@
package nfs
import (
"bufio"
"io"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
func _tail_create(m *ice.Message, arg ...string) {
h := m.Cmdx(mdb.INSERT, m.PrefixKey(), "", mdb.HASH, arg)
kit.ForEach(kit.Split(m.Option(FILE)), func(file string) {
r, w := io.Pipe()
m.Go(func() {
for bio := bufio.NewScanner(r); bio.Scan(); {
m.Log_IMPORT(FILE, file, SIZE, len(bio.Text()))
m.Grow(TAIL, kit.Keys(mdb.HASH, h), kit.Dict(
FILE, file, SIZE, len(bio.Text()), mdb.TEXT, bio.Text(),
))
}
})
m.Option("cmd_output", w)
m.Option(mdb.CACHE_CLEAR_ON_EXIT, ice.TRUE)
m.Cmd("cli.daemon", TAIL, "-n", "0", "-f", file)
})
}
func _tail_count(m *ice.Message, name string) string {
return m.Conf(TAIL, kit.KeyHash(name, kit.Keym(mdb.COUNT)))
}
const TAIL = "tail"
func init() {
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
TAIL: {Name: TAIL, Help: "日志流", Value: kit.Data(
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,id,file,text",
)},
}, Commands: map[string]*ice.Command{
TAIL: {Name: "tail name id auto page filter:text create", Help: "日志流", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Richs(TAIL, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
value, _ = kit.GetMeta(value), m.Option(mdb.HASH, key)
m.Cmd(TAIL, mdb.CREATE, kit.SimpleKV("file,name", value))
})
}},
mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case FILE:
m.Cmdy(DIR, kit.Select(PWD, arg, 1), PATH).RenameAppend(PATH, FILE)
m.ProcessAgain()
case mdb.NAME:
m.Push(arg[0], kit.Split(m.Option(FILE), ice.PS))
case mdb.LIMIT:
m.Push(arg[0], kit.List("10", "20", "30", "50"))
}
}},
mdb.CREATE: {Name: "create file name", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
_tail_create(m, arg...)
}},
}, mdb.ZoneAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Fields(len(kit.Slice(arg, 0, 2)), "time,name,count,file", m.Config(mdb.FIELD))
m.OptionPage(kit.Slice(arg, 2)...)
mdb.ZoneSelect(m.Spawn(c), arg...).Table(func(index int, value map[string]string, head []string) {
if strings.Contains(value[mdb.TEXT], m.Option(ice.CACHE_FILTER)) {
m.Push("", value, head)
}
})
if len(arg) > 0 {
m.StatusTimeCountTotal(_tail_count(m, arg[0]))
}
}},
}})
}

View File

@ -5,7 +5,6 @@ import (
"compress/gzip" "compress/gzip"
"io" "io"
"os" "os"
"path"
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
@ -13,100 +12,77 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _tar_list(m *ice.Message, p string, cb func(*tar.Header, io.Reader, int)) {
Open(m, p, func(r io.Reader) {
for {
switch kit.Ext(p) {
case TGZ:
p = kit.Keys(kit.TrimExt(p, kit.Ext(p)), TAR, GZ)
case GZ:
if f, e := gzip.NewReader(r); m.WarnNotValid(e, p) {
return
} else {
defer f.Close()
r, p = f, kit.TrimExt(p, GZ)
}
case TAR:
i := 0
for r := tar.NewReader(r); ; i++ {
h, e := r.Next()
if m.WarnNotValid(e) || e == io.EOF {
break
}
if h.Size == 0 {
i--
continue
}
cb(h, r, i)
}
m.StatusTimeCount(mdb.TOTAL, i)
return
default:
return
}
}
})
}
const (
XZ = "xz"
GZ = "gz"
TGZ = "tgz"
)
const TAR = "tar" const TAR = "tar"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
TAR: {Name: "tar path file auto page", Help: "打包", Actions: ice.MergeActions(ice.Actions{ TAR: {Name: "tar file path auto", Help: "打包", Action: map[string]*ice.Action{
mdb.NEXT: {Hand: func(m *ice.Message, arg ...string) { mdb.PrevPage(m, arg[0], kit.Slice(arg, 1)...) }}, mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
mdb.PREV: {Hand: func(m *ice.Message, arg ...string) { mdb.NextPageLimit(m, arg[0], kit.Slice(arg, 1)...) }}, if len(arg) == 1 {
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) { arg = append(arg, arg[0])
if kit.Ext(m.Option(PATH)) == ZIP {
m.Cmdy(ZIP, mdb.EXPORT, arg)
return
} }
list, size := kit.Dict(), 0 if !strings.HasSuffix(arg[0], ".tar.gz") {
_tar_list(m, m.Option(PATH), func(h *tar.Header, r io.Reader, i int) { arg[0] += ".tar.gz"
if h.Name == m.Option(FILE) || m.Option(FILE) == "" {
p := path.Join(path.Dir(m.Option(PATH)), h.Name)
if strings.HasSuffix(h.Name, PS) {
MkdirAll(m, p)
return
} }
kit.IfNoKey(list, path.Dir(p), func(p string) { MkdirAll(m, p) }) m.Cmd("cli.system", "tar", "zcvf", arg)
Create(m, p, func(w io.Writer) { m.Echo(arg[0])
os.Chmod(p, os.FileMode(h.Mode))
Copy(m, w, r, func(n int) { size += n })
kit.If(m.Option(FILE), func() { m.Cmdy(DIR, p).Cmdy(CAT, p) })
})
}
})
}}, }},
}, mdb.PageListAction()), Hand: func(m *ice.Message, arg ...string) { mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) { m.Cmd("cli.system", "tar", "xvf", arg)
m.Cmdy(DIR, arg) m.Echo(arg[0])
return
}
if kit.Ext(arg[0]) == ZIP {
m.Cmdy(ZIP, arg)
return
}
page, size := mdb.OptionPages(m, kit.Slice(arg, 2)...)
_tar_list(m, arg[0], func(h *tar.Header, r io.Reader, i int) {
if len(kit.Slice(arg, 0, 2)) > 1 {
if h.Name != arg[1] {
return
}
m.Echo(string(ReadAll(m, r)[:]))
}
if i >= (page-1)*size && i < page*size {
m.Push(mdb.TIME, h.ModTime.Format(ice.MOD_TIME)).Push(FILE, h.Name).Push(SIZE, kit.FmtSize(h.Size))
}
})
m.PushAction(mdb.EXPORT)
}}, }},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option("cmd_dir", m.Option(DIR_ROOT))
m.Debug("cmd_dir: %v", m.Option("cmd_dir"))
m.Cmdy("cli.system", "tar", "zcvf", arg)
return
file, err := os.Create(arg[0])
m.Assert(err)
defer file.Close()
var out io.WriteCloser = file
if strings.HasSuffix(arg[0], ".gz") {
out = gzip.NewWriter(out)
defer out.Close()
}
t := tar.NewWriter(out)
defer t.Close()
dir_root := m.Option(DIR_ROOT)
var count, total int64
for _, k := range arg[1:] {
m.Option(DIR_TYPE, TYPE_CAT)
m.Option(DIR_DEEP, ice.TRUE)
m.Cmdy(DIR, k, func(f os.FileInfo, p string) {
total += f.Size()
header, err := tar.FileInfoHeader(f, p)
if m.Warn(err != nil, err) {
return
}
header.Name = strings.TrimPrefix(p, dir_root+ice.PS)
if err = t.WriteHeader(header); m.Warn(err != nil, "err: %v", err) {
return
}
file, err := os.Open(p)
if m.Warn(err != nil, "err: %v", err) {
return
}
defer file.Close()
m.PushNoticeGrow(kit.Format("%v %v %v\n", header.Name, kit.FmtSize(f.Size()), kit.FmtSize(total)))
if _, err = io.Copy(t, file); m.Warn(err != nil, "err: %v", err) {
return
}
count++
m.Toast(kit.Format("%v %v %v", count, m.Cost(), kit.FmtSize(total)))
}) })
} }
func TarExport(m *ice.Message, path string, file ...string) { m.StatusTimeCountTotal(kit.FmtSize(total))
m.Cmd(TAR, mdb.EXPORT, ice.Maps{PATH: path, FILE: kit.Select("", file, 0)}) }},
}})
} }

View File

@ -1,55 +0,0 @@
package nfs
import (
"path"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const TEMPLATE = "template"
func init() {
Index.MergeCommands(ice.Commands{
TEMPLATE: {Name: "template index path auto", Help: "模板", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
ice.AddRender(ice.RENDER_TEMPLATE, func(m *ice.Message, args ...ice.Any) string {
return Template(m, kit.Format(args[0]), args[1:]...)
})
}},
}), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
m.Cmdy(ice.COMMAND).Option(ice.MSG_DISPLAY, "")
return
}
m.Search(arg[0], func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
if p := TemplatePath(m); p != "" {
if len(kit.Slice(arg, 0, 2)) == 1 {
m.Cmdy(DIR, p)
} else {
m.Cmdy(CAT, arg[1])
}
}
})
}},
})
}
func init() { ice.Info.Template = Template }
func Template(m *ice.Message, p string, data ...ice.Any) string {
if text := TemplateText(m, p); text == "" {
return ""
} else if len(data) == 0 {
return kit.Renders(text, m)
} else {
return kit.Renders(text, data[0])
}
}
var TemplateText = func(m *ice.Message, p string) string {
return m.Cmdx(CAT, kit.Select(TemplatePath(m, path.Base(p)), m.Option("_template")))
}
var TemplatePath = func(m *ice.Message, arg ...string) string {
return path.Join(ice.SRC_TEMPLATE, m.PrefixKey(), path.Join(arg...))
}

View File

@ -1,7 +1,7 @@
package nfs package nfs
import ( import (
"io" "os"
"path" "path"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
@ -9,43 +9,56 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _trash_create(m *ice.Message, from string) { func _trash_create(m *ice.Message, name string) {
if m.WarnNotValid(from == "", FROM) { if s, e := os.Stat(name); m.Assert(e) {
return if s.IsDir() {
} name = m.Cmdx(TAR, mdb.IMPORT, name)
s, e := StatFile(m, from)
if m.WarnNotFound(e, from) {
return
}
defer Remove(m, from)
p := path.Join(ice.VAR_TRASH, path.Base(from))
kit.If(!s.IsDir(), func() { Open(m, from, func(r io.Reader) { p = path.Join(ice.VAR_TRASH, kit.HashsPath(r)) }) })
RemoveAll(m, p)
kit.If(!m.WarnNotValid(Rename(m, from, p)), func() { mdb.HashCreate(m, FROM, kit.Paths(from), FILE, p) })
} }
if f, e := os.Open(name); m.Assert(e) {
defer f.Close()
p := path.Join(m.Config(PATH), kit.HashsPath(f))
MkdirAll(m, path.Dir(p))
os.Remove(p)
os.Rename(name, p)
m.Cmdy(mdb.INSERT, TRASH, "", mdb.HASH, FILE, p, FROM, name)
}
}
}
const (
FROM = "from"
)
const TRASH = "trash" const TRASH = "trash"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
TRASH: {Name: "trash hash auto", Help: "回收站", Actions: ice.MergeActions(ice.Actions{ TRASH: {Name: TRASH, Help: "回收站", Value: kit.Data(
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) { mdb.SHORT, FROM, mdb.FIELD, "time,hash,file,from", PATH, ice.VAR_TRASH,
_trash_create(m, kit.Paths(m.Option(FROM))) )},
}, Commands: map[string]*ice.Command{
TRASH: {Name: "trash hash auto prunes", Help: "回收站", Action: ice.MergeAction(map[string]*ice.Action{
mdb.REVERT: {Name: "revert", Help: "恢复", Hand: func(m *ice.Message, arg ...string) {
os.Rename(m.Option(FILE), m.Option(FROM))
m.Cmd(mdb.DELETE, TRASH, "", mdb.HASH, m.OptionSimple(mdb.HASH))
}}, }},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) { mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
Remove(m, m.Option(FILE)) os.Remove(m.Option(FILE))
mdb.HashRemove(m, m.OptionSimple(mdb.HASH)) m.Cmd(mdb.DELETE, TRASH, "", mdb.HASH, m.OptionSimple(mdb.HASH))
}}, }},
mdb.REVERT: {Help: "恢复", Icon: "bi bi-folder-symlink", Hand: func(m *ice.Message, arg ...string) { mdb.PRUNES: {Name: "prunes before@date", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
msg := mdb.HashSelect(m.Spawn(), m.Option(mdb.HASH)) mdb.HashPrunes(m, func(value map[string]string) bool {
Rename(m, msg.Append(FILE), msg.Append(FROM)) os.Remove(value[FILE])
mdb.HashRemove(m, m.OptionSimple(mdb.HASH)) return false
}},
mdb.PRUNES: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashPrunes(m, nil).Table(func(value ice.Maps) { Remove(m, value[FILE]) })
}},
}, mdb.HashAction(mdb.SHORT, FROM, mdb.FIELD, "time,hash,from,file", mdb.ACTION, mdb.REVERT))},
}) })
}},
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if mdb.HashSelect(m, arg...); len(arg) == 0 || !kit.FileExists(arg[0]) {
m.PushAction(mdb.REVERT, mdb.REMOVE)
return
}
_trash_create(m, arg[0])
}},
}})
} }
func Trash(m *ice.Message, p string, arg ...string) *ice.Message { return m.Cmd(TRASH, mdb.CREATE, p) }

View File

@ -1,72 +0,0 @@
package nfs
import (
"archive/zip"
"io"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
func _zip_list(m *ice.Message, p string, cb func(zip.FileHeader, io.Reader, int)) {
if f, e := zip.OpenReader(p); m.WarnNotFound(e, p) {
return
} else {
defer f.Close()
for i, f := range f.File {
if r, e := f.Open(); e == nil {
defer r.Close()
cb(f.FileHeader, r, i)
}
}
}
}
const ZIP = "zip"
func init() {
Index.MergeCommands(ice.Commands{
ZIP: {Name: "zip path file auto page", Help: "打包", Actions: ice.MergeActions(ice.Actions{
mdb.NEXT: {Hand: func(m *ice.Message, arg ...string) { mdb.PrevPage(m, arg[0], kit.Slice(arg, 1)...) }},
mdb.PREV: {Hand: func(m *ice.Message, arg ...string) { mdb.NextPageLimit(m, arg[0], kit.Slice(arg, 1)...) }},
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) {
list, size := kit.Dict(), 0
_zip_list(m, m.Option(PATH), func(h zip.FileHeader, r io.Reader, i int) {
p := path.Join(path.Dir(m.Option(PATH)), kit.Split(path.Base(m.Option(PATH)), "_-.")[0], h.Name)
if strings.HasSuffix(h.Name, PS) {
MkdirAll(m, p)
return
}
kit.IfNoKey(list, path.Dir(p), func(p string) { MkdirAll(m, p) })
Create(m, p, func(w io.Writer) {
os.Chmod(p, os.FileMode(h.Mode()))
Copy(m, w, r, func(n int) { size += n })
kit.If(m.Option(FILE), func() { m.Cmdy(DIR, p).Cmdy(CAT, p) })
})
})
}},
}, mdb.PageListAction()), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) {
m.Cmdy(DIR, arg)
return
}
page, size := mdb.OptionPages(m, kit.Slice(arg, 2)...)
_zip_list(m, arg[0], func(h zip.FileHeader, r io.Reader, i int) {
if len(kit.Slice(arg, 0, 2)) > 1 {
if h.Name != arg[1] {
return
}
m.Echo(string(ReadAll(m, r)[:]))
}
if i >= (page-1)*size && i < page*size {
m.Push(mdb.TIME, h.ModTime().Format(ice.MOD_TIME)).Push(FILE, h.Name).Push(SIZE, kit.FmtSize(int64(h.UncompressedSize)))
}
})
m.PushAction(mdb.EXPORT)
}},
})
}

View File

@ -1,32 +0,0 @@
package ssh
import (
"fmt"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/lex"
kit "shylinux.com/x/toolkits"
)
func Render(m *ice.Message, cmd string, arg ...ice.Any) (res string) {
switch args := kit.Simple(arg...); cmd {
case ice.RENDER_RESULT:
kit.If(len(args) > 0, func() { m.Resultv(args) })
res = m.Result()
case ice.RENDER_VOID:
return res
default:
if res = m.Result(); res == "" {
if m.IsCliUA() {
res = m.TableEchoWithStatus().Result()
} else {
res = m.TableEcho().Result()
}
}
}
if fmt.Fprint(m.O, res); !strings.HasSuffix(res, lex.NL) {
fmt.Fprint(m.O, lex.NL)
}
return res
}

View File

@ -1,235 +0,0 @@
package ssh
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"path"
"strings"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/log"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits"
)
type Frame struct {
source string
target *ice.Context
stdout io.Writer
stdin io.Reader
pipe io.Writer
ps1 []string
ps2 []string
res string
count int
}
func (f *Frame) prompt(m *ice.Message, arg ...string) *Frame {
if f.source != STDIO {
return f
}
kit.If(len(arg) == 0, func() { arg = append(arg, f.ps1...) })
fmt.Fprintf(f.stdout, kit.Select("\r", "\r\033[2K", ice.Info.Colors))
kit.For(arg, func(k string) {
switch k {
case mdb.COUNT:
fmt.Fprintf(f.stdout, "%d", f.count)
case tcp.HOSTNAME:
fmt.Fprintf(f.stdout, ice.Info.NodeName)
case mdb.TIME:
fmt.Fprintf(f.stdout, kit.Slice(kit.Split(time.Now().Format(ice.MOD_TIME)), -1)[0])
case TARGET:
fmt.Fprintf(f.stdout, f.target.Name)
default:
kit.If(ice.Info.Colors || k[0] != '\033', func() { fmt.Fprintf(f.stdout, k) })
}
})
return f
}
func (f *Frame) printf(m *ice.Message, str string, arg ...ice.Any) *Frame {
if f.source != STDIO {
return f
}
fmt.Fprint(f.stdout, kit.Format(str, arg...))
return f
}
func (f *Frame) change(m *ice.Message, ls []string) []string {
if len(ls) == 1 && ls[0] == "~" {
ls = []string{ctx.CONTEXT}
} else if len(ls) > 0 && strings.HasPrefix(ls[0], "~") {
target := ls[0][1:]
if ls = ls[1:]; len(target) == 0 && len(ls) > 0 {
target, ls = ls[0], ls[1:]
}
kit.If(target == "~", func() { target = "" })
m.Spawn(f.target).Search(target+nfs.PT, func(p *ice.Context, s *ice.Context) { f.target = s })
}
return ls
}
func (f *Frame) alias(m *ice.Message, ls []string) []string {
if len(ls) == 0 {
return ls
} else if alias := kit.Simple(kit.Value(m.Optionv(ice.SSH_ALIAS), ls[0])); len(alias) > 0 {
ls = append(alias, ls[1:]...)
}
return ls
}
func (f *Frame) parse(m *ice.Message, h, line string) string {
ls := kit.Split(strings.TrimSpace(line))
for i, v := range ls {
if v == "#" {
ls = ls[:i]
break
}
}
if ls = f.change(m, f.alias(m, ls)); len(ls) == 0 {
return ""
}
msg := m.Spawn(f.target)
kit.If(h == STDIO, func() { msg.Option(ice.LOG_TRACEID, log.Traceid(m)) })
if msg.Cmdy(ls); h == STDIO && msg.IsErrNotFoundIndex() {
msg.SetResult().Cmdy(cli.SYSTEM, ls)
}
kit.If(m.Option(ice.MSG_STATUS) == "", func() { m.StatusTimeCount() })
f.res = Render(msg, msg.Option(ice.MSG_OUTPUT), kit.List(msg.Optionv(ice.MSG_ARGS))...)
return ""
}
func (f *Frame) scan(m *ice.Message, h, line string) *Frame {
kit.If(f.source == STDIO, func() { m.Option(ice.LOG_DISABLE, ice.TRUE) })
f.ps1 = kit.Simple(mdb.Confv(m, PROMPT, kit.Keym(PS1)))
f.ps2 = kit.Simple(mdb.Confv(m, PROMPT, kit.Keym(PS2)))
ps, bio := f.ps1, bufio.NewScanner(f.stdin)
m.I, m.O = f.stdin, f.stdout
for f.prompt(m.Sleep300ms(), ps...); f.stdin != nil && bio.Scan(); f.prompt(m, ps...) {
if len(bio.Text()) == 0 && h == STDIO {
continue
}
f.count++
if line += bio.Text(); strings.Count(line, "`")%2 == 1 {
line += lex.NL
ps = f.ps2
continue
} else if len(bio.Text()) == 0 {
continue
} else if strings.HasSuffix(bio.Text(), "\\") {
line += bio.Text()[:len(bio.Text())-1]
ps = f.ps2
continue
} else if strings.HasPrefix(strings.TrimSpace(line), "#") {
line = ""
continue
} else if ps = f.ps1; f.stdout == os.Stdout && ice.Info.Colors {
f.printf(m, "\033[0m")
}
line = f.parse(m, h, line)
}
return f
}
func (f *Frame) Begin(m *ice.Message, arg ...string) {
ice.Info.Colors = kit.IsIn(strings.Split(os.Getenv(cli.TERM), "-")[0], "xterm", "screen")
}
func (f *Frame) Start(m *ice.Message, arg ...string) {
m.Optionv(FRAME, f)
switch f.source = kit.Select(STDIO, arg, 0); f.source {
case STDIO:
r, w, _ := os.Pipe()
go func() { io.Copy(w, os.Stdin) }()
f.pipe, f.stdin, f.stdout = w, r, os.Stdout
kit.If(f.target == nil, func() { f.target = m.Target() })
m.Optionv(ice.MSG_OPTS, ice.MSG_USERNAME, ice.MSG_USERROLE)
m.Option(ice.MSG_USERWEB, "http://localhost:9020")
f.scan(m, STDIO, "")
default:
if m.Option(ice.MSG_SCRIPT) != "" {
ls := kit.Split(m.Option(ice.MSG_SCRIPT), nfs.PS)
for i := len(ls) - 1; i > 0; i-- {
if p := path.Join(path.Join(ls[:i]...), f.source); nfs.Exists(m, p) {
f.source = p
}
}
}
if msg := m.Cmd(nfs.CAT, m.Option(ice.MSG_SCRIPT, f.source)); msg.IsErr() {
return
} else {
kit.If(m.Option(nfs.CAT_CONTENT), func() { m.Option(nfs.CAT_CONTENT, "") })
buf := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
f.stdin, f.stdout = bytes.NewBufferString(msg.Result()), buf
defer func() { m.Echo(buf.String()) }()
}
if target, ok := m.Optionv(ice.SSH_TARGET).(*ice.Context); ok {
f.target = target
} else {
f.target = m.Source()
}
f.scan(m, "", "")
}
}
func (f *Frame) Close(m *ice.Message, arg ...string) {
nfs.Close(m, f.stdin)
f.stdin = nil
}
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server { return &Frame{} }
const (
FRAME = "frame"
SHELL = "shell"
STDIO = "stdio"
PS1 = "PS1"
PS2 = "PS2"
)
const (
SOURCE = "source"
RETURN = "return"
TARGET = "target"
PROMPT = "prompt"
PRINTF = "printf"
)
func init() {
Index.MergeCommands(ice.Commands{
SOURCE: {Name: "source file run", Help: "脚本解析", Actions: mdb.HashAction(), Hand: func(m *ice.Message, arg ...string) {
if f, ok := m.Target().Server().(*Frame); ok {
f.Spawn(m, m.Target()).Start(m, arg...)
}
}},
RETURN: {Name: "return run", Help: "结束脚本", Hand: func(m *ice.Message, arg ...string) {
if f, ok := m.Optionv(FRAME).(*Frame); ok {
f.Close(m, arg...)
}
}},
TARGET: {Name: "target name run", Help: "当前模块", Hand: func(m *ice.Message, arg ...string) {
if f, ok := m.Target().Server().(*Frame); ok {
m.Search(arg[0]+nfs.PT, func(p *ice.Context, s *ice.Context) { f.target = s })
f.prompt(m)
}
}},
PROMPT: {Name: "prompt arg run", Help: "命令提示", Actions: ctx.ConfAction(
PS1, ice.List{"\033[33;44m", mdb.COUNT, mdb.AT, tcp.HOSTNAME, "[", mdb.TIME, "]", "\033[5m", TARGET, "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"},
PS2, ice.List{mdb.COUNT, lex.SP, TARGET, "> "},
), Hand: func(m *ice.Message, arg ...string) {
if f, ok := m.Target().Server().(*Frame); ok {
f.prompt(m, arg...)
}
}},
PRINTF: {Name: "printf run text", Help: "输出显示", Hand: func(m *ice.Message, arg ...string) {
if f, ok := m.Target().Server().(*Frame); ok {
f.printf(m, kit.Select(m.Option(nfs.CONTENT), arg, 0))
}
}},
})
}
func PrintQRCode(m *ice.Message, url string) {
m.Spawn(ice.OptionSilent()).Cmd(PRINTF, kit.Dict(nfs.CONTENT, lex.NL+ice.Render(m, ice.RENDER_QRCODE, url))).Cmd(PROMPT)
}

301
base/ssh/scripts.go Normal file
View File

@ -0,0 +1,301 @@
package ssh
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"path"
"strings"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
func Render(msg *ice.Message, cmd string, args ...interface{}) (res string) {
switch arg := kit.Simple(args...); cmd {
case ice.RENDER_VOID:
return res
case ice.RENDER_RESULT:
if len(arg) > 0 {
msg.Resultv(arg)
}
res = msg.Result()
default:
if res = msg.Result(); res == "" {
res = msg.Table().Result()
}
}
if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, ice.NL) {
fmt.Fprint(msg.O, ice.NL)
}
return res
}
type Frame struct {
source string
target *ice.Context
stdout io.Writer
stdin io.Reader
pipe io.Writer
ps1 []string
ps2 []string
res string
count int
}
func (f *Frame) prompt(m *ice.Message, list ...string) *Frame {
if f.source != STDIO {
return f
}
if len(list) == 0 {
list = append(list, f.ps1...)
}
fmt.Fprintf(f.stdout, "\r")
for _, v := range list {
switch v {
case mdb.COUNT:
fmt.Fprintf(f.stdout, "%d", f.count)
case mdb.TIME:
fmt.Fprintf(f.stdout, time.Now().Format("15:04:05"))
case TARGET:
fmt.Fprintf(f.stdout, f.target.Name)
default:
if ice.Info.Colors || v[0] != '\033' {
fmt.Fprintf(f.stdout, v)
}
}
}
return f
}
func (f *Frame) printf(m *ice.Message, str string, arg ...interface{}) *Frame {
fmt.Fprint(f.stdout, kit.Format(str, arg...))
return f
}
func (f *Frame) change(m *ice.Message, ls []string) []string {
if len(ls) == 1 && ls[0] == "~" { // 模块列表
ls = []string{ctx.CONTEXT}
} else if len(ls) > 0 && strings.HasPrefix(ls[0], "~") { // 切换模块
target := ls[0][1:]
if ls = ls[1:]; len(target) == 0 && len(ls) > 0 {
target, ls = ls[0], ls[1:]
}
if target == "~" {
target = ""
}
m.Spawn(f.target).Search(target+ice.PT, func(p *ice.Context, s *ice.Context, key string) {
m.Log_SELECT(ctx.CONTEXT, s.Name)
f.target = s
})
}
return ls
}
func (f *Frame) alias(m *ice.Message, ls []string) []string {
if len(ls) == 0 {
return ls
}
if alias := kit.Simple(kit.Value(m.Optionv(ice.MSG_ALIAS), ls[0])); len(alias) > 0 {
ls = append(alias, ls[1:]...)
}
return ls
}
func (f *Frame) parse(m *ice.Message, line string) string {
// for _, one := range kit.Split(line, ";", ";", ";") {
for _, one := range kit.Simple(line) {
msg := m.Spawn(f.target)
ls := f.change(msg, f.alias(msg, kit.Split(strings.TrimSpace(one))))
if len(ls) == 0 {
continue
}
msg.Render("", kit.List())
if msg.Cmdy(ls[0], ls[1:]); msg.IsErrNotFound() {
msg.SetResult().Cmdy(cli.SYSTEM, ls)
}
f.res = Render(msg, msg.Option(ice.MSG_OUTPUT), msg.Optionv(ice.MSG_ARGS).([]interface{})...)
}
m.Sleep("10ms")
return ""
}
func (f *Frame) scan(m *ice.Message, h, line string) *Frame {
f.ps1 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS1)))
f.ps2 = kit.Simple(m.Confv(PROMPT, kit.Keym(PS2)))
ps := f.ps1
m.Sleep("100ms")
m.I, m.O = f.stdin, f.stdout
bio := bufio.NewScanner(f.stdin)
for f.prompt(m, ps...); bio.Scan() && f.stdin != nil; f.prompt(m, ps...) {
if h == STDIO && len(bio.Text()) == 0 {
continue // 空行
}
m.Cmdx(mdb.INSERT, SOURCE, kit.Keys(mdb.HASH, h), mdb.LIST, mdb.TEXT, bio.Text())
f.count++
if len(bio.Text()) == 0 {
if strings.Count(line, "`")%2 == 1 {
line += ice.NL
}
continue // 空行
}
if strings.HasSuffix(bio.Text(), "\\") {
line += bio.Text()[:len(bio.Text())-1]
ps = f.ps2
continue // 续行
}
if line += bio.Text(); strings.Count(line, "`")%2 == 1 {
line += ice.NL
ps = f.ps2
continue // 多行
}
if strings.HasPrefix(strings.TrimSpace(line), "#") {
line = ""
continue
}
// if line = strings.Split(line, " # ")[0]; len(line) == 0 {
// continue // 注释
// }
if ps = f.ps1; f.stdout == os.Stdout {
if ice.Info.Colors {
f.printf(m, "\033[0m") // 清空格式
}
}
line = f.parse(m, line)
}
return f
}
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
return f
}
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
return &Frame{}
}
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
m.Optionv(FRAME, f)
switch f.source = kit.Select(STDIO, arg, 0); f.source {
case STDIO: // 终端交互
m.Cap(ice.CTX_STREAM, f.source)
if f.target == nil {
f.target = m.Target()
}
r, w, _ := os.Pipe()
m.Go(func() { io.Copy(w, os.Stdin) })
f.stdin, f.stdout = r, os.Stdout
f.pipe = w
m.Option(ice.MSG_OPTS, ice.MSG_USERNAME)
m.Conf(SOURCE, kit.Keys(mdb.HASH, STDIO, kit.Keym(mdb.NAME)), STDIO)
m.Conf(SOURCE, kit.Keys(mdb.HASH, STDIO, kit.Keym(mdb.TIME)), m.Time())
f.count = kit.Int(m.Conf(SOURCE, kit.Keys(mdb.HASH, STDIO, kit.Keym(mdb.COUNT)))) + 1
f.scan(m, STDIO, "")
default: // 脚本文件
if strings.Contains(m.Option(ice.MSG_SCRIPT), ice.PS) {
f.source = path.Join(path.Dir(m.Option(ice.MSG_SCRIPT)), f.source)
}
m.Option(ice.MSG_SCRIPT, f.source)
f.target = m.Source()
if msg := m.Cmd(nfs.CAT, f.source); msg.Result(0) == ice.ErrWarn {
return true // 查找失败
} else {
buf := bytes.NewBuffer(make([]byte, 0, ice.MOD_BUFS))
defer func() { m.Echo(buf.String()) }()
f.stdin, f.stdout = bytes.NewBuffer([]byte(msg.Result())), buf
}
f.count = 1
f.scan(m, m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, mdb.NAME, f.source), "")
}
return true
}
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
if stdin, ok := f.stdin.(io.Closer); ok {
stdin.Close()
}
f.stdin = nil
return true
}
const (
FRAME = "frame"
STDIO = "stdio"
PS1 = "PS1"
PS2 = "PS2"
)
const (
SCRIPT = "script"
SOURCE = "source"
TARGET = "target"
PROMPT = "prompt"
PRINTF = "printf"
SCREEN = "screen"
RETURN = "return"
)
func init() {
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SOURCE: {Name: SOURCE, Help: "加载脚本", Value: kit.Data()},
PROMPT: {Name: PROMPT, Help: "命令提示", Value: kit.Data(
PS1, []interface{}{"\033[33;44m", mdb.COUNT, "[", mdb.TIME, "]", "\033[5m", TARGET, "\033[0m", "\033[44m", ">", "\033[0m ", "\033[?25h", "\033[32m"},
PS2, []interface{}{mdb.COUNT, " ", TARGET, "> "},
)},
}, Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
SOURCE: {Name: "source file", Help: "脚本解析", Action: ice.MergeAction(map[string]*ice.Action{
"repeat": {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(SCREEN, m.Option(mdb.TEXT))
m.ProcessInner()
}},
}, mdb.ZoneAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 0 && kit.Ext(arg[0]) == ice.SHY {
(&Frame{}).Start(m, arg...)
return // 脚本解析
}
}},
TARGET: {Name: "target name run", Help: "当前模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
f := c.Server().(*Frame)
m.Search(arg[0]+ice.PT, func(p *ice.Context, s *ice.Context, key string) { f.target = s })
f.prompt(m)
}},
PROMPT: {Name: "prompt arg run", Help: "命令提示", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
f := m.Optionv(FRAME).(*Frame)
f.ps1 = arg
f.prompt(m)
}},
PRINTF: {Name: "printf run text", Help: "输出显示", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
f := m.Optionv(FRAME).(*Frame)
f.printf(m, arg[0])
}},
SCREEN: {Name: "screen run text", Help: "输出命令", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
f := m.Optionv(FRAME).(*Frame)
for _, line := range kit.Split(arg[0], ice.NL, ice.NL) {
fmt.Fprintf(f.pipe, line+ice.NL)
f.printf(m, line+ice.NL)
m.Sleep300ms()
}
m.Echo(f.res)
}},
RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
f := m.Optionv(FRAME).(*Frame)
f.Close(m, arg...)
}},
}})
}

View File

@ -6,4 +6,4 @@ const SSH = "ssh"
var Index = &ice.Context{Name: SSH, Help: "终端模块"} var Index = &ice.Context{Name: SSH, Help: "终端模块"}
func init() { ice.Index.Register(Index, &Frame{}, SOURCE, RETURN, TARGET, PROMPT, PRINTF) } func init() { ice.Index.Register(Index, &Frame{}, SOURCE, TARGET, PROMPT, PRINTF, SCREEN, RETURN) }

8
base/ssh/ssh.shy Normal file
View File

@ -0,0 +1,8 @@
chapter "ssh"
field "脚本" ssh.source
field "模块" ssh.target
field "提示" ssh.prompt
field "输出" ssh.printf
field "屏显" ssh.screen

View File

@ -1,58 +0,0 @@
package tcp
import (
"net"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
func _server_udp(m *ice.Message, arg ...string) {
l, e := net.ListenUDP(UDP4, UDPAddr(m, "0.0.0.0", m.Option(PORT)))
defer kit.If(e == nil, func() { l.Close() })
mdb.HashCreate(m, arg, kit.Dict(mdb.TARGET, l), STATUS, kit.Select(ERROR, OPEN, e == nil), ERROR, kit.Format(e))
switch cb := m.OptionCB("").(type) {
case func(*net.UDPAddr, []byte):
m.Assert(e)
buf := make([]byte, 2*ice.MOD_BUFS)
for {
if n, from, e := l.ReadFromUDP(buf[:]); !m.WarnNotValid(e) {
cb(from, buf[:n])
} else {
break
}
}
default:
m.ErrorNotImplement(cb)
}
}
func _client_dial_udp4(m *ice.Message, arg ...string) {
c, e := net.DialUDP(UDP4, nil, UDPAddr(m, kit.Select("255.255.255.255", m.Option(HOST)), m.Option(PORT)))
defer kit.If(e == nil, func() { c.Close() })
switch cb := m.OptionCB("").(type) {
case func(*net.UDPConn):
kit.If(!m.WarnNotValid(e), func() { cb(c) })
default:
m.ErrorNotImplement(cb)
}
}
const (
UDP4 = "udp4"
SEND = "send"
RECV = "recv"
ECHO = "echo"
DONE = "done"
DIRECT = "direct"
)
func UDPAddr(m *ice.Message, host, port string) *net.UDPAddr {
if addr, e := net.ResolveUDPAddr(UDP4, host+nfs.DF+port); !m.WarnNotValid(e, host, port, logs.FileLineMeta(2)) {
return addr
}
return nil
}
func HostPort(host, port string) string { return host + nfs.DF + port }

View File

@ -2,19 +2,22 @@ package tcp
import ( import (
"net" "net"
"time"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
type Stat struct {
nc, nr, nw int
}
type Conn struct { type Conn struct {
net.Conn
m *ice.Message m *ice.Message
h string h string
s *Stat s *Stat
net.Conn
} }
func (c *Conn) Read(b []byte) (int, error) { func (c *Conn) Read(b []byte) (int, error) {
@ -27,36 +30,71 @@ func (c *Conn) Write(b []byte) (int, error) {
c.s.nw += n c.s.nw += n
return n, e return n, e
} }
func (c *Conn) Close() error { return c.Conn.Close() } func (c *Conn) Close() error {
return c.Conn.Close()
}
func _client_dial(m *ice.Message, arg ...string) { func _client_dial(m *ice.Message, arg ...string) {
c, e := net.DialTimeout(TCP, m.Option(HOST)+nfs.DF+m.Option(PORT), 3*time.Second) c, e := net.Dial(TCP, m.Option(HOST)+ice.DF+m.Option(PORT))
c = &Conn{Conn: c, m: m, s: &Stat{}}
defer kit.If(e == nil, func() { c.Close() }) c = &Conn{m: m, s: &Stat{}, Conn: c}
switch cb := m.OptionCB("").(type) { if e == nil {
defer c.Close()
}
switch cb := m.OptionCB(CLIENT).(type) {
case func(net.Conn, error):
cb(c, e)
case func(net.Conn): case func(net.Conn):
kit.If(!m.WarnNotValid(e), func() { cb(c) }) m.Assert(e)
cb(c)
case func(net.Conn, []byte, error):
b := make([]byte, ice.MOD_BUFS)
for {
n, e := c.Read(b)
if cb(c, b[:n], e); e != nil {
break
}
}
default: default:
m.ErrorNotImplement(cb) c.Write([]byte("hello world\n"))
} }
} }
const (
PROTO = "proto"
STATUS = "status"
ERROR = "error"
OPEN = "open"
CLOSE = "close"
START = "start"
STOP = "stop"
)
const ( const (
DIAL = "dial" DIAL = "dial"
) )
const CLIENT = "client" const CLIENT = "client"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CLIENT: {Help: "客户端", Actions: ice.MergeActions(ice.Actions{ CLIENT: {Name: CLIENT, Help: "客户端", Value: kit.Data(
DIAL: {Name: "dial type name port=9010 host=", Help: "连接", Hand: func(m *ice.Message, arg ...string) { mdb.FIELD, "time,hash,status,type,name,host,port,error,nread,nwrite",
switch m.Option(mdb.TYPE) { )},
case UDP4: }, Commands: map[string]*ice.Command{
_client_dial_udp4(m, arg...) CLIENT: {Name: "client hash auto prunes", Help: "客户端", Action: ice.MergeAction(map[string]*ice.Action{
default: ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
_client_dial(m, arg...) m.Richs(CLIENT, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
} kit.Value(value, kit.Keym(STATUS), CLOSE)
}},
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error"), mdb.ClearOnExitHashAction())},
}) })
m.Cmdy(SERVER, mdb.PRUNES)
}},
DIAL: {Name: "dial type name port=9010 host=", Help: "连接", Hand: func(m *ice.Message, arg ...string) {
_client_dial(m, arg...)
}},
}, mdb.HashActionStatus()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...).Table(func(index int, value map[string]string, head []string) {
m.PushButton(kit.Select("", mdb.REMOVE, value[STATUS] == OPEN))
})
}},
}})
} }

View File

@ -2,123 +2,98 @@ package tcp
import ( import (
"net" "net"
"os"
"strings" "strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _host_domain(m *ice.Message) string { func _host_list(m *ice.Message, name string) {
return kit.GetValid(
func() string { return m.Option(ice.TCP_DOMAIN) },
func() string { return mdb.Config(m, DOMAIN) },
func() string { return os.Getenv(ice.TCP_DOMAIN) },
func() string {
if !kit.IsIn(m.ActionKey(), "", ice.LIST) {
return m.Cmdv(HOST, mdb.Config(m, ice.MAIN), aaa.IP)
}
return ""
},
func() string {
return LOCALHOST
},
)
}
func _host_list(m *ice.Message, name string) *ice.Message {
if ifs, e := net.Interfaces(); m.Assert(e) { if ifs, e := net.Interfaces(); m.Assert(e) {
for _, v := range ifs { for _, v := range ifs {
if !strings.Contains(v.Name, name) || len(v.HardwareAddr.String()) == 0 { if name != "" && !strings.Contains(v.Name, name) {
continue continue
} }
if len(v.HardwareAddr.String()) == 0 {
continue
}
if ips, e := v.Addrs(); m.Assert(e) { if ips, e := v.Addrs(); m.Assert(e) {
for _, x := range ips { for _, x := range ips {
ip := strings.Split(x.String(), nfs.PS) ip := strings.Split(x.String(), ice.PS)
if strings.Contains(ip[0], nfs.DF) || len(ip) == 0 { if strings.Contains(ip[0], ice.DF) || len(ip) == 0 {
continue continue
} }
m.Push(mdb.INDEX, v.Index).Push(mdb.NAME, v.Name).Push(aaa.IP, ip[0]).Push(MASK, ip[1]).Push(MAC_ADDRESS, v.HardwareAddr.String())
m.Push(mdb.INDEX, v.Index)
m.Push(mdb.NAME, v.Name)
m.Push(aaa.IP, ip[0])
m.Push("mask", ip[1])
m.Push("hard", v.HardwareAddr.String())
} }
} }
} }
} }
return m.SortInt(mdb.INDEX).StatusTimeCount(DOMAIN, _host_domain(m))
if len(m.Appendv(aaa.IP)) == 0 {
m.Push(mdb.INDEX, -1)
m.Push(mdb.NAME, LOCALHOST)
m.Push(aaa.IP, "127.0.0.1")
m.Push("mask", "255.0.0.0")
m.Push("hard", "")
}
}
func _islocalhost(m *ice.Message, ip string) (ok bool) {
if ip == "::1" || strings.HasPrefix(ip, "127.") {
return true
}
if m.Richs(HOST, kit.Keym(aaa.BLACK), ip, nil) != nil {
return false
}
if m.Richs(HOST, kit.Keym(aaa.WHITE), ip, nil) != nil {
m.Log_AUTH(aaa.WHITE, ip)
return true
}
return false
}
func IsLocalHost(m *ice.Message, ip string) bool { return _islocalhost(m, ip) }
func ReplaceLocalhost(m *ice.Message, url string) string {
if strings.Contains(url, "://"+LOCALHOST) {
url = strings.Replace(url, "://"+LOCALHOST, "://"+m.Cmd(HOST).Append(aaa.IP), 1)
}
return url
} }
const ( const (
LOCALHOST = "localhost" LOCALHOST = "localhost"
MAC_ADDRESS = "mac-address"
MASK = "mask"
DOMAIN = "domain"
GATEWAY = "gateway"
MACHINE = "machine"
ISLOCAL = "islocal"
PUBLISH = "publish"
) )
const HOST = "host" const HOST = "host"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
HOST: {Name: "host name auto domain", Help: "主机", Meta: kit.Dict( HOST: {Name: HOST, Help: "主机", Value: kit.Data(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict( aaa.BLACK, kit.Data(mdb.SHORT, mdb.TEXT), aaa.WHITE, kit.Data(mdb.SHORT, mdb.TEXT),
aaa.IP, "网络地址", MASK, "子网掩码", MAC_ADDRESS, "物理地址", )},
)), }, Commands: map[string]*ice.Command{
), Actions: ice.MergeActions(ice.Actions{ HOST: {Name: "host name auto", Help: "主机", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd("", func(value ice.Maps) { m.Cmd("", aaa.WHITE, LOCALHOST, value[aaa.IP]) }) m.Cmd(HOST).Table(func(index int, value map[string]string, head []string) {
ice.Info.Host = mdb.Config(m, DOMAIN) m.Cmd(HOST, aaa.WHITE, value[aaa.IP])
}},
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
if mdb.IsSearchPreview(m, arg) && m.Cmd(HOST).Length() > 0 {
ip := m.Cmdv(HOST, GATEWAY, aaa.IP)
m.PushSearch(mdb.TYPE, GATEWAY, mdb.NAME, ip, mdb.TEXT, "http://"+ip)
}
}},
aaa.WHITE: {Name: "white name text", Help: "白名单", Hand: func(m *ice.Message, arg ...string) {
mdb.HashCreate(m, mdb.TYPE, m.ActionKey(), m.OptionSimple(mdb.NAME, mdb.TEXT))
}},
aaa.BLACK: {Name: "black name text", Help: "黑名单", Hand: func(m *ice.Message, arg ...string) {
mdb.HashCreate(m, mdb.TYPE, m.ActionKey(), m.OptionSimple(mdb.NAME, mdb.TEXT))
}},
ISLOCAL: {Hand: func(m *ice.Message, arg ...string) {
if arg[0] = strings.Split(strings.TrimPrefix(arg[0], "["), "]")[0]; arg[0] == "::1" || strings.HasPrefix(arg[0], "127.") || arg[0] == LOCALHOST {
m.Echo(ice.OK)
} else if mdb.HashSelectField(m, strings.Split(arg[0], nfs.DF)[0], mdb.TYPE) == aaa.WHITE {
m.Echo(ice.OK)
}
}},
PUBLISH: {Hand: func(m *ice.Message, arg ...string) {
for _, p := range []string{LOCALHOST, "127.0.0.1", m.Option("tcp_localhost")} {
if p != "" && strings.Contains(arg[0], p) {
arg[0] = strings.Replace(arg[0], p, _host_domain(m), 1)
break
}
}
m.Echo(arg[0])
}},
GATEWAY: {Hand: func(m *ice.Message, arg ...string) {
m.Push(aaa.IP, kit.Keys(kit.Slice(strings.Split(m.Cmdv(HOST, aaa.IP), nfs.PT), 0, 3), "1"))
}},
DOMAIN: {Name: "domain ip", Help: "主机", Icon: "bi bi-house-check", Hand: func(m *ice.Message, arg ...string) {
kit.If(m.Option(aaa.IP), func(p string) { ice.Info.Host = p; mdb.Config(m, DOMAIN, p) })
m.Echo(mdb.Config(m, DOMAIN))
}},
}, mdb.HashAction(mdb.SHORT, mdb.TEXT)), Hand: func(m *ice.Message, arg ...string) {
_host_list(m, kit.Select("", arg, 0)).Table(func(value ice.Maps) {
if value[aaa.IP] == mdb.Config(m, DOMAIN) {
m.Push(mdb.STATUS, "current").PushButton("")
} else {
m.Push(mdb.STATUS, "").PushButton(DOMAIN)
}
}) })
}}, }},
}) aaa.BLACK: {Name: "black", Help: "黑名单", Hand: func(m *ice.Message, arg ...string) {
m.Log_CREATE(aaa.BLACK, arg[0])
m.Rich(HOST, kit.Keym(aaa.BLACK), kit.Dict(mdb.TEXT, arg[0]))
}},
aaa.WHITE: {Name: "white", Help: "白名单", Hand: func(m *ice.Message, arg ...string) {
m.Log_CREATE(aaa.WHITE, arg[0])
m.Rich(HOST, kit.Keym(aaa.WHITE), kit.Dict(mdb.TEXT, arg[0]))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_host_list(m, kit.Select("", arg, 0))
}},
}})
} }
func IsLocalHost(m *ice.Message, ip string) bool { return m.Cmdx(HOST, ISLOCAL, ip) == ice.OK }
func PublishLocalhost(m *ice.Message, url string) string { return m.Cmdx(HOST, PUBLISH, url) }

View File

@ -1,52 +0,0 @@
package tcp
import (
"bytes"
"net"
"net/http"
"strings"
kit "shylinux.com/x/toolkits"
)
type Buf struct {
buf []byte
}
type PeekConn struct {
net.Conn
*Buf
}
func (s PeekConn) Read(b []byte) (n int, err error) {
if len(s.buf) == 0 {
return s.Conn.Read(b)
}
if len(s.buf) < len(b) {
copy(b, s.buf)
s.buf = s.buf[:0]
return len(s.buf), nil
}
copy(b, s.buf)
s.buf = s.buf[len(b):]
return len(b), nil
}
func (s PeekConn) Peek(n int) (res []byte) {
b := make([]byte, n)
_n, _ := s.Conn.Read(b)
s.Buf.buf = b[:_n]
return b[:_n]
}
func (s PeekConn) IsHTTP() bool {
if head := s.Peek(4); bytes.Equal(head, []byte("GET ")) {
return true
}
return false
}
func (s PeekConn) Redirect(status int, location string) {
DF, NL := ": ", "\r\n"
s.Conn.Write([]byte(strings.Join([]string{
kit.Format("HTTP/1.1 %d %s", status, http.StatusText(status)),
kit.JoinKV(DF, NL, "Location", location, "Content-Length", "0"),
}, NL) + NL + NL))
}
func NewPeekConn(c net.Conn) PeekConn { return PeekConn{Conn: c, Buf: &Buf{}} }

View File

@ -2,169 +2,76 @@ package tcp
import ( import (
"net" "net"
"os"
"path" "path"
"runtime"
"strconv"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _port_right(m *ice.Message, current, begin, end int) string { func _port_right(m *ice.Message, arg ...string) string {
kit.If(current >= end, func() { current = begin }) current := kit.Int(kit.Select(m.Config(CURRENT), arg, 0))
for i := current; i < end; i++ { end := kit.Int(m.Config(END))
if p := path.Join(ice.USR_LOCAL_DAEMON, kit.Format(i)); nfs.Exists(m, p) { if current >= end {
current = kit.Int(m.Config(BEGIN))
}
} else if c, e := net.Dial(TCP, kit.Format(":%d", i)); e == nil { for i := current; i < end; i++ {
if c, e := net.Dial(TCP, kit.Format(":%d", i)); e == nil {
m.Info("port exists %v", i) m.Info("port exists %v", i)
c.Close() c.Close()
} else { continue
nfs.MkdirAll(m, p)
m.Logs(mdb.SELECT, PORT, i)
return mdb.Config(m, CURRENT, i)
} }
p := path.Join(m.Conf(cli.DAEMON, kit.Keym(nfs.PATH)), kit.Format(i))
if _, e := os.Stat(p); e == nil {
continue
}
nfs.MkdirAll(m, p)
m.Log_SELECT(PORT, i)
return m.Config(CURRENT, i)
} }
return "" return ""
} }
const ( const (
PORT_22 = "22"
PORT_80 = "80"
PORT_443 = "443"
PORT_9020 = "9020"
PORT_9022 = "9022"
SOCKET = "socket"
BEGIN = "begin"
CURRENT = "current"
RANDOM = "random" RANDOM = "random"
CURRENT = "current"
BEGIN = "begin"
END = "end" END = "end"
PID = "pid"
SPACE = "space"
) )
const PORT = "port" const PORT = "port"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
PORT: {Name: "port port path auto socket", Help: "端口", Actions: ice.MergeActions(ice.Actions{ PORT: {Name: PORT, Help: "端口", Value: kit.Data(BEGIN, 10000, CURRENT, 10000, END, 20000)},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { }, Commands: map[string]*ice.Command{
switch arg[0] { PORT: {Name: "port port path auto", Help: "端口", Action: map[string]*ice.Action{
case HOST, SERVER: aaa.RIGHT: {Name: "right", Help: "分配", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(PORT, SOCKET, func(value ice.Maps) { m.Echo(_port_right(m, arg...))
switch value[mdb.STATUS] { }},
case "LISTEN": }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Push(arg[0], strings.Replace(value["local"], "0.0.0.0", "127.0.0.1", 1)) if len(arg) == 0 {
m.Option(nfs.DIR_ROOT, m.Conf(cli.DAEMON, kit.Keym(nfs.PATH)))
m.Cmd(nfs.DIR, nfs.PWD, nfs.DIR_CLI_FIELDS).Table(func(index int, value map[string]string, head []string) {
bin := m.Cmd(nfs.DIR, path.Join(value[nfs.PATH], ice.BIN), nfs.DIR_CLI_FIELDS).Append(nfs.PATH)
if bin == "" {
bin = m.Cmd(nfs.DIR, path.Join(value[nfs.PATH], "sbin"), nfs.DIR_CLI_FIELDS).Append(nfs.PATH)
} }
m.Push(mdb.TIME, value[mdb.TIME])
m.Push(PORT, path.Base(value[nfs.PATH]))
m.Push(nfs.SIZE, value[nfs.SIZE])
m.Push(ice.BIN, bin)
}) })
case PORT: m.SortInt(PORT)
if runtime.GOOS == "darwin" {
ls := kit.SplitLine(m.Cmd("system", "sh", "-c", `lsof -nP -i4TCP | grep LISTEN | awk '{print $1 " " $9 }'`).Result())
kit.For(ls, func(p string) {
ls := kit.SplitWord(p)
m.Push(arg[0], kit.Split(ls[1], ":")[1]).Push(SERVER, ls[0])
})
m.Sort(arg[0], ice.INT)
return return
} }
m.Cmd(PORT, SOCKET, func(value ice.Maps) { m.Option(nfs.DIR_ROOT, path.Join(m.Conf(cli.DAEMON, kit.Keym(nfs.PATH)), arg[0]))
switch value[mdb.STATUS] { m.Cmdy(nfs.DIR, arg[1:])
case "LISTEN":
m.Push(arg[0], strings.TrimPrefix(value["local"], "0.0.0.0:"))
m.Push(mdb.NAME, "listen")
}
})
}
}}, }},
SOCKET: {Help: "端口", Hand: func(m *ice.Message, arg ...string) { }})
parse := func(str string) int64 { port, _ := strconv.ParseInt(str, 16, 32); return port }
trans := func(str string) string {
switch str {
case "01":
return "ESTABLISHED"
case "02":
return "TCP_SYNC_SEND"
case "03":
return "TCP_SYNC_RECV"
case "04":
return "TCP_FIN_WAIT1"
case "05":
return "TCP_FIN_WAIT2"
case "06":
return "TIME_WAIT"
case "07":
return "TCP_CLOSE"
case "08":
return "TCP_CLOSE_WAIT"
case "0A":
return "LISTEN"
default:
return str
}
}
stats := map[string]int{}
m.Spawn().Split(m.Cmdx(nfs.CAT, "/proc/net/tcp")).Table(func(value ice.Maps) {
stats[trans(value["st"])]++
m.Push(mdb.STATUS, trans(value["st"]))
ls := kit.Split(value["local_address"], ":")
m.Push("local", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][6:8]), parse(ls[0][4:6]), parse(ls[0][2:4]), parse(ls[0][:2]), parse(ls[1])))
ls = kit.Split(value["rem_address"], ":")
m.Push("remote", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][6:8]), parse(ls[0][4:6]), parse(ls[0][2:4]), parse(ls[0][:2]), parse(ls[1])))
})
m.Spawn().Split(m.Cmdx(nfs.CAT, "/proc/net/tcp6")).Table(func(value ice.Maps) {
stats[trans(value["st"])]++
m.Push(mdb.STATUS, trans(value["st"]))
ls := kit.Split(value["local_address"], ":")
m.Push("local", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][30:32]), parse(ls[0][28:30]), parse(ls[0][26:28]), parse(ls[0][24:26]), parse(ls[1])))
ls = kit.Split(value["remote_address"], ":")
m.Push("remote", kit.Format("%d.%d.%d.%d:%d", parse(ls[0][30:32]), parse(ls[0][28:30]), parse(ls[0][26:28]), parse(ls[0][24:26]), parse(ls[1])))
})
m.Sort("status,local", []string{"LISTEN", "ESTABLISHED", "TIME_WAIT"}).StatusTimeCount(stats)
}},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
m.Assert(m.Option(PORT) != "")
nfs.Trash(m, path.Join(ice.USR_LOCAL_DAEMON, m.Option(PORT)))
mdb.HashRemove(m)
}},
aaa.RIGHT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(PortRight(m, arg...)) }},
CURRENT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(mdb.Config(m, CURRENT)) }},
STOP: {Hand: func(m *ice.Message, arg ...string) { PortCmds(m, arg...); mdb.HashModify(m, PID, "") }},
START: {Hand: func(m *ice.Message, arg ...string) { PortCmds(m, arg...); mdb.HashModify(m, PID, m.Append(PID)) }},
}, mdb.HashAction(BEGIN, 10000, END, 20000,
mdb.SHORT, PORT, mdb.FIELD, "time,port,pid,cmd,name,text,icon,space,index",
)), Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 {
m.Cmdy(nfs.DIR, arg[1:], kit.Dict(nfs.DIR_ROOT, path.Join(ice.USR_LOCAL_DAEMON, arg[0])))
return
}
current := kit.Int(mdb.Config(m, BEGIN))
mdb.HashSelect(m, arg...).Table(func(value ice.Maps) {
current = kit.Max(current, kit.Int(value[PORT]))
if value[PID] == "" {
m.PushButton(START, nfs.TRASH)
} else {
m.PushButton(STOP)
}
})
mdb.Config(m, CURRENT, current)
m.StatusTimeCount(mdb.ConfigSimple(m, BEGIN, CURRENT, END)).SortInt(PORT)
}},
})
ice.Info.Inputs = append(ice.Info.Inputs, func(m *ice.Message, arg ...string) {
switch arg[0] {
case PORT:
m.SetAppend().Cmdy(PORT, mdb.INPUTS, arg)
}
})
}
func PortRight(m *ice.Message, arg ...string) string {
current, begin, end := kit.Select("20000", mdb.Config(m, CURRENT)), kit.Select("20000", mdb.Config(m, BEGIN)), kit.Select("30000", mdb.Config(m, END))
return _port_right(m, kit.Int(kit.Select(kit.Select(begin, current), arg, 0)), kit.Int(kit.Select(begin, arg, 1)), kit.Int(kit.Select(end, arg, 2)))
}
func PortCmds(m *ice.Message, arg ...string) {
m.Cmdy(SPACE, m.Option(SPACE), m.Option(ctx.INDEX), m.ActionKey())
} }

View File

@ -5,23 +5,21 @@ import (
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
type Stat struct{ nc, nr, nw int }
type Listener struct { type Listener struct {
net.Listener
m *ice.Message m *ice.Message
h string h string
s *Stat s *Stat
net.Listener
} }
func (l Listener) Accept() (net.Conn, error) { func (l Listener) Accept() (net.Conn, error) {
c, e := l.Listener.Accept() c, e := l.Listener.Accept()
l.s.nc += 1 l.s.nc += 1
return &Conn{m: l.m, s: &Stat{}, Conn: c}, e return &Conn{m: l.m, h: "", s: &Stat{}, Conn: c}, e
} }
func (l Listener) Close() error { func (l Listener) Close() error {
l.m.Cmd(mdb.MODIFY, SERVER, "", mdb.HASH, mdb.HASH, l.h, STATUS, CLOSE) l.m.Cmd(mdb.MODIFY, SERVER, "", mdb.HASH, mdb.HASH, l.h, STATUS, CLOSE)
@ -29,25 +27,50 @@ func (l Listener) Close() error {
} }
func _server_listen(m *ice.Message, arg ...string) { func _server_listen(m *ice.Message, arg ...string) {
l, e := net.Listen(TCP, m.Option(HOST)+nfs.DF+m.Option(PORT)) l, e := net.Listen(TCP, m.Option(HOST)+":"+m.Option(PORT))
if m.WarnNotValid(e) { h := m.Cmdx(mdb.INSERT, SERVER, "", mdb.HASH, arg,
return STATUS, kit.Select(ERROR, OPEN, e == nil), ERROR, kit.Format(e))
l = &Listener{m: m, h: h, s: &Stat{}, Listener: l}
if e == nil {
defer l.Close()
} }
l = &Listener{Listener: l, m: m, h: mdb.HashCreate(m, arg, kit.Dict(mdb.TARGET, l), STATUS, kit.Select(ERROR, OPEN, e == nil), ERROR, kit.Format(e)), s: &Stat{}}
defer kit.If(e == nil, func() { l.Close() }) switch cb := m.OptionCB(SERVER).(type) {
switch cb := m.OptionCB("").(type) { case func(net.Listener, error):
cb(l, e)
case func(net.Listener): case func(net.Listener):
m.Assert(e)
cb(l) cb(l)
case func(net.Conn): case func(net.Conn):
for { for {
if c, e := l.Accept(); !m.WarnNotValid(e) { if c, e := l.Accept(); e == nil {
cb(c) cb(c)
} else { } else {
break break
} }
} }
case func(net.Conn, error):
for {
c, e := l.Accept()
if cb(c, e); e != nil {
break
}
}
default: default:
m.ErrorNotImplement(cb) for {
c, e := l.Accept()
if e != nil {
break
}
b := make([]byte, ice.MOD_BUFS)
if n, e := c.Read(b); e == nil {
m.Info("nonce", string(b[:n]))
c.Write(b[:n])
}
c.Close()
}
} }
} }
@ -55,37 +78,32 @@ const (
PROTOCOL = "protocol" PROTOCOL = "protocol"
HOSTPORT = "hostport" HOSTPORT = "hostport"
HOSTNAME = "hostname" HOSTNAME = "hostname"
NODENAME = "nodename"
NODETYPE = "nodetype"
BANDWIDTH = "bandwidth"
ADDRESS = "address"
)
const (
PROTO = "proto"
STATUS = "status"
ERROR = "error"
START = "start"
OPEN = "open"
CLOSE = "close"
STOP = "stop"
) )
const ( const (
LISTEN = "listen" LISTEN = "listen"
UNIX = "unix"
) )
const SERVER = "server" const SERVER = "server"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SERVER: {Help: "服务器", Actions: ice.MergeActions(ice.Actions{ SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data(
LISTEN: {Name: "listen type name port=9030 host=", Hand: func(m *ice.Message, arg ...string) { mdb.FIELD, "time,hash,status,type,name,host,port,error,nconn",
switch m.Option(mdb.TYPE) { )},
case UDP4: }, Commands: map[string]*ice.Command{
_server_udp(m, arg...) SERVER: {Name: "server hash auto prunes", Help: "服务器", Action: ice.MergeAction(map[string]*ice.Action{
default: ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
_server_listen(m, arg...) m.Richs(SERVER, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
} kit.Value(value, kit.Keym(STATUS), CLOSE)
}},
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error"), mdb.ClearOnExitHashAction())},
}) })
m.Cmdy(SERVER, mdb.PRUNES)
}},
LISTEN: {Name: "LISTEN type name port=9030 host=", Help: "监听", Hand: func(m *ice.Message, arg ...string) {
_server_listen(m, arg...)
}},
}, mdb.HashActionStatus()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...).Table(func(index int, value map[string]string, head []string) {
m.PushButton(kit.Select("", mdb.REMOVE, value[STATUS] == CLOSE))
})
}},
}})
} }

View File

@ -1,14 +1,9 @@
package tcp package tcp
import ( import ice "shylinux.com/x/icebergs"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
const TCP = "tcp" const TCP = "tcp"
var Index = &ice.Context{Name: TCP, Help: "通信模块"} var Index = &ice.Context{Name: TCP, Help: "通信模块"}
func init() { ice.Index.Register(Index, nil, WIFI, HOST, PORT, CLIENT, SERVER) } func init() { ice.Index.Register(Index, nil, HOST, PORT, CLIENT, SERVER) }
func Prefix(arg ...ice.Any) string { return kit.Keys(TCP, kit.Keys(arg...)) }

6
base/tcp/tcp.shy Normal file
View File

@ -0,0 +1,6 @@
chapter "tcp"
field "主机" tcp.host
field "端口" tcp.port
field "客户端" tcp.client
field "服务器" tcp.server

View File

@ -1,47 +0,0 @@
package tcp
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
const (
SSID = "ssid"
)
const WIFI = "wifi"
func init() {
const (
NETWORKSETUP = "networksetup"
CONNECT = "connect"
)
Index.MergeCommands(ice.Commands{
WIFI: {Help: "无线", Icon: "AirPort Utility.png", Actions: ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case SSID:
kit.For(kit.Slice(kit.SplitLine(m.System(NETWORKSETUP, "-listpreferredwirelessnetworks", "en0").Result()), 1), func(name string) {
m.Push(arg[0], strings.TrimSpace(name))
})
}
}},
CONNECT: {Help: "连接", Hand: func(m *ice.Message, arg ...string) {
m.ToastProcess()
msg := mdb.HashSelect(m.Spawn(), m.Option(SSID, strings.TrimSpace(m.Option(SSID))))
if res := m.System(NETWORKSETUP, "-setairportnetwork", "en0", kit.Select(m.Option(SSID), msg.Append(SSID)), msg.Append(aaa.PASSWORD)); res.Result() != "" {
m.Echo(res.Result()).ToastFailure(res.Result())
} else {
m.ProcessHold()
}
}},
}, mdb.ExportHashAction(mdb.SHORT, SSID, mdb.FIELD, "time,ssid,password")), Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...).PushAction(CONNECT, mdb.REMOVE); len(arg) > 0 {
m.EchoQRCode(kit.Format("WIFI:T:WPA;S:%s;P:%s;H:false;;", m.Append(SSID), m.Append(aaa.PASSWORD)))
}
}},
})
}

View File

@ -1,67 +0,0 @@
package web
import (
"net/http"
"os"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
const ADMIN = "admin"
func init() {
Index.MergeCommands(ice.Commands{
ADMIN: {Name: "admin index list", Help: "后台", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { DreamProcessIframe(m, arg...) }},
}, DreamTablesAction()), Hand: func(m *ice.Message, arg ...string) {
if m.Option(ice.MSG_SOURCE) != "" {
RenderMain(m)
} else {
kit.If(len(arg) == 0, func() { arg = append(arg, SPACE, DOMAIN) })
m.Cmd(SPIDE, mdb.CREATE, HostPort(m, tcp.LOCALHOST, kit.GetValid(
func() string { return m.Cmdx(nfs.CAT, ice.VAR_LOG_ICE_PORT) },
func() string { return m.Cmdx(nfs.CAT, kit.Path(os.Args[0], "../", ice.VAR_LOG_ICE_PORT)) },
func() string { return m.Cmdx(nfs.CAT, kit.Path(os.Args[0], "../../", ice.VAR_LOG_ICE_PORT)) },
func() string { return tcp.PORT_9020 },
)), ice.OPS)
args := []string{}
for i := range arg {
if arg[i] == "--" {
arg, args = arg[:i], arg[i+1:]
break
}
}
kit.If(os.Getenv(cli.CTX_OPS), func(p string) { m.Optionv(SPIDE_HEADER, html.XHost, p) })
m.Cmdy(SPIDE, ice.OPS, SPIDE_RAW, http.MethodPost, C(arg...), cli.PWD, kit.Path(""), args)
}
}},
})
}
func AdminCmd(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
if ice.Info.NodeType == WORKER {
return m.Cmd(append([]ice.Any{SPACE, ice.OPS, cmd}, arg...)...)
} else {
return m.Cmd(append([]ice.Any{cmd}, arg...)...)
}
}
func OpsCmd(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
if ice.Info.NodeType == WORKER {
return m.Cmd(append([]ice.Any{SPACE, ice.OPS, cmd}, arg...)...)
} else {
return m.Cmd(append([]ice.Any{cmd}, arg...)...)
}
}
func DevCmd(m *ice.Message, cmd string, arg ...ice.Any) *ice.Message {
if ice.Info.NodeType == WORKER {
return m.Cmd(append([]ice.Any{SPACE, ice.OPS, SPACE, ice.DEV, cmd}, arg...)...)
} else {
return m.Cmd(append([]ice.Any{SPACE, ice.DEV, cmd}, arg...)...)
}
}

View File

@ -1,52 +0,0 @@
package web
import (
"encoding/base64"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func init() {
Index.MergeCommands(ice.Commands{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { aaa.White(m, "basic") }},
"/basic/check": {Hand: func(m *ice.Message, arg ...string) {
kit.For(m.R.Header, func(key string, value []string) { m.Debug("what %v %v", key, value) })
if BasicSess(m); m.Option(ice.MSG_USERNAME) == "" {
BasicCheck(m, "请输入账号密码")
}
}},
"/basic/login": {Hand: func(m *ice.Message, arg ...string) { RenderMain(m) }},
"/basic/auths": {Hand: func(m *ice.Message, arg ...string) {
kit.If(m.R.URL.Query().Get(ice.MSG_SESSID), func(p string) { RenderCookie(m, m.Option(ice.MSG_SESSID, p)) })
RenderRedirect(m, kit.Select(nfs.PS, m.R.URL.Query().Get("redirect_uri")))
}},
})
}
func BasicSess(m *ice.Message) {
m.Options(ice.MSG_USERWEB, _serve_domain(m))
m.Options(ice.MSG_SESSID, kit.Select(m.Option(ice.MSG_SESSID), m.Option(CookieName(m.Option(ice.MSG_USERWEB)))))
aaa.SessCheck(m, m.Option(ice.MSG_SESSID))
}
func BasicCheck(m *ice.Message, realm string, check ...func(*ice.Message) bool) bool {
switch ls := kit.Split(m.R.Header.Get(html.Authorization)); kit.Select("", ls, 0) {
case html.Basic:
if buf, err := base64.StdEncoding.DecodeString(kit.Select("", ls, 1)); !m.WarnNotValid(err) {
if ls := strings.SplitN(string(buf), ":", 2); !m.WarnNotValid(len(ls) < 2 || ls[1] == "", html.Basic) {
if msg := m.Cmd(TOKEN, ls[1]); !m.WarnNotValid(msg.Time() > msg.Append(mdb.TIME)) {
if len(check) == 0 || check[0](msg) {
return true
}
}
}
}
}
m.W.Header().Add("WWW-Authenticate", kit.Format(`Basic realm="%s"`, realm))
m.RenderStatusUnauthorized()
return false
}

View File

@ -1,89 +0,0 @@
package web
import (
"net"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
func _broad_send(m *ice.Message, to_host, to_port string, host, port string, arg ...string) {
m.Cmd(tcp.CLIENT, tcp.DIAL, mdb.TYPE, tcp.UDP4, tcp.HOST, to_host, tcp.PORT, kit.Select(tcp.PORT_9020, to_port), func(s *net.UDPConn) {
msg := m.Spawn(kit.Dict(tcp.HOST, host, tcp.PORT, port, arg))
msg.Logs(tcp.SEND, BROAD, msg.FormatsMeta(nil), nfs.TO, tcp.HostPort(to_host, to_port)).FormatsMeta(s)
})
}
func _broad_serve(m *ice.Message) {
if m.Cmd(tcp.HOST).Length() == 0 {
return
}
m.GoSleep300ms(func() {
m.Cmd(tcp.HOST, func(value ice.Maps) {
_broad_send(m, "", "", value[aaa.IP], m.Option(tcp.PORT), kit.Simple(gdb.EVENT, tcp.LISTEN, mdb.NAME, ice.Info.NodeName, mdb.TYPE, ice.Info.NodeType, mdb.TIME, m.Time(), cli.SimpleMake())...)
})
})
m.Cmd(tcp.SERVER, tcp.LISTEN, mdb.TYPE, tcp.UDP4, mdb.NAME, logs.FileLine(1), m.OptionSimple(tcp.HOST, tcp.PORT), func(from *net.UDPAddr, buf []byte) {
if m.WarnNotValid(len(buf) > 1024, "broad recv buf size too large") {
return
}
msg := m.Spawn(buf).Logs(tcp.RECV, BROAD, string(buf), nfs.FROM, from)
if strings.HasPrefix(msg.Option(tcp.HOST), "169.254") {
return
}
if m.Cmd(BROAD, mdb.CREATE, msg.OptionSimple(kit.Simple(msg.Optionv(ice.MSG_OPTION))...)); msg.Option(gdb.EVENT) == tcp.LISTEN {
m.Cmds(BROAD, func(value ice.Maps) {
_broad_send(m, msg.Option(tcp.HOST), msg.Option(tcp.PORT), value[tcp.HOST], value[tcp.PORT], kit.Simple(value)...)
})
}
})
}
const BROAD = "broad"
func init() {
Index.MergeCommands(ice.Commands{
BROAD: {Help: "广播台", Icon: "Podcasts.png", Actions: ice.MergeActions(ice.Actions{
SERVE_START: {Hand: func(m *ice.Message, arg ...string) { gdb.Go(m, _broad_serve) }},
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
if mdb.IsSearchPreview(m, arg) {
host, domain := m.Cmdv(tcp.HOST, aaa.IP), UserWeb(m).Hostname()
m.Cmds("", func(value ice.Maps) {
switch kit.If(value[tcp.HOST] == host, func() { value[tcp.HOST] = domain }); value[mdb.TYPE] {
case "sshd":
m.PushSearch(mdb.NAME, Script(m, "ssh -p %s %s@%s", value[tcp.PORT], m.Option(ice.MSG_USERNAME), value[tcp.HOST]), mdb.TEXT, HostPort(m, value[tcp.HOST], value[tcp.PORT]), value)
default:
m.PushSearch(mdb.TEXT, HostPort(m, value[tcp.HOST], value[tcp.PORT]), value)
}
})
}
}},
SERVE: {Name: "serve port=9020 host", Hand: func(m *ice.Message, arg ...string) { gdb.Go(m, _broad_serve) }},
ADMIN: {Hand: func(m *ice.Message, arg ...string) { broadOpen(m) }},
DREAM: {Hand: func(m *ice.Message, arg ...string) { broadOpen(m) }},
VIMER: {Hand: func(m *ice.Message, arg ...string) { broadOpen(m) }},
SPIDE: {Name: "spide name type=repos", Icon: "bi bi-house-add", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPIDE, mdb.CREATE, HostPort(m, m.Option(tcp.HOST), m.Option(tcp.PORT)), m.Option(mdb.NAME))
}},
OPEN: {Hand: func(m *ice.Message, arg ...string) {
m.ProcessOpen(HostPort(m, m.Option(tcp.HOST), m.Option(tcp.PORT)))
}},
tcp.SEND: {Hand: func(m *ice.Message, arg ...string) { _broad_send(m, "", "", "", "", arg...) }},
}, gdb.EventsAction(SERVE_START), mdb.HashAction(mdb.SHORT, "host,port",
mdb.FIELD, "time,hash,type,name,host,port,module,version,commitTime,compileTime,bootTime,kernel,arch",
mdb.ACTION, "admin,dream,vimer,spide,open", mdb.SORT, "type,name,host,port"), mdb.ClearOnExitHashAction()), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m, arg...)
m.StatusTimeCount("nodename", ice.Info.NodeName)
}},
})
}
func broadOpen(m *ice.Message) {
m.ProcessOpen(HostPort(m, m.Option(mdb.NAME), m.Option(tcp.PORT)) + C(m.ActionKey()))
}

View File

@ -5,98 +5,124 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"strings"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/miss"
) )
func _cache_name(m *ice.Message, h string) string { return path.Join(ice.VAR_FILE, h[:2], h) } func _cache_name(m *ice.Message, h string) string {
func _cache_mime(m *ice.Message, mime, name string) string { return path.Join(m.Config(nfs.PATH), h[:2], h)
if mime == html.ApplicationOctet {
if kit.ExtIsImage(name) {
mime = IMAGE + nfs.PS + kit.Ext(name)
} else if kit.ExtIsVideo(name) {
mime = VIDEO + nfs.PS + kit.Ext(name)
} }
} else if mime == "" { func _cache_save(m *ice.Message, kind, name, text string, arg ...string) { // file size
return kit.Ext(name) if name == "" {
}
return mime
}
func _cache_save(m *ice.Message, mime, name, text string, arg ...string) {
if m.WarnNotValid(name == "", mdb.NAME) {
return return
} else if len(text) > 512 { }
p := m.Cmdx(nfs.SAVE, _cache_name(m, kit.Hashs(text)), kit.Dict(nfs.CONTENT, text)) if len(text) > 512 || kind == "go" { // 存入文件
p := m.Cmdx(nfs.SAVE, _cache_name(m, kit.Hashs(text)), text)
text, arg = p, kit.Simple(p, len(text)) text, arg = p, kit.Simple(p, len(text))
} }
file, size := kit.Select("", arg, 0), kit.Int(kit.Select(kit.Format(len(text)), arg, 1))
mime, text = _cache_mime(m, mime, name), kit.Select(file, text) // 添加数据
m.Push(mdb.TIME, m.Time()).Push(mdb.HASH, mdb.HashCreate(m.Spawn(), kit.SimpleKV("", mime, name, text), nfs.FILE, file, nfs.SIZE, size)) size := kit.Int(kit.Select(kit.Format(len(text)), arg, 1))
m.Push(mdb.TYPE, mime).Push(mdb.NAME, name).Push(mdb.TEXT, text).Push(nfs.FILE, file).Push(nfs.SIZE, size) file := kit.Select("", arg, 0)
text = kit.Select(file, text)
h := m.Cmdx(mdb.INSERT, CACHE, "", mdb.HASH, kit.SimpleKV("", kind, name, text), nfs.FILE, file, nfs.SIZE, size)
// 返回结果
m.Push(mdb.TIME, m.Time())
m.Push(mdb.TYPE, kind)
m.Push(mdb.NAME, name)
m.Push(mdb.TEXT, text)
m.Push(nfs.SIZE, size)
m.Push(nfs.FILE, file)
m.Push(mdb.HASH, h)
m.Push(mdb.DATA, h)
} }
func _cache_watch(m *ice.Message, key, path string) { func _cache_watch(m *ice.Message, key, file string) {
mdb.HashSelect(m.Spawn(), key).Table(func(value ice.Maps) { mdb.HashSelect(m.Spawn(), key).Table(func(index int, value map[string]string, head []string) {
if value[nfs.FILE] == "" { if value[nfs.FILE] == "" {
m.Cmdy(nfs.SAVE, path, value[mdb.TEXT]) m.Cmdy(nfs.SAVE, file, value[mdb.TEXT])
} else { } else {
m.Cmdy(nfs.LINK, path, value[nfs.FILE]) m.Cmdy(nfs.LINK, file, value[nfs.FILE])
} }
}) })
} }
func _cache_catch(m *ice.Message, path string) (file string, size string) { func _cache_catch(m *ice.Message, name string) (file, size string) {
if msg := m.Cmd(nfs.DIR, path, "hash,size"); msg.Length() > 0 { if f, e := os.Open(name); m.Assert(e) {
return m.Cmdx(nfs.LINK, _cache_name(m, msg.Append(mdb.HASH)), path), msg.Append(nfs.SIZE) defer f.Close()
if s, e := f.Stat(); m.Assert(e) {
return m.Cmdx(nfs.LINK, _cache_name(m, kit.Hashs(f)), name), kit.Format(s.Size())
}
} }
return "", "0" return "", "0"
} }
func _cache_upload(m *ice.Message, r *http.Request) (mime, name, file, size string) { func _cache_upload(m *ice.Message, r *http.Request) (kind, name, file, size string) {
if b, h, e := r.FormFile(UPLOAD); !m.WarnNotValid(e, UPLOAD) { if buf, h, e := r.FormFile(UPLOAD); e == nil {
defer b.Close() defer buf.Close()
if f, p, e := miss.CreateFile(_cache_name(m, kit.Hashs(b))); !m.WarnNotValid(e, UPLOAD) {
// 创建文件
if f, p, e := kit.Create(_cache_name(m, kit.Hashs(buf))); m.Assert(e) {
defer f.Close() defer f.Close()
b.Seek(0, os.SEEK_SET)
if n, e := io.Copy(f, b); !m.WarnNotValid(e, UPLOAD) { // 导入数据
m.Logs(nfs.SAVE, nfs.FILE, p, nfs.SIZE, kit.FmtSize(int64(n))) buf.Seek(0, os.SEEK_SET)
return h.Header.Get(html.ContentType), h.Filename, p, kit.Format(n) if n, e := io.Copy(f, buf); m.Assert(e) {
m.Log_IMPORT(nfs.FILE, p, nfs.SIZE, kit.FmtSize(int64(n)))
return h.Header.Get(ContentType), h.Filename, p, kit.Format(n)
} }
} }
} }
return "", "", "", "0" return "", "", "", "0"
} }
func _cache_download(m *ice.Message, r *http.Response, file string, cb ice.Any) string { func _cache_download(m *ice.Message, r *http.Response) (file, size string) {
m.Option(ice.MSG_USERROLE, aaa.TECH) defer r.Body.Close()
if f, p, e := miss.CreateFile(file); !m.WarnNotValid(e, DOWNLOAD) {
defer func() { if f, p, e := kit.Create(path.Join(ice.VAR_TMP, kit.Hashs("uniq"))); m.Assert(e) {
if s, e := os.Stat(file); e == nil && s.Size() == 0 { step, total := 0, kit.Int(kit.Select("1", r.Header.Get(ContentLength)))
nfs.Remove(m, file) size, buf := 0, make([]byte, ice.MOD_BUFS)
}
}() for {
defer f.Close() if n, _ := r.Body.Read(buf); n > 0 {
last, base := 0, 10 size += n
nfs.CopyStream(m, f, r.Body, base*ice.MOD_BUFS, kit.Int(kit.Select("100", r.Header.Get(html.ContentLength))), func(count, total, value int) { f.Write(buf[0:n])
if value/base == last { s := size * 100 / total
return
} switch cb := m.OptionCB(SPIDE).(type) {
last = value / base
switch m.Logs(nfs.SAVE, nfs.FILE, p, mdb.COUNT, kit.FmtSize(int64(count)), mdb.TOTAL, kit.FmtSize(int64(total)), mdb.VALUE, value); cb := cb.(type) {
case func(int, int, int): case func(int, int, int):
kit.If(cb != nil, func() { cb(count, total, value) }) cb(size, total, s)
case nil: case func(int, int):
default: cb(size, total)
m.ErrorNotImplement(cb) case []string:
} m.Richs(cb[0], cb[1], cb[2], func(key string, value map[string]interface{}) {
value = kit.GetMeta(value)
value[mdb.COUNT], value[mdb.TOTAL], value[mdb.VALUE] = size, total, kit.Format(s)
}) })
return p default:
if s != step && s%10 == 0 {
m.Log_IMPORT(nfs.FILE, p, mdb.VALUE, s, mdb.COUNT, kit.FmtSize(int64(size)), mdb.TOTAL, kit.FmtSize(int64(total)))
} }
return "" }
step = s
continue
}
f.Close()
break
}
if f, e := os.Open(p); m.Assert(e) {
defer f.Close()
m.Log_IMPORT(nfs.FILE, p, nfs.SIZE, kit.FmtSize(int64(size)))
c := _cache_name(m, kit.Hashs(f))
m.Cmd(nfs.LINK, c, p)
return c, kit.Format(size)
}
}
return "", "0"
} }
const ( const (
@ -105,160 +131,57 @@ const (
WRITE = "write" WRITE = "write"
UPLOAD = "upload" UPLOAD = "upload"
DOWNLOAD = "download" DOWNLOAD = "download"
PREVIEW = "preview"
PAGES = "pages"
IMAGE = "image"
VIDEO = "video"
) )
const CACHE = "cache" const CACHE = "cache"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CACHE: {Name: "cache hash auto upload", Help: "缓存池", Actions: ice.MergeActions(ice.Actions{ CACHE: {Name: CACHE, Help: "缓存池", Value: kit.Data(
ice.RENDER_DOWNLOAD: {Hand: func(m *ice.Message, arg ...string) { mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,hash,size,type,name,text",
m.Echo(_share_link(m, kit.Select(arg[0], arg, 1), ice.POD, m.Option(ice.MSG_USERPOD), nfs.FILENAME, kit.Select("", arg[0], len(arg) > 1))) mdb.STORE, ice.VAR_DATA, nfs.PATH, ice.VAR_FILE, mdb.FSIZE, "200000",
}}, mdb.LIMIT, "50", mdb.LEAST, "30",
WRITE: {Name: "write type name* text*", Help: "添加", Hand: func(m *ice.Message, arg ...string) { )},
_cache_save(m, m.Option(mdb.TYPE), m.Option(mdb.NAME), m.Option(mdb.TEXT)) }, Commands: map[string]*ice.Command{
}}, "/cache/": {Name: "/cache/", Help: "缓存池", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
CATCH: {Name: "catch path* type", Help: "导入", Hand: func(m *ice.Message, arg ...string) { m.Richs(CACHE, nil, arg[0], func(key string, value map[string]interface{}) {
file, size := _cache_catch(m, m.Option(nfs.PATH)) if kit.Format(value[nfs.FILE]) == "" {
_cache_save(m, m.Option(mdb.TYPE), m.Option(nfs.PATH), "", file, size) m.RenderResult(value[mdb.TEXT])
}}, } else {
WATCH: {Name: "watch hash* path*", Help: "导出", Hand: func(m *ice.Message, arg ...string) { m.RenderDownload(value[nfs.FILE])
_cache_watch(m, m.Option(mdb.HASH), m.Option(nfs.PATH)) }
}},
UPLOAD: {Hand: func(m *ice.Message, arg ...string) {
mime, name, file, size := _cache_upload(m, m.R)
_cache_save(m, mime, name, "", file, size)
}},
DOWNLOAD: {Name: "download type name*", Hand: func(m *ice.Message, arg ...string) {
if res, ok := m.Optionv(RESPONSE).(*http.Response); !m.WarnNotValid(!ok, RESPONSE) {
nfs.Temp(m, func(p string) {
file, size := _cache_catch(m, _cache_download(m, res, p, m.OptionCB("")))
_cache_save(m, m.Option(mdb.TYPE), m.Option(mdb.NAME), "", file, size)
}) })
}},
CACHE: {Name: "cache hash auto", Help: "缓存池", Action: ice.MergeAction(map[string]*ice.Action{
WATCH: {Name: "watch key file", Help: "释放", Hand: func(m *ice.Message, arg ...string) {
_cache_watch(m, arg[0], arg[1])
}},
CATCH: {Name: "catch type name", Help: "捕获", Hand: func(m *ice.Message, arg ...string) {
file, size := _cache_catch(m, arg[1])
_cache_save(m, arg[0], arg[1], "", file, size)
}},
WRITE: {Name: "write type name text", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
_cache_save(m, arg[0], arg[1], arg[2])
}},
UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) {
kind, name, file, size := _cache_upload(m, m.R)
_cache_save(m, kind, name, "", file, size)
}},
DOWNLOAD: {Name: "download type name", Help: "下载", Hand: func(m *ice.Message, arg ...string) {
if r, ok := m.Optionv(RESPONSE).(*http.Response); ok {
file, size := _cache_download(m, r)
_cache_save(m, arg[0], arg[1], "", file, size)
} }
}}, }},
nfs.PS: {Hand: func(m *ice.Message, arg ...string) { }, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if mdb.HashSelectDetail(m, arg[0], func(value ice.Map) {
kit.If(kit.Format(value[nfs.FILE]), func() { m.RenderDownload(value[nfs.FILE]) }, func() { m.RenderResult(value[mdb.TEXT]) })
}) {
return
}
if pod := m.Option(ice.POD); pod != "" {
msg := m.Options(ice.POD, "").Cmd(SPACE, pod, CACHE, arg[0])
kit.If(kit.Format(msg.Append(nfs.FILE)), func() {
m.RenderDownload(path.Join(ice.USR_LOCAL_WORK, pod, msg.Append(nfs.FILE)))
}, func() { m.RenderResult(msg.Append(mdb.TEXT)) })
}
}},
}, mdb.HashAction(mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,hash,size,type,name,text,file"), ice.RenderAction(ice.RENDER_DOWNLOAD)), Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...); len(arg) == 0 { if mdb.HashSelect(m, arg...); len(arg) == 0 {
return return
} }
if m.Length() == 0 {
return if m.Append(nfs.FILE) == "" {
} else if m.Append(nfs.FILE) == "" { m.PushScript("inner", m.Append(mdb.TEXT))
m.PushScript(mdb.TEXT, m.Append(mdb.TEXT))
} else { } else {
PushDisplay(m, m.Append(mdb.TYPE), m.Append(mdb.NAME), m.MergeLink(P(SHARE, CACHE, arg[0]))) m.PushDownload(m.Append(mdb.NAME), m.MergeURL2("/share/cache/"+arg[0]))
} }
}}, }},
}) }})
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) {
switch sub {
case UPLOAD:
if kit.FileLines(action.Hand) == kit.FileLines(1) {
break
}
watch := action.Hand == nil
action.Hand = ice.MergeHand(func(m *ice.Message, arg ...string) {
up := Upload(m)
m.Assert(len(up) > 1)
msg := m.Cmd(CACHE, m.Option(ice.MSG_UPLOAD))
// if m.Cmd(CACHE, m.Option(ice.MSG_UPLOAD)).Table(func(value ice.Maps) { m.Options(value) }).Length() == 0 {
if msg.Length() == 0 {
SpideCache(m.Spawn(), m.MergeLink(SHARE_CACHE+up[0]))
}
// if m.Options(mdb.HASH, up[0], mdb.NAME, up[1]); watch {
if watch {
m.Cmdy(CACHE, WATCH, up[0], path.Join(kit.Select(m.Option(nfs.PATH), msg.Append(nfs.PATH)), up[1]))
}
}, action.Hand)
}
})
}
func UploadSave(m *ice.Message, p string) string {
up := kit.Simple(m.Optionv(ice.MSG_UPLOAD))
kit.If(strings.HasSuffix(p, nfs.PS), func() { p = path.Join(p, up[1]) })
m.Cmd(CACHE, WATCH, up[0], p)
return p
}
func Upload(m *ice.Message) []string {
if up := kit.Simple(m.Optionv(ice.MSG_UPLOAD)); len(up) == 1 {
msg := m.Cmd(CACHE, UPLOAD)
if m.Optionv(ice.MSG_UPLOAD, kit.Simple(msg.Append(mdb.HASH), msg.Append(mdb.NAME), msg.Append(nfs.SIZE))); m.Option(ice.MSG_USERPOD) != "" {
if nfs.Exists(m, nfs.USR_LOCAL_WORK+m.Option(ice.MSG_USERPOD)) {
m.Cmd(nfs.LINK, path.Join(nfs.USR_LOCAL_WORK+m.Option(ice.MSG_USERPOD), msg.Append(nfs.FILE)), msg.Append(nfs.FILE))
m.Cmd(SPACE, m.Option(ice.MSG_USERPOD), CACHE, mdb.CREATE, msg.AppendSimple(mdb.NAME, mdb.TEXT, nfs.FILE, nfs.SIZE))
} else {
m.Cmd(SPACE, m.Option(ice.MSG_USERPOD), SPIDE, ice.DEV, SPIDE_CACHE, http.MethodGet, tcp.PublishLocalhost(m, m.MergeLink(PP(SHARE, CACHE, msg.Append(mdb.HASH)))))
}
}
return kit.Simple(m.Optionv(ice.MSG_UPLOAD))
} else {
return up
}
}
func Download(m *ice.Message, link string, cb func(count, total, value int)) *ice.Message {
return m.Cmdy(Prefix(SPIDE), ice.DEV, SPIDE_CACHE, http.MethodGet, link, cb)
}
func PushDisplay(m *ice.Message, mime, name, link string) {
if html.IsImage(name, mime) {
m.PushImages(nfs.FILE, link)
} else if html.IsVideo(name, mime) {
m.PushVideos(nfs.FILE, link)
} else if html.IsAudio(name, mime) {
m.PushAudios(nfs.FILE, link)
} else {
m.PushDownload(nfs.FILE, name, link)
}
}
func RenderCache(m *ice.Message, h string) {
if msg := m.Cmd(CACHE, h); msg.Append(nfs.FILE) == "" {
m.RenderResult(msg.Append(mdb.TEXT))
} else {
m.RenderDownload(msg.Append(mdb.FILE), msg.Append(mdb.TYPE), msg.Append(mdb.NAME))
}
}
func ExportCacheAction(field string) ice.Actions {
return ice.Actions{
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m.Spawn(kit.Dict(ice.MSG_FIELDS, field))).Table(func(value ice.Maps) {
kit.For(kit.Split(value[field]), func(h string) {
msg := m.Cmd(CACHE, h)
m.Cmd(nfs.LINK, kit.Keys(path.Join(ice.USR_LOCAL_EXPORT, m.PrefixKey(), field, h), kit.Select("", kit.Split(msg.Append(mdb.TYPE), nfs.PS), -1)), msg.Append(nfs.FILE))
})
})
}},
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
list := map[string]string{}
m.Cmd(nfs.DIR, path.Join(ice.USR_LOCAL_EXPORT, m.PrefixKey(), field), func(value ice.Maps) {
list[kit.TrimExt(value[nfs.PATH])] = m.Cmd(CACHE, CATCH, value[nfs.PATH]).Append(mdb.HASH)
})
mdb.HashSelectUpdate(m, "", func(value ice.Map) {
value[field] = kit.Join(kit.Simple(kit.For(kit.Split(kit.Format(value[field])), func(p string) string { return kit.Select(p, list[p]) })))
})
}},
UPLOAD: {Hand: func(m *ice.Message, arg ...string) {
nfs.Temp(m, func(p string) {
msg := m.Cmd(CACHE, Upload(m)[0])
if os.Link(msg.Append(nfs.FILE), p); nfs.ImageResize(m, p, 390, 390) {
m.Echo(m.Cmd(CACHE, CATCH, p, msg.Append(mdb.TYPE)).Append(mdb.HASH))
}
})
}},
}
} }

View File

@ -1,114 +0,0 @@
package web
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func _count_stat(m *ice.Message, arg ...string) map[string]int {
stat := map[string]int{}
m.Table(func(value ice.Maps) {
count := kit.Int(value[mdb.COUNT])
stat[mdb.TOTAL] += count
for _, agent := range []string{"美国", "电信", "联通", "移动", "阿里云", "腾讯云"} {
if strings.Contains(value[aaa.LOCATION], agent) {
stat[agent] += count
break
}
}
for _, agent := range []string{"GoModuleMirror", "Go-http-client", "git", "compatible"} {
if strings.Contains(value[mdb.TEXT], agent) {
stat[agent] += count
return
}
}
for _, agent := range html.AgentList {
if strings.Contains(value[mdb.TEXT], agent) {
stat[agent] += count
break
}
}
for _, agent := range html.SystemList {
if strings.Contains(value[mdb.TEXT], agent) {
stat[agent] += count
break
}
}
})
return stat
}
const COUNT = "count"
func init() {
Index.MergeCommands(ice.Commands{
COUNT: &ice.Command{Name: "count hash auto group valid location", Help: "计数器", Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(aaa.LOCATION, "地理位置")),
), Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelectUpdate(m, mdb.HashCreate(m), func(value ice.Map) { value[mdb.COUNT] = kit.Int(value[mdb.COUNT]) + 1 })
// m.Cmd("count", mdb.CREATE, OFFER, m.Option(FROM), kit.Dict(ice.LOG_DISABLE, ice.TRUE))
}},
mdb.VALID: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) {
if !strings.HasPrefix(value[mdb.TEXT], html.Mozilla) {
return
} else if count := kit.Int(value[mdb.COUNT]); count < 1 {
return
} else {
m.Push("", value, kit.Split(mdb.Config(m, mdb.FIELD)))
}
})
m.StatusTimeCount(_count_stat(m))
}},
mdb.GROUP: {Hand: func(m *ice.Message, arg ...string) {
count := map[string]int{}
list := map[string]map[string]string{}
m.Cmd("", mdb.VALID).Table(func(value ice.Maps) {
count[value[aaa.LOCATION]] += kit.Int(value[mdb.COUNT])
list[value[aaa.LOCATION]] = value
})
stat := map[string]int{}
for _, v := range list {
func() {
for _, agent := range []string{"美国", "电信", "联通", "移动", "阿里云", "腾讯云", "北京市", "香港"} {
if strings.Contains(v[aaa.LOCATION], agent) {
stat[agent] += kit.Int(v[mdb.COUNT])
return
}
}
m.Push("", v, kit.Split(mdb.Config(m, mdb.FIELD)))
}()
}
m.StatusTimeCount(stat)
}},
aaa.LOCATION: {Hand: func(m *ice.Message, arg ...string) {
GoToast(mdb.HashSelects(m).Sort(mdb.COUNT, ice.INT_R), func(toast func(string, int, int)) []string {
m.Table(func(value ice.Maps, index, total int) {
if value[aaa.LOCATION] == "" {
location := kit.Format(kit.Value(SpideGet(m, "http://opendata.baidu.com/api.php?co=&resource_id=6006&oe=utf8", "query", value[mdb.NAME]), "data.0.location"))
mdb.HashModify(m, mdb.HASH, value[mdb.HASH], aaa.LOCATION, location)
toast(kit.Select(value[mdb.NAME], location), index, total)
m.Sleep300ms()
}
})
return nil
})
}},
}, mdb.HashAction(mdb.LIMIT, 1000, mdb.LEAST, 500, mdb.SHORT, "type,name", mdb.FIELD, "time,hash,count,location,type,name,text")), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m, arg...).Sort(mdb.TIME, ice.STR_R).StatusTimeCount(_count_stat(m))
}},
})
}
func Count(m *ice.Message, arg ...string) *ice.Message {
kit.If(len(arg) > 0 && arg[0] == "", func() { arg[0] = m.ShortKey() })
kit.If(len(arg) > 1 && arg[1] == "", func() { arg[1] = m.ActionKey() })
m.Cmd(COUNT, mdb.CREATE, arg, kit.Dict(ice.LOG_DISABLE, ice.TRUE))
return m
}

View File

@ -3,602 +3,161 @@ package web
import ( import (
"os" "os"
"path" "path"
"regexp"
"runtime"
"strings" "strings"
"time"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/gdb" "shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp" "shylinux.com/x/icebergs/base/tcp"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _dream_list(m *ice.Message) *ice.Message { func _dream_list(m *ice.Message) *ice.Message {
list := m.CmdMap(SPACE, mdb.NAME) return m.Cmdy(nfs.DIR, m.Config(nfs.PATH), "time,size,name").Table(func(index int, value map[string]string, head []string) {
mdb.HashSelects(m.Spawn()).Table(func(value ice.Maps, index int, head []string) { if m.Richs(SPACE, nil, value[mdb.NAME], func(key string, val map[string]interface{}) {
if value[aaa.ACCESS] == aaa.PRIVATE && (m.Option(ice.FROM_SPACE) != "" || !aaa.IsTechOrRoot(m)) { m.Push(mdb.TYPE, val[mdb.TYPE])
return m.Push(cli.STATUS, cli.START)
} m.PushButton(cli.STOP)
if space, ok := list[value[mdb.NAME]]; ok { m.PushAnchor(strings.Split(m.MergePOD(value[mdb.NAME]), "?")[0])
value[mdb.HELP] = space[mdb.HELP] }) == nil {
value[ice.MAIN] = space[ice.MAIN] m.Push(mdb.TYPE, WORKER)
value[mdb.ICONS] = space[mdb.ICONS] m.Push(cli.STATUS, cli.STOP)
m.Push("", value, kit.Slice(head, 0, -1)) m.PushButton(cli.START)
m.Push(mdb.TYPE, space[mdb.TYPE]).Push(cli.STATUS, cli.START) m.PushAnchor("")
m.Push(nfs.MODULE, space[nfs.MODULE]).Push(nfs.VERSION, space[nfs.VERSION])
button := []ice.Any{PORTAL, DESKTOP, ADMIN, WORD}
text := space[nfs.MODULE]
kit.If(m.Option(ice.DREAM_SIMPLE) != ice.TRUE && aaa.IsTechOrRoot(m), func() {
kit.If(m.IsDebug(), func() {
button = append(button, VIMER, STATUS, COMPILE, cli.RUNTIME, XTERM)
text += "\n" + DreamStat(m, value[mdb.NAME])
})
button = append(button, "settings", cli.STOP)
})
m.Push(mdb.TEXT, text)
m.PushButton(append(button, OPEN)...)
} else if aaa.IsTechOrRoot(m) {
m.Push("", value, kit.Slice(head, 0, -1))
m.Push(nfs.MODULE, "").Push(nfs.VERSION, "").Push(mdb.TEXT, "")
if m.Push(mdb.TYPE, WORKER); nfs.Exists(m, path.Join(ice.USR_LOCAL_WORK, value[mdb.NAME])) {
m.Push(cli.STATUS, cli.STOP).PushButton(cli.START, nfs.TRASH)
} else {
m.Push(cli.STATUS, cli.BEGIN).PushButton(cli.START, mdb.REMOVE)
}
} }
}) })
m.RewriteAppend(func(value, key string, index int) string {
if key == mdb.TIME {
if space, ok := list[m.Appendv(mdb.NAME)[index]]; ok {
return space[mdb.TIME]
} }
} else if key == mdb.ICONS { func _dream_show(m *ice.Message, name string) {
if kit.HasPrefix(value, HTTP, nfs.PS) { if !strings.Contains(name, "-") || !strings.HasPrefix(name, "20") {
return value name = m.Time("20060102-") + kit.ReplaceAll(name, "-", "_")
} else if nfs.ExistsFile(m, path.Join(ice.USR_LOCAL_WORK, m.Appendv(mdb.NAME)[index], value)) {
return m.Spawn(kit.Dict(ice.MSG_USERPOD, m.Appendv(mdb.NAME)[index])).FileURI(value)
} else if nfs.ExistsFile(m, value) {
return m.FileURI(value)
} }
defer m.ProcessOpen(m.MergePOD(m.Option(mdb.NAME, name)))
defer m.Echo(m.MergePOD(m.Option(mdb.NAME, name)))
// 任务目录
p := path.Join(m.Config(nfs.PATH), name)
if m.Option(nfs.REPOS) != "" { // 下载源码
m.Cmd("web.code.git.repos", mdb.CREATE, m.OptionSimple(nfs.REPOS), nfs.PATH, p)
} else { // 创建目录
nfs.MkdirAll(m, p)
} }
return value
}) // 任务模板
return m if m.Option(nfs.TEMPLATE) != "" {
for _, file := range []string{ice.ETC_MISS_SH, ice.SRC_MAIN_SHY, ice.SRC_MAIN_GO, ice.GO_MOD, ice.MAKEFILE} {
if kit.FileExists(path.Join(p, file)) {
continue
} }
func _dream_list_more(m *ice.Message) *ice.Message { switch m.Cmdy(nfs.COPY, path.Join(p, file), path.Join(m.Option(nfs.TEMPLATE), file)); file {
field := kit.Split(mdb.Config(m, mdb.FIELD) + ",type,status,module,version,text")
m.Cmds(SPACE).Table(func(value ice.Maps) {
value[nfs.REPOS] = "https://" + value[nfs.MODULE]
value[aaa.ACCESS] = kit.Select("", value[aaa.USERROLE], value[aaa.USERROLE] != aaa.VOID)
value[mdb.STATUS] = cli.START
button := []ice.Any{PORTAL, DESKTOP, ADMIN, WORD}
kit.If(m.IsDebug(), func() { button = append(button, VIMER, STATUS, COMPILE, cli.RUNTIME, XTERM) })
switch value[mdb.TYPE] {
case ORIGIN:
if m.IsCliUA() {
return
}
value[mdb.TEXT] = kit.JoinLine(value[nfs.MODULE], value[mdb.TEXT])
kit.If(aaa.IsTechOrRoot(m), func() { button = append(button, GETTOKEN) })
kit.If(value[aaa.ACCESS] == "", func() { button = []ice.Any{PORTAL} })
button = append(button, OPEN)
case SERVER:
if !m.IsCliUA() {
value[mdb.TEXT] = kit.JoinLine(value[nfs.MODULE], value[mdb.TEXT])
} else if !strings.HasPrefix(value[mdb.TEXT], ice.HTTP) {
return
}
kit.If(aaa.IsTechOrRoot(m), func() { button = append(button, SETTOKEN) })
button = append(button, OPEN)
case aaa.LOGIN:
if m.IsCliUA() {
return
}
value[mdb.TEXT] = kit.JoinWord(value[AGENT], value[cli.SYSTEM], value[aaa.IP], kit.Format(PublicIP(m, value[aaa.IP])))
defer func() { button = []ice.Any{GRANT} }()
default:
return
}
m.Push("", value, field)
m.PushButton(button...)
})
return m
}
func _dream_start(m *ice.Message, name string) {
if m.WarnNotValid(name == "", mdb.NAME) {
return
}
if !m.IsCliUA() {
defer m.ProcessRefresh()
}
defer mdb.Lock(m, m.PrefixKey(), cli.START, name)()
p := _dream_check(m, name)
if p == "" {
return
}
if !nfs.Exists(m, p) {
gdb.Event(m, DREAM_CREATE, m.OptionSimple(mdb.NAME))
}
defer m.Options(cli.CMD_DIR, "", cli.CMD_ENV, "", cli.CMD_OUTPUT, "")
m.Options(cli.CMD_DIR, kit.Path(p), cli.CMD_ENV, kit.EnvList(kit.Simple(m.OptionSimple(ice.TCP_DOMAIN),
cli.CTX_OPS, HostPort(m, tcp.LOCALHOST, m.Cmdv(SERVE, tcp.PORT)), cli.CTX_LOG, ice.VAR_LOG_BOOT_LOG,
cli.CTX_ROOT, kit.Path(""), cli.PATH, cli.BinPath(p, ""), cli.USER, ice.Info.UserName,
)...), cli.CMD_OUTPUT, path.Join(p, ice.VAR_LOG_BOOT_LOG), mdb.CACHE_CLEAR_ONEXIT, ice.TRUE)
kit.If(m.Option(nfs.BINARY) == "" && !cli.SystemFindGo(m), func(p string) { m.Option(nfs.BINARY, S(name)) })
kit.If(m.Option(nfs.BINARY), func(p string) { _dream_binary(m, p) })
kit.If(m.Option(nfs.TEMPLATE), func(p string) { _dream_template(m, p) })
bin := kit.Select(kit.Path(os.Args[0]), cli.SystemFind(m, ice.ICE_BIN, nfs.PWD+path.Join(p, ice.BIN), nfs.PWD+ice.BIN))
if cli.IsSuccess(m.Cmd(cli.DAEMON, bin, SPACE, tcp.DIAL, ice.DEV, ice.OPS, cli.DAEMON, ice.OPS)) {
gdb.WaitEvent(m, DREAM_OPEN, func(m *ice.Message, arg ...string) bool { return m.Option(mdb.NAME) == name })
m.Sleep300ms()
}
}
func _dream_check(m *ice.Message, name string) string {
p := path.Join(ice.USR_LOCAL_WORK, name)
msg := m.Spawn(kit.Dict(ice.MSG_USERROLE, aaa.ROOT))
if pp := path.Join(p, ice.VAR_LOG_ICE_PID); nfs.Exists(m, pp) {
for i := 0; i < 5; i++ {
pid := msg.Cmdx(nfs.CAT, pp)
if pid == "" {
return p
}
m.Sleep("1s")
if m.Cmd(SPACE, name).Length() > 0 {
m.Info("already exists %v", name)
return ""
}
if runtime.GOOS == cli.LINUX && !nfs.Exists(m, "/proc/"+pid) {
return p
}
if nfs.Exists(m, "/proc/"+pid) && runtime.GOOS == cli.LINUX {
if !kit.HasPrefix(msg.Cmdx(nfs.CAT, "/proc/"+pid+"/cmdline"), kit.Path(ice.BIN_ICE_BIN), kit.Path(p, ice.BIN_ICE_BIN)) {
return p
} else {
return ""
}
}
if gdb.SignalProcess(m, pid) {
m.Info("already exists %v", pid)
return ""
}
}
}
return p
}
func _dream_binary(m *ice.Message, p string) {
if bin := path.Join(m.Option(cli.CMD_DIR), ice.BIN_ICE_BIN); nfs.Exists(m, bin) {
return
} else if kit.IsUrl(p) || strings.HasPrefix(p, S()) {
// m.Cmd(DREAM, DOWNLOAD, bin, kit.MergeURL2(p, kit.Format("/publish/ice.%s.%s", runtime.GOOS, runtime.GOARCH), ice.POD, m.Option(mdb.NAME)))
m.Cmd(DREAM, DOWNLOAD, bin, kit.MergeURL(p, cli.GOOS, runtime.GOOS, cli.GOARCH, runtime.GOARCH))
} else {
m.Cmd(nfs.LINK, bin, kit.Path(p))
}
}
func _dream_template(m *ice.Message, p string) {
kit.For([]string{
ice.LICENSE, ice.README_MD, ice.MAKEFILE, ice.GO_MOD, ice.GO_SUM,
ice.SRC_MAIN_SH, ice.SRC_MAIN_SHY, ice.SRC_MAIN_GO, ice.SRC_MAIN_JS,
ice.ETC_MISS_SH, ice.ETC_INIT_SHY, ice.ETC_EXIT_SHY,
}, func(file string) {
if nfs.Exists(m, kit.Path(m.Option(cli.CMD_DIR), file)) {
return
}
switch m.Cmdy(nfs.COPY, kit.Path(m.Option(cli.CMD_DIR), file), kit.Path(ice.USR_LOCAL_WORK, p, file)); file {
case ice.GO_MOD: case ice.GO_MOD:
nfs.Rewrite(m, path.Join(p, file), func(line string) string { kit.Rewrite(path.Join(p, file), func(line string) string {
return kit.Select(line, nfs.MODULE+lex.SP+m.Option(mdb.NAME), strings.HasPrefix(line, nfs.MODULE)) return kit.Select(line, "module "+name, strings.HasPrefix(line, "module"))
}) })
} }
}) }
}
// 任务脚本
m.Cmd(nfs.DEFS, path.Join(p, ice.ETC_MISS_SH), m.Config("miss"))
defer m.Cmdy(nfs.DIR, p)
if pid := m.Cmdx(nfs.CAT, path.Join(p, m.Conf(gdb.SIGNAL, kit.Keym(nfs.PATH)))); pid != "" && kit.FileExists("/proc/"+pid) {
m.Info("already exists %v", pid)
return // 已经启动
} else if m.Cmd(SPACE, name).Length() > 0 {
return // 已经启动
}
defer m.ToastProcess()()
m.Optionv(cli.CMD_DIR, p)
m.Optionv(cli.CMD_ENV, kit.Simple(
cli.CTX_OPS, "http://:"+m.Cmd(SERVE, ice.OptionFields("")).Append(tcp.PORT),
cli.PATH, cli.BinPath(kit.Path(p, ice.BIN)), cli.HOME, kit.Env(cli.HOME),
cli.SHELL, kit.Env(cli.SHELL), cli.TERM, kit.Env(cli.TERM),
cli.USER, ice.Info.UserName, m.Configv(cli.ENV),
))
m.Optionv(cli.CMD_OUTPUT, path.Join(p, ice.BIN_BOOT_LOG))
// 启动任务
bin := kit.Select(os.Args[0], cli.SystemFind(m, ice.ICE_BIN, kit.Path(path.Join(p, ice.BIN)), kit.Path(ice.BIN)))
m.Cmd(cli.DAEMON, bin, SPACE, tcp.DIAL, ice.DEV, ice.OPS, m.OptionSimple(mdb.NAME, RIVER))
m.Sleep3s()
m.Option(cli.CMD_ENV, "")
m.Option(cli.CMD_OUTPUT, "")
m.Event(DREAM_CREATE, kit.SimpleKV("", m.Option(mdb.TYPE), name)...)
} }
const ( const (
ALWAYS = "always"
STARTALL = "startall"
STOPALL = "stopall"
FOR_EACH = "forEach"
FOR_FLOW = "forFlow"
GETTOKEN = "gettoken"
SETTOKEN = "settoken"
DREAM_INPUTS = "dream.inputs"
DREAM_CREATE = "dream.create" DREAM_CREATE = "dream.create"
DREAM_REMOVE = "dream.remove"
DREAM_TRASH = "dream.trash"
DREAM_START = "dream.start" DREAM_START = "dream.start"
DREAM_STOP = "dream.stop" DREAM_STOP = "dream.stop"
DREAM_OPEN = "dream.open"
DREAM_CLOSE = "dream.close"
DREAM_TABLES = "dream.tables"
DREAM_ACTION = "dream.action"
OPS_DREAM_CREATE = "ops.dream.create"
OPS_DREAM_REMOVE = "ops.dream.remove"
) )
const DREAM = "dream" const DREAM = "dream"
func init() { func init() {
Index.MergeCommands(ice.Commands{ Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
DREAM: {Name: "dream refresh", Help: "梦想家", Icon: "Launchpad.png", Role: aaa.VOID, Meta: kit.Dict( DREAM: {Name: "dream name path auto start", Help: "梦想家", Action: map[string]*ice.Action{
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(WORKER, "空间", SERVER, "门户", ORIGIN, "主机")), mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
), Actions: ice.MergeActions(ice.Actions{ _dream_list(m).Cut("name,status,time")
ice.AFTER_INIT: {Hand: func(m *ice.Message, arg ...string) {
AddPortalProduct(m, "云空间", `
比虚拟机和容器更加轻量每个空间都是一个完整的系统拥有各种软件与独立的环境
空间内所有的软件配置数据以源码库形式保存每个空间都可以随时启动停止上传下载分享
每个空间都自带软件开发工具也可以随时编程添加新的功能
`, 200.0)
}}, }},
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) { cli.START: {Name: "start name repos river", Help: "启动", Hand: func(m *ice.Message, arg ...string) {
if mdb.IsSearchPreview(m, arg) { _dream_show(m, m.Option(mdb.NAME, kit.Select(path.Base(m.Option(nfs.REPOS)), m.Option(mdb.NAME))))
mdb.HashSelects(m.Spawn()).Table(func(value ice.Maps) { m.PushSearch(mdb.TYPE, WORKER, mdb.TEXT, m.MergePod(value[mdb.NAME]), value) })
}
}}, }},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { cli.STOP: {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
switch arg[0] { m.Cmdy(SPACE, mdb.MODIFY, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
case mdb.NAME: m.Cmdy(SPACE, m.Option(mdb.NAME), ice.EXIT)
DreamEach(m, "", kit.Select(cli.START, cli.STOP, m.Option(ctx.ACTION) == STARTALL), func(name string) { m.Push(arg[0], name) }) }},
case tcp.NODENAME: DREAM_STOP: {Name: "dream.stop type name", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(SPACE, m.Option(mdb.NAME), SPACE, ice.INFO).CutTo(mdb.NAME, arg[0]) if m.Cmd(SPACE, m.Option(mdb.NAME)).Append(mdb.STATUS) == cli.STOP {
case aaa.USERNAME: m.Cmdy(SPACE, mdb.REMOVE, m.OptionSimple(mdb.NAME))
if aaa.IsTechOrRoot(m) && m.Option(ctx.ACTION) == GRANT {
m.Cmdy(aaa.USER).Cut(aaa.USERNAME, aaa.USERNICK).Option(ice.TABLE_CHECKBOX, ice.FALSE)
} else { } else {
m.Push(arg[0], m.Option(tcp.NODENAME)) m.Cmdy(SPACE, mdb.REMOVE, m.OptionSimple(mdb.NAME))
m.Push(arg[0], m.Option(ice.MSG_USERNAME)) m.Sleep("1s", DREAM, cli.START, m.OptionSimple(mdb.NAME))
}
case nfs.REPOS:
case nfs.BINARY:
default:
gdb.Event(m, DREAM_INPUTS, arg)
} }
}}, }},
nfs.SCAN: {Hand: func(m *ice.Message, arg ...string) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
list := m.CmdMap(CODE_GIT_REPOS, nfs.REPOS)
GoToastTable(m.Cmd(nfs.DIR, nfs.USR_LOCAL_WORK, mdb.NAME), mdb.NAME, func(value ice.Maps) {
if repos, ok := list[value[mdb.NAME]]; ok {
m.Cmd("", mdb.CREATE, value[mdb.NAME], repos[ORIGIN])
}
})
}},
mdb.CREATE: {Name: "create name*=hi repos binary", Hand: func(m *ice.Message, arg ...string) {
kit.If(!strings.Contains(m.Option(mdb.NAME), "-") || !strings.HasPrefix(m.Option(mdb.NAME), "20"), func() { m.Option(mdb.NAME, m.Time("20060102-")+m.Option(mdb.NAME)) })
m.Option(nfs.REPOS, kit.Select("", kit.Split(m.Option(nfs.REPOS)), -1))
if mdb.HashCreate(m); ice.Info.Important == true {
_dream_start(m, m.Option(mdb.NAME))
SpaceEvent(m, OPS_DREAM_CREATE, m.Option(mdb.NAME), m.OptionSimple(mdb.NAME, nfs.REPOS, nfs.BINARY)...)
}
}},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
gdb.Event(m, DREAM_REMOVE, m.OptionSimple(mdb.NAME))
mdb.HashRemove(m)
}},
STARTALL: {Name: "startall name", Help: "启动", Icon: "bi bi-play-circle", Hand: func(m *ice.Message, arg ...string) {
DreamEach(m, m.Option(mdb.NAME), cli.STOP, func(name string) {
m.Cmd("", cli.START, ice.Maps{mdb.NAME: name, ice.MSG_DAEMON: ""})
})
}},
STOPALL: {Name: "stopall name", Help: "停止", Icon: "bi bi-stop-circle", Hand: func(m *ice.Message, arg ...string) {
DreamEach(m, m.Option(mdb.NAME), cli.START, func(name string) {
m.Cmd("", cli.STOP, ice.Maps{mdb.NAME: name, ice.MSG_DAEMON: ""})
})
}},
cli.BUILD: {Name: "build name", Hand: func(m *ice.Message, arg ...string) {
compile := cli.SystemFindGo(m)
m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD0), m.Option(ice.MSG_USERPOD), m.CommandKey(), m.ActionKey()))
m.Cmd("", FOR_FLOW, m.Option(mdb.NAME), kit.JoinWord(cli.SH, ice.ETC_MISS_SH), func(p string) bool {
if compile && nfs.Exists(m, path.Join(p, ice.SRC_MAIN_GO)) {
return false
} else {
m.Cmd(SPACE, path.Base(p), cli.RUNTIME, UPGRADE)
return true
}
}).Sleep3s()
m.ProcessHold()
}},
PUBLISH: {Name: "publish name", Hand: func(m *ice.Message, arg ...string) {
m.Option(ice.MSG_TITLE, kit.Keys(m.Option(ice.MSG_USERPOD0), m.Option(ice.MSG_USERPOD), m.CommandKey(), m.ActionKey()))
list := []string{cli.LINUX, cli.DARWIN, cli.WINDOWS}
msg := m.Spawn(ice.Maps{ice.MSG_DAEMON: ""})
func() {
if m.Option(mdb.NAME) != "" {
return
}
defer ToastProcess(m, PUBLISH, ice.Info.PathName)()
m.Cmd(AUTOGEN, BINPACK)
kit.For(list, func(goos string) {
list := []string{cli.AMD64}
kit.If(goos == cli.DARWIN, func() { list = append(list, cli.ARM64) })
kit.For(list, func(arch string) {
PushNoticeRich(m, mdb.NAME, ice.Info.NodeName, msg.Cmd(COMPILE, goos, arch).AppendSimple())
})
})
}()
DreamEach(m, m.Option(mdb.NAME), "", func(name string) {
m.Cmd(SPACE, name, AUTOGEN, BINPACK)
kit.For(list, func(goos string) {
list := []string{cli.AMD64}
kit.If(goos == cli.DARWIN, func() { list = append(list, cli.ARM64) })
kit.For(list, func(arch string) {
PushNoticeRich(m.Options(ice.MSG_COUNT, "0", ice.LOG_DISABLE, ice.TRUE), mdb.NAME, name, msg.Cmd(SPACE, name, COMPILE, goos, arch, kit.Dict(ice.MSG_USERPOD, name)).AppendSimple())
})
})
})
m.ProcessHold()
}},
FOR_FLOW: {Name: "forFlow name cmd*='sh etc/miss.sh'", Help: "流程", Icon: "bi bi-terminal", Hand: func(m *ice.Message, arg ...string) {
m.Options(ctx.DISPLAY, html.PLUGIN_XTERM, cli.CMD_OUTPUT, nfs.NewWriteCloser(func(buf []byte) (int, error) {
PushNoticeGrow(m.Options(ice.MSG_COUNT, "0", ice.LOG_DEBUG, ice.FALSE, ice.LOG_DISABLE, ice.TRUE), strings.ReplaceAll(string(buf), lex.NL, "\r\n"))
return len(buf), nil
}, nil))
msg := m.Spawn(ice.Maps{ice.MSG_DEBUG: ice.FALSE})
DreamEach(m, m.Option(mdb.NAME), "", func(name string) {
p := path.Join(ice.USR_LOCAL_WORK, name)
if cb, ok := m.OptionCB("").(func(string) bool); ok && cb(p) {
return
}
defer PushNoticeGrow(msg, "\r\n\r\n")
PushNoticeGrow(msg, kit.Format("\033[33m[%s]%s$\033[0m %s\r\n", time.Now().Format(ice.MOD_TIME_ONLY), name, m.Option(ice.CMD)))
m.Cmd(cli.SYSTEM, kit.Split(m.Option(ice.CMD)), kit.Dict(cli.CMD_DIR, p)).Sleep300ms()
})
}},
cli.START: {Hand: func(m *ice.Message, arg ...string) {
_dream_start(m, m.Option(mdb.NAME))
gdb.Event(m, DREAM_START, arg)
}},
cli.STOP: {Hand: func(m *ice.Message, arg ...string) {
gdb.Event(m, DREAM_STOP, arg)
m.Cmd(SPACE, mdb.MODIFY, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT).Sleep3s()
}},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
gdb.Event(m, DREAM_TRASH, arg)
nfs.Trash(m, path.Join(ice.USR_LOCAL_WORK, m.Option(mdb.NAME)))
}},
cli.RUNTIME: {Hand: func(m *ice.Message, arg ...string) {
ProcessPodCmd(m, m.Option(mdb.NAME), "", nil, arg...)
}},
"settings": {Name: "settings restart=manual,always access=public,private", Help: "设置", Style: html.DANGER, Hand: func(m *ice.Message, arg ...string) {
kit.If(m.Option(cli.RESTART) == "manual", func() { m.Option(cli.RESTART, "") })
kit.If(m.Option(aaa.ACCESS) == aaa.PUBLIC, func() { m.Option(aaa.ACCESS, "") })
mdb.HashModify(m, m.OptionSimple(mdb.NAME, cli.RESTART, aaa.ACCESS))
}},
SETTOKEN: {Name: "settoken nodename* username*", Help: "令牌", Style: html.DANGER, Hand: func(m *ice.Message, arg ...string) {
token := m.Cmdx(TOKEN, mdb.CREATE, mdb.TYPE, SERVER, mdb.NAME, m.Option(aaa.USERNAME), mdb.TEXT, m.Option(tcp.NODENAME))
m.Cmd(SPACE, m.Option(mdb.NAME), SPIDE, DEV_CREATE_TOKEN, ice.Maps{TOKEN: token})
}},
GETTOKEN: {Help: "令牌", Style: html.DANGER, Hand: func(m *ice.Message, arg ...string) {
m.Options(m.Cmd(SPIDE, m.Option(mdb.NAME)).AppendSimple()).Cmdy(SPIDE, mdb.DEV_REQUEST)
}},
GRANT: {Name: "grant username", Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
if aaa.IsTechOrRoot(m) && m.Option(aaa.USERNAME) != "" {
m.Option(ice.MSG_USERNAME, m.Option(aaa.USERNAME))
}
m.Cmd(CHAT_GRANT, aaa.CONFIRM, kit.Dict(SPACE, m.Option(mdb.NAME)))
}},
OPEN: {Style: html.NOTICE, Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) {
if strings.HasSuffix(m.Option(ice.MAIN), ".portal") || kit.HasPrefixList(arg, ctx.RUN) {
if !kit.HasPrefixList(arg, ctx.RUN) {
defer m.Push(TITLE, m.Option(mdb.NAME))
defer m.Push("_icon", m.Option(mdb.ICON))
defer m.Push("_style", "portal")
defer m.Push("_height", "844")
defer m.Push("_width", "390")
}
ctx.ProcessFloat(m, CHAT_IFRAME, S(m.Option(mdb.NAME)), arg...)
} else if m.Option(mdb.TYPE) == ORIGIN {
m.ProcessOpen(SpideOrigin(m, m.Option(mdb.NAME)))
} else if p := ProxyDomain(m, m.Option(mdb.NAME)); p != "" {
m.ProcessOpen(p)
} else {
m.ProcessOpen(S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME))))
}
}},
DREAM_OPEN: {Hand: func(m *ice.Message, arg ...string) {}},
DREAM_CLOSE: {Hand: func(m *ice.Message, arg ...string) {
kit.For(arg, func(k, v string) {
if k == cli.DAEMON && v == ice.OPS && m.Cmdv(SPACE, m.Option(mdb.NAME), mdb.STATUS) != cli.STOP {
m.GoSleep300ms(func() { m.Cmd(DREAM, cli.START, m.OptionSimple(mdb.NAME)) })
}
})
}},
DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
button := []ice.Any{}
if aaa.IsTechOrRoot(m) {
switch m.Option(mdb.TYPE) {
case ORIGIN:
button = append(button, DREAM, GETTOKEN)
case SERVER:
button = append(button, DREAM, SETTOKEN)
case WORKER:
button = append(button, "settings")
}
}
m.PushButton(append(button, OPEN)...)
}},
SERVE_START: {Hand: func(m *ice.Message, arg ...string) {
for _, cmd := range kit.Reverse(kit.Split(mdb.Config(m, html.BUTTON))) {
m.Cmd(gdb.EVENT, gdb.LISTEN, gdb.EVENT, DREAM_TABLES, ice.CMD, cmd)
m.Cmd(gdb.EVENT, gdb.LISTEN, gdb.EVENT, DREAM_ACTION, ice.CMD, cmd)
aaa.White(m, kit.Keys(m.ShortKey(), ctx.ACTION, cmd))
}
mdb.HashSelects(m.Spawn()).SortStrR(mdb.NAME).Table(func(value ice.Maps) {
if value[cli.RESTART] == ALWAYS && nfs.Exists(m, path.Join(ice.USR_LOCAL_WORK+value[mdb.NAME])) {
m.Cmd(DREAM, cli.START, kit.Dict(mdb.NAME, value[mdb.NAME]))
}
})
}},
STATS_TABLES: {Hand: func(m *ice.Message, arg ...string) {
if msg := _dream_list(m.Spawn()); msg.Length() > 0 {
stat := map[string]int{}
msg.Table(func(value ice.Maps) { stat[value[mdb.TYPE]]++; stat[value[mdb.STATUS]]++ })
PushStats(m, kit.Keys(m.CommandKey(), cli.START), stat[cli.START], "", "已启动空间")
PushStats(m, kit.Keys(m.CommandKey(), SERVER), stat[SERVER], "", "已连接机器")
PushStats(m, kit.Keys(m.CommandKey(), ORIGIN), stat[ORIGIN], "", "已连接主机")
}
}},
ORIGIN: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPACE).Table(func(value ice.Maps, index int, head []string) {
kit.If(value[mdb.TYPE] == m.ActionKey(), func() { m.PushRecord(value, head...) })
})
m.SortStrR(mdb.NAME)
kit.If(len(arg) > 0, func() { m.Cut(arg...) })
}},
SERVER: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPACE).Table(func(value ice.Maps, index int, head []string) {
kit.If(value[mdb.TYPE] == m.ActionKey(), func() { m.PushRecord(value, head...) })
})
m.SortStrR(mdb.NAME)
kit.If(len(arg) > 0, func() { m.Cut(arg...) })
}},
WORKER: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPACE).Table(func(value ice.Maps, index int, head []string) {
kit.If(value[mdb.TYPE] == m.ActionKey(), func() { m.PushRecord(value, head...) })
})
m.SortStrR(mdb.NAME)
kit.If(len(arg) > 0, func() { m.Cut(arg...) })
}},
DOWNLOAD: {Name: "download path link", Hand: func(m *ice.Message, arg ...string) {
GoToast(m, func(toast func(string, int, int)) []string {
SpideSave(m, m.Option(nfs.PATH), kit.MergeURL(m.Option(mdb.LINK), cli.GOOS, runtime.GOOS, cli.GOARCH, runtime.GOARCH), func(count, total, value int) {
toast(m.Option(mdb.NAME), count, total)
})
return nil
})
os.Chmod(m.Option(nfs.PATH), ice.MOD_DIR)
}},
VERSION: {Hand: func(m *ice.Message, arg ...string) {
m.Cmdy("web.code.version")
}},
nfs.GOWORK: {Name: "gowork name", Help: "工作区", Icon: "bi bi-exclude", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(cli.SYSTEM, cli.GO, "work", "init")
kit.For([]string{".", nfs.USR_RELEASE, nfs.USR_ICEBERGS, nfs.USR_TOOLKITS}, func(p string) { m.Cmd(cli.SYSTEM, cli.GO, "work", "use", p) })
DreamEach(m, m.Option(mdb.NAME), "", func(name string) { m.Cmd(cli.SYSTEM, cli.GO, "work", "use", path.Join(ice.USR_LOCAL_WORK, name)) })
m.Cmdy(nfs.CAT, "go.work")
}},
}, StatsAction(), DreamAction(), DreamTablesAction(), mdb.ImportantHashAction(
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,help,main,icons,repos,binary,template,restart,access",
html.BUTTON, kit.JoinWord(PORTAL, DESKTOP, ADMIN, WORD, VIMER, STATUS, COMPILE, XTERM, DREAM),
)), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
if ice.Info.NodeType == WORKER {
return
}
_dream_list(m) _dream_list(m)
if _dream_list_more(m); !aaa.IsTechOrRoot(m) || m.IsCliUA() { m.Sort("status,type,name")
m.Action()
} else if m.IsDebug() && cli.SystemFindGo(m) {
m.Action(mdb.CREATE, STARTALL, STOPALL, cli.BUILD, PUBLISH)
} else {
m.Action(mdb.CREATE, STARTALL, STOPALL)
}
if m.Length() == 0 {
m.EchoInfoButton(m.Trans("please scan or create new dream", "请扫描或创建新空间"), mdb.CREATE, nfs.SCAN)
return return
} }
ctx.DisplayTableCard(m)
m.Options(ice.MSG_TOOLKIT, "web.code.compose.insight")
m.Sort("type,status,name", []string{aaa.LOGIN, WORKER, SERVER, ORIGIN}, []string{cli.START, cli.STOP, cli.BEGIN}, ice.STR_R)
m.StatusTimeCountStats(mdb.TYPE, mdb.STATUS)
} else if arg[0] == ctx.ACTION {
m.Cmdy(arg[1], DREAM_ACTION, arg)
// gdb.Event(m, DREAM_ACTION, arg)
}
}},
})
}
func DreamTablesAction(arg ...string) ice.Actions { m.Option(nfs.DIR_ROOT, path.Join(m.Config(nfs.PATH), arg[0]))
return ice.Actions{ice.CTX_INIT: {Hand: DreamWhiteHandle}, m.Cmdy(nfs.CAT, arg[1:])
DREAM_TABLES: {Hand: func(m *ice.Message, _ ...string) {
m.PushButton(kit.Dict(m.CommandKey(), kit.Select(m.Commands("").Help, arg, 0)))
}}, }},
DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { DreamProcess(m, "", nil, arg...) }}, }, Configs: map[string]*ice.Config{
} DREAM: {Name: DREAM, Help: "梦想家", Value: kit.Data(nfs.PATH, ice.USR_LOCAL_WORK,
} "miss", `#! /bin/sh
func DreamAction() ice.Actions { if [ "$ISH_CONF_PRE" = "" ]; then
return gdb.EventsAction( [ -f $PWD/.ish/plug.sh ] || [ -f $HOME/.ish/plug.sh ] || git clone ${ISH_CONF_HUB_PROXY:="https://"}shylinux.com/x/intshell $PWD/.ish
DREAM_INPUTS, DREAM_CREATE, DREAM_REMOVE, DREAM_TRASH, DREAM_OPEN, DREAM_CLOSE, source $PWD/.ish/plug.sh || source $HOME/.ish/plug.sh
OPS_ORIGIN_OPEN, OPS_SERVER_OPEN, OPS_DREAM_CREATE, OPS_DREAM_REMOVE, fi
SERVE_START, SPACE_LOGIN,
) require miss.sh
} ish_miss_prepare_compile
func DreamWhiteHandle(m *ice.Message, arg ...string) { ish_miss_prepare_develop
aaa.White(m, kit.Keys(DREAM, ctx.ACTION, m.ShortKey())) ish_miss_prepare_install
aaa.White(m, kit.Keys(m.ShortKey(), ctx.ACTION, DREAM_ACTION))
} # ish_miss_prepare wubi-dict
func DreamProcessIframe(m *ice.Message, arg ...string) { # ish_miss_prepare word-dict
if !kit.HasPrefixList(arg, ctx.ACTION, m.ShortKey()) && !kit.HasPrefixList(arg, ctx.ACTION, m.CommandKey()) {
return # ish_miss_prepare linux-story
} # ish_miss_prepare mysql-story
if len(arg) == 2 { # ish_miss_prepare release
defer m.Push(TITLE, kit.Keys(m.Option(mdb.NAME), m.ShortKey())+kit.Format("(%s)", m.Command().Help))
defer m.Push("_icon", m.Option(mdb.ICON)) ish_miss_prepare_contexts
} ish_miss_prepare_intshell
DreamProcess(m, CHAT_IFRAME, func() string { # ish_miss_prepare_icebergs
p := S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME))) # ish_miss_prepare_toolkits
kit.If(m.Option(mdb.TYPE) == ORIGIN && m.CommandKey() == PORTAL, func() { p = SpideOrigin(m, m.Option(mdb.NAME)) }) # ish_miss_prepare_volcanos
return kit.MergeURL(p+C(m.ShortKey()), ice.MSG_DEBUG, m.Option(ice.MSG_DEBUG)) # ish_miss_prepare_learning
}, arg...)
} make
func DreamProcess(m *ice.Message, cmd string, args ice.Any, arg ...string) { `,
if !kit.HasPrefixList(arg, ctx.ACTION, m.ShortKey()) && !kit.HasPrefixList(arg, ctx.ACTION, m.CommandKey()) { )},
return }})
} else if arg = arg[2:]; len(arg) == 0 {
arg = append(arg, m.Option(mdb.NAME))
defer m.ProcessField(ctx.ACTION, m.ShortKey(), arg[0], ctx.RUN)
defer processSpace(m, arg[0], arg[0], m.ShortKey())
}
ctx.ProcessFloat(m.Options(ice.POD, arg[0]), kit.Select(m.ShortKey(), cmd), args, arg[1:]...)
}
func DreamEach(m *ice.Message, name string, status string, cb func(string)) *ice.Message {
reg, err := regexp.Compile(name)
if m.WarnNotValid(err) {
return m
}
msg := m.Spawn()
m.Cmds(DREAM, kit.Dict(ice.DREAM_SIMPLE, ice.TRUE)).Table(func(value ice.Maps) {
if value[mdb.STATUS] == kit.Select(cli.START, status) && value[mdb.TYPE] == WORKER && (value[mdb.NAME] == name || reg.MatchString(kit.Format("%s:%s=%s@%d", value[mdb.NAME], value[mdb.TYPE], value[nfs.MODULE], value[nfs.VERSION]))) {
msg.Push(mdb.NAME, value[mdb.NAME])
}
})
return GoToastTable(msg, mdb.NAME, func(value ice.Maps) { cb(value[mdb.NAME]) })
}
func DreamListSpide(m *ice.Message, list []string, types string, cb func(dev, origin string)) {
msg := m.Spawn()
kit.For(list, func(name string) { msg.Push(mdb.NAME, name) })
m.Cmds(SPACE).Table(func(value ice.Maps) { kit.If(value[mdb.TYPE] == types, func() { msg.Push(mdb.NAME, value[mdb.NAME]) }) })
has := map[string]bool{}
GoToastTable(msg, mdb.NAME, func(value ice.Maps) {
origin := SpideOrigin(m, value[mdb.NAME])
kit.If(!has[origin], func() { has[origin] = true; cb(value[mdb.NAME], origin) })
})
}
func DreamList(m *ice.Message) *ice.Message {
return AdminCmd(m.Options(ice.DREAM_SIMPLE, ice.TRUE), DREAM)
}
func DreamStat(m *ice.Message, name string) (res string) {
if cli.SystemFindGit(m) {
text := []string{}
for _, line := range kit.Split(m.Cmdx(cli.SYSTEM, cli.GIT, "diff", "--shortstat", kit.Dict(cli.CMD_DIR, path.Join(ice.USR_LOCAL_WORK, name))), mdb.FS, mdb.FS) {
if list := kit.Split(line); strings.Contains(line, nfs.FILE) {
text = append(text, kit.Format("<span class='files'>%s file</span>", list[0]))
} else if strings.Contains(line, "ins") {
text = append(text, kit.Format("<span class='add'>%s+++</span>", list[0]))
} else if strings.Contains(line, "del") {
text = append(text, kit.Format("<span class='del'>%s---</span>", list[0]))
}
}
res = strings.Join(text, "")
}
return
} }

Some files were not shown because too many files have changed in this diff Show More