1
0
mirror of https://shylinux.com/x/icebergs synced 2025-05-12 23:40:15 +08:00

Compare commits

..

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

501 changed files with 16356 additions and 30193 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2025 shylinux
Copyright (c) 2021 码神
Permission is hereby granted, free of charge, to any person obtaining a copy
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可以将各种设备自由的组合在一起快速搭建起分布式的服务器。
## 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"
const (
RSA = "rsa"
SIGN = "sign"
CERT = "cert"
VERIFY = "verify"
BASE64 = "base64"
)
const AAA = "aaa"
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
import (
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
func _role_keys(key ...string) string {
if _key := kit.Select("", strings.Split(key[0], ice.PT), -1); _key != "" {
if c, ok := ice.Info.Index[_key].(*ice.Context); ok && kit.Keys(c.Prefix(), _key) == key[0] {
key[0] = _key
}
}
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.")
}
func _role_set(m *ice.Message, role, zone, key string, status bool) {
m.Logs(mdb.INSERT, mdb.KEY, ROLE, ROLE, role, zone, key)
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) }
func _role_check(value ice.Map, key []string, ok bool) bool {
white, black := value[WHITE].(ice.Map), value[BLACK].(ice.Map)
for i := 0; i < len(key); i++ {
kit.If(white[kit.Join(key[:i+1], ice.PT)], func() { ok = true })
kit.If(black[kit.Join(key[:i+1], ice.PT)], func() { ok = false })
}
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 _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)
}
func _role_list(m *ice.Message, userrole string) {
m.Richs(ROLE, nil, kit.Select(mdb.FOREACH, userrole), func(key string, value map[string]interface{}) {
kit.Fetch(value[BLACK], func(k string, v interface{}) {
m.Push(ROLE, kit.Value(value, mdb.NAME))
m.Push(mdb.ZONE, BLACK)
m.Push(mdb.KEY, k)
})
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)
}
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)
})
})
return m.Sort(mdb.KEY)
}
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 // 在黑名单
}
}
if m.Warn(!ok, ice.ErrNotRight, keys, USERROLE, userrole) {
return // 没有权限
}
if userrole == TECH {
return // 管理权限
}
ok = false
list = value[WHITE].(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 = true // 在白名单
}
}
if m.Warn(!ok, ice.ErrNotRight, keys, USERROLE, userrole) {
return // 没有权限
}
if userrole == VOID {
return // 用户权限
}
})
return ok
}
func RoleRight(m *ice.Message, userrole string, keys ...string) bool {
return _role_right(m, userrole, kit.Split(kit.Keys(keys), ice.PT)...)
}
const (
@ -57,116 +84,55 @@ const (
VOID = "void"
)
const (
WHITE = "white"
BLACK = "black"
WHITE = "white"
RIGHT = "right"
)
const (
AUTH = "auth"
ACCESS = "access"
PUBLIC = "public"
PRIVATE = "private"
CONFIRM = "confirm"
)
const ROLE = "role"
func init() {
Index.MergeCommands(ice.Commands{
ROLE: {Name: "role name key auto", Help: "角色", Actions: ice.MergeActions(ice.Actions{
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
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) {
m.Cmd(ROLE, mdb.CREATE, VOID, TECH)
has := map[string]bool{VOID: true, TECH: true}
m.Travel(func(p *ice.Context, c *ice.Context, key string, cmd *ice.Command) {
role := map[string][]string{}
kit.For(kit.Split(cmd.Role), func(k string) { role[k] = []string{} })
for sub, action := range cmd.Actions {
kit.For(kit.Split(action.Role), func(k string) { role[k] = append(role[k], sub) })
}
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)
m.Rich(ROLE, nil, kit.Dict(mdb.NAME, TECH, BLACK, kit.Dict(), WHITE, kit.Dict()))
m.Rich(ROLE, nil, kit.Dict(mdb.NAME, VOID, WHITE, kit.Dict(), BLACK, kit.Dict()))
m.Cmd(ROLE, WHITE, VOID, ice.SRC)
m.Cmd(ROLE, WHITE, VOID, ice.BIN)
m.Cmd(ROLE, WHITE, VOID, ice.USR)
m.Cmd(ROLE, BLACK, VOID, ice.USR_LOCAL)
m.Cmd(ROLE, WHITE, VOID, ice.USR_LOCAL_GO)
}},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
if arg[0] == mdb.KEY {
mdb.HashInputs(m, ice.INDEX).CutTo(ice.INDEX, arg[0])
}
}},
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,tech zone=white,black key=", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
m.Richs(ROLE, nil, m.Option(ROLE), func(key string, value map[string]interface{}) {
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.INSERT: {Name: "insert role*=void zone*=white,black key*", Hand: func(m *ice.Message, arg ...string) {
_role_set(m, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY), true)
mdb.DELETE: {Name: "delete", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
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))
list := value[m.Option(mdb.ZONE)].(map[string]interface{})
delete(list, m.Option(mdb.KEY))
})
}},
mdb.DELETE: {Hand: func(m *ice.Message, arg ...string) {
_role_set(m, m.Option(ROLE), m.Option(mdb.ZONE), m.Option(mdb.KEY), false)
BLACK: {Name: "black role chain", Help: "黑名单", Hand: func(m *ice.Message, arg ...string) {
_role_black(m, arg[0], _role_chain(arg[1:]...))
}},
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)...) {
m.Echo(ice.OK)
break
}
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)
}
}},
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name")), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
mdb.HashSelect(m, arg...)
} else {
_role_list(m, kit.Select("", arg, 0), kit.Slice(arg, 1)...)
}
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_role_list(m, kit.Select("", arg, 0))
m.PushAction(mdb.DELETE)
}},
})
}})
}
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"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
func _sess_create(m *ice.Message, username string, arg ...string) {
if msg := m.Cmd(USER, username); msg.Length() > 0 {
mdb.HashCreate(m, msg.AppendSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg)
} else {
mdb.HashCreate(m, m.OptionSimple(USERROLE, USERNAME, USERNICK, AVATAR), arg)
func _sess_check(m *ice.Message, sessid string) bool {
m.Option(ice.MSG_USERROLE, VOID)
m.Option(ice.MSG_USERNAME, "")
m.Option(ice.MSG_USERNICK, "")
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 // 会话超时
}
if m.Richs(USER, nil, value[USERNAME], func(value map[string]interface{}) {
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]),
)
}) == 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_check(m *ice.Message, sessid string) {
if val := mdb.HashSelectDetails(m, sessid, func(value ice.Map) bool {
return kit.Format(value[mdb.TIME]) > m.Time()
}); len(val) > 0 {
SessAuth(m, val)
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 (
@ -27,46 +59,25 @@ const (
UA = "ua"
)
const (
CHECK = "check"
GRANT = "grant"
LOGIN = "login"
LOGOUT = "logout"
)
const (
SESS_CREATE = "sess.create"
)
const SESS = "sess"
func init() {
Index.MergeCommands(ice.Commands{
SESS: {Name: "sess hash auto", Help: "会话", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create username*", Hand: func(m *ice.Message, arg ...string) {
_sess_create(m, m.Option(USERNAME), UA, m.Option(ice.MSG_USERUA), IP, m.Option(ice.MSG_USERIP))
}},
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) })
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SESS: {Name: SESS, Help: "会话", Value: kit.Data(
mdb.SHORT, "uniq", mdb.FIELD, "time,hash,userrole,username,usernick,ip,ua", mdb.EXPIRE, "720h",
)},
}, 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...)
}},
}})
}

View File

@ -21,48 +21,68 @@ func _totp_gen(per int64) string {
b := hmac.New(sha1.New, buf.Bytes()).Sum(nil)
return strings.ToUpper(base32.StdEncoding.EncodeToString(b[:]))
}
func _totp_get(key string, per int64, num int) string {
buf, now := []byte{}, 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) })
func _totp_get(key string, num int, per int64) string {
now := kit.Int64(time.Now().Unix() / per)
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))
hm := hmac.New(sha1.New, s)
hm.Write(buf)
b := hm.Sum(nil)
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)
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"
func init() {
const (
NUMBER = "number"
PERIOD = "period"
SECRET = "secret"
)
Index.MergeCommands(ice.Commands{
TOTP: {Help: "令牌", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create name*=hi number*=6 period*=30 secret", Hand: func(m *ice.Message, arg ...string) {
kit.If(m.Option(SECRET) == "", func() { m.Option(SECRET, _totp_gen(kit.Int64(m.Option(PERIOD)))) })
mdb.HashCreate(m, m.OptionSimple(mdb.NAME, NUMBER, PERIOD, SECRET))
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
TOTP: {Name: TOTP, Help: "令牌", Value: kit.Data(
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,secret,period,number", mdb.LINK, "otpauth://totp/%s?secret=%s",
)},
}, Commands: map[string]*ice.Command{
TOTP: {Name: "totp name auto create", Help: "令牌", Action: ice.MergeAction(map[string]*ice.Action{
mdb.CREATE: {Name: "create name secret period=30 number=6", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
if m.Option(SECRET) == "" { // 创建密钥
m.Option(SECRET, _totp_gen(kit.Int64(m.Option(PERIOD))))
}
m.Cmd(mdb.INSERT, TOTP, "", mdb.HASH, m.OptionSimple(mdb.NAME, SECRET, PERIOD, NUMBER))
}},
}, 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])))
}, 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.PushQRCode(mdb.SCAN, kit.Format(mdb.Config(m, mdb.LINK), value[mdb.NAME], value[SECRET]))
m.Echo(m.Append(mdb.VALUE))
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])))
}
})
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) }

View File

@ -2,111 +2,138 @@ package aaa
import (
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 _user_create(m *ice.Message, name string, arg ...string) {
mdb.HashCreate(m, USERNAME, name, arg)
gdb.Event(m, USER_CREATE, USER, name)
func _user_exists(m *ice.Message, name string) bool {
return m.Richs(USER, nil, name, nil) != nil
}
func _user_remove(m *ice.Message, name string, arg ...string) {
gdb.Event(m, USER_REMOVE, m.OptionSimple(USERNAME, USERNICK))
mdb.HashRemove(m, m.OptionSimple(USERNAME))
func _user_login(m *ice.Message, name, word string) (ok bool) {
if !_user_exists(m, name) {
_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 (
BACKGROUND = "background"
AVATAR_URL = "avatar_url"
AVATAR = "avatar"
GENDER = "gender"
MOBILE = "mobile"
PHONE = "phone"
SECRET = "secret"
THEME = "theme"
LANGUAGE = "language"
LOCATION = "location"
LONGITUDE = "longitude"
LATITUDE = "latitude"
COMPANY = "company"
PROVINCE = "province"
COUNTRY = "country"
CITY = "city"
AVATAR = "avatar"
GENDER = "gender"
MOBILE = "mobile"
EMAIL = "email"
CITY = "city"
COUNTRY = "country"
LANGUAGE = "language"
PROVINCE = "province"
)
const (
USERNICK = "usernick"
USERROLE = "userrole"
USERNAME = "username"
PASSWORD = "password"
USERROLE = "userrole"
USERNICK = "usernick"
USERZONE = "userzone"
)
const (
USER_CREATE = "user.create"
USER_REMOVE = "user.remove"
)
const (
INVITE = "invite"
)
const USER = "user"
func init() {
Index.MergeCommands(ice.Commands{
USER: {Help: "用户", Icon: "Contacts.png", Actions: ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch mdb.HashInputs(m, arg); arg[0] {
case USERNICK:
m.Push(arg[0], m.Option(ice.MSG_USERNICK))
case USERNAME:
m.Push(arg[0], m.Option(ice.MSG_USERNAME))
}
if arg[0] == USERROLE {
m.Option(ice.TABLE_CHECKBOX, ice.TRUE)
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
USER: {Name: USER, Help: "用户", Value: kit.Data(
mdb.SHORT, USERNAME, mdb.FIELD, "time,userrole,username,usernick,userzone",
)},
}, Commands: map[string]*ice.Command{
USER: {Name: "user username auto create", Help: "用户", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(mdb.SEARCH, mdb.CREATE, m.CommandKey(), m.PrefixKey())
UserRoot(ice.Pulse)
}},
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) {
_user_create(m, m.Option(USERNAME), m.OptionSimple(USERROLE, USERNICK, LANGUAGE, AVATAR, BACKGROUND, USERZONE, EMAIL)...)
mdb.CREATE: {Name: "create userrole=void,tech username password", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
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.ImportantHashAction(mdb.SHORT, USERNAME, mdb.FIELD, "time,userrole,username,usernick,language,avatar,background,userzone", html.CHECKBOX, ice.TRUE))},
})
}
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))
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...)
}},
}})
}

View File

@ -1,18 +1,18 @@
package base
package shy
import (
_ "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/web"
_ "shylinux.com/x/icebergs/base/gdb"
_ "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/cli"
_ "shylinux.com/x/icebergs/base/log"
_ "shylinux.com/x/icebergs/base/mdb"
_ "shylinux.com/x/icebergs/base/nfs"
_ "shylinux.com/x/icebergs/base/ssh"
_ "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
import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
import ice "shylinux.com/x/icebergs"
const CLI = "cli"
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, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE, SUDO) }
func init() { ice.Index.Register(Index, nil, RUNTIME, QRCODE, MIRROR, SYSTEM, DAEMON, FOREVER) }

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,73 +1,69 @@
package cli
import (
"bytes"
"io"
"os/exec"
"runtime"
"strings"
ice "shylinux.com/x/icebergs"
"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/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits"
)
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 {
cmd.Stdout, cmd.Stderr = w, w
cmd.Stdout = w
cmd.Stderr = w
}
if w := _system_out(m, CMD_ERRPUT); w != nil {
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.WarnNotValid(e, cmd.Args, err.String()) {
mdb.HashModify(m, h, STATUS, ERROR, ERROR, e)
return
// 启动进程
if e := cmd.Start(); m.Warn(e, ice.ErrNotStart, cmd.Args) {
return // 启动失败
}
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)
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.Wait(); !m.Warn(e, ice.ErrNotStart, cmd.Args) && cmd.ProcessState.ExitCode() == 0 {
m.Cost(CODE, cmd.ProcessState.ExitCode(), ctx.ARGS, cmd.Args)
m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, mdb.HASH, h, STATUS, STOP)
} else {
mdb.HashSelectUpdate(m, h, func(value ice.Map) { value[STATUS], value[ERROR] = ERROR, e })
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)
}
}
switch status := mdb.HashSelectField(m.Sleep300ms(), h, STATUS); cb := m.OptionCB("").(type) {
switch m.Sleep300ms(); cb := m.OptionCB(DAEMON).(type) {
case func(string) bool:
kit.If(!cb(status), func() { m.Cmdy(DAEMON, cmd.Path, cmd.Args) })
if !cb(m.Conf(DAEMON, kit.Keys(mdb.HASH, h, kit.Keym(STATUS)))) {
m.Cmdy(DAEMON, cmd.Path, cmd.Args)
}
case func(string):
cb(status)
cb(m.Conf(DAEMON, kit.Keys(mdb.HASH, h, kit.Keym(STATUS))))
case func():
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))
}
})
}
const (
DIR = "dir"
ENV = "env"
API = "api"
MOD = "mod"
PWD = "pwd"
PID = "pid"
PPID = "ppid"
DIR = "dir"
ENV = "env"
API = "api"
PID = "pid"
PWD = "pwd"
)
const (
BUILD = "build"
@ -76,129 +72,78 @@ const (
CHECK = "check"
BENCH = "bench"
PPROF = "pprof"
CLEAR = "clear"
TIMEOUT = "timeout"
STATUS = "status"
ERROR = "error"
CLEAR = "clear"
STASH = "stash"
DELAY = "delay"
RECORD = "record"
RELOAD = "reload"
REBOOT = "reboot"
RESTART = "restart"
INTERVAL = "interval"
OPTS = "opts"
ARGS = "args"
LOGS = "logs"
TIMEOUT = "timeout"
STATUS = "status"
ERROR = "error"
START = "start"
RESTART = "restart"
RELOAD = "reload"
STOP = "stop"
BEGIN = "begin"
END = "end"
START = "start"
STOP = "stop"
OPEN = "open"
CLOSE = "close"
PLAY = "play"
MAIN = "main"
CODE = "code"
COST = "cost"
FROM = "from"
BACK = "back"
FROM = "from"
MAIN = "main"
KILL = "kill"
OPEN = "open"
CLOSE = "close"
BEGIN = "begin"
END = "end"
)
const DAEMON = "daemon"
func init() {
Index.MergeCommands(ice.Commands{
DAEMON: {Name: "daemon hash auto", Help: "守护进程", Actions: ice.MergeActions(ice.Actions{
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
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) {
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) {
m.Options(CMD_DIR, m.Option(DIR), CMD_ENV, kit.Split(m.Option(ENV), " ="))
_daemon_exec(m, _system_cmd(m, kit.Split(m.Option(ice.CMD))...))
mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(mdb.FIELD))
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) {
m.Cmdy("", STOP).Sleep3s().Cmdy("", START)
START: {Name: "start cmd env dir", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
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) {
h, pid := m.Option(mdb.HASH), m.Option(PID)
mdb.HashSelects(m.Spawn(), h).Table(func(value ice.Maps) {
if h == "" && value[PID] != pid {
return
}
mdb.HashModify(m, mdb.HASH, kit.Select(h, value[mdb.HASH]), STATUS, STOP)
kit.If(value[PID], func() { m.Cmd(gdb.SIGNAL, gdb.KILL, value[PID]) })
RESTART: {Name: "restart", Help: "重启", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(DAEMON, STOP).Sleep3s().Cmdy(DAEMON, START)
}},
STOP: {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
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) {
m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, m.OptionSimple(mdb.HASH), STATUS, STOP)
m.Cmdy(SYSTEM, KILL, value[PID])
})
}},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
h, pid := m.Option(mdb.HASH), m.Option(PID)
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) {
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
mdb.HashSelect(m, arg...).Set(ctx.ACTION).Table(func(index int, value map[string]string, head []string) {
switch value[STATUS] {
case START:
m.PushButton(RESTART, STOP)
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 !tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
// return
} else if len(arg) == 0 || arg[0] == "" {
// return
}
switch runtime.GOOS {
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])
}
}
if len(arg) == 0 || m.Length() > 0 {
return
}
if len(arg) == 1 {
arg = kit.Split(arg[0])
}
_daemon_exec(m, _system_cmd(m, arg...))
}},
}})
}
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,54 @@ package cli
import (
"os"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/nfs"
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"
func init() {
Index.MergeCommands(ice.Commands{
FOREVER: {Help: "启动", Actions: ice.Actions{
START: {Hand: func(m *ice.Message, arg ...string) {
env := []string{PATH, BinPath(""), HOME, kit.Select(kit.Path(""), os.Getenv(HOME))}
kit.For(ENV_LIST, func(k string) { kit.If(kit.Env(k) != "", func() { env = append(env, k, kit.Env(k)) }) })
kit.For(os.Environ(), func(v string) {
if ls := kit.Split(v, mdb.EQ, mdb.EQ); kit.IndexOf(env, ls[0]) == -1 && len(ls) > 1 {
env = append(env, ls[0], ls[1])
const SERVE = "serve"
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
FOREVER: {Name: "forever", Help: "启动", Action: map[string]*ice.Action{
SERVE: {Name: "serve", Help: "服务", Hand: func(m *ice.Message, arg ...string) {
env := []string{PATH, BinPath(), HOME, kit.Select(kit.Path(""), os.Getenv(HOME))}
for _, k := range []string{TERM, SHELL, CTX_SHY, CTX_DEV, CTX_OPS, CTX_ARG, CTX_PID, CTX_USER, CTX_SHARE, CTX_RIVER} {
if kit.Env(k) != "" {
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)
}
}},
RESTART: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(gdb.SIGNAL, gdb.RESTART) }},
STOP: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(gdb.SIGNAL, gdb.STOP) }},
DELAY: {Hand: func(m *ice.Message, arg ...string) { m.Sleep(arg[0]).Cmdy(arg[1:]) }},
}, Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
m.Cmdy(RUNTIME, BOOTINFO)
return
}
for {
if logs.Println("run %s", kit.Join(arg, lex.SP)); IsSuccess(m.Cmd(SYSTEM, arg)) {
logs.Println(ice.EXIT)
break
}
logs.Println()
}
}},
})
}
m.Option(CMD_ENV, env)
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)) })
})
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)
}
if p := m.Cmdx(nfs.CAT, m.Conf("gdb.signal", kit.Keym(nfs.PATH))); p != "" {
m.Cmd(SYSTEM, "kill", "-n", 3, 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)
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
for {
println(kit.Format("%s run %s", kit.Now(), kit.Join(arg, ice.SP)))
if m.Sleep("1s"); IsSuccess(m.Cmd(SYSTEM, arg)) {
println(kit.Format("%s exit", kit.Now()))
return
}
}
}}},
})
kit.For(strings.Split(kit.Env(PATH), _path_sep()), func(p string) { push(p) })
return kit.Join(list, _path_sep())
}

View File

@ -1,122 +1,57 @@
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"
func IsAlpine(m *ice.Message, arg ...string) bool {
if strings.Contains(m.Conf(RUNTIME, "host.OSID"), ALPINE) {
if len(arg) > 0 {
m.Cmd(MIRROR, mdb.CREATE, "cli", arg[0], "cmd", arg[1])
}
return true
}
return false
}
ETC_OS_RELEASE = "/etc/os-release"
ETC_APK_REPOS = "/etc/apk/repositories"
const (
OSID = "OSID"
ALPINE = "alpine"
CENTOS = "centos"
UBUNTU = "ubuntu"
)
const MIRRORS = "mirrors"
const MIRROR = "mirror"
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])))
})
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
MIRROR: {Name: "mirror cli auto", Help: "软件镜像", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Go(func() {
m.Sleep("1s")
IsAlpine(m, "curl", "system apk add curl")
IsAlpine(m, "make", "system apk add make")
IsAlpine(m, "gcc", "system apk add gcc")
IsAlpine(m, "vim", "system apk add vim")
IsAlpine(m, "tmux", "system apk add tmux")
if IsAlpine(m, "git", "system apk add git"); !IsAlpine(m, "go", "system apk add git go") {
m.Cmd(MIRROR, mdb.CREATE, kit.SimpleKV("cli,cmd", "go", "install download https://golang.google.cn/dl/go1.15.5.linux-amd64.tar.gz usr/local"))
}
IsAlpine(m, "node", "system apk add nodejs")
IsAlpine(m, "java", "system apk add openjdk8")
IsAlpine(m, "javac", "system apk add openjdk8")
IsAlpine(m, "python", "system apk add python2")
IsAlpine(m, "python2", "system apk add python2")
IsAlpine(m, "python3", "system apk add python3")
})
}},
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...)
mdb.CREATE: {Name: "create cli cmd", Help: "创建"},
}, mdb.HashAction(mdb.SHORT, "cli", mdb.FIELD, "time,cli,cmd"))},
}})
}

View File

@ -2,22 +2,71 @@ package cli
import (
"encoding/base64"
"fmt"
"image/color"
"math/rand"
"strconv"
"strings"
"shylinux.com/x/go-qrcode"
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"
)
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) {
sc := qrcode.New(text)
fg := ParseCliColor(m.Option(FG))
bg := ParseCliColor(m.Option(BG))
data := sc.Bitmap()
qr, _ := qrcode.New(text, qrcode.Medium)
fg := _parse_cli_color(m.Option(FG))
bg := _parse_cli_color(m.Option(BG))
data := qr.Bitmap()
for i, row := range data {
if n := len(data); i < 3 || i >= n-3 {
continue
@ -26,63 +75,76 @@ func _qrcode_cli(m *ice.Message, text string) {
if n := len(row); i < 3 || i >= n-3 {
continue
}
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 {
sc := qrcode.New(text)
sc.ForegroundColor = ParseColor(m.Option(FG))
sc.BackgroundColor = ParseColor(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)
func _qrcode_web(m *ice.Message, text string) {
qr, _ := qrcode.New(text, qrcode.Medium)
qr.ForegroundColor = _parse_color(m.Option(FG))
qr.BackgroundColor = _parse_color(m.Option(BG))
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 (
FG = "fg"
BG = "bg"
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"
func init() {
Index.MergeCommands(ice.Commands{
QRCODE: {Name: "qrcode text fg@key bg@key size auto", Help: "二维码", Icon: "Chess.png", Role: aaa.VOID, Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(mdb.TEXT, "文本", BG, "背景色", FG, "字体色")),
), Actions: ice.MergeActions(ice.Actions{
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
QRCODE: {Name: "qrcode text fg bg size auto", Help: "二维码", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
ice.AddRender(ice.RENDER_QRCODE, func(m *ice.Message, args ...ice.Any) string {
if m.IsMobileUA() {
m.Option(SIZE, "280")
}
return m.Cmd(Prefix(QRCODE), kit.Simple(args...)).Result()
ice.AddRender(ice.RENDER_QRCODE, func(m *ice.Message, cmd string, args ...interface{}) string {
return m.Cmd(QRCODE, kit.Simple(args...)).Result()
})
}},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case FG, BG:
m.Push(arg[0], kit.SortedKey(_color_map))
}
}},
}), Hand: func(m *ice.Message, arg ...string) {
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(SIZE, kit.Select("240", arg, 3))
m.Option(BG, kit.Select(WHITE, arg, 2))
m.Option(FG, kit.Select(BLUE, arg, 1))
if m.IsCliUA() {
m.OptionDefault(FG, BLACK, BG, WHITE)
_qrcode_cli(m, kit.Select(kit.Select(ice.Info.Make.Domain, ice.Info.Domain), arg, 0))
_qrcode_cli(m, kit.Select(ice.Info.Domain, arg, 0))
} else {
// m.OptionDefault(SIZE, kit.Select("360", "280", m.IsMobileUA()))
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))))
_qrcode_web(m, kit.Select(m.Option(ice.MSG_USERWEB), arg, 0))
}
}},
})
}})
}

View File

@ -2,306 +2,221 @@ package cli
import (
"os"
"os/user"
"path"
"runtime"
"strings"
"time"
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/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits"
)
func _runtime_init(m *ice.Message) {
count := kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT)))
defer m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT), count+1)
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) })
// 版本信息 make
kit.Fetch(kit.UnMarshal(kit.Format(ice.Info.Make)), func(key string, value interface{}) {
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, 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, PWD), kit.Path(""))
m.Conf(RUNTIME, kit.Keys(HOST, HOME), kit.HomePath(""))
m.Conf(RUNTIME, kit.Keys(HOST, MAXPROCS), runtime.GOMAXPROCS(0))
ice.Info.System = m.Conf(RUNTIME, kit.Keys(HOST, OSID))
kit.For(ENV_LIST, func(k string) { m.Conf(RUNTIME, kit.Keys(CONF, k), kit.Env(k)) })
ice.Info.Lang = m.Conf(RUNTIME, kit.Keys(CONF, LANG))
m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.UserName())
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)
}
ice.Info.Username = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME))
ice.Info.Hostname = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME))
ice.Info.Pathname = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME))
kit.HashSeed = append(kit.HashSeed, ice.Info.Username)
kit.HashSeed = append(kit.HashSeed, ice.Info.Hostname)
kit.HashSeed = append(kit.HashSeed, ice.Info.Pathname)
aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Author, "", "", ice.DEV, ice.Info.Make.Email)
aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Username, "", "", ice.DEV, ice.Info.Make.Email)
aaa.UserRoot(ice.Pulse, aaa.ROOT, ice.Info.Username)
aaa.UserRoot(ice.Pulse, aaa.ROOT, aaa.ROOT)
ice.Info.Time = m.Time()
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.TIME), ice.Info.Time)
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) {
m.Push("time", ice.Info.Make.Time)
m.Push("nCPU", runtime.NumCPU())
m.Push("GOMAXPROCS", runtime.GOMAXPROCS(0))
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 {
break
}
m.Conf(RUNTIME, kit.Keys(HOST, HOME), kit.Env(HOME))
osid := ""
m.Cmd(nfs.CAT, "/etc/os-release", func(text string) {
if ls := kit.Split(text, "="); len(ls) > 1 {
switch ls[0] {
case "ID", "ID_LIKE":
osid = strings.TrimSpace(ls[1] + ice.SP + osid)
}
}
} else {
m.Push("MemAvailable", "")
m.Push("MemTotal", "")
m.Push("MemFree", "")
})
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.HostName = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME))
ice.Info.PathName = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME))
ice.Info.UserName = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME))
// 启动次数 boot
m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT), kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, mdb.COUNT)))+1)
m.Conf(RUNTIME, kit.Keys(BOOT, ice.BIN), _system_find(m, os.Args[0]))
// 环境变量 conf
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(CONF, k), kit.Env(k))
}
}
func _runtime_hostinfo(m *ice.Message) {
m.Push("nCPU", strings.Count(m.Cmdx(nfs.CAT, "/proc/cpuinfo"), "processor"))
for i, ls := range strings.Split(m.Cmdx(nfs.CAT, "/proc/meminfo"), ice.NL) {
vs := kit.Split(ls, ": ")
if m.Push(strings.TrimSpace(vs[0]), kit.FmtSize(kit.Int64(strings.TrimSpace(vs[1]))*1024)); i > 1 {
break
}
}
m.Push("uptime", kit.Split(m.Cmdx(SYSTEM, "uptime"), ice.FS)[0])
}
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) {
kit.If(strings.HasPrefix(value["Filesystem"], "/dev"), func() { m.Push("", value, head) })
m.Spawn().Split(m.Cmdx(SYSTEM, "df", "-h"), "", ice.SP, ice.NL).Table(func(index int, value map[string]string, head []string) {
if strings.HasPrefix(value["Filesystem"], "/dev") {
m.Push("", value, head)
}
})
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 (
MAKE = "make"
TEST = "test"
HOST = "host"
CONF = "conf"
BOOT = "boot"
CONF = "conf"
NODE = "node"
)
const (
GOARCH = "GOARCH"
AMD64 = "amd64"
X86 = "386"
ARM = "arm"
ARM64 = "arm64"
MIPSLE = "mipsle"
GOARCH = "GOARCH"
AMD64 = "amd64"
X386 = "386"
ARM = "arm"
ARM64 = "arm64"
GOOS = "GOOS"
LINUX = "linux"
MACOS = "macos"
DARWIN = "darwin"
WINDOWS = "windows"
COMMIT_TIME = "commitTime"
COMPILE_TIME = "compileTime"
BOOT_TIME = "bootTime"
KERNEL = "kernel"
ARCH = "arch"
CPU = "cpu"
OS = "os"
)
const (
PATH = "PATH"
HOME = "HOME"
USER = "USER"
TERM = "TERM"
SHELL = "SHELL"
LANG = "LANG"
TZ = "TZ"
TERM = "TERM"
USER = "USER"
HOME = "HOME"
PATH = "PATH"
)
const (
CTX_SHY = "ctx_shy"
CTX_DEV = "ctx_dev"
CTX_DEV_IP = "ctx_dev_ip"
CTX_OPS = "ctx_ops"
CTX_REPOS = "ctx_repos"
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_LOG = "ctx_log"
CTX_POD = "ctx_pod"
CTX_ENV = "ctx_env"
CTX_CLI = "ctx_cli"
CTX_SHY = "ctx_shy"
CTX_DEV = "ctx_dev"
CTX_OPS = "ctx_ops"
CTX_ARG = "ctx_arg"
CTX_PID = "ctx_pid"
CTX_LOG = "ctx_log"
CTX_USER = "ctx_user"
CTX_SHARE = "ctx_share"
CTX_RIVER = "ctx_river"
)
var ENV_LIST = []string{TZ, LANG, TERM, SHELL, CTX_SHY, CTX_DEV, CTX_OPS, CTX_DEMO, CTX_MAIL, CTX_ROOT, CTX_PID}
const (
USERNAME = "username"
HOSTNAME = "hostname"
PATHNAME = "pathname"
USERNAME = "username"
)
const (
MAXPROCS = "maxprocs"
IFCONFIG = "ifconfig"
DISKINFO = "diskinfo"
HOSTINFO = "hostinfo"
USERINFO = "userinfo"
PROCINFO = "procinfo"
PROCKILL = "prockill"
BOOTINFO = "bootinfo"
MAXPROCS = "maxprocs"
DISKINFO = "diskinfo"
)
const RUNTIME = "runtime"
func init() {
Index.MergeCommands(ice.Commands{
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{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { _runtime_init(m) }},
IFCONFIG: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(tcp.HOST) }},
DISKINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_diskinfo(m) }},
HOSTINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_hostinfo(m) }},
HOSTNAME: {Hand: func(m *ice.Message, arg ...string) {
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]))
}
m.Echo(ice.Info.Hostname)
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
RUNTIME: {Name: RUNTIME, Help: "运行环境", Value: kit.Dict()},
}, Commands: map[string]*ice.Command{
RUNTIME: {Name: "runtime info=ifconfig,hostinfo,hostname,userinfo,procinfo,bootinfo,diskinfo,env,file,route auto", Help: "运行环境", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
_runtime_init(m)
m.Cmd(RUNTIME, MAXPROCS, "1")
}},
MAXPROCS: {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]))) })
MAXPROCS: {Name: "maxprocs", Help: "最大并发", Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 {
runtime.GOMAXPROCS(kit.Int(m.Conf(RUNTIME, kit.Keys(HOST, "GOMAXPROCS"), kit.Select("1", arg, 0))))
}
m.Echo("%d", runtime.GOMAXPROCS(0))
}},
USERINFO: {Hand: func(m *ice.Message, arg ...string) { m.Split(m.Cmdx(SYSTEM, "who"), "user term time") }},
aaa.ROLE: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(aaa.ROLE, func(value ice.Maps) { m.Push(mdb.KEY, kit.Keys(value[aaa.ROLE], value[mdb.ZONE], value[mdb.KEY])) })
ctx.DisplayStorySpide(m.Options(nfs.DIR_ROOT, "ice."), mdb.FIELD, mdb.KEY, lex.SPLIT, nfs.PT)
IFCONFIG: {Name: "ifconfig", Help: "网卡配置", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy("tcp.host")
}},
API: {Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 1 {
m.Cmdy(ctx.COMMAND, "inner").Push(ctx.ARGS, kit.Format(nfs.SplitPath(m, m.Option(nfs.FILE))))
return
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)
}},
USERINFO: {Name: "userinfo", Help: "用户信息", 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) {
m.Split(m.Cmdx(SYSTEM, "ps", "u")).PushAction(PROCKILL)
m.StatusTimeCount()
}},
PROCKILL: {Name: "prockill", Help: "结束进程", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(SYSTEM, KILL, m.Option("PID"))
m.ProcessRefresh30ms()
}},
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)
}},
CLI: {Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 1 {
m.Cmdy(ctx.COMMAND, "inner").Push(ctx.ARGS, kit.Format(nfs.SplitPath(m, m.Option(nfs.FILE))))
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)
kit.For(ice.Info.File, func(k, v string) { m.Push(nfs.FILE, k).Push(mdb.NAME, v) })
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)
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) > 0 && arg[0] == BOOTINFO {
arg = arg[1:]
}
m.Cmdy(ctx.CONFIG, RUNTIME, arg)
m.DisplayStoryJSON()
}},
})
}
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,104 @@ package cli
import (
"bytes"
"io"
"net/http"
"os"
"os/exec"
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
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 {
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 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)
arg[0] = file
}
}
// 环境变量
env := kit.Simple(m.Optionv(CMD_ENV))
for i := 0; i < len(env)-1; i += 2 {
if env[i] == PATH {
if file := _system_find(m, arg[0], strings.Split(env[i+1], ice.DF)...); file != "" {
m.Debug("cmd: %v", file)
arg[0] = file
}
}
})
if bin == "" {
if bin = _system_find(m, arg[0], EtcPath(m)...); bin != "" {
m.Logs(FIND, "etcpath cmd", bin)
}
// 自动安装
if _system_find(m, arg[0]) == "" {
if cmds := m.Cmd(MIRROR, arg[0]).Append("cmd"); cmds != "" {
m.Cmd(kit.Split(cmds))
if file := _system_find(m, arg[0]); file != "" {
m.Debug("cmd: %v", file)
arg[0] = file
}
}
}
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:]...)
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)) })
_system_cmds(m, cmd, arg...)
// 环境变量
for i := 0; i < len(env)-1; i += 2 {
cmd.Env = append(cmd.Env, kit.Format("%s=%s", env[i], env[i+1]))
}
if len(cmd.Env) > 0 {
m.Log_EXPORT(CMD_ENV, cmd.Env)
}
return cmd
}
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 {
return w
} else if m.Option(out) == "" {
return nil
} else if f, p, e := file.CreateFile(m.Option(out)); m.Assert(e) {
m.Logs(nfs.SAVE, out, p).Optionv(out, f)
} else if f, p, e := kit.Create(m.Option(out)); m.Assert(e) {
m.Log_EXPORT(out, p)
m.Optionv(out, f)
return f
}
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 kit.FileExists(path.Join(p, bin)) {
return kit.Path(path.Join(p, bin))
}
}
return ""
}
func _system_exec(m *ice.Message, cmd *exec.Cmd) {
// 输入流
if r, ok := m.Optionv(CMD_INPUT).(io.Reader); ok {
cmd.Stdin = r
}
// 输出流
if w := _system_out(m, CMD_OUTPUT); w != nil {
cmd.Stdout, cmd.Stderr = w, w
if w := _system_out(m, CMD_ERRPUT); w != nil {
@ -92,54 +109,29 @@ func _system_exec(m *ice.Message, cmd *exec.Cmd) {
} else {
out := 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() {
m.Push(CMD_OUT, out.String()).Push(CMD_ERR, err.String())
if m.Echo(out.String()).Echo(err.String()); m.IsErr() {
m.Option(ice.MSG_ARGS, kit.Simple(http.StatusBadRequest, cmd.Args, err.String()))
m.Echo(strings.TrimRight(err.String(), lex.NL))
m.Info("err: %v", err.String())
m.Info("out: %v", out.String())
}
m.Push(CMD_OUT, out.String())
m.Push(CMD_ERR, err.String())
m.Echo(strings.TrimSpace(kit.Select(out.String(), err.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 {
return kit.Select("1", "0", cmd.ProcessState != nil && cmd.ProcessState.Success())
func IsSuccess(m *ice.Message) bool {
return m.Append(CODE) == "0" || m.Append(CODE) == ""
}
func _system_find(m *ice.Message, bin string, dir ...string) string {
if strings.Contains(bin, nfs.DF) {
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 ""
func SystemFind(m *ice.Message, bin string, dir ...string) string {
return _system_find(m, bin, dir...)
}
const (
TIME_300ms = "300ms"
TIME_30ms = "30ms"
TIME_30s = "30s"
TIME_3s = "3s"
TIME_1s = "1s"
CMD_DIR = "cmd_dir"
CMD_ENV = "cmd_env"
@ -147,103 +139,52 @@ const (
CMD_OUTPUT = "cmd_output"
CMD_ERRPUT = "cmd_errput"
CMD_ERR = "cmd_err"
CMD_OUT = "cmd_out"
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"
CMD_ERR = "cmd_err"
)
const SYSTEM = "system"
func init() {
Index.MergeCommands(ice.Commands{
SYSTEM: {Name: "system cmd", Help: "系统命令", Actions: ice.MergeActions(ice.Actions{
nfs.PUSH: {Hand: func(m *ice.Message, arg ...string) {
kit.For(arg, func(p string) {
kit.If(!kit.IsIn(p, EtcPath(m)...), func() {
m.Cmd(nfs.PUSH, ice.ETC_PATH, strings.TrimSpace(p)+lex.NL)
})
})
m.Cmdy(nfs.CAT, ice.ETC_PATH)
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SYSTEM: {Name: SYSTEM, Help: "系统命令", Value: kit.Data(mdb.FIELD, "time,id,cmd")},
}, Commands: map[string]*ice.Command{
SYSTEM: {Name: "system cmd run", Help: "系统命令", Action: map[string]*ice.Action{
nfs.FIND: {Name: "find", Help: "查找", Hand: func(m *ice.Message, arg ...string) {
m.Echo(_system_find(m, arg[0], arg[1:]...))
}},
FIND: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_system_find(m, arg[0], arg[1:]...)) }},
MAN: {Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) == 1, func() { arg = append(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()
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) == 0 {
mdb.ListSelect(m, arg...)
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])
}
if strings.HasSuffix(arg[0], ".sh") {
arg = []string{"sh", path.Join("src", arg[0])}
}
_system_exec(m, _system_cmd(m, arg...))
}},
})
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
}})
}
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 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
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,227 +1,100 @@
package ctx
import (
"path"
"runtime"
"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 _command_list(m *ice.Message, name string) *ice.Message {
func _command_list(m *ice.Message, name string) {
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)
m.Option(ice.MSG_NODEICON, m.Resource(ice.Info.NodeIcon))
if name == "" { // 命令列表
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) {
icon := kit.Format(kit.Value(cmd.Meta, kit.Keys(ice.CTX_ICONS, key)))
icons := kit.Select(cmd.Icon, icon, !kit.HasPrefix(icon, "bi ", "{"))
if icons != "" {
icons = m.Resource(icons)
}
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))
m.Push(mdb.INDEX, kit.Keys(s.Cap(ice.CTX_FOLLOW), key))
m.Push(mdb.NAME, kit.Format(cmd.Name))
m.Push(mdb.HELP, kit.Format(cmd.Help))
m.Push(mdb.META, kit.Format(cmd.Meta))
m.Push(mdb.LIST, kit.Format(cmd.List))
})
return m
}
func _command_search(m *ice.Message, kind, name, text string) {
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
}
m.PushSearch(ice.CTX, kit.PathName(1), ice.CMD, kit.FileName(1),
kit.SimpleKV("", s.Prefix(), kit.Select(key, cmd.Name), cmd.Help),
INDEX, kit.Keys(s.Prefix(), key))
}).Sort(m.OptionFields())
kit.SimpleKV("", s.Cap(ice.CTX_FOLLOW), cmd.Name, cmd.Help),
CONTEXT, s.Cap(ice.CTX_FOLLOW), COMMAND, key,
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 (
ACTION = "action"
INDEX = "index"
CMDS = "cmds"
ARGS = "args"
OPTS = "opts"
STYLE = "style"
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"
func init() {
Index.MergeCommands(ice.Commands{
COMMAND: {Name: "command key auto", Help: "命令", Role: aaa.VOID, Actions: ice.MergeActions(ice.Actions{
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
COMMAND: {Name: "command key auto", Help: "命令", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
TravelCmd(m, func(key, file, line string) { AddFileCmd(file, key) })
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) }}
}
})
m.Cmd(mdb.SEARCH, mdb.CREATE, m.CommandKey(), m.PrefixKey())
}},
mdb.SEARCH: {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))
}
mdb.SEARCH: {Name: "search type name text", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
_command_search(m, arg[0], kit.Select("", arg, 1), kit.Select("", arg, 2))
}},
mdb.INPUTS: {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)
}
})
}
INDEX: {Name: "index", Help: "索引", Hand: func(m *ice.Message, arg ...string) {
}},
"default": {Hand: func(m *ice.Message, 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) {
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
m.OptionFields(INDEX)
m.Cmdy("", mdb.SEARCH, COMMAND)
} else {
kit.For(arg, func(k string) { _command_list(m, k) })
arg = append(arg, "")
}
for _, key := range arg {
_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 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 (
"encoding/json"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/miss"
)
func _config_only(v ice.Any, arg ...string) bool {
switch v := v.(type) {
case nil:
return true
case ice.Map:
if len(v) > len(arg) {
return false
func _config_list(m *ice.Message) {
for k, v := range m.Source().Configs {
if k[0] == '/' || k[0] == '_' {
continue // 内部配置
}
for k, v := range v {
if v, ok := v.(ice.Map); ok && len(v) == 0 {
continue
} else if kit.IndexOf(arg, k) == -1 {
return false
}
}
return true
m.Push(mdb.KEY, k)
m.Push(mdb.NAME, v.Name)
m.Push(mdb.VALUE, kit.Format(v.Value))
}
return false
m.Sort(mdb.KEY)
}
func _config_save(m *ice.Message, name string, arg ...string) {
if !ice.HasVar() {
return
}
data, msg := ice.Map{}, m.Spawn(m.Source())
for _, k := range arg {
if v := mdb.Confv(msg, k); _config_only(v, mdb.META) && _config_only(kit.Value(v, mdb.META),
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
}
}
if len(data) == 0 {
return
}
if f, _, e := miss.CreateFile(path.Join(ice.VAR_CONF, name)); m.Assert(e) {
name = path.Join(m.Config(nfs.PATH), name)
if f, p, e := kit.Create(name); m.Assert(e) {
defer f.Close()
if s, e := json.MarshalIndent(data, "", " "); !m.WarnNotValid(e) {
if _, e := f.Write(s); !m.WarnNotValid(e) {
msg := m.Spawn(m.Source())
data := map[string]interface{}{}
for _, k := range arg {
if v := msg.Confv(k); v != "" {
data[k] = v
}
}
// 保存配置
if s, e := json.MarshalIndent(data, "", " "); m.Assert(e) {
if n, e := f.Write(s); m.Assert(e) {
m.Log_EXPORT(CONFIG, name, nfs.FILE, p, nfs.SIZE, n)
}
}
m.Echo(p)
}
}
func _config_load(m *ice.Message, name string, arg ...string) {
if !ice.HasVar() {
return
}
if f, e := miss.OpenFile(path.Join(ice.VAR_CONF, name)); e == nil {
name = path.Join(m.Config(nfs.PATH), name)
if f, e := os.Open(name); e == nil {
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)
// 加载配置
for k, v := range data {
msg.Search(k, func(p *ice.Context, s *ice.Context, key string, conf *ice.Config) {
kit.If(s.Configs[key] == nil, func() { s.Configs[key] = &ice.Config{} })
msg.Search(k, func(p *ice.Context, s *ice.Context, key string) {
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
})
}
@ -79,87 +70,68 @@ func _config_load(m *ice.Message, name string, arg ...string) {
func _config_make(m *ice.Message, key string, arg ...string) {
msg := m.Spawn(m.Source())
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]) })
kit.If(strings.HasPrefix(arg[1], mdb.AT), func() { arg[1] = msg.Cmdx(nfs.CAT, arg[1][1:]) })
mdb.Confv(msg, key, arg[0], kit.Parse(nil, "", arg[1:]...))
if strings.HasPrefix(arg[1], "@") {
arg[1] = msg.Cmdx(nfs.CAT, arg[1][1:])
}
// 修改配置
msg.Confv(key, arg[0], kit.Parse(nil, "", arg[1:]...))
}
if len(arg) > 0 {
m.Echo(kit.Formats(mdb.Confv(msg, key, arg[0])))
m.Echo(kit.Formats(msg.Confv(key, arg[0])))
} else {
m.Echo(kit.Formats(mdb.Confv(msg, key))).StatusTime(mdb.COUNT, kit.Length(mdb.Confv(msg, key, mdb.HASH)))
m.Echo(kit.Formats(msg.Confv(key)))
}
}
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)
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"
func init() {
Index.MergeCommands(ice.Commands{
CONFIG: {Name: "config key auto", Help: "配置", Actions: ice.Actions{
nfs.SAVE: {Hand: func(m *ice.Message, arg ...string) { _config_save(m, arg[0], arg[1:]...) }},
nfs.LOAD: {Hand: func(m *ice.Message, arg ...string) { _config_load(m, arg[0], arg[1:]...) }},
mdb.EXPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], mdb.EXPORT) }},
mdb.IMPORT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(arg[0], mdb.IMPORT) }},
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, "")
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CONFIG: {Name: CONFIG, Help: "配置", Value: kit.Data(nfs.PATH, ice.VAR_CONF)},
}, Commands: map[string]*ice.Command{
CONFIG: {Name: "config key auto reset", Help: "配置", Action: map[string]*ice.Action{
SAVE: {Name: "save", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
_config_save(m, arg[0], arg[1:]...)
}},
mdb.CREATE: {Name: "create name value", 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))
LOAD: {Name: "load", Help: "加载", Hand: func(m *ice.Message, arg ...string) {
_config_load(m, arg[0], arg[1:]...)
}},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), "")
RICH: {Name: "rich", Help: "富有", Hand: func(m *ice.Message, arg ...string) {
_config_rich(m, arg[0], arg[1], arg[2:]...)
}},
mdb.MODIFY: {Hand: func(m *ice.Message, arg ...string) {
if arg[0] == mdb.VALUE {
m.Confv(m.Option(mdb.KEY), kit.Keys(mdb.META, m.Option(mdb.NAME)), arg[1])
GROW: {Name: "grow", Help: "成长", Hand: func(m *ice.Message, arg ...string) {
_config_grow(m, arg[0], arg[1], arg[2:]...)
}},
"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) {
"reset": {Name: "reset key sub", Help: "重置", Hand: func(m *ice.Message, arg ...string) {
m.Conf(m.Option("key"), m.Option("sub"), "")
m.Go(func() { m.Cmd(ice.EXIT, 1) })
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
_config_list(m)
} else {
_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)
return
}
_config_make(m, arg[0], arg[1:]...)
}},
})
}
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"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
func _context_list(m *ice.Message, sub *ice.Context, name string) {
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
}
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"
func init() {
Index.MergeCommands(ice.Commands{
CONTEXT: {Name: "context name=ice action=context,command,config key auto", Help: "模块", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) == 0, func() { arg = append(arg, m.Source().Prefix()) })
m.Search(arg[0]+nfs.PT, func(p *ice.Context, s *ice.Context) {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
CONTEXT: {Name: "context name=web action=context,command,config key auto spide", Help: "模块", Action: ice.MergeAction(map[string]*ice.Action{
"spide": {Name: "spide", Help: "架构图", Hand: func(m *ice.Message, arg ...string) {
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)
defer m.Copy(msg)
switch kit.Select(CONTEXT, arg, 1) {
case CONTEXT:
_context_list(msg, s, arg[0])
@ -37,5 +72,5 @@ func init() {
}
})
}},
})
}})
}

View File

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

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
import (
"sync"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
const (
LISTEN = "listen"
HAPPEN = "happen"
)
func _event_listen(m *ice.Message, event string, cmd string) {
m.Cmdy(mdb.INSERT, EVENT, "", mdb.HASH, EVENT, event)
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"
func init() {
Index.MergeCommands(ice.Commands{
EVENT: {Name: "event event id auto listen happen", Help: "事件流", Actions: ice.MergeActions(ice.Actions{
LISTEN: {Name: "listen event* cmd*", Help: "监听", Hand: func(m *ice.Message, arg ...string) {
mdb.ZoneInsert(m, m.OptionSimple(EVENT, ice.CMD))
list[m.Option(EVENT)]++
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
EVENT: {Name: EVENT, Help: "事件流", Value: kit.Data(mdb.SHORT, EVENT, mdb.FIELD, "time,id,cmd")},
}, Commands: map[string]*ice.Command{
EVENT: {Name: "event event id auto listen", Help: "事件流", Action: ice.MergeAction(map[string]*ice.Action{
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) {
defer m.Cost()
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 })
ACTION: {Name: "action event arg", Help: "触发", Hand: func(m *ice.Message, arg ...string) {
_event_action(m, m.Option(EVENT), arg[2:]...)
}},
}, mdb.ZoneAction(mdb.SHORT, EVENT, mdb.FIELDS, "time,id,cmd"), mdb.ClearOnExitHashAction())},
})
}
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()
}, 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)
}
}},
}})
}

View File

@ -1,56 +1,57 @@
package gdb
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
type Frame struct{ s chan os.Signal }
func (f *Frame) Begin(m *ice.Message, arg ...string) {
f.s = make(chan os.Signal, 10)
type Frame struct {
s chan os.Signal
t time.Duration
e chan bool
}
func (f *Frame) Start(m *ice.Message, arg ...string) {
if ice.HasVar() {
if f, p, e := logs.CreateFile(ice.VAR_LOG_ICE_PID); e == nil {
m.Logs("save", "file", p, PID, os.Getpid())
fmt.Fprint(f, os.Getpid())
f.Close()
}
}
t := time.NewTicker(kit.Duration(mdb.Conf(m, TIMER, kit.Keym(TICK))))
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
return &Frame{}
}
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
f.s = make(chan os.Signal, ice.MOD_CHAN)
f.e = make(chan bool, 1)
return f
}
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
f.t = kit.Duration(m.Conf(TIMER, kit.Keym(TICK)))
for {
select {
case <-t.C:
m.Options(ice.LOG_DISABLE, ice.TRUE).Cmd(TIMER, HAPPEN)
case s, ok := <-f.s:
if !ok {
return
}
m.Cmd(SIGNAL, HAPPEN, SIGNAL, s)
case <-f.e:
return true
// case <-time.Tick(f.t):
// // m.Cmd(TIMER, ACTION)
case s := <-f.s:
m.Cmd(SIGNAL, ACTION, ACTION, SIGNAL, s)
}
}
return true
}
func (f *Frame) Close(m *ice.Message, arg ...string) {
close(f.s)
}
func (f *Frame) listen(m *ice.Message, s int, arg ...string) {
signal.Notify(f.s, syscall.Signal(s))
mdb.HashCreate(m, SIGNAL, s, arg)
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
f.e <- true
return true
}
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{}, SIGNAL, EVENT, TIMER, ROUTINE) }
func init() { ice.Index.Register(Index, &Frame{}, ROUTINE, SIGNAL, EVENT, TIMER) }

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
import (
"path"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
)
const ROUTINE = "routine"
func init() {
Index.MergeCommands(ice.Commands{
ROUTINE: {Help: "协程池", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Name: "create name cmd", Hand: func(m *ice.Message, arg ...string) {
m.Go(func() {
cb := m.OptionCB("")
m.OptionDefault(ice.CMD, logs.FileLine(cb))
h := mdb.HashCreate(m, m.OptionSimple(mdb.NAME, ice.CMD), mdb.STATUS, START)
defer func() {
if e := recover(); e == nil {
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))
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
ROUTINE: {Name: ROUTINE, Help: "协程池", Value: kit.Data(mdb.SHORT, "time,hash,status,fileline")},
}, Commands: map[string]*ice.Command{
ROUTINE: {Name: "routine hash auto prunes", Help: "协程池", Action: ice.MergeAction(map[string]*ice.Action{
mdb.CREATE: {Name: "create fileline status", Help: "创建"},
mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(mdb.SHORT))
m.Cmdy(mdb.PRUNES, ROUTINE, "", mdb.HASH, cli.STATUS, cli.STOP)
m.Cmdy(mdb.PRUNES, ROUTINE, "", mdb.HASH, cli.STATUS, cli.ERROR)
}},
}, mdb.StatusHashAction(mdb.LIMIT, 1000, mdb.LEAST, 500, mdb.FIELD, "time,hash,status,name,cmd"), mdb.ClearOnExitHashAction())},
})
}
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)
"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...)
}},
}, 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 (
"os"
"os/signal"
"path"
"syscall"
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"
"shylinux.com/x/toolkits/file"
log "shylinux.com/x/toolkits/logs"
)
func _signal_listen(m *ice.Message, s int, arg ...string) {
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) {
mdb.HashSelect(m.Spawn(), arg...).Table(func(value ice.Maps) { 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...)
}},
mdb.HashSelect(m.Spawn(), arg...).Table(func(index int, value map[string]string, head []string) {
m.Cmdy(kit.Split(value[ice.CMD]))
})
}
func SignalNotify(m *ice.Message, sig syscall.Signal, cb func()) {
func SignalNotify(m *ice.Message, sig int, cb func()) {
ch := make(chan os.Signal)
signal.Notify(ch, sig)
signal.Notify(ch, syscall.Signal(sig))
m.Go(func() {
for {
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"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func _timer_action(m *ice.Message, now time.Time, arg ...string) {
mdb.HashSelects(m).Table(func(value ice.Maps) {
count := kit.Int(value[mdb.COUNT])
if count == 0 || value[mdb.TIME] > now.Format(ice.MOD_TIME) {
func _timer_action(m *ice.Message, arg ...string) {
now := time.Now().UnixNano()
m.OptionFields(m.Config(mdb.FIELD))
m.Richs(TIMER, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
if value = kit.GetMeta(value); value[cli.STATUS] == cli.STOP {
return
}
m.Options(ice.LOG_DISABLE, ice.FALSE)
m.Cmd(kit.Split(value[ice.CMD])).Cost()
kit.If(count < 0, func() { count++ })
mdb.HashModify(m, mdb.NAME, value[mdb.NAME], mdb.COUNT, count-1, mdb.TIME, m.Time(value[INTERVAL]))
order := kit.Int(value[ORDER])
if n := kit.Time(kit.Format(value[NEXT])); now > n && order > 0 {
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 (
DELAY = "delay"
INTERVAL = "interval"
ORDER = "order"
NEXT = "next"
TICK = "tick"
)
const TIMER = "timer"
func init() {
Index.MergeCommands(ice.Commands{
TIMER: {Help: "定时器", Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(DELAY, "延时", INTERVAL, "间隔", TICK, "周期")),
), Actions: ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch mdb.HashInputs(m, arg); arg[0] {
case mdb.COUNT:
m.Push(arg[0], "-1")
case ice.CMD:
m.Push(arg[0], "cli.procstat insert")
}
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
TIMER: {Name: TIMER, Help: "定时器", Value: kit.Data(
mdb.FIELD, "time,hash,delay,interval,order,next,cmd", TICK, "1s",
)},
}, Commands: map[string]*ice.Command{
TIMER: {Name: "timer hash id auto create action prunes", Help: "定时器", Action: ice.MergeAction(map[string]*ice.Action{
mdb.CREATE: {Name: "create delay=10ms interval=10s order=3 cmd=runtime", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(mdb.INSERT, TIMER, "", mdb.HASH, DELAY, "10ms", INTERVAL, "10m", ORDER, 1, NEXT, m.Time(m.Option(DELAY)), arg)
}},
mdb.CREATE: {Name: "create name*=hi delay=10ms interval=10s count=3 cmd*=runtime"},
mdb.PRUNES: {Hand: func(m *ice.Message, arg ...string) { mdb.HashPrunesValue(m, mdb.COUNT, "0") }},
HAPPEN: {Hand: func(m *ice.Message, arg ...string) { _timer_action(m, time.Now(), arg...) }},
}, 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))
mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(mdb.FIELD))
m.Cmdy(mdb.PRUNES, TIMER, "", mdb.HASH, ORDER, 0)
}},
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"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
@ -345,10 +346,10 @@ func (mat *Matrix) show(m *ice.Message) {
value = append(value, "*")
}
if node.next > 0 {
// value = append(value, cli.ColorGreen(m, node.next))
value = append(value, cli.ColorGreen(m, node.next))
}
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, ","))
@ -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))
}
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)
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]))
})
value[MATRIX] = mat
@ -384,29 +385,29 @@ const (
const MATRIX = "matrix"
func init() {
Index.MergeCommands(ice.Commands{
MATRIX: {Name: "matrix hash npage text auto", Help: "魔方矩阵", Actions: ice.Actions{
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
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) {
// _lex_load(m.Load())
}},
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))))
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) {
case func(string, *Matrix):
cb(h, mat)
default:
m.ErrorNotImplement(cb)
}
m.Echo(h)
}},
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)
mat, _ := value[MATRIX].(*Matrix)
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),
))
@ -418,7 +419,7 @@ func init() {
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) {
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)
mat, _ := value[MATRIX].(*Matrix)
@ -431,13 +432,13 @@ func init() {
m.ProcessInner()
}},
"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[MATRIX].(*Matrix).show(m)
})
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 { // 矩阵列表
m.Fields(len(arg), "time,hash,npage,nhash")
m.Cmdy(mdb.SELECT, m.PrefixKey(), "", mdb.HASH)
@ -452,7 +453,7 @@ func init() {
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)
mat, _ := value[MATRIX].(*Matrix)
@ -467,5 +468,5 @@ func init() {
m.Push("word", string(word))
})
}},
})
}})
}

View File

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

View File

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

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 (
"bufio"
"fmt"
"path"
"strings"
"sync/atomic"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
log "shylinux.com/x/toolkits/logs"
)
type Log struct {
c bool
p, l, s string
m *ice.Message
p string
l string
s string
}
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) {
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)
}
})
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
f.p = make(chan *Log, ice.MOD_BUFS)
ice.Info.Log = func(m *ice.Message, p, l, s string) {
f.p <- &Log{c: m.Option(ice.LOG_DEBUG) == ice.TRUE, p: p, l: l, s: s}
ice.Info.Log = func(msg *ice.Message, p, l, s string) {
f.p <- &Log{m: msg, p: p, l: l, s: s}
}
return f
}
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
for {
select {
case l, ok := <-f.p:
if !ok {
return
break
}
kit.For([]string{m.Conf(SHOW, kit.Keys(l.l, FILE)), BENCH}, func(file string) {
if file == "" {
return
file := kit.Select(BENCH, m.Conf(SHOW, kit.Keys(l.l, FILE)))
view := m.Confm(VIEW, m.Conf(SHOW, kit.Keys(l.l, VIEW)))
bio := m.Confv(FILE, kit.Keys(file, FILE)).(*bufio.Writer)
if bio == nil {
continue
}
bio.WriteString(l.p)
bio.WriteString(ice.SP)
if ice.Info.Colors == true {
if p, ok := view[PREFIX].(string); ok {
bio.WriteString(p)
}
conf := m.Confv(FILE, file)
bio := kit.Value(conf, FILE).(*bufio.Writer)
if bio == nil {
return
}
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)
}
defer bio.Flush()
defer fmt.Fprintln(bio)
fmt.Fprint(bio, l.p, lex.SP)
view := mdb.Confm(m, VIEW, m.Conf(SHOW, kit.Keys(l.l, VIEW)))
kit.If(ice.Info.Colors || l.c, func() { bio.WriteString(kit.Format(view[PREFIX])) })
defer kit.If(ice.Info.Colors || l.c, func() { bio.WriteString(kit.Format(view[SUFFIX])) })
fmt.Fprint(bio, l.l, lex.SP, l.s)
})
}
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 (
PREFIX = "prefix"
SUFFIX = "suffix"
TRACEID = "traceid"
PREFIX = "prefix"
SUFFIX = "suffix"
)
const (
GREEN = "green"
YELLOW = "yellow"
RED = "red"
)
const (
BENCH = "bench"
WATCH = "watch"
ERROR = "error"
TRACE = "trace"
)
const (
FILE = "file"
VIEW = "view"
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(
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}),
ERROR, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, ERROR_LOG), mdb.LIST, []string{ice.LOG_WARN, ice.LOG_ERROR}),
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}),
BENCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "bench.log"), mdb.LIST, []string{}),
WATCH, kit.Dict(nfs.PATH, path.Join(ice.VAR_LOG, "watch.log"), mdb.LIST, []string{
ice.LOG_CREATE, ice.LOG_REMOVE,
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(
GREEN, kit.Dict(PREFIX, "\033[32m", SUFFIX, "\033[0m", mdb.LIST, []string{ice.CTX_START, ice.LOG_CMDS}),
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.CTX_CLOSE, ice.LOG_WARN}),
GREEN, kit.Dict(PREFIX, "\033[32m", SUFFIX, "\033[0m", mdb.LIST, []string{
ice.LOG_START, ice.LOG_SERVE, ice.LOG_CMDS,
}),
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()},
}, Commands: ice.Commands{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
ice.Info.Load(m)
mdb.Confm(m, FILE, nil, func(key string, value ice.Map) {
kit.For(value[mdb.LIST], func(index int, k string) { m.Conf(SHOW, kit.Keys(k, FILE), key) })
}, Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if log.LogDisable {
return // 禁用日志
}
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.Info.Save(m)
}},
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
}}
func init() { ice.Index.Register(Index, &Frame{}, TAIL) }
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, "-")
}
func init() { ice.Index.Register(Index, &Frame{}) }

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
import ice "shylinux.com/x/icebergs"
import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
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 (
"encoding/json"
"io"
"net/http"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
"shylinux.com/x/toolkits/miss"
)
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) {
list := map[string]int{}
defer func() {
delete(list, "")
kit.For(list, func(k string, i int) { m.Push(field, k).Push(COUNT, i) })
m.SortIntR(COUNT)
}()
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]))
})
}
func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) string {
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 {
m.Echo(arg[1]).Conf(prefix, kit.Keys(chain, HASH, arg[1]), kit.Data(arg[2:]))
} else {
if target, ok := m.Optionv(TARGET).([]string); ok && len(target) == 0 {
m.Echo(Rich(m, prefix, chain, kit.Data(arg)))
m.Richs(prefix, chain, FOREACH, func(key string, val map[string]interface{}) {
if val = kit.GetMeta(val); kit.Format(val[COUNT]) != "" {
list[kit.Format(val[field])] = kit.Int(val[COUNT])
} else {
m.Echo(Rich(m, prefix, chain, kit.Data(arg, TARGET, m.Optionv(TARGET))))
list[kit.Format(val[field])]++
}
})
for k, i := range list {
m.Push(field, k)
m.Push(COUNT, i)
}
saveImportant(m, prefix, chain, kit.Simple(INSERT, prefix, chain, HASH, HASH, m.Result(), TIME, m.Time(), arg)...)
return m.Result()
m.SortIntR(COUNT)
}
func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) {
if m.Option(ice.MSG_DOMAIN) != "" {
m.Conf(prefix, kit.Keys(chain, kit.Keym(SHORT)), m.Conf(prefix, kit.Keym(SHORT)))
}
m.Log_INSERT(KEY, path.Join(prefix, chain), arg[0], arg[1])
m.Echo(m.Rich(prefix, chain, kit.Data(arg)))
}
func _hash_delete(m *ice.Message, prefix, chain, field, value string) {
defer Lock(m, prefix)()
Richs(m, prefix, chain, value, func(key string, val Map) {
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))
if field != HASH {
field, value = HASH, kit.Select(kit.Hashs(value), m.Option(HASH))
}
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), "")
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) {
m.Logs(MODIFY, KEY, path.Join(prefix, chain), field, value, arg)
defer Lock(m, prefix)()
Richs(m, prefix, chain, value, func(key string, val Map) {
_mdb_modify(m, val, field, arg...)
saveImportant(m, prefix, chain, kit.Simple(MODIFY, prefix, chain, HASH, HASH, key, arg)...)
m.Richs(prefix, chain, value, func(key string, val map[string]interface{}) {
val = kit.GetMeta(val)
m.Log_MODIFY(KEY, path.Join(prefix, chain), 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 _hash_select(m *ice.Message, prefix, chain, field, value string) {
kit.If(field == HASH && value == RANDOM, func() { value = RANDOMS })
defer m.SortStrR(TIME)
if field == HASH && value == RANDOM {
value = RANDOMS
}
fields := _hash_fields(m)
defer RLock(m, prefix)()
if strings.Contains(value, ",") {
kit.For(kit.Split(value), func(value string) {
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) })
})
} else {
Richs(m, prefix, chain, value, func(key string, value Map) { _mdb_select(m, m.OptionCB(""), key, value, fields, nil) })
m.Richs(prefix, chain, value, func(key string, val map[string]interface{}) {
switch val = kit.GetMeta(val); cb := m.OptionCB(SELECT).(type) {
case func(fields []string, value map[string]interface{}):
cb(fields, val)
case func(value map[string]interface{}):
cb(val)
default:
if m.OptionFields() == DETAIL {
m.Push(DETAIL, val)
} else {
m.Push(key, val, fields)
}
}
})
if !m.FieldsIsDetail() {
m.SortTimeR(TIME)
}
}
func _hash_select_field(m *ice.Message, prefix, chain string, key string, field string) (value string) {
defer RLock(m, prefix)()
Richs(m, prefix, chain, key, func(key string, val Map) { value = kit.Select(kit.Format(val[field]), key, field == HASH) })
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) {
fields := _hash_fields(m)
kit.If(kit.IndexOf(fields, HASH) == -1, func() { fields = append(fields, HASH) })
defer RLock(m, prefix)()
Richs(m, prefix, chain, FOREACH, func(key string, value Map) {
switch value = kit.GetMeta(value); cb := m.OptionCB("").(type) {
case func(string, Map) bool:
kit.If(cb(key, value), func() { m.Push(key, value, fields) })
m.Richs(prefix, chain, FOREACH, func(key string, val map[string]interface{}) {
switch val = kit.GetMeta(val); cb := m.OptionCB(PRUNES).(type) {
case func(string, map[string]interface{}) bool:
if !cb(key, val) {
return
}
default:
kit.For(arg, func(k, v string) {
kit.If(value[k] == v || kit.Value(value, k) == v, func() { m.Push(key, value, fields) })
})
for i := 0; i < len(arg)-1; i += 2 {
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"
func HashAction(arg ...Any) ice.Actions {
return ice.Actions{
ice.CTX_INIT: AutoConfig(append(kit.List(FIELD, HASH_FIELD), arg...)...),
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { HashSelectClose(m) }},
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 {
return ice.MergeActions(ice.Actions{
PRUNES: &ice.Action{Name: "prunes status", Hand: func(m *ice.Message, arg ...string) {
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 HashShort(m)
}
func HashShort(m *ice.Message) string {
if m.Option(SHORT) != "" {
return m.Option(SHORT)
}
short := ""
if m.Option(SUBKEY) != "" {
if short = Conf(m, m.PrefixKey(), kit.Keys(m.Option(SUBKEY), META, SHORT)); short == "" {
short = Config(m, SHORTS)
func AutoConfig(args ...interface{}) *ice.Action {
return &ice.Action{Hand: func(m *ice.Message, arg ...string) {
if cs := m.Target().Configs; cs[m.CommandKey()] == nil {
cs[m.CommandKey()] = &ice.Config{Value: kit.Data(args...)}
m.Load(m.CommandKey())
}
} else {
short = Config(m, SHORT)
}
return kit.Select(HASH, short, short != UNIQ)
}}
}
func HashField(m *ice.Message) string {
if m.Option(FIELD) != "" {
return m.Option(FIELD)
}
field := ""
if m.Option(SUBKEY) != "" {
if field = Conf(m, m.PrefixKey(), kit.Keys(m.Option(SUBKEY), META, FIELDS)); field == "" {
field = Config(m, FIELDS)
func HashAction(args ...interface{}) map[string]*ice.Action {
_key := func(m *ice.Message) string {
if m.Config(HASH) == "uniq" {
return HASH
}
} else {
field = Config(m, FIELD)
if m.Config(SHORT) == "uniq" {
return HASH
}
return kit.Select(HASH, m.Config(SHORT))
}
return kit.Select(HASH_FIELD, field)
}
func HashInputs(m *ice.Message, arg ...Any) *ice.Message {
return m.Cmdy(INPUTS, m.PrefixKey(), m.Option(SUBKEY), HASH, 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)...))
return ice.SelectAction(map[string]*ice.Action{ice.CTX_INIT: AutoConfig(args...),
INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(INPUTS, m.PrefixKey(), "", HASH, arg)
}},
CREATE: {Name: "create type name text", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg)
}},
REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(FIELD))
m.Cmdy(DELETE, m.PrefixKey(), "", HASH, m.OptionSimple(_key(m)), arg)
m.Event(kit.Keys(m.CommandKey(), REMOVE), m.CommandKey(), m.Option(m.Config(SHORT)))
}},
MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(MODIFY, m.PrefixKey(), "", HASH, m.OptionSimple(_key(m)), arg)
}},
EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(FIELD))
m.Cmdy(EXPORT, m.PrefixKey(), "", HASH, arg)
}},
IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(IMPORT, m.PrefixKey(), "", HASH, arg)
}},
PRUNES: &ice.Action{Name: "prunes before@date", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
HashPrunes(m, nil)
}},
SELECT: &ice.Action{Name: "select hash auto", Help: "列表", Hand: func(m *ice.Message, arg ...string) {
HashSelect(m, arg...)
}},
})
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 {
if args := kit.Simple(arg...); len(args) == 0 {
arg = append(arg, m.OptionSimple(HashKey(m)))
} else if len(args) == 1 {
arg = kit.List(HashKey(m), args[0])
}
return m.Cmdy(DELETE, m.PrefixKey(), m.Option(SUBKEY), HASH, arg)
}
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 HashActionStatus(args ...interface{}) map[string]*ice.Action {
list := HashAction(args...)
list[PRUNES] = &ice.Action{Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
m.OptionFields(m.Config(FIELD))
m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, STATUS, "error")
m.Cmdy(PRUNES, m.PrefixKey(), "", HASH, STATUS, "close")
}}
return list
}
func HashSelect(m *ice.Message, arg ...string) *ice.Message {
if len(arg) > 0 && (arg[0] == FOREACH || strings.Contains(arg[0], ",")) {
m.Fields(0, HashField(m))
} else {
m.Fields(len(kit.Slice(arg, 0, 1)), HashField(m))
}
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) })
m.Fields(len(arg), m.Config(FIELD))
m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg)
m.PushAction(m.Config("action"), REMOVE)
m.StatusTimeCount()
return m
}
func HashSelectUpdate(m *ice.Message, key string, cb Any) *ice.Message {
defer Lock(m, m.PrefixKey())()
Richs(m, m.PrefixKey(), nil, kit.Select(FOREACH, key), func(key string, value Map) { _mdb_select(m, cb, key, value, nil, nil) })
return m
}
func HashSelectDetail(m *ice.Message, key string, cb Any) (has bool) {
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 })
return
}
func HashSelectDetails(m *ice.Message, key string, cb func(Map) bool) Map {
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
}
func HashSelectTarget(m *ice.Message, key string, create Any) (target Any) {
HashSelectUpdate(m, key, func(value Map) {
target = value[TARGET]
if _target, ok := target.([]string); ok && len(_target) == 0 {
target = nil
func HashPrunes(m *ice.Message, cb func(map[string]string) bool) *ice.Message {
_key := func(m *ice.Message) string {
if m.Config(HASH) == "uniq" {
return HASH
}
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 kit.Select(HASH, m.Config(SHORT))
}
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
}
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)
if cb != nil && cb(value) {
return
}
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)
m.OptionFields(m.Config(FIELD))
m.Cmdy(DELETE, m.PrefixKey(), "", HASH, _key(m), value[_key(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"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/miss"
)
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) {
list := map[string]int{}
defer func() {
delete(list, "")
kit.For(list, func(k string, i int) { m.Push(field, k).Push(COUNT, i) })
m.SortIntR(COUNT)
}()
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]))
m.Grows(prefix, chain, "", "", func(index int, val map[string]interface{}) {
if val = kit.GetMeta(val); kit.Format(val[COUNT]) != "" {
list[kit.Format(val[field])] = kit.Int(val[COUNT])
} else {
list[kit.Format(val[field])]++
}
})
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) {
m.Logs(INSERT, KEY, path.Join(prefix, chain), arg)
defer Lock(m, prefix)()
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)...)
m.Log_INSERT(KEY, path.Join(prefix, chain), arg[0], arg[1])
m.Echo("%d", m.Grow(prefix, chain, kit.Dict(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) {
m.Logs(MODIFY, KEY, path.Join(prefix, chain), field, value, arg)
defer Lock(m, prefix)()
Grows(m, prefix, chain, field, value, func(index int, val ice.Map) { _mdb_modify(m, val, field, arg...) })
saveImportant(m, prefix, chain, kit.Simple(MODIFY, prefix, chain, LIST, field, value, arg)...)
m.Grows(prefix, chain, field, value, func(index int, val map[string]interface{}) {
val = kit.GetMeta(val)
m.Log_MODIFY(KEY, path.Join(prefix, chain), 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) {
defer m.SortIntR(ID)
if value == "" {
field = ""
}
fields := _list_fields(m)
defer RLock(m, prefix)()
Grows(m, prefix, chain, kit.Select(m.Option(CACHE_FIELD), field), kit.Select(m.Option(CACHE_VALUE), value), func(value ice.Map) {
_mdb_select(m, m.OptionCB(""), "", value, fields, nil)
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{}) {
switch val = kit.GetMeta(val); cb := m.OptionCB(SELECT).(type) {
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) {
defer Lock(m, prefix)()
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)
f, p, e := kit.Create(kit.Keys(file, CSV))
m.Assert(e)
defer f.Close()
defer m.Echo(p)
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
w := csv.NewWriter(f)
defer w.Flush()
head := kit.Split(ListField(m))
Grows(m, prefix, chain, "", "", func(index int, value ice.Map) {
if value = kit.GetMeta(value); index == 0 {
kit.If(len(head) == 0 || head[0] == ice.FIELDS_DETAIL, func() { head = kit.SortedKey(value) })
w.Write(head)
count := 0
head := kit.Split(m.OptionFields())
m.Grows(prefix, chain, "", "", func(index int, val map[string]interface{}) {
if val = kit.GetMeta(val); index == 0 {
if len(head) == 0 || head[0] == ice.CACHE_DETAIL { // 默认表头
for k := range val {
head = append(head, k)
}
kit.Sort(head)
}
w.Write(head) // 输出表头
}
w.Write(kit.Simple(head, func(k string) string { return kit.Format(value[k]) }))
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, LIST), "")
m.Echo(p)
}
func _list_import(m *ice.Message, prefix, chain, file string) {
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
}
f, e := os.Open(kit.Keys(file, CSV))
m.Assert(e)
defer f.Close()
r := csv.NewReader(f)
head, _ := r.Read()
count := 0
head, _ := r.Read()
for {
line, e := r.Read()
if e != nil {
break
}
data := kit.Dict()
for i, k := range head {
if k == EXTRA {
@ -100,134 +120,63 @@ func _list_import(m *ice.Message, prefix, chain, file string) {
kit.Value(data, k, line[i])
}
}
Grow(m, prefix, chain, data)
m.Grow(prefix, chain, data)
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)
}
func _list_prunes(m *ice.Message, prefix, chain string, arg ...string) {
}
const (
LIST_FIELD = "time,id,type,name,text"
)
const LIST = "list"
func ListAction(arg ...ice.Any) ice.Actions {
return ice.Actions{ice.CTX_INIT: AutoConfig(append(kit.List(FIELD, LIST_FIELD), arg...)...),
INPUTS: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(INPUTS, m.PrefixKey(), "", LIST, arg) }},
INSERT: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(INSERT, 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)...)
func ListAction(fields ...string) map[string]*ice.Action {
return ice.SelectAction(map[string]*ice.Action{
INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(INPUTS, m.PrefixKey(), "", LIST, arg)
}},
PREV: {Hand: func(m *ice.Message, arg ...string) {
PrevPageLimit(m, kit.Select(Config(m, COUNT), arg, 0), kit.Slice(arg, 1)...)
INSERT: {Name: "insert type=go name=hi text=hello", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
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 {
m.Fields(len(kit.Slice(arg, 0, 1)), ListField(m))
if m.Cmdy(SELECT, m.PrefixKey(), "", LIST, ID, arg); !m.FieldsIsDetail() {
return m.StatusTimeCountTotal(Config(m, COUNT))
m.OptionPage(kit.Slice(arg, 1)...)
m.Fields(len(kit.Slice(arg, 0, 1)), m.Config(FIELD))
m.Cmdy(SELECT, m.PrefixKey(), "", LIST, ID, arg)
if !m.FieldsIsDetail() {
m.StatusTimeCountTotal(m.Config(COUNT))
}
return m.StatusTime()
}
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)
return m
}

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,231 @@ import (
kit "shylinux.com/x/toolkits"
)
type Any = ice.Any
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 {
func _file_name(m *ice.Message, arg ...string) string {
if len(arg) > 3 && strings.Contains(arg[3], ice.PS) {
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 (
DICT = kit.MDB_DICT
META = kit.MDB_META
CSV = "csv"
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
FIELD = kit.MDB_FIELD
COUNT = kit.MDB_COUNT
TOTAL = kit.MDB_TOTAL
COUNT = kit.MDB_COUNT
LIMIT = kit.MDB_LIMIT
LEAST = kit.MDB_LEAST
STORE = kit.MDB_STORE
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
VALUE = kit.MDB_VALUE
EXTRA = kit.MDB_EXTRA
ALIAS = kit.MDB_ALIAS
EXPIRE = kit.MDB_EXPIRE
STATUS = kit.MDB_STATUS
STREAM = kit.MDB_STREAM
TOOLS = "tools"
ICONS = "icons"
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"
FOREACH = "*"
RANDOMS = "%"
)
const (
INPUTS = "inputs"
DETAIL = "detail"
RANDOM = "random"
CREATE = "create"
REMOVE = "remove"
UPDATE = "update"
INSERT = "insert"
DELETE = "delete"
MODIFY = "modify"
SELECT = "select"
INPUTS = "inputs"
PRUNES = "prunes"
EXPORT = "export"
IMPORT = "import"
DETAIL = "detail"
FIELDS = "fields"
SHORTS = "shorts"
PARAMS = "params"
OFFEND = "offend"
OFFSET = "offset"
RANDOM = "random"
WEIGHT = "weight"
SUBKEY = "mdb.sub"
UPLOAD = "upload"
REVERT = "revert"
REPEAT = "repeat"
ACTION = "action"
UPLOAD = "upload"
RECENT = "recent"
REPEAT = "repeat"
REVERT = "revert"
RENAME = "rename"
VENDOR = "vendor"
PRUNE = "prune"
TABLE = "table"
CLASS = "class"
DATABASE = "database"
PAGE = "page"
NEXT = "next"
PREV = "prev"
PLAY = "play"
SORT = "sort"
JSON = "json"
CSV = "csv"
SUB = "sub"
QS = ice.QS
EQ = ice.EQ
AT = ice.AT
FS = ice.FS
PAGE = "page"
)
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
}
if offends == 0 {
m.ProcessRewrite("offend", "")
} else {
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
}
if offends == 0 {
m.ProcessRewrite("offend", "")
} else {
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"
var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {}},
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {}},
INPUTS: {Name: "inputs key sub type field value", Hand: func(m *ice.Message, arg ...string) {
kit.Switch(arg[2],
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)) },
LIST, func() { _list_inputs(m, arg[0], arg[1], kit.Select(NAME, arg, 3), kit.Select("", arg, 4)) },
)
for _, inputs := range ice.Info.Inputs {
if arg[2] == ZONE {
inputs(m, arg[4])
} else {
inputs(m, arg[3])
}
var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
ice.Pulse.Option(ice.CACHE_LIMIT, "10")
}},
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},
INSERT: {Name: "insert key sub type arg...", Help: "添加", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[2] {
case ZONE: // insert key sub type zone arg...
_list_insert(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...)
case HASH:
_hash_insert(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...)
case LIST:
_list_insert(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...)
}
m.ProcessRefresh3ms()
}},
DELETE: {Name: "delete key sub type field value", Help: "删除", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[2] {
case ZONE: // delete key sub type zone field value
_list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5])
case HASH:
_hash_delete(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4])
case LIST:
_list_delete(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4])
}
m.ProcessRefresh3ms()
}},
MODIFY: {Name: "modify key sub type field value arg...", Help: "编辑", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[2] {
case ZONE: // modify key sub type zone id field value
_list_modify(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), ID, arg[4], arg[5:]...)
case HASH:
_hash_modify(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4], arg[5:]...)
case LIST:
_list_modify(m, arg[0], _domain_chain(m, arg[1]), arg[3], arg[4], arg[5:]...)
}
}},
INSERT: {Name: "insert key sub type arg...", Hand: func(m *ice.Message, arg ...string) {
kit.Switch(arg[2],
HASH, func() { _hash_insert(m, arg[0], arg[1], arg[3:]...) },
ZONE, func() {
if arg[3] == ZONE {
_zone_insert(m, arg[0], arg[1], arg[4], arg[5:]...)
} else {
_zone_insert(m, arg[0], 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) {
kit.Switch(arg[2],
HASH, func() { _hash_delete(m, arg[0], arg[1], arg[3], arg[4]) },
// ZONE, func() { _list_delete(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4], arg[5]) },
// LIST, func() { _list_delete(m, arg[0], arg[1], arg[3], arg[4]) },
)
}},
MODIFY: {Name: "modify key sub type field value arg...", Hand: func(m *ice.Message, arg ...string) {
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) {
HashSelect(m).Table(func(value ice.Maps) {
if value[ENABLE] != ice.FALSE {
m.Cmd(EXPORT, value[INDEX], "", value[TYPE])
}
})
}},
}, ExportHashAction(SHORT, INDEX, FIELD, "time,index,type,enable")), Hand: func(m *ice.Message, arg ...string) {
if len(arg) < 2 {
HashSelect(m, arg...).PushAction(REMOVE)
return
SELECT: {Name: "select key sub type field value", Help: "查询", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[2] {
case ZONE:
_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))
}
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) {
file := _mdb_export_file(m, arg...)
kit.Switch(arg[2],
HASH, func() { _hash_import(m, arg[0], arg[1], file) },
ZONE, func() { _hash_import(m, arg[0], arg[1], file); _zone_import(m, arg[0], arg[1], file) },
LIST, func() { _list_import(m, arg[0], arg[1], file) },
)
INPUTS: {Name: "inputs key sub type field value", Help: "补全", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[2] {
case ZONE: // inputs key sub type zone field value
_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))
}
}},
PRUNES: {Name: "prunes key sub type [field value]...", Help: "清理", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[2] {
case ZONE: // prunes key sub type zone field value
_list_prunes(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...)
case HASH:
_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() {
ice.Index.Register(Index, nil, INPUTS, INSERT, DELETE, MODIFY, SELECT, PRUNES, EXPORT, IMPORT, PLUGIN, RENDER, ENGINE, SEARCH)
}
func init() {
ice.Module(MDB,
HashInputs, HashCreate, HashRemove, func(m *ice.Message) { HashPrunes(m, nil) }, HashModify, HashSelect,
ZoneInputs, ZoneCreate, ZoneRemove, ZoneInsert, ZoneModify, ZoneSelect,
ice.Index.Register(Index, nil,
INSERT, DELETE, MODIFY, SELECT,
INPUTS, PRUNES, EXPORT, IMPORT,
SEARCH, ENGINE, PLUGIN, RENDER,
)
}
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
import ice "shylinux.com/x/icebergs"
import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
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.DisplayStoryJSON()
m.Echo(kit.Formats(m.Confv(m.Append(NAME), "meta.plug")))
}
}},
}})
}

View File

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

View File

@ -8,24 +8,26 @@ import (
const SEARCH = "search"
func init() {
Index.MergeCommands(ice.Commands{SEARCH: {Help: "搜索", Actions: RenderAction()}})
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) ice.Handler {
if sub == SEARCH {
return func(m *ice.Message, arg ...string) { m.Cmd(sub, CREATE, m.CommandKey(), m.PrefixKey()) }
}
return nil
})
}
func IsSearchPreview(m *ice.Message, arg []string, cb ...func() []string) bool {
if arg[0] == FOREACH && arg[1] == "" {
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))
}
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SEARCH: {Name: SEARCH, Help: "搜索", Value: kit.Data(SHORT, TYPE, FIELD, "time,type,name,text")},
}, Commands: map[string]*ice.Command{
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) {
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
}
}
return true
}
return false
if HashSelect(m, arg...); len(arg) == 0 {
m.Sort(TYPE)
}
}},
}})
}

View File

@ -8,118 +8,106 @@ import (
ice "shylinux.com/x/icebergs"
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 {
return kit.Split(kit.Select(ZONE_FIELD, 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...)
return kit.Split(kit.Select("zone,id,time,type,name,text", m.OptionFields()))
}
func _zone_select(m *ice.Message, prefix, chain, zone string, id string) {
if zone == "" {
_hash_select(m, prefix, chain, HASH, FOREACH)
return
} else if zone == RANDOM {
if zone == RANDOM {
zone = RANDOMS
}
defer m.SortIntR(ID)
fields := _zone_fields(m)
defer RLock(m, prefix)()
Richs(m, prefix, chain, kit.Select(FOREACH, zone), func(key string, val Map) {
chain := kit.Keys(chain, HASH, key)
Grows(m, prefix, chain, ID, id, func(value ice.Map) {
_mdb_select(m, m.OptionCB(""), key, value, fields, val)
cb := m.OptionCB(SELECT)
m.Richs(prefix, chain, kit.Select(FOREACH, zone), func(key string, val map[string]interface{}) {
if val = kit.GetMeta(val); zone == "" {
if m.OptionFields() == DETAIL {
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) {
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, CSV))
f, p, e := kit.Create(kit.Keys(file, CSV))
m.Assert(e)
defer f.Close()
defer m.Echo(p)
w := csv.NewWriter(f)
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
for _, key := range kit.SortedKey(m.Confv(prefix, kit.Keys(chain, HASH))) {
Richs(m, prefix, chain, key, func(key string, val ice.Map) {
val = kit.GetMeta(val)
chain := kit.Keys(chain, HASH, key)
Grows(m, prefix, chain, "", "", func(value ice.Map) {
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)))
}))
count++
})
m.Richs(prefix, chain, FOREACH, func(key string, val map[string]interface{}) {
val = kit.GetMeta(val)
m.Grows(prefix, kit.Keys(chain, HASH, key), "", "", func(index int, value map[string]interface{}) {
value = kit.GetMeta(value)
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++
})
m.Conf(prefix, kit.Keys(chain, HASH, key, LIST), "")
m.Conf(prefix, kit.Keys(chain, HASH, key, META, COUNT), "")
}
kit.If(count == 0, func() { os.Remove(p) })
m.Logs(EXPORT, KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
})
m.Log_EXPORT(KEY, path.Join(prefix, chain), FILE, p, COUNT, count)
m.Conf(prefix, kit.Keys(chain, HASH), "")
m.Echo(p)
}
func _zone_import(m *ice.Message, prefix, chain, file string) {
if !ice.HasUsr() {
return
}
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
}
f, e := os.Open(kit.Keys(file, CSV))
m.Assert(e)
defer f.Close()
r := csv.NewReader(f)
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
list := map[string]string{}
zkey := kit.Select(head[0], m.OptionFields())
for {
line, e := r.Read()
if e != nil {
break
}
zone, data := "", kit.Dict()
zone := ""
data := kit.Dict()
for i, k := range head {
switch k {
case zkey:
@ -127,163 +115,105 @@ func _zone_import(m *ice.Message, prefix, chain, file string) {
case ID:
continue
case EXTRA:
if line[i] != "" {
kit.Value(data, k, kit.UnMarshal(line[i]))
}
kit.Value(data, k, kit.UnMarshal(line[i]))
default:
kit.Value(data, k, line[i])
}
}
if list[zone] == "" {
list[zone] = Rich(m, 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) })
list[zone] = m.Rich(prefix, chain, kit.Data(zkey, zone))
}
func() { chain := kit.Keys(chain, HASH, list[zone]); Grow(m, prefix, chain, data) }()
m.Grow(prefix, kit.Keys(chain, HASH, list[zone]), data)
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)
}
const (
ZONE_FIELD = "time,id,type,name,text"
)
const ZONE = "zone"
func ZoneConfig(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 := kit.Select(ZONE, Config(m, SHORT))
kit.If(s == UNIQ || strings.Contains(s, ","), func() { s = HASH })
if cmd.Name == "" {
cmd.Name = kit.Format("%s %s id auto", m.CommandKey(), s)
cmd.List = ice.SplitCmd(cmd.Name, cmd.Actions)
func ZoneAction(args ...interface{}) map[string]*ice.Action {
_zone := func(m *ice.Message) string { return kit.Select(ZONE, m.Config(SHORT)) }
return ice.SelectAction(map[string]*ice.Action{ice.CTX_INIT: AutoConfig(args...),
INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
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)
}
add := func(list []string) (inputs []Any) {
kit.For(list, func(k string) {
kit.If(!kit.IsIn(k, TIME, HASH, COUNT, ID), func() {
inputs = append(inputs, k+kit.Select("", FOREACH, strings.Contains(s, k)))
})
})
return
}},
CREATE: {Name: "create zone", Help: "创建", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg)
}},
REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(DELETE, m.PrefixKey(), "", HASH, m.OptionSimple(_zone(m)), arg)
}},
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))
}
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)
}
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, _zone(m), arg[1])
m.Cmdy(INSERT, m.PrefixKey(), "", ZONE, m.Option(_zone(m)), arg[2:])
}},
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...)
}},
})
}
func ZoneSelect(m *ice.Message, arg ...string) *ice.Message {
arg = kit.Slice(arg, 0, 2)
short, field, fields := Config(m, SHORT), Config(m, FIELD), ZoneField(m)
m.Fields(len(arg), kit.Select(kit.Fields(TIME, short, COUNT), field), fields)
if m.Cmdy(SELECT, m.PrefixKey(), "", ZONE, arg, logs.FileLineMeta(-1)); len(arg) == 0 {
m.Sort(short).PushAction(REMOVE).Action(CREATE)
} else if len(arg) == 1 {
m.Action(INSERT)
} else {
sortByField(m, fields)
m.Fields(len(arg), kit.Fields(TIME, m.Config(SHORT), COUNT), m.Config(FIELD))
if m.Cmdy(SELECT, m.PrefixKey(), "", ZONE, arg); kit.Select("", arg, 0) == "" {
m.Sort(m.Config(SHORT))
m.PushAction(REMOVE)
}
m.StatusTimeCount()
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 {
m.Option(CACHE_LIMIT, "-1")
m.Option(ice.CACHE_LIMIT, "-1")
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.Option(CACHE_LIMIT, "-1")
m.Option(ice.CACHE_LIMIT, "-1")
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
import (
"bufio"
"bytes"
"encoding/csv"
"encoding/json"
"io"
"io/ioutil"
"os"
"path"
"strings"
@ -16,221 +14,177 @@ import (
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) != "" {
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))
}
func _cat_hash(m *ice.Message, p string) (h string) {
Open(m, p, func(r io.Reader) { h = kit.Hashs(r) })
return
}
func _cat_line(m *ice.Message, p string) (n int) {
Open(m, p, func(r io.Reader) { kit.For(r, func(s string) { n++ }) })
return
}
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
// 模块回调
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
}
case func(m *ice.Message, name string) []byte:
if b := h(m, name); b != nil {
return NewReadCloser(bytes.NewBuffer(b))
}
case func(m *ice.Message, name string) string:
if s := h(m, name); s != "" {
return NewReadCloser(bytes.NewBufferString(s))
}
}
}
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()
switch cb := m.OptionCB("").(type) {
switch cb := m.OptionCB(CAT).(type) {
case func(string, int) string:
list := []string{}
kit.For(f, func(s string, i int) { list = append(list, cb(s, i)) })
m.Echo(strings.Join(list, ice.NL) + ice.NL)
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))
for bio, i := bufio.NewScanner(f), 0; bio.Scan(); i++ {
list = append(list, cb(bio.Text(), i))
}
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:
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)...)
} else {
break
}
}
m.Echo(string(buf))
}
}
const (
CAT_CONTENT = "cat_content"
CONFIGURE = "configure"
STDIO = "stdio"
TEMPLATE = "template"
TAGS = "tags"
MODULE = "module"
SOURCE = "source"
TARGET = "target"
BINARY = "binary"
SCRIPT = "script"
FORMAT = "format"
TRANS = "trans"
TARGET = "target"
CLONE = "clone"
REPOS = "repos"
REMOTE = "remote"
ORIGIN = "origin"
COMMIT = "commit"
BRANCH = "branch"
MASTER = "master"
VERSION = "version"
COMPILE = "compile"
MASTER = "master"
BRANCH = "branch"
REPOS = "repos"
LOAD = "load"
TAGS = "tags"
)
const (
HTML = ice.HTML
CSS = ice.CSS
SVG = ice.SVG
JS = ice.JS
GO = ice.GO
SH = ice.SH
SHY = ice.SHY
CSV = ice.CSV
JSON = ice.JSON
MOD = "mod"
YML = "yml"
IML = "iml"
TXT = "txt"
SHY = "shy"
SVG = "svg"
PROTO = "proto"
YAML = "yaml"
CONF = "conf"
XML = "xml"
YML = "yml"
TXT = "txt"
MD = "md"
PY = "py"
IMAGE = "image"
JPEG = "jpeg"
JPG = "jpg"
PNG = "png"
MP4 = "mp4"
MOV = "mov"
PDF = "pdf"
DF = ice.DF
PS = ice.PS
PT = ice.PT
PWD = "./"
)
const (
PATH = "path"
FILE = "file"
LINE = "line"
SIZE = "size"
)
const CAT = "cat"
func init() {
Index.MergeCommands(ice.Commands{
CAT: {Name: "cat path auto", Help: "文件", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: mdb.AutoConfig(SOURCE, kit.DictList(
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),
)),
}, DIR), Hand: func(m *ice.Message, arg ...string) {
if !DirList(m, arg...) {
if arg[0] != "" {
m.Logs(FIND, m.OptionSimple(DIR_ROOT), FILE, arg[0])
}
_cat_list(m, arg[0])
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CAT: {Name: CAT, Help: "文件", Value: kit.Data(
SOURCE, kit.Dict(
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,
"conf", ice.TRUE, YML, ice.TRUE, IML, ice.TRUE, "txt", ice.TRUE,
"py", ice.TRUE,
),
)},
}, 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])
}},
})
}
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
import (
"bufio"
"crypto/sha1"
"io/ioutil"
"os"
"path"
"regexp"
"runtime"
"strings"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
@ -14,314 +15,257 @@ import (
kit "shylinux.com/x/toolkits"
)
func _dir_size(m *ice.Message, p string) (n int) {
Open(m, p+PS, func(ls []os.FileInfo) { n = len(ls) })
return
}
func _dir_hash(m *ice.Message, p string) (h string) {
list := []string{}
Open(m, p+PS, func(s os.FileInfo) { list = append(list, kit.Format("%s%d%s", s.Name(), s.Size(), s.ModTime())) })
kit.If(len(list) > 0, func() { h = kit.Hashs(list) })
return ""
}
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) {
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
}
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 {
if !_cat_right(m, path.Join(root, name)) {
return m // 没有权限
}
for _, s := range ls {
if s.Name() == PT || s.Name() == ".." || strings.HasPrefix(s.Name(), PT) && dir_type != TYPE_ALL {
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())) {
switch cb := m.OptionCB("").(type) {
case func(os.FileInfo, string):
cb(s, p)
continue
case func(string):
cb(p)
continue
case nil:
default:
m.ErrorNotImplement(cb)
if len(ice.Info.Pack) > 0 && m.Option(DIR_PACK) == ice.TRUE {
for k, b := range ice.Info.Pack {
p := strings.TrimPrefix(k, root)
if !strings.HasPrefix(p, name) {
if p = strings.TrimPrefix(k, root+ice.PS); !strings.HasPrefix(p, name) {
if p = strings.TrimPrefix(k, ice.PS); !strings.HasPrefix(p, name) {
continue
}
}
}
kit.If(s.ModTime().After(last), func() { last = s.ModTime() })
m.Debug("dir binpack %s", p)
for _, field := range fields {
switch field {
case mdb.TIME:
m.Push(field, s.ModTime().Format(ice.MOD_TIME))
case mdb.TYPE:
m.Push(field, kit.Select(CAT, DIR, isDir))
case TREE:
if level == 0 {
m.Push(field, s.Name())
} else {
m.Push(field, strings.Repeat("| ", level-1)+"|-"+s.Name())
}
case FULL:
m.Push(field, p+kit.Select("", PS, isDir))
case PATH:
m.Push(field, pp+kit.Select("", PS, isDir))
case FILE:
m.Push(field, s.Name()+kit.Select("", PS, isDir))
case NAME:
m.Push(field, s.Name())
m.Push(field, p)
case SIZE:
if isDir {
m.Push(field, _dir_size(m, p))
} else {
m.Push(field, kit.FmtSize(s.Size()))
total += s.Size()
}
case LINE:
if isDir {
m.Push(field, _dir_size(m, p))
} else {
m.Push(field, _cat_line(m, p))
}
case mdb.HASH, "hashs":
h := ""
if isDir {
h = _dir_hash(m, p)
} else {
h = _cat_hash(m, p)
}
m.Push(mdb.HASH, kit.Select(h[:6], h[:], field == mdb.HASH))
case mdb.LINK:
if isDir {
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:
switch p := m.MergeLink(SHARE_LOCAL+p, ice.POD, m.Option(ice.MSG_USERPOD)); kit.Ext(s.Name()) {
case PNG, JPG:
m.PushImages(field, p)
case MP4:
m.PushVideos(field, p)
default:
m.Push(field, "")
}
case mdb.ACTION:
if m.IsCliUA() || m.Option(ice.MSG_USERROLE) == aaa.VOID {
break
}
m.PushButton(mdb.SHOW, "rename", TRASH)
m.Push(field, len(b))
default:
m.Push(field, "")
}
}
}
if deep && isDir {
switch s.Name() {
case "pluged", "node_modules":
continue
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)
}
_total, _last := _dir_list(m, root, pp, level+1, deep, dir_type, dir_reg, fields)
if total += _total; _last.After(last) {
last = _last
}
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]
}
}
}
return
for _, f := range list {
if f.Name() == ice.PT || f.Name() == ".." {
continue
}
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)
continue
}
for _, field := range fields {
switch field {
case mdb.TIME:
m.Push(field, f.ModTime().Format(ice.MOD_TIME))
case mdb.TYPE:
m.Push(field, kit.Select(CAT, DIR, f.IsDir()))
case "tree":
if level == 0 {
m.Push(field, f.Name())
} else {
m.Push(field, strings.Repeat("| ", level-1)+"|-"+f.Name())
}
case "full":
m.Push(field, path.Join(root, name, f.Name())+kit.Select("", ice.PS, f.IsDir()))
case PATH:
m.Push(field, path.Join(name, f.Name())+kit.Select("", ice.PS, f.IsDir()))
case FILE:
m.Push(field, f.Name()+kit.Select("", ice.PS, f.IsDir()))
case mdb.NAME:
m.Push(field, f.Name())
case SIZE:
if f.IsDir() {
if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil {
m.Push(field, len(ls))
} else {
m.Push(field, 0)
}
} else {
m.Push(field, kit.FmtSize(f.Size()))
}
case LINE:
if f.IsDir() {
if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil {
m.Push(field, len(ls))
} else {
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":
var h [20]byte
if f.IsDir() {
if d, e := ioutil.ReadDir(p); m.Assert(e) {
meta := []string{}
for _, v := range d {
meta = append(meta, kit.Format("%s%d%s", v.Name(), v.Size(), v.ModTime()))
}
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:
m.PushDownload(mdb.LINK, kit.Select("", f.Name(), !f.IsDir()), path.Join(root, name, f.Name()))
case mdb.SHOW:
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":
m.PushImages(field, p)
case "mp4":
m.PushVideos(field, p)
default:
m.Push(field, "")
}
case "action":
if m.IsCliUA() || m.Option(ice.MSG_USERROLE) == aaa.VOID {
break
}
m.PushButton(kit.Select("", TRASH, !f.IsDir()))
default:
m.Push(field, "")
}
}
}
switch f.Name() {
case "node_modules", "pluged", "target", "trash":
continue
}
if f.IsDir() && deep {
_dir_list(m, root, path.Join(name, f.Name()), level+1, deep, dir_type, dir_reg, fields)
}
}
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
}
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 (
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_BIN = "bin"
TYPE_CAT = "cat"
TYPE_DIR = "dir"
TYPE_BOTH = "both"
)
const (
DIR_PACK = "dir_pack"
DIR_ROOT = "dir_root"
DIR_DEEP = "dir_deep"
DIR_TYPE = "dir_type"
DIR_DEEP = "dir_deep"
DIR_REG = "dir_reg"
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"
ROOT = "root"
TREE = "tree"
FULL = "full"
PATH = "path"
FILE = "file"
NAME = "name"
SIZE = "size"
LINE = "line"
)
const DIR = "dir"
func init() {
Index.MergeCommands(ice.Commands{
DIR: {Name: "dir path auto upload app", Icon: "dir.png", Help: "文件夹", Actions: ice.Actions{
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
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) {
aaa.White(m, ice.MAKEFILE, ice.README_MD, ice.LICENSE)
aaa.White(m, ice.SRC, ice.BIN, ice.USR)
aaa.Black(m, ice.SRC_PRIVATE)
aaa.Black(m, ice.USR_LOCAL)
m.Cmd(mdb.SEARCH, mdb.CREATE, m.CommandKey(), m.PrefixKey())
m.Cmd(mdb.RENDER, mdb.CREATE, m.CommandKey(), m.PrefixKey())
}},
ice.APP: {Help: "本机", Hand: func(m *ice.Message, arg ...string) {
switch runtime.GOOS {
case "darwin":
m.System("open", kit.Path(m.Option(PATH)))
mdb.SEARCH: {Name: "search type name", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
if arg[0] == mdb.FOREACH {
return
}
_dir_search(m, arg[0], arg[1])
}},
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))
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())))
}},
"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))
mdb.UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) {
m.Upload(m.Option(PATH))
}},
TRASH: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(TRASH, mdb.CREATE, m.Option(PATH))
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
os.Remove(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
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))
}
m.Logs(FIND, DIR_ROOT, root, PATH, dir, m.OptionSimple(DIR_TYPE, DIR_REG))
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))
_dir_list(m, kit.Select(PWD, m.Option(DIR_ROOT)), kit.Select(PWD, arg, 0),
0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), kit.Regexp(m.Option(DIR_REG)),
kit.Split(kit.Select(kit.Select(DIR_DEF_FIELDS, m.OptionFields()), kit.Join(kit.Slice(arg, 1)))))
m.SortTimeR(mdb.TIME)
m.StatusTimeCount()
}},
})
}
func Relative(m *ice.Message, p string) string {
if _p := kit.ExtChange(p, JS); Exists(m, _p) {
return _p
} 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]) {
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"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
const FIND = "find"
func init() {
const CMD_DIR = "cmd_dir"
Index.MergeCommands(ice.Commands{
FIND: {Name: "find word file auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) == 0, func() { arg = append(arg, "main.go") })
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)))
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
FIND: {Name: "find path word auto", Help: "搜索", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
for _, file := range strings.Split(m.Cmdx("cli.system", FIND, PWD, "-name", arg[1]), ice.NL) {
m.Push(FILE, strings.TrimPrefix(file, PWD))
}
}},
})
}})
}

View File

@ -1,33 +1,14 @@
package nfs
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
const (
OPENS = "opens"
)
import ice "shylinux.com/x/icebergs"
const GREP = "grep"
func init() {
const CMD_DIR = "cmd_dir"
Index.MergeCommands(ice.Commands{
GREP: {Name: "grep word file auto", Help: "搜索", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) == 0, func() { arg = append(arg, ice.MAIN) })
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")
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
GREP: {Name: "grep path word auto", Help: "搜索", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option("cmd_dir", arg[0])
m.Split(m.Cmdx("cli.system", GREP, "--exclude=.[a-z]*", "--exclude-dir=.[a-z]*", "-rni", arg[1]), "file:line:text", ":")
}},
})
}})
}

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
import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
import ice "shylinux.com/x/icebergs"
const NFS = "nfs"
var Index = &ice.Context{Name: NFS, Help: "存储模块"}
var Index = &ice.Context{Name: "nfs", Help: "存储模块"}
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,119 @@
package nfs
import (
"fmt"
"io"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
kit "shylinux.com/x/toolkits"
)
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 kit.FileExists(path.Join(m.Option(DIR_ROOT), name)) {
return
}
for i, v := range text {
if b, e := kit.Render(v, m); !m.WarnNotValid(e) {
text[i] = string(b)
}
b, _ := kit.Render(v, m)
text[i] = string(b)
}
_save_file(m, name, text...)
}
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) {
defer m.Echo(p)
kit.For(text, func(s string) { Save(m, w, s, func(n int) { m.Logs(SAVE, FILE, p, SIZE, n) }) })
})
if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
defer f.Close()
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) {
Append(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) {
defer m.Echo(p)
kit.For(text, func(s string) { Save(m, w, s, func(n int) { m.Logs(SAVE, FILE, p, SIZE, n) }) })
})
p := path.Join(m.Option(DIR_ROOT), name)
if strings.Contains(p, ice.PS) {
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) {
Create(m, path.Join(m.Option(DIR_ROOT), name), func(w io.Writer, p string) {
defer m.Echo(p)
kit.For(from, func(f string) {
Open(m, path.Join(m.Option(DIR_ROOT), f), func(r io.Reader) {
Copy(m, w, r, func(n int) { m.Logs(LOAD, FILE, f, SIZE, n).Logs(SAVE, FILE, p, SIZE, n) })
})
})
})
if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) {
defer f.Close()
for _, v := range from {
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) {
if m.WarnNotValid(from == "", FROM) {
if from == "" {
return
}
name = path.Join(m.Option(DIR_ROOT), name)
from = path.Join(m.Option(DIR_ROOT), from)
if m.WarnNotFound(!Exists(m, from), from) {
return
os.Remove(name)
MkdirAll(m, path.Dir(name))
if e := os.Link(from, name); e != nil {
m.Warn(os.Symlink(from, name), ice.ErrFailure, from)
}
Remove(m, 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)
m.Echo(name)
}
const (
CONTENT = "content"
OFFSET = "offset"
ALIAS = "alias"
FROM = "from"
TO = "to"
)
const DEFS = "defs"
const SAVE = "save"
const PUSH = "push"
const COPY = "copy"
const LINK = "link"
const LOAD = "load"
const MOVE = "move"
const MOVETO = "moveto"
func init() {
Index.MergeCommands(ice.Commands{
DEFS: {Name: "defs file text run", Help: "默认", Hand: func(m *ice.Message, arg ...string) {
OptionFiles(m, DiskFile)
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
DEFS: {Name: "defs file text...", Help: "默认", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
_defs_file(m, arg[0], arg[1:]...)
}},
SAVE: {Name: "save file text run", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) == 1, func() { arg = append(arg, m.Option(CONTENT)) })
SAVE: {Name: "save file text...", Help: "保存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 1 {
arg = append(arg, m.Option(CONTENT))
}
_save_file(m, arg[0], arg[1:]...)
}},
PUSH: {Name: "push file text run", Help: "追加", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) == 1, func() { arg = append(arg, m.Option(CONTENT)) })
PUSH: {Name: "push file text...", Help: "追加", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 1 {
arg = append(arg, m.Option(CONTENT))
}
_push_file(m, arg[0], arg[1:]...)
}},
COPY: {Name: "copy file from run", Help: "复制", Hand: func(m *ice.Message, arg ...string) {
kit.If(len(arg) > 1 && Exists(m, arg[1]), func() { _copy_file(m, arg[0], arg[1:]...) })
COPY: {Name: "copy file from...", Help: "复制", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
for _, file := range arg[1:] {
if kit.FileExists(file) {
_copy_file(m, arg[0], arg[1:]...)
return
}
}
}},
LINK: {Name: "link file from run", Help: "链接", Hand: func(m *ice.Message, arg ...string) {
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])
}},
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
}
if n, e := fmt.Fprint(w, s); !m.WarnNotValid(e) {
switch cb := cb.(type) {
case func(int):
cb(n)
default:
m.ErrorNotImplement(cb)
}
}
}
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"
"io"
"os"
"path"
"strings"
ice "shylinux.com/x/icebergs"
@ -13,100 +12,77 @@ import (
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"
func init() {
Index.MergeCommands(ice.Commands{
TAR: {Name: "tar 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) {
if kit.Ext(m.Option(PATH)) == ZIP {
m.Cmdy(ZIP, mdb.EXPORT, arg)
return
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
TAR: {Name: "tar file path auto", Help: "打包", Action: map[string]*ice.Action{
mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 1 {
arg = append(arg, arg[0])
}
list, size := kit.Dict(), 0
_tar_list(m, m.Option(PATH), func(h *tar.Header, r io.Reader, i int) {
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) })
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) })
})
}
})
if !strings.HasSuffix(arg[0], ".tar.gz") {
arg[0] += ".tar.gz"
}
m.Cmd("cli.system", "tar", "zcvf", arg)
m.Echo(arg[0])
}},
}, mdb.PageListAction()), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 || strings.HasSuffix(arg[0], PS) {
m.Cmdy(DIR, arg)
return
mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
m.Cmd("cli.system", "tar", "xvf", arg)
m.Echo(arg[0])
}},
}, 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()
}
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] {
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
}
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)
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)))
})
}
m.StatusTimeCountTotal(kit.FmtSize(total))
}},
})
}
func TarExport(m *ice.Message, path string, file ...string) {
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
import (
"io"
"os"
"path"
ice "shylinux.com/x/icebergs"
@ -9,43 +9,56 @@ import (
kit "shylinux.com/x/toolkits"
)
func _trash_create(m *ice.Message, from string) {
if m.WarnNotValid(from == "", FROM) {
return
func _trash_create(m *ice.Message, name string) {
if s, e := os.Stat(name); m.Assert(e) {
if s.IsDir() {
name = m.Cmdx(TAR, mdb.IMPORT, name)
}
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)
}
}
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) })
}
const (
FROM = "from"
)
const TRASH = "trash"
func init() {
Index.MergeCommands(ice.Commands{
TRASH: {Name: "trash hash auto", Help: "回收站", Actions: ice.MergeActions(ice.Actions{
mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) {
_trash_create(m, kit.Paths(m.Option(FROM)))
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
TRASH: {Name: TRASH, Help: "回收站", Value: kit.Data(
mdb.SHORT, FROM, mdb.FIELD, "time,hash,file,from", PATH, ice.VAR_TRASH,
)},
}, 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) {
Remove(m, m.Option(FILE))
mdb.HashRemove(m, m.OptionSimple(mdb.HASH))
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
os.Remove(m.Option(FILE))
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) {
msg := mdb.HashSelect(m.Spawn(), m.Option(mdb.HASH))
Rename(m, msg.Append(FILE), msg.Append(FROM))
mdb.HashRemove(m, m.OptionSimple(mdb.HASH))
mdb.PRUNES: {Name: "prunes before@date", Help: "清理", Hand: func(m *ice.Message, arg ...string) {
mdb.HashPrunes(m, func(value map[string]string) bool {
os.Remove(value[FILE])
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)
}

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

@ -0,0 +1,303 @@
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 {
if 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: "终端模块"}
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 (
"net"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
type Stat struct {
nc, nr, nw int
}
type Conn struct {
net.Conn
m *ice.Message
h string
s *Stat
net.Conn
}
func (c *Conn) Read(b []byte) (int, error) {
@ -27,36 +30,71 @@ func (c *Conn) Write(b []byte) (int, error) {
c.s.nw += n
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) {
c, e := net.DialTimeout(TCP, m.Option(HOST)+nfs.DF+m.Option(PORT), 3*time.Second)
c = &Conn{Conn: c, m: m, s: &Stat{}}
defer kit.If(e == nil, func() { c.Close() })
switch cb := m.OptionCB("").(type) {
c, e := net.Dial(TCP, m.Option(HOST)+ice.DF+m.Option(PORT))
c = &Conn{m: m, s: &Stat{}, Conn: c}
if e == nil {
defer c.Close()
}
switch cb := m.OptionCB(CLIENT).(type) {
case func(net.Conn, error):
cb(c, e)
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:
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 (
DIAL = "dial"
)
const CLIENT = "client"
func init() {
Index.MergeCommands(ice.Commands{
CLIENT: {Help: "客户端", Actions: ice.MergeActions(ice.Actions{
DIAL: {Name: "dial type name port=9010 host=", Help: "连接", Hand: func(m *ice.Message, arg ...string) {
switch m.Option(mdb.TYPE) {
case UDP4:
_client_dial_udp4(m, arg...)
default:
_client_dial(m, arg...)
}
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CLIENT: {Name: CLIENT, Help: "客户端", Value: kit.Data(
mdb.FIELD, "time,hash,status,type,name,host,port,error,nread,nwrite",
)},
}, Commands: map[string]*ice.Command{
CLIENT: {Name: "client hash auto prunes", Help: "客户端", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
m.Richs(CLIENT, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
kit.Value(value, kit.Keym(STATUS), CLOSE)
})
m.Cmdy(SERVER, mdb.PRUNES)
}},
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error"), mdb.ClearOnExitHashAction())},
})
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 (
"net"
"os"
"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 _host_domain(m *ice.Message) 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 {
func _host_list(m *ice.Message, name string) {
if ifs, e := net.Interfaces(); m.Assert(e) {
for _, v := range ifs {
if !strings.Contains(v.Name, name) || len(v.HardwareAddr.String()) == 0 {
if name != "" && !strings.Contains(v.Name, name) {
continue
}
if len(v.HardwareAddr.String()) == 0 {
continue
}
if ips, e := v.Addrs(); m.Assert(e) {
for _, x := range ips {
ip := strings.Split(x.String(), nfs.PS)
if strings.Contains(ip[0], nfs.DF) || len(ip) == 0 {
ip := strings.Split(x.String(), ice.PS)
if strings.Contains(ip[0], ice.DF) || len(ip) == 0 {
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 (
LOCALHOST = "localhost"
MAC_ADDRESS = "mac-address"
MASK = "mask"
DOMAIN = "domain"
GATEWAY = "gateway"
MACHINE = "machine"
ISLOCAL = "islocal"
PUBLISH = "publish"
LOCALHOST = "localhost"
)
const HOST = "host"
func init() {
Index.MergeCommands(ice.Commands{
HOST: {Name: "host name auto domain", Help: "主机", Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(
aaa.IP, "网络地址", MASK, "子网掩码", MAC_ADDRESS, "物理地址",
)),
), Actions: ice.MergeActions(ice.Actions{
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
HOST: {Name: HOST, Help: "主机", Value: kit.Data(
aaa.BLACK, kit.Data(mdb.SHORT, mdb.TEXT), aaa.WHITE, kit.Data(mdb.SHORT, mdb.TEXT),
)},
}, Commands: map[string]*ice.Command{
HOST: {Name: "host name auto", Help: "主机", Action: map[string]*ice.Action{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd("", func(value ice.Maps) { m.Cmd("", aaa.WHITE, LOCALHOST, value[aaa.IP]) })
ice.Info.Host = mdb.Config(m, DOMAIN)
m.Cmd(HOST).Table(func(index int, value map[string]string, head []string) {
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.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 name text", Help: "白名单", Hand: func(m *ice.Message, arg ...string) {
mdb.HashCreate(m, mdb.TYPE, m.ActionKey(), m.OptionSimple(mdb.NAME, mdb.TEXT))
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]))
}},
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)
}
})
}, 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

@ -3,168 +3,74 @@ package tcp
import (
"net"
"path"
"runtime"
"strconv"
"strings"
ice "shylinux.com/x/icebergs"
"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/nfs"
kit "shylinux.com/x/toolkits"
)
func _port_right(m *ice.Message, current, begin, end int) string {
kit.If(current >= end, func() { current = begin })
for i := current; i < end; i++ {
if p := path.Join(ice.USR_LOCAL_DAEMON, kit.Format(i)); nfs.Exists(m, p) {
func _port_right(m *ice.Message, arg ...string) string {
current := kit.Int(kit.Select(m.Config(CURRENT), arg, 0))
end := kit.Int(m.Config(END))
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)
c.Close()
} else {
nfs.MkdirAll(m, p)
m.Logs(mdb.SELECT, PORT, i)
return mdb.Config(m, CURRENT, i)
continue
}
p := path.Join(m.Conf(cli.DAEMON, kit.Keym(nfs.PATH)), kit.Format(i))
if kit.FileExists(p) {
continue
}
nfs.MkdirAll(m, p)
m.Log_SELECT(PORT, i)
return m.Config(CURRENT, i)
}
return ""
}
const (
PORT_22 = "22"
PORT_80 = "80"
PORT_443 = "443"
PORT_9020 = "9020"
PORT_9022 = "9022"
SOCKET = "socket"
BEGIN = "begin"
CURRENT = "current"
RANDOM = "random"
CURRENT = "current"
BEGIN = "begin"
END = "end"
PID = "pid"
SPACE = "space"
)
const PORT = "port"
func init() {
Index.MergeCommands(ice.Commands{
PORT: {Name: "port port path auto socket", Help: "端口", Actions: ice.MergeActions(ice.Actions{
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case HOST, SERVER:
m.Cmd(PORT, SOCKET, func(value ice.Maps) {
switch value[mdb.STATUS] {
case "LISTEN":
m.Push(arg[0], strings.Replace(value["local"], "0.0.0.0", "127.0.0.1", 1))
}
})
case 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
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
PORT: {Name: PORT, Help: "端口", Value: kit.Data(BEGIN, 10000, CURRENT, 10000, END, 20000)},
}, Commands: map[string]*ice.Command{
PORT: {Name: "port port path auto", Help: "端口", Action: map[string]*ice.Action{
aaa.RIGHT: {Name: "right", Help: "分配", Hand: func(m *ice.Message, arg ...string) {
m.Echo(_port_right(m, arg...))
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
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.Cmd(PORT, SOCKET, func(value ice.Maps) {
switch value[mdb.STATUS] {
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.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)
})
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])))
m.SortInt(PORT)
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)
m.Option(nfs.DIR_ROOT, path.Join(m.Conf(cli.DAEMON, kit.Keym(nfs.PATH)), arg[0]))
m.Cmdy(nfs.DIR, arg[1:])
}},
})
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"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
type Stat struct{ nc, nr, nw int }
type Listener struct {
net.Listener
m *ice.Message
h string
s *Stat
net.Listener
}
func (l Listener) Accept() (net.Conn, error) {
c, e := l.Listener.Accept()
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 {
l.m.Cmd(mdb.MODIFY, SERVER, "", mdb.HASH, mdb.HASH, l.h, STATUS, CLOSE)
@ -29,63 +27,83 @@ func (l Listener) Close() error {
}
func _server_listen(m *ice.Message, arg ...string) {
l, e := net.Listen(TCP, m.Option(HOST)+nfs.DF+m.Option(PORT))
if m.WarnNotValid(e) {
return
l, e := net.Listen(TCP, m.Option(HOST)+":"+m.Option(PORT))
h := m.Cmdx(mdb.INSERT, SERVER, "", mdb.HASH, arg,
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("").(type) {
switch cb := m.OptionCB(SERVER).(type) {
case func(net.Listener, error):
cb(l, e)
case func(net.Listener):
m.Assert(e)
cb(l)
case func(net.Conn):
for {
if c, e := l.Accept(); !m.WarnNotValid(e) {
if c, e := l.Accept(); e == nil {
cb(c)
} else {
break
}
}
case func(net.Conn, error):
for {
c, e := l.Accept()
if cb(c, e); e != nil {
break
}
}
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()
}
}
}
const (
PROTOCOL = "protocol"
HOSTPORT = "hostport"
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"
PROTOCOL = "protocol"
HOSTPORT = "hostport"
HOSTNAME = "hostname"
)
const (
LISTEN = "listen"
UNIX = "unix"
)
const SERVER = "server"
func init() {
Index.MergeCommands(ice.Commands{
SERVER: {Help: "服务器", Actions: ice.MergeActions(ice.Actions{
LISTEN: {Name: "listen type name port=9030 host=", Hand: func(m *ice.Message, arg ...string) {
switch m.Option(mdb.TYPE) {
case UDP4:
_server_udp(m, arg...)
default:
_server_listen(m, arg...)
}
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
SERVER: {Name: SERVER, Help: "服务器", Value: kit.Data(
mdb.FIELD, "time,hash,status,type,name,host,port,error,nconn",
)},
}, Commands: map[string]*ice.Command{
SERVER: {Name: "server hash auto prunes", Help: "服务器", Action: ice.MergeAction(map[string]*ice.Action{
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) {
m.Richs(SERVER, "", mdb.FOREACH, func(key string, value map[string]interface{}) {
kit.Value(value, kit.Keym(STATUS), CLOSE)
})
m.Cmdy(SERVER, mdb.PRUNES)
}},
}, mdb.StatusHashAction(mdb.FIELD, "time,hash,status,type,name,host,port,error"), mdb.ClearOnExitHashAction())},
})
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
import (
ice "shylinux.com/x/icebergs"
kit "shylinux.com/x/toolkits"
)
import ice "shylinux.com/x/icebergs"
const TCP = "tcp"
var Index = &ice.Context{Name: TCP, Help: "通信模块"}
func init() { ice.Index.Register(Index, nil, WIFI, HOST, PORT, CLIENT, SERVER) }
func Prefix(arg ...ice.Any) string { return kit.Keys(TCP, kit.Keys(arg...)) }
func init() { ice.Index.Register(Index, nil, HOST, PORT, CLIENT, SERVER) }

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"
"os"
"path"
"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/tcp"
"shylinux.com/x/icebergs/base/web/html"
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_mime(m *ice.Message, mime, name string) string {
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 == "" {
return kit.Ext(name)
}
return mime
func _cache_name(m *ice.Message, h string) string {
return path.Join(m.Config(nfs.PATH), h[:2], h)
}
func _cache_save(m *ice.Message, mime, name, text string, arg ...string) {
if m.WarnNotValid(name == "", mdb.NAME) {
func _cache_save(m *ice.Message, kind, name, text string, arg ...string) { // file size
if name == "" {
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))
}
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))
m.Push(mdb.TYPE, mime).Push(mdb.NAME, name).Push(mdb.TEXT, text).Push(nfs.FILE, file).Push(nfs.SIZE, size)
// 添加数据
size := kit.Int(kit.Select(kit.Format(len(text)), arg, 1))
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) {
mdb.HashSelect(m.Spawn(), key).Table(func(value ice.Maps) {
func _cache_watch(m *ice.Message, key, file string) {
mdb.HashSelect(m.Spawn(), key).Table(func(index int, value map[string]string, head []string) {
if value[nfs.FILE] == "" {
m.Cmdy(nfs.SAVE, path, value[mdb.TEXT])
m.Cmdy(nfs.SAVE, file, value[mdb.TEXT])
} 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) {
if msg := m.Cmd(nfs.DIR, path, "hash,size"); msg.Length() > 0 {
return m.Cmdx(nfs.LINK, _cache_name(m, msg.Append(mdb.HASH)), path), msg.Append(nfs.SIZE)
func _cache_catch(m *ice.Message, name string) (file, size string) {
if f, e := os.Open(name); m.Assert(e) {
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"
}
func _cache_upload(m *ice.Message, r *http.Request) (mime, name, file, size string) {
if b, h, e := r.FormFile(UPLOAD); !m.WarnNotValid(e, UPLOAD) {
defer b.Close()
if f, p, e := miss.CreateFile(_cache_name(m, kit.Hashs(b))); !m.WarnNotValid(e, UPLOAD) {
func _cache_upload(m *ice.Message, r *http.Request) (kind, name, file, size string) {
if buf, h, e := r.FormFile(UPLOAD); e == nil {
defer buf.Close()
// 创建文件
if f, p, e := kit.Create(_cache_name(m, kit.Hashs(buf))); m.Assert(e) {
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)))
return h.Header.Get(html.ContentType), h.Filename, p, kit.Format(n)
// 导入数据
buf.Seek(0, os.SEEK_SET)
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"
}
func _cache_download(m *ice.Message, r *http.Response, file string, cb ice.Any) string {
m.Option(ice.MSG_USERROLE, aaa.TECH)
if f, p, e := miss.CreateFile(file); !m.WarnNotValid(e, DOWNLOAD) {
defer func() {
if s, e := os.Stat(file); e == nil && s.Size() == 0 {
nfs.Remove(m, file)
func _cache_download(m *ice.Message, r *http.Response) (file, size string) {
defer r.Body.Close()
if f, p, e := kit.Create(path.Join(ice.VAR_TMP, kit.Hashs("uniq"))); m.Assert(e) {
step, total := 0, kit.Int(kit.Select("1", r.Header.Get(ContentLength)))
size, buf := 0, make([]byte, ice.MOD_BUFS)
for {
if n, _ := r.Body.Read(buf); n > 0 {
size += n
f.Write(buf[0:n])
s := size * 100 / total
switch cb := m.OptionCB(SPIDE).(type) {
case func(int, int, int):
cb(size, total, s)
case func(int, int):
cb(size, total)
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)
})
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)))
}
}
step = s
continue
}
}()
defer f.Close()
last, base := 0, 10
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) {
if value/base == last {
return
}
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):
kit.If(cb != nil, func() { cb(count, total, value) })
case nil:
default:
m.ErrorNotImplement(cb)
}
})
return p
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 ""
return "", "0"
}
const (
@ -105,160 +131,57 @@ const (
WRITE = "write"
UPLOAD = "upload"
DOWNLOAD = "download"
PREVIEW = "preview"
PAGES = "pages"
IMAGE = "image"
VIDEO = "video"
)
const CACHE = "cache"
func init() {
Index.MergeCommands(ice.Commands{
CACHE: {Name: "cache hash auto upload", Help: "缓存池", Actions: ice.MergeActions(ice.Actions{
ice.RENDER_DOWNLOAD: {Hand: func(m *ice.Message, arg ...string) {
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)))
Index.Merge(&ice.Context{Configs: map[string]*ice.Config{
CACHE: {Name: CACHE, Help: "缓存池", Value: kit.Data(
mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,hash,size,type,name,text",
mdb.STORE, ice.VAR_DATA, nfs.PATH, ice.VAR_FILE, mdb.FSIZE, "200000",
mdb.LIMIT, "50", mdb.LEAST, "30",
)},
}, Commands: map[string]*ice.Command{
"/cache/": {Name: "/cache/", Help: "缓存池", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Richs(CACHE, nil, arg[0], func(key string, value map[string]interface{}) {
if kit.Format(value[nfs.FILE]) == "" {
m.RenderResult(value[mdb.TEXT])
} else {
m.RenderDownload(value[nfs.FILE])
}
})
}},
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])
}},
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))
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)
}},
CATCH: {Name: "catch path* type", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
file, size := _cache_catch(m, m.Option(nfs.PATH))
_cache_save(m, m.Option(mdb.TYPE), m.Option(nfs.PATH), "", 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])
}},
WATCH: {Name: "watch hash* path*", Help: "导出", Hand: func(m *ice.Message, arg ...string) {
_cache_watch(m, m.Option(mdb.HASH), m.Option(nfs.PATH))
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)
}},
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)
})
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) {
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) {
}, mdb.HashAction()), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if mdb.HashSelect(m, arg...); len(arg) == 0 {
return
}
if m.Length() == 0 {
return
} else if m.Append(nfs.FILE) == "" {
m.PushScript(mdb.TEXT, m.Append(mdb.TEXT))
if m.Append(nfs.FILE) == "" {
m.PushScript("inner", m.Append(mdb.TEXT))
} 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(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,599 +3,165 @@ package web
import (
"os"
"path"
"regexp"
"runtime"
"strings"
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli"
"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/nfs"
"shylinux.com/x/icebergs/base/tcp"
"shylinux.com/x/icebergs/base/web/html"
kit "shylinux.com/x/toolkits"
)
func _dream_list(m *ice.Message) *ice.Message {
list := m.CmdMap(SPACE, mdb.NAME)
mdb.HashSelects(m.Spawn()).Table(func(value ice.Maps, index int, head []string) {
if value[aaa.ACCESS] == aaa.PRIVATE && (m.Option(ice.FROM_SPACE) != "" || !aaa.IsTechOrRoot(m)) {
return
return m.Cmdy(nfs.DIR, m.Config(nfs.PATH), "time,size,name").Table(func(index int, value map[string]string, head []string) {
if m.Richs(SPACE, nil, value[mdb.NAME], func(key string, val map[string]interface{}) {
m.Push(mdb.TYPE, val[mdb.TYPE])
m.Push(cli.STATUS, cli.START)
m.PushButton(cli.STOP)
m.PushAnchor(strings.Split(m.MergePOD(value[mdb.NAME]), "?")[0])
}) == nil {
m.Push(mdb.TYPE, WORKER)
m.Push(cli.STATUS, cli.STOP)
m.PushButton(cli.START)
m.PushAnchor("")
}
if space, ok := list[value[mdb.NAME]]; ok {
value[ice.MAIN] = space[ice.MAIN]
value[mdb.ICONS] = space[mdb.ICONS]
m.Push("", value, kit.Slice(head, 0, -1))
m.Push(mdb.TYPE, space[mdb.TYPE]).Push(cli.STATUS, cli.START)
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])
})
}
func _dream_show(m *ice.Message, name string) {
if !strings.Contains(name, "-") || !strings.HasPrefix(name, "20") {
name = m.Time("20060102-") + kit.ReplaceAll(name, "-", "_")
}
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)
}
// 任务模板
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, ice.README_MD,
} {
if kit.FileExists(path.Join(p, file)) {
continue
}
switch m.Cmdy(nfs.COPY, path.Join(p, file), path.Join(m.Config(nfs.PATH), m.Option(nfs.TEMPLATE), file)); file {
case ice.GO_MOD:
kit.Rewrite(path.Join(p, file), func(line string) string {
return kit.Select(line, "module "+name, strings.HasPrefix(line, "module"))
})
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 {
if kit.HasPrefix(value, HTTP, nfs.PS) {
return value
} 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)
}
}
return value
})
return m
}
func _dream_list_more(m *ice.Message) *ice.Message {
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])
button = append(button, GETTOKEN, OPEN)
kit.If(value[aaa.ACCESS] == "", func() { button = []ice.Any{PORTAL, 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
}
button = append(button, SETTOKEN, 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])))
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))
// 任务脚本
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 // 已经启动
}
}
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:
nfs.Rewrite(m, 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))
})
}
})
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 (
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_REMOVE = "dream.remove"
DREAM_TRASH = "dream.trash"
DREAM_START = "dream.start"
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"
func init() {
Index.MergeCommands(ice.Commands{
DREAM: {Name: "dream refresh", Help: "梦想家", Icon: "Launchpad.png", Role: aaa.VOID, Meta: kit.Dict(
ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict(WORKER, "空间", SERVER, "门户", ORIGIN, "主机")),
), Actions: ice.MergeActions(ice.Actions{
ice.AFTER_INIT: {Hand: func(m *ice.Message, arg ...string) {
AddPortalProduct(m, "云空间", `
比虚拟机和容器更加轻量每个空间都是一个完整的系统拥有各种软件与独立的环境
空间内所有的软件配置数据以源码库形式保存每个空间都可以随时启动停止上传下载分享
每个空间都自带软件开发工具也可以随时编程添加新的功能
`, 200.0)
}},
mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) {
if mdb.IsSearchPreview(m, arg) {
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) {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
DREAM: {Name: "dream name path auto start", Help: "梦想家", Action: map[string]*ice.Action{
mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case mdb.NAME:
DreamEach(m, "", kit.Select(cli.START, cli.STOP, m.Option(ctx.ACTION) == STARTALL), func(name string) { m.Push(arg[0], name) })
case tcp.NODENAME:
m.Cmdy(SPACE, m.Option(mdb.NAME), SPACE, ice.INFO).CutTo(mdb.NAME, arg[0])
case aaa.USERNAME:
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 {
m.Push(arg[0], m.Option(tcp.NODENAME))
m.Push(arg[0], m.Option(ice.MSG_USERNAME))
}
case nfs.REPOS:
case nfs.BINARY:
case "repos":
default:
gdb.Event(m, DREAM_INPUTS, arg)
_dream_list(m).Cut("name,status,time")
}
}},
nfs.SCAN: {Hand: func(m *ice.Message, 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])
}
})
cli.START: {Name: "start name repos river", Help: "启动", Hand: func(m *ice.Message, arg ...string) {
_dream_show(m, m.Option(mdb.NAME, kit.Select(path.Base(m.Option(nfs.REPOS)), m.Option(mdb.NAME))))
}},
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)...)
}
cli.STOP: {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(SPACE, mdb.MODIFY, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
m.Cmdy(SPACE, m.Option(mdb.NAME), ice.EXIT)
}},
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)
DREAM_STOP: {Name: "dream.stop type name", Help: "停止", Hand: func(m *ice.Message, arg ...string) {
if m.Cmd(SPACE, m.Option(mdb.NAME)).Append(mdb.STATUS) == cli.STOP {
m.Cmdy(SPACE, mdb.REMOVE, m.OptionSimple(mdb.NAME))
} else {
m.ProcessOpen(S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME))))
m.Cmdy(SPACE, mdb.REMOVE, m.OptionSimple(mdb.NAME))
m.Sleep("1s", DREAM, cli.START, m.OptionSimple(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,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) {
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 {
if ice.Info.NodeType == WORKER {
return
}
_dream_list(m)
if _dream_list_more(m); !aaa.IsTechOrRoot(m) || m.IsCliUA() {
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
}
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)
m.Sort("status,type,name")
return
}
}},
})
}
func DreamTablesAction(arg ...string) ice.Actions {
return ice.Actions{ice.CTX_INIT: {Hand: DreamWhiteHandle},
DREAM_TABLES: {Hand: func(m *ice.Message, _ ...string) {
m.PushButton(kit.Dict(m.CommandKey(), kit.Select(m.Commands("").Help, arg, 0)))
m.Option(nfs.DIR_ROOT, path.Join(m.Config(nfs.PATH), arg[0]))
m.Cmdy(nfs.CAT, arg[1:])
}},
DREAM_ACTION: {Hand: func(m *ice.Message, arg ...string) { DreamProcess(m, "", nil, arg...) }},
}
}
func DreamAction() ice.Actions {
return gdb.EventsAction(
DREAM_INPUTS, DREAM_CREATE, DREAM_REMOVE, DREAM_TRASH, DREAM_OPEN, DREAM_CLOSE,
OPS_ORIGIN_OPEN, OPS_SERVER_OPEN, OPS_DREAM_CREATE, OPS_DREAM_REMOVE,
SERVE_START, SPACE_LOGIN,
)
}
func DreamWhiteHandle(m *ice.Message, arg ...string) {
aaa.White(m, kit.Keys(DREAM, ctx.ACTION, m.ShortKey()))
aaa.White(m, kit.Keys(m.ShortKey(), ctx.ACTION, DREAM_ACTION))
}
func DreamProcessIframe(m *ice.Message, arg ...string) {
if !kit.HasPrefixList(arg, ctx.ACTION, m.ShortKey()) && !kit.HasPrefixList(arg, ctx.ACTION, m.CommandKey()) {
return
}
if len(arg) == 2 {
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))
}
DreamProcess(m, CHAT_IFRAME, func() string {
p := S(kit.Keys(m.Option(ice.MSG_USERPOD), m.Option(mdb.NAME)))
kit.If(m.Option(mdb.TYPE) == ORIGIN && m.CommandKey() == PORTAL, func() { p = SpideOrigin(m, m.Option(mdb.NAME)) })
return kit.MergeURL(p+C(m.ShortKey()), ice.MSG_DEBUG, m.Option(ice.MSG_DEBUG))
}, arg...)
}
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
}, Configs: map[string]*ice.Config{
DREAM: {Name: DREAM, Help: "梦想家", Value: kit.Data(nfs.PATH, ice.USR_LOCAL_WORK,
"miss", `#! /bin/sh
if [ "$ISH_CONF_PRE" = "" ]; then
[ -f $PWD/.ish/plug.sh ] || [ -f $HOME/.ish/plug.sh ] || git clone ${ISH_CONF_HUB_PROXY:="https://"}shylinux.com/x/intshell $PWD/.ish
source $PWD/.ish/plug.sh || source $HOME/.ish/plug.sh
fi
require miss.sh
ish_miss_prepare_compile
ish_miss_prepare_develop
ish_miss_prepare_install
# ish_miss_prepare redis-story
# ish_miss_prepare mysql-story
# ish_miss_prepare release
ish_miss_prepare_intshell
ish_miss_prepare_contexts
# ish_miss_prepare_icebergs
# ish_miss_prepare_toolkits
# ish_miss_prepare_volcanos
# ish_miss_prepare_learning
make
`,
)},
}})
}

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