1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-26 01:24:05 +08:00
This commit is contained in:
harveyshao 2022-11-28 00:36:04 +08:00
parent 6d7e26b887
commit ec83a5b39c
20 changed files with 397 additions and 992 deletions

View File

@ -71,11 +71,11 @@ func SessCheck(m *ice.Message, sessid string) bool {
m.Options(ice.MSG_USERNAME, "", ice.MSG_USERNICK, "", ice.MSG_USERROLE, VOID)
return sessid != "" && m.Cmdy(SESS, CHECK, sessid).Option(ice.MSG_USERNAME) != ""
}
func SessAuth(m *ice.Message, value ice.Map, arg ...string) {
func SessAuth(m *ice.Message, value ice.Any, arg ...string) {
m.Auth(
USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
USERNICK, m.Option(ice.MSG_USERNICK, value[USERNICK]),
USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
USERNAME, m.Option(ice.MSG_USERNAME, kit.Value(value, USERNAME)),
USERNICK, m.Option(ice.MSG_USERNICK, kit.Value(value, USERNICK)),
USERROLE, m.Option(ice.MSG_USERROLE, kit.Value(value, USERROLE)),
arg, logs.FileLineMeta(kit.Select(logs.FileLine(-1), m.Option("log.caller"))),
)
}

View File

@ -53,3 +53,7 @@ func init() {
}, mdb.HashAction(mdb.SHORT, FROM, mdb.FIELD, "time,hash,from,file", mdb.ACTION, mdb.REVERT))},
})
}
func Trash(m *ice.Message, p string) *ice.Message {
return m.Cmd(TRASH, mdb.CREATE, p)
}

View File

@ -19,7 +19,7 @@ func _port_right(m *ice.Message, arg ...string) string {
}
for i := current; i < end; i++ {
if p := path.Join(ice.USR_LOCAL_DAEMON, kit.Format(i)); nfs.ExistsFile(m, p) {
} else if c, e := net.Dial(TCP, kit.Format(":%d", i)); e == nil {
m.Info("port exists %v", i)
c.Close()
@ -43,11 +43,11 @@ const PORT = "port"
func init() {
Index.MergeCommands(ice.Commands{
PORT: {Name: "port port path auto", Help: "端口", Actions: ice.MergeActions(ice.Actions{
CURRENT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(m.Config(CURRENT)) }},
CURRENT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(m.Config(CURRENT)) }},
aaa.RIGHT: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_port_right(m, arg...)) }},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
m.Assert(m.Option(PORT) != "")
m.Cmd(nfs.TRASH, path.Join(ice.USR_LOCAL_DAEMON, m.Option(PORT)))
nfs.Trash(m, path.Join(ice.USR_LOCAL_DAEMON, m.Option(PORT)))
}},
}, mdb.HashAction(BEGIN, 10000, CURRENT, 10000, END, 20000)), Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 {

View File

@ -1,428 +0,0 @@
package web
import (
"time"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
func _story_list(m *ice.Message, name string, key string) {
if name == "" {
m.Richs(STORY, HEAD, mdb.FOREACH, func(key string, value ice.Map) {
m.Push(key, value, []string{mdb.TIME, mdb.COUNT, STORY})
})
m.SortTimeR(mdb.TIME)
return
}
if key == "" {
_story_history(m, name)
return
}
m.Richs(STORY, nil, key, func(key string, value ice.Map) {
m.Push(mdb.DETAIL, value)
})
}
func _story_index(m *ice.Message, name string, withdata bool) {
m.Richs(STORY, HEAD, name, func(key string, value ice.Map) {
// 查询索引
m.Push(HEAD, key)
name = kit.Format(value[LIST])
})
m.Richs(STORY, nil, name, func(key string, value ice.Map) {
// 查询节点
m.Push(LIST, key)
m.Push(key, value, []string{SCENE, STORY})
name = kit.Format(value[DATA])
})
m.Richs(CACHE, nil, name, func(key string, value ice.Map) {
// 查询数据
m.Push(DATA, key)
m.Push(key, value, []string{mdb.TEXT, nfs.FILE, nfs.SIZE, mdb.TIME, mdb.NAME, mdb.TYPE})
if withdata {
if value[nfs.FILE] == "" {
m.Echo("%s", kit.Format(value[mdb.TEXT]))
} else {
m.Echo("%s", m.Cmdx(nfs.CAT, value[nfs.FILE]))
}
}
})
}
func _story_history(m *ice.Message, name string) {
// 历史记录
list := m.Cmd(STORY, INDEX, name).Append(LIST)
for i := 0; i < kit.Int(kit.Select("30", m.Option(ice.CACHE_LIMIT))) && list != ""; i++ {
m.Richs(STORY, nil, list, func(key string, value ice.Map) {
// 直连节点
m.Push(key, value, []string{mdb.TIME, mdb.KEY, mdb.COUNT, SCENE, STORY})
m.Richs(CACHE, nil, value[DATA], func(key string, value ice.Map) {
m.Push(DRAMA, value[mdb.TEXT])
m.Push(DATA, key)
})
kit.Fetch(value[LIST], func(key string, val string) {
m.Richs(STORY, nil, val, func(key string, value ice.Map) {
// 复合节点
m.Push(key, value, []string{mdb.TIME, mdb.KEY, mdb.COUNT, SCENE, STORY})
m.Richs(CACHE, nil, value[DATA], func(key string, value ice.Map) {
m.Push(DRAMA, value[mdb.TEXT])
m.Push(DATA, key)
})
})
})
// 切换节点
list = kit.Format(value[PREV])
})
}
}
func _story_write(m *ice.Message, scene, name, text string, arg ...string) {
if len(arg) < 1 || text == "" || m.Richs(CACHE, nil, text, func(key string, value ice.Map) { text = key }) == nil {
// 添加缓存
m.Cmdy(CACHE, CATCH, scene, name, text, arg)
scene, name, text = m.Append(mdb.TYPE), m.Append(mdb.NAME), m.Append(DATA)
}
// 查询索引
head, prev, value, count := "", "", kit.Dict(), 0
m.Richs(STORY, HEAD, name, func(key string, val ice.Map) {
head, prev, value, count = key, kit.Format(val[LIST]), val, kit.Int(val[mdb.COUNT])
m.Logs("info", HEAD, head, PREV, prev, mdb.COUNT, count)
})
if last := m.Richs(STORY, nil, prev, nil); prev != "" && last != nil && last[DATA] == text {
// 重复提交
m.Push(prev, last, []string{mdb.TIME, mdb.COUNT, mdb.KEY})
m.Logs("info", "file", "exists")
m.Echo(prev)
return
}
// 添加节点
list := m.Rich(STORY, nil, kit.Dict(
SCENE, scene, STORY, name, mdb.COUNT, count+1, DATA, text, PREV, prev,
))
m.Log_CREATE(STORY, list, mdb.TYPE, scene, mdb.NAME, name)
m.Push(mdb.COUNT, count+1)
m.Push(mdb.KEY, list)
if head == "" {
// 添加索引
m.Rich(STORY, HEAD, kit.Dict(SCENE, scene, STORY, name, mdb.COUNT, count+1, LIST, list))
} else {
// 更新索引
value[mdb.COUNT] = count + 1
value[mdb.TIME] = m.Time()
value[LIST] = list
}
m.Echo(list)
}
func _story_catch(m *ice.Message, scene, name string, arg ...string) {
if last := m.Richs(STORY, HEAD, name, nil); last != nil {
if t, e := time.ParseInLocation(ice.MOD_TIME, kit.Format(last[mdb.TIME]), time.Local); e == nil {
if s, e := nfs.StatFile(m, name); e == nil && s.ModTime().Before(t) {
m.Push(name, last, []string{mdb.TIME, mdb.COUNT, mdb.KEY})
m.Logs("info", "file", "exists")
m.Echo("%s", last[LIST])
// 重复提交
return
}
}
}
_story_write(m, scene, name, "", arg...)
}
func _story_watch(m *ice.Message, key, file string) {
_story_index(m, key, false)
_cache_watch(m, m.Append(DATA), file)
}
const (
HEAD = "head"
LIST = "list"
PREV = "prev"
DATA = "data"
HISTORY = "history"
PULL = "pull"
PUSH = "push"
COMMIT = "commit"
)
const (
SCENE = "scene"
DRAMA = "drama"
)
const STORY = "story"
func init() {
Index.Merge(&ice.Context{Configs: ice.Configs{
STORY: {Name: "story", Help: "故事会", Value: kit.Dict(
mdb.META, kit.Dict(mdb.SHORT, DATA),
HEAD, kit.Data(mdb.SHORT, STORY),
)},
}, Commands: ice.Commands{
STORY: {Name: "story story auto", Help: "故事会", Actions: ice.Actions{
WRITE: {Name: "write type name text arg...", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
_story_write(m, arg[0], arg[1], arg[2], arg[3:]...)
}},
CATCH: {Name: "catch type name arg...", Help: "捕捉", Hand: func(m *ice.Message, arg ...string) {
_story_catch(m, arg[0], arg[1], arg[2:]...)
}},
WATCH: {Name: "watch key name", Help: "释放", Hand: func(m *ice.Message, arg ...string) {
_story_watch(m, arg[0], arg[1])
}},
INDEX: {Name: "index key", Help: "索引", Hand: func(m *ice.Message, arg ...string) {
_story_index(m, arg[0], false)
}},
HISTORY: {Name: "history name", Help: "历史", Hand: func(m *ice.Message, arg ...string) {
_story_history(m, arg[0])
}},
}, Hand: func(m *ice.Message, arg ...string) {
_story_list(m, kit.Select("", arg, 0), kit.Select("", arg, 1))
}},
"/story/": {Name: "/story/", Help: "故事会", Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case PULL:
list := m.Cmd(STORY, INDEX, m.Option("begin")).Append("list")
for i := 0; i < 10 && list != "" && list != m.Option("end"); i++ {
if m.Richs(STORY, nil, list, func(key string, value ice.Map) {
// 节点信息
m.Push("list", key)
m.Push("node", kit.Format(value))
m.Push("data", value["data"])
m.Push("save", kit.Format(m.Richs(CACHE, nil, value["data"], nil)))
list = kit.Format(value["prev"])
}) == nil {
break
}
}
m.Log(ice.LOG_EXPORT, "%s %s", m.Option("begin"), m.FormatSize())
case PUSH:
if m.Richs(CACHE, nil, m.Option("data"), nil) == nil {
// 导入缓存
m.Log(ice.LOG_IMPORT, "%v: %v", m.Option("data"), m.Option("save"))
m.Conf(CACHE, kit.Keys("hash", m.Option("data")), kit.UnMarshal(m.Option("save")))
}
node := kit.UnMarshal(m.Option("node")).(ice.Map)
if m.Richs(STORY, nil, m.Option("list"), nil) == nil {
// 导入节点
m.Log(ice.LOG_IMPORT, "%v: %v", m.Option("list"), m.Option("node"))
m.Conf(STORY, kit.Keys("hash", m.Option("list")), node)
}
if head := m.Richs(STORY, "head", m.Option("story"), nil); head == nil {
// 自动创建
h := m.Rich(STORY, "head", kit.Dict(
"scene", node["scene"], "story", m.Option("story"),
"count", node["count"], "list", m.Option("list"),
))
m.Log(ice.LOG_CREATE, "%v: %v", h, m.Option("story"))
} else if head["list"] == kit.Format(node["prev"]) || head["list"] == kit.Format(node["pull"]) {
// 快速合并
head["list"] = m.Option("list")
head["count"] = node["count"]
head["time"] = node["time"]
} else {
// 推送失败
}
case UPLOAD:
// 上传数据
m.Cmdy(CACHE, "upload")
case DOWNLOAD:
// 下载数据
m.Cmdy(STORY, INDEX, arg[1])
m.Render(kit.Select(ice.RENDER_DOWNLOAD, ice.RENDER_RESULT, m.Append("file") == ""), m.Append("text"))
}
}},
}})
}
func _story_pull(m *ice.Message, arg ...string) {
// 起止节点
prev, begin, end := "", arg[3], ""
repos := kit.Keys("remote", arg[2], arg[3])
m.Richs(STORY, "head", arg[1], func(key string, val ice.Map) {
end = kit.Format(kit.Value(val, kit.Keys(repos, "pull", "list")))
prev = kit.Format(val["list"])
})
pull := end
var first ice.Map
for begin != "" && begin != end {
if m.Cmd(SPIDE, arg[2], "msg", "/story/pull", "begin", begin, "end", end).Table(func(index int, value ice.Maps, head []string) {
if m.Richs(CACHE, nil, value["data"], nil) == nil {
m.Log(ice.LOG_IMPORT, "%v: %v", value["data"], value["save"])
if node := kit.UnMarshal(value["save"]); kit.Format(kit.Value(node, "file")) != "" {
// 下载文件
m.Cmd(SPIDE, arg[2], "cache", "GET", "/story/download/"+value["data"])
} else {
// 导入缓存
m.Conf(CACHE, kit.Keys("hash", value["data"]), node)
}
}
node := kit.UnMarshal(value["node"]).(ice.Map)
if m.Richs(STORY, nil, value["list"], nil) == nil {
// 导入节点
m.Log(ice.LOG_IMPORT, "%v: %v", value["list"], value["node"])
m.Conf(STORY, kit.Keys("hash", value["list"]), node)
}
if first == nil {
if m.Richs(STORY, "head", arg[1], nil) == nil {
// 自动创建
h := m.Rich(STORY, "head", kit.Dict(
"scene", node["scene"], "story", arg[1],
"count", node["count"], "list", value["list"],
))
m.Log(ice.LOG_CREATE, "%v: %v", h, node["story"])
}
pull, first = kit.Format(value["list"]), node
m.Richs(STORY, "head", arg[1], func(key string, val ice.Map) {
prev = kit.Format(val["list"])
if kit.Int(node["count"]) > kit.Int(kit.Value(val, kit.Keys(repos, "pull", "count"))) {
// 更新分支
m.Log(ice.LOG_IMPORT, "%v: %v", arg[2], pull)
kit.Value(val, kit.Keys(repos, "pull"), kit.Dict(
"head", arg[3], "time", node["time"], "list", pull, "count", node["count"],
))
}
})
}
if prev == kit.Format(node["prev"]) || prev == kit.Format(node["push"]) {
// 快速合并
m.Log(ice.LOG_IMPORT, "%v: %v", pull, arg[2])
m.Richs(STORY, "head", arg[1], func(key string, val ice.Map) {
val["count"] = first["count"]
val["time"] = first["time"]
val["list"] = pull
})
prev = pull
}
begin = kit.Format(node["prev"])
}).Appendv("list") == nil {
break
}
}
}
func _story_push(m *ice.Message, arg ...string) {
// 更新分支
m.Cmdx(STORY, "pull", arg[1:])
repos := kit.Keys("remote", arg[2], arg[3])
// 查询索引
prev, pull, some, list := "", "", "", ""
m.Richs(STORY, "head", arg[1], func(key string, val ice.Map) {
prev = kit.Format(val["list"])
pull = kit.Format(kit.Value(val, kit.Keys(repos, "pull", "list")))
for some = pull; prev != some && some != ""; {
local := m.Richs(STORY, nil, prev, nil)
remote := m.Richs(STORY, nil, some, nil)
if diff := kit.Time(kit.Format(remote["time"])) - kit.Time(kit.Format(local["time"])); diff > 0 {
some = kit.Format(remote["prev"])
} else if diff < 0 {
prev = kit.Format(local["prev"])
}
}
if prev = kit.Format(val["list"]); prev == pull {
// 相同节点
return
}
if some != pull {
// 合并节点
local := m.Richs(STORY, nil, prev, nil)
remote := m.Richs(STORY, nil, pull, nil)
list = m.Rich(STORY, nil, kit.Dict(
"scene", val["scene"], "story", val["story"], "count", kit.Int(remote["count"])+1,
"data", local["data"], "prev", pull, "push", prev,
))
m.Log(ice.LOG_CREATE, "merge: %s %s->%s", list, prev, pull)
val["list"] = list
prev = list
val["count"] = kit.Int(remote["count"]) + 1
}
// 查询节点
nodes := []string{}
for list = prev; list != some; {
m.Richs(STORY, nil, list, func(key string, value ice.Map) {
nodes, list = append(nodes, list), kit.Format(value["prev"])
})
}
for _, v := range kit.Revert(nodes) {
m.Richs(STORY, nil, v, func(list string, node ice.Map) {
m.Richs(CACHE, nil, node["data"], func(data string, save ice.Map) {
if kit.Format(save["file"]) != "" {
// 推送缓存
m.Cmd(SPIDE, arg[2], "/story/upload",
"part", "upload", "@"+kit.Format(save["file"]),
)
}
// 推送节点
m.Log(ice.LOG_EXPORT, "%s: %s", v, kit.Format(node))
m.Cmd(SPIDE, arg[2], "/story/push",
"story", arg[3], "list", v, "node", kit.Format(node),
"data", node["data"], "save", kit.Format(save),
)
})
})
}
})
// 更新分支
m.Cmd(STORY, "pull", arg[1:])
}
func _story_commit(m *ice.Message, arg ...string) {
// 查询索引
head, prev, value, count := "", "", ice.Map{}, 0
m.Richs(STORY, "head", arg[1], func(key string, val ice.Map) {
head, prev, value, count = key, kit.Format(val["list"]), val, kit.Int(val["count"])
m.Log("info", "head: %v prev: %v count: %v", head, prev, count)
})
// 提交信息
arg[2] = m.Cmdx(STORY, "add", "submit", arg[2], "hostname,username")
// 节点信息
menu := ice.Maps{}
for i := 3; i < len(arg); i++ {
menu[arg[i]] = m.Cmdx(STORY, INDEX, arg[i])
}
// 添加节点
list := m.Rich(STORY, nil, kit.Dict(
"scene", "commit", "story", arg[1], "count", count+1, "data", arg[2], "list", menu, "prev", prev,
))
m.Log(ice.LOG_CREATE, "commit: %s %s: %s", list, arg[1], arg[2])
m.Push("list", list)
if head == "" {
// 添加索引
m.Rich(STORY, "head", kit.Dict("scene", "commit", "story", arg[1], "count", count+1, "list", list))
} else {
// 更新索引
value["count"] = count + 1
value["time"] = m.Time()
value["list"] = list
}
m.Echo(list)
}

View File

@ -41,7 +41,6 @@ func _dream_show(m *ice.Message, name string) {
name = m.Time("20060102-") + name
}
defer m.ProcessOpen(MergePod(m, m.Option(mdb.NAME, name)))
p := path.Join(ice.USR_LOCAL_WORK, name)
if pid := m.Cmdx(nfs.CAT, path.Join(p, ice.Info.PidPath)); pid != "" && nfs.ExistsFile(m, "/proc/"+pid) {
m.Info("already exists %v", pid)
@ -50,10 +49,8 @@ func _dream_show(m *ice.Message, name string) {
m.Info("already exists %v", name)
return
}
nfs.MkdirAll(m, p)
_dream_template(m, p)
m.Optionv(cli.CMD_DIR, kit.Path(p))
m.Optionv(cli.CMD_ENV, kit.Simple(
cli.CTX_OPS, "http://:"+m.CmdAppend(SERVE, tcp.PORT),
@ -63,7 +60,6 @@ func _dream_show(m *ice.Message, name string) {
m.Optionv(cli.CMD_OUTPUT, path.Join(p, ice.BIN_BOOT_LOG))
defer m.Options(cli.CMD_DIR, "", cli.CMD_ENV, "", cli.CMD_OUTPUT, "")
gdb.Event(m, DREAM_CREATE, m.OptionSimple(mdb.NAME, mdb.TYPE))
defer ToastProcess(m)()
bin := kit.Select(os.Args[0], cli.SystemFind(m, ice.ICE_BIN, nfs.PWD+path.Join(p, ice.BIN), nfs.PWD+ice.BIN))
m.Cmd(cli.DAEMON, bin, SPACE, tcp.DIAL, ice.DEV, ice.OPS, m.OptionSimple(mdb.NAME, RIVER), cli.DAEMON, ice.OPS)
@ -117,20 +113,20 @@ func init() {
cli.START: {Hand: func(m *ice.Message, arg ...string) {
_dream_show(m, m.Option(mdb.NAME))
}},
OPEN: {Hand: func(m *ice.Message, arg ...string) { ProcessIframe(m, MergePod(m, m.Option(mdb.NAME)), arg...) }},
cli.STOP: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(SPACE, mdb.MODIFY, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
m.Go(func() { m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT) })
ctx.ProcessRefresh(m, "1s")
}},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.TRASH, mdb.CREATE, path.Join(ice.USR_LOCAL_WORK, m.Option(mdb.NAME)))
nfs.Trash(m, path.Join(ice.USR_LOCAL_WORK, m.Option(mdb.NAME)))
}},
DREAM_STOP: {Hand: func(m *ice.Message, arg ...string) {
if m.CmdAppend(SPACE, m.Option(mdb.NAME), mdb.STATUS) != cli.STOP {
m.Go(func() { m.Sleep3s(DREAM, cli.START, m.OptionSimple(mdb.NAME)) })
}
}},
OPEN: {Hand: func(m *ice.Message, arg ...string) { ProcessIframe(m, MergePod(m, m.Option(mdb.NAME)), arg...) }},
}, ctx.CmdAction()), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
_dream_list(m)

View File

@ -2,7 +2,6 @@ package web
import (
"encoding/json"
"io"
"net/http"
"net/url"
"path"
@ -13,7 +12,6 @@ import (
"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/ssh"
@ -22,40 +20,48 @@ import (
"shylinux.com/x/toolkits/logs"
)
var rewriteList = []ice.Any{}
func AddRewrite(cb ice.Any) { rewriteList = append(rewriteList, cb) }
func _serve_rewrite(m *ice.Message) {
AddRewrite(func(w http.ResponseWriter, r *http.Request) bool {
if r.Method != SPIDE_GET {
return false
func _serve_start(m *ice.Message) {
if cli.NodeInfo(m, kit.Select(ice.Info.HostName, m.Option("nodename")), SERVER); m.Option(tcp.PORT) == tcp.RANDOM {
m.Option(tcp.PORT, m.Cmdx(tcp.PORT, aaa.RIGHT))
}
aaa.UserRoot(m, m.Option(aaa.USERNAME), m.Option(aaa.USERNICK))
m.Target().Start(m, m.OptionSimple(tcp.HOST, tcp.PORT)...)
m.Sleep300ms().Go(func() { m.Cmd(BROAD, SERVE) })
for _, k := range kit.Split(m.Option(ice.DEV)) {
m.Cmd(SPACE, tcp.DIAL, ice.DEV, k, mdb.NAME, ice.Info.NodeName)
}
}
func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
if r.Header.Get("Index-Module") == "" {
r.Header.Set("Index-Module", m.Prefix())
} else {
return true
}
if ip := r.Header.Get("X-Real-Ip"); ip != "" {
if r.Header.Set(ice.MSG_USERIP, ip); r.Header.Get("X-Real-Port") != "" {
r.Header.Set(ice.MSG_USERADDR, ip+":"+r.Header.Get("X-Real-Port"))
}
msg, repos := m.Spawn(SERVE, w, r), kit.Select(ice.INTSHELL, ice.VOLCANOS, strings.Contains(r.Header.Get(UserAgent), "Mozilla/5.0"))
switch r.URL.Path {
case ice.PS:
if repos == ice.VOLCANOS {
return Render(msg, ice.RENDER_RESULT, RenderMain(msg, "", "").Result())
}
return Render(msg, ice.RENDER_DOWNLOAD, path.Join(msg.Config(kit.Keys(repos, nfs.PATH)), msg.Config(kit.Keys(repos, INDEX))))
case PP(ice.HELP):
r.URL.Path = P(ice.HELP, "tutor.shy")
}
p := path.Join(ice.USR, repos, r.URL.Path)
if _, e := nfs.DiskFile.StatFile(p); e == nil {
http.ServeFile(w, r, kit.Path(p))
return true
} else if f, e := nfs.PackFile.OpenFile(p); e == nil {
defer f.Close()
RenderType(w, p, "")
io.Copy(w, f)
return true
} else if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
r.Header.Set(ice.MSG_USERIP, kit.Split(ip)[0])
} else if strings.HasPrefix(r.RemoteAddr, "[") {
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, "]")[0][1:])
} else {
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, ":")[0])
}
meta := logs.FileLineMeta("")
m.Info("%s %s %s", r.Header.Get(ice.MSG_USERIP), r.Method, r.URL, meta)
if m.Config(LOGHEADERS) == ice.TRUE {
for k, v := range r.Header {
m.Info("%s: %v", k, kit.Format(v), meta)
}
m.Info("", meta)
}
repos := kit.Select(ice.INTSHELL, ice.VOLCANOS, strings.Contains(r.Header.Get(UserAgent), "Mozilla/5.0"))
if msg := gdb.Event(m.Spawn(w, r), SERVE_REWRITE, r.Method, r.URL.Path, path.Join(m.Conf(SERVE, kit.Keym(repos, nfs.PATH)), r.URL.Path), repos); msg.Option(ice.MSG_OUTPUT) != "" {
Render(msg, msg.Option(ice.MSG_OUTPUT), kit.List(msg.Optionv(ice.MSG_ARGS))...)
return false
})
}
return true
}
func _serve_domain(m *ice.Message) string {
if p := ice.Info.Domain; p != "" {
@ -75,244 +81,97 @@ func _serve_domain(m *ice.Message) string {
return kit.Format("https://%s", m.R.Host)
}
}
func _serve_spide(m *ice.Message, prefix string, c *ice.Context) {
for k := range c.Commands {
if strings.HasPrefix(k, ice.PS) {
m.Push(nfs.PATH, path.Join(prefix, k)+kit.Select("", ice.PS, strings.HasSuffix(k, ice.PS)))
}
}
for k, v := range c.Contexts {
_serve_spide(m, path.Join(prefix, k), v)
}
}
func _serve_start(m *ice.Message) {
if cli.NodeInfo(m, kit.Select(ice.Info.HostName, m.Option("nodename")), SERVER); m.Option(tcp.PORT) == tcp.RANDOM {
m.Option(tcp.PORT, m.Cmdx(tcp.PORT, aaa.RIGHT))
}
aaa.UserRoot(m, m.Option(aaa.USERNAME), m.Option(aaa.USERNICK))
m.Target().Start(m, m.OptionSimple(tcp.HOST, tcp.PORT)...)
m.Go(func() { m.Cmd(BROAD, SERVE) })
m.Sleep300ms()
for _, k := range kit.Split(m.Option(ice.DEV)) {
m.Cmd(SPACE, tcp.DIAL, ice.DEV, k, mdb.NAME, ice.Info.NodeName)
}
}
func _serve_main(m *ice.Message, w http.ResponseWriter, r *http.Request) bool {
if r.Header.Get("Index-Module") == "" {
r.Header.Set("Index-Module", m.Prefix())
} else {
return true
}
// 用户地址
if ip := r.Header.Get("X-Real-Ip"); ip != "" {
if r.Header.Set(ice.MSG_USERIP, ip); r.Header.Get("X-Real-Port") != "" {
r.Header.Set(ice.MSG_USERADDR, ip+":"+r.Header.Get("X-Real-Port"))
}
} else if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
r.Header.Set(ice.MSG_USERIP, kit.Split(ip)[0])
} else if strings.HasPrefix(r.RemoteAddr, "[") {
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, "]")[0][1:])
} else {
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, ":")[0])
}
func _serve_handle(key string, cmd *ice.Command, m *ice.Message, w http.ResponseWriter, r *http.Request) {
meta := logs.FileLineMeta("")
m.Info("%s %s %s", r.Header.Get(ice.MSG_USERIP), r.Method, r.URL, meta)
// 参数日志
if m.Config(LOGHEADERS) == ice.TRUE {
for k, v := range r.Header {
m.Info("%s: %v", k, kit.Format(v), meta)
}
m.Info("", meta)
defer func() {
m.Info("", meta)
for k, v := range w.Header() {
m.Info("%s: %v", k, kit.Format(v), meta)
}
}()
}
// 模块回调
for _, h := range rewriteList {
if m.Config(LOGHEADERS) == ice.TRUE {
m.Info("%s: %v", r.URL.Path, logs.FileLine(h), meta)
}
switch h := h.(type) {
case func(w http.ResponseWriter, r *http.Request) func():
defer h(w, r)
case func(p string, w http.ResponseWriter, r *http.Request) bool:
if h(r.URL.Path, w, r) {
return false
}
case func(w http.ResponseWriter, r *http.Request) bool:
if h(w, r) {
return false
}
default:
m.ErrorNotImplement(h)
}
}
return true
}
func _serve_params(msg *ice.Message, path string) {
switch ls := strings.Split(path, ice.PS); kit.Select("", ls, 1) {
case SHARE:
switch ls[2] {
case "local":
default:
msg.Logs("refer", ls[1], ls[2])
msg.Option(ls[1], ls[2])
}
case ice.POD:
msg.Logs("refer", ls[1], ls[2])
msg.Option(ls[1], ls[2])
case "chat":
switch kit.Select("", ls, 2) {
case ice.POD:
msg.Logs("refer", ls[2], ls[3])
msg.Option(ls[2], ls[3])
}
}
}
func _serve_handle(key string, cmd *ice.Command, msg *ice.Message, w http.ResponseWriter, r *http.Request) {
meta := logs.FileLineMeta("")
msg.Options(ice.HEIGHT, "480", ice.WIDTH, "320")
if u, e := url.Parse(r.Header.Get(Referer)); e == nil {
_serve_params(msg, u.Path)
kit.Fetch(u.Query(), func(k string, v []string) {
msg.Logs("refer", k, v, meta)
msg.Optionv(k, v)
})
gdb.Event(m, SERVE_PARSE, strings.Split(strings.TrimPrefix(u.Path, ice.PS), ice.PS))
kit.Fetch(u.Query(), func(k string, v []string) { m.Logs("refer", k, v, meta).Optionv(k, v) })
}
_serve_params(msg, r.URL.Path)
// 解析参数
switch r.Header.Get(ContentType) {
case ContentJSON:
defer r.Body.Close()
var data ice.Any
if e := json.NewDecoder(r.Body).Decode(&data); !msg.Warn(e, ice.ErrNotFound, data) {
msg.Logs(mdb.IMPORT, mdb.VALUE, kit.Format(data))
msg.Optionv(ice.MSG_USERDATA, data)
if e := json.NewDecoder(r.Body).Decode(&data); !m.Warn(e, ice.ErrNotFound, data) {
m.Logs(mdb.IMPORT, mdb.VALUE, kit.Format(data))
m.Optionv(ice.MSG_USERDATA, data)
}
kit.Fetch(data, func(key string, value ice.Any) { msg.Optionv(key, value) })
kit.Fetch(data, func(key string, value ice.Any) { m.Optionv(key, value) })
default:
r.ParseMultipartForm(kit.Int64(kit.Select("4096", r.Header.Get(ContentLength))))
if r.ParseForm(); len(r.PostForm) > 0 {
kit.Fetch(r.PostForm, func(k string, v []string) {
if len(v) > 1 {
msg.Logs("form", k, len(v), kit.Join(v, ice.SP), meta)
m.Logs("form", k, len(v), kit.Join(v, ice.SP), meta)
} else {
msg.Logs("form", k, v, meta)
m.Logs("form", k, v, meta)
}
})
}
}
// 请求参数
msg.R, msg.W = r, w
m.R, m.W = r, w
for k, v := range r.Form {
if msg.IsCliUA() {
if m.IsCliUA() {
for i, p := range v {
v[i], _ = url.QueryUnescape(p)
}
}
msg.Optionv(k, v)
m.Optionv(k, v)
}
for k, v := range r.PostForm {
msg.Optionv(k, v)
m.Optionv(k, v)
}
for _, v := range r.Cookies() {
msg.Optionv(v.Name, v.Value)
m.Optionv(v.Name, v.Value)
}
// 用户参数
msg.Option(ice.MSG_USERWEB, _serve_domain(msg))
msg.Option(ice.MSG_USERADDR, kit.Select(r.RemoteAddr, r.Header.Get(ice.MSG_USERADDR)))
msg.Option(ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
msg.Option(ice.MSG_USERUA, r.Header.Get(UserAgent))
if msg.Option(ice.POD) != "" {
msg.Option(ice.MSG_USERPOD, msg.Option(ice.POD))
m.Option(ice.MSG_USERADDR, kit.Select(r.RemoteAddr, r.Header.Get(ice.MSG_USERADDR)))
m.Option(ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
m.Option(ice.MSG_USERUA, r.Header.Get(UserAgent))
if m.Option(ice.MSG_USERWEB, _serve_domain(m)); m.Option(ice.POD) != "" {
m.Option(ice.MSG_USERPOD, m.Option(ice.POD))
}
// 会话参数
if sessid := msg.Option(CookieName(msg.Option(ice.MSG_USERWEB))); msg.Option(ice.MSG_SESSID) == "" {
msg.Option(ice.MSG_SESSID, sessid)
if sessid := m.Option(CookieName(m.Option(ice.MSG_USERWEB))); m.Option(ice.MSG_SESSID) == "" {
m.Option(ice.MSG_SESSID, sessid)
}
// 解析命令
if msg.Optionv(ice.MSG_CMDS) == nil {
if m.Optionv(ice.MSG_CMDS) == nil {
if p := strings.TrimPrefix(r.URL.Path, key); p != "" {
msg.Optionv(ice.MSG_CMDS, strings.Split(p, ice.PS))
m.Optionv(ice.MSG_CMDS, strings.Split(p, ice.PS))
}
}
// 执行命令
if cmds, ok := _serve_login(msg, key, kit.Simple(msg.Optionv(ice.MSG_CMDS)), w, r); ok {
defer func() { msg.Cost(kit.Format("%s %v %v", r.URL.Path, cmds, msg.FormatSize())) }()
msg.Option(ice.MSG_OPTS, kit.Filter(kit.Simple(msg.Optionv(ice.MSG_OPTION)), func(k string) bool {
return !strings.HasPrefix(k, ice.MSG_SESSID)
}))
if cmds, ok := _serve_login(m, key, kit.Simple(m.Optionv(ice.MSG_CMDS)), w, r); ok {
defer func() { m.Cost(kit.Format("%s %v %v", r.URL.Path, cmds, m.FormatSize())) }()
m.Option(ice.MSG_OPTS, kit.Simple(m.Optionv(ice.MSG_OPTION), func(k string) bool { return !strings.HasPrefix(k, ice.MSG_SESSID) }))
if len(cmds) > 0 && cmds[0] == ctx.ACTION {
msg.Target().Cmd(msg, key, cmds...)
m.Target().Cmd(m, key, cmds...)
} else {
msg.CmdHand(cmd, key, cmds...)
m.CmdHand(cmd, key, cmds...)
}
}
// 输出响应
switch args := msg.Optionv(ice.MSG_ARGS).(type) {
case []ice.Any:
Render(msg, msg.Option(ice.MSG_OUTPUT), args...)
default:
Render(msg, msg.Option(ice.MSG_OUTPUT), args)
}
gdb.Event(m, SERVE_RENDER, m.Option(ice.MSG_OUTPUT))
Render(m, m.Option(ice.MSG_OUTPUT), m.Optionv(ice.MSG_ARGS))
}
func _serve_login(msg *ice.Message, key string, cmds []string, w http.ResponseWriter, r *http.Request) ([]string, bool) {
aaa.SessCheck(msg, msg.Option(ice.MSG_SESSID)) // 会话认证
if msg.Option(ice.MSG_USERNAME) == "" && msg.Config(tcp.LOCALHOST) == ice.TRUE && tcp.IsLocalHost(msg, msg.Option(ice.MSG_USERIP)) {
aaa.UserRoot(msg) // 本机认证
func _serve_login(m *ice.Message, key string, cmds []string, w http.ResponseWriter, r *http.Request) ([]string, bool) {
if aaa.SessCheck(m, m.Option(ice.MSG_SESSID)); m.Option(ice.MSG_USERNAME) == "" {
gdb.Event(m, SERVE_LOGIN)
}
if msg.Option(ice.MSG_USERNAME) == "" && msg.Option(SHARE) != "" {
switch share := msg.Cmd(SHARE, msg.Option(SHARE)); share.Append(mdb.TYPE) {
case STORM, FIELD: // 共享认证
msg.Option(ice.MSG_USERNAME, share.Append(aaa.USERNAME))
msg.Option(ice.MSG_USERROLE, share.Append(aaa.USERROLE))
msg.Option(ice.MSG_USERNICK, share.Append(aaa.USERNICK))
}
if _, ok := m.Target().Commands[WEB_LOGIN]; ok {
return cmds, !m.Target().Cmd(m, WEB_LOGIN, kit.Simple(key, cmds)...).IsErr()
} else if gdb.Event(m, SERVE_CHECK, key, cmds); m.IsErr() {
return cmds, false
} else if m.IsOk() {
return cmds, m.SetResult() != nil
} else {
return cmds, aaa.Right(m, key, cmds)
}
if _, ok := msg.Target().Commands[WEB_LOGIN]; ok { // 单点认证
msg.Target().Cmd(msg, WEB_LOGIN, kit.Simple(key, cmds)...)
return cmds, !msg.IsErr() && msg.Result(0) != ice.FALSE
}
if aaa.Right(msg.Spawn(), key, cmds) {
return cmds, true
}
if msg.Warn(msg.Option(ice.MSG_USERNAME) == "", ice.ErrNotLogin, r.URL.Path) {
msg.Render(STATUS, http.StatusUnauthorized, ice.ErrNotLogin)
return cmds, false // 未登录
} else if !aaa.Right(msg, r.URL.Path) {
msg.Render(STATUS, http.StatusForbidden, ice.ErrNotRight)
return cmds, false // 未授权
}
return cmds, true
}
const (
SERVE_START = "serve.start"
SERVE_STOP = "serve.stop"
SERVE_START = "serve.start"
SERVE_REWRITE = "serve.rewrite"
SERVE_PARSE = "serve.parse"
SERVE_LOGIN = "serve.login"
SERVE_CHECK = "serve.check"
SERVE_RENDER = "serve.render"
SERVE_STOP = "serve.stop"
WEB_LOGIN = "_login"
SSO = "sso"
@ -327,51 +186,62 @@ func init() {
SERVE: {Name: "serve name auto start spide", Help: "服务器", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
cli.NodeInfo(m, ice.Info.PathName, WORKER)
for _, p := range []string{LOGIN, SHARE, SPACE, ice.VOLCANOS, ice.INTSHELL, ice.PUBLISH, ice.REQUIRE, ice.HELP, ice.CMD} {
m.Cmd(aaa.ROLE, aaa.WHITE, aaa.VOID, p)
}
gdb.Watch(m, SERVE_START)
_serve_rewrite(m)
}},
SERVE_START: {Name: "source.stdio", Help: "终端", Hand: func(m *ice.Message, arg ...string) {
m.Go(func() {
defer m.Cmd(ssh.PROMPT)
m.Sleep("30ms", ssh.PRINTF, kit.Dict(nfs.CONTENT, "\r"+ice.Render(m, ice.RENDER_QRCODE, m.Cmdx(SPACE, DOMAIN))+ice.NL))
})
}},
DOMAIN: {Name: "domain", Help: "域名", Hand: func(m *ice.Message, arg ...string) {
m.Config(tcp.LOCALHOST, ice.FALSE)
ice.Info.Domain = arg[0]
}},
SPIDE: {Name: "spide", Help: "架构图", Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { // 模块列表
_serve_spide(m, ice.PS, m.Target())
ctx.DisplayStorySpide(m, lex.PREFIX, m.ActionKey(), nfs.ROOT, MergeLink(m, ice.PS))
}
aaa.White(m, LOGIN)
}},
cli.START: {Name: "start dev proto=http host port=9020 nodename username usernick", Hand: func(m *ice.Message, arg ...string) {
_serve_start(m)
}},
SERVE_START: {Hand: func(m *ice.Message, arg ...string) {
m.Go(func() {
m.Sleep("30ms", ssh.PRINTF, kit.Dict(nfs.CONTENT, "\r"+ice.Render(m, ice.RENDER_QRCODE, m.Cmdx(SPACE, DOMAIN))+ice.NL))
m.Cmd(ssh.PROMPT)
})
}},
SERVE_REWRITE: {Hand: func(m *ice.Message, arg ...string) {
if arg[0] != SPIDE_GET {
return
}
switch arg[1] {
case ice.PS:
if arg[3] == ice.INTSHELL {
RenderIndex(m, arg[3])
} else {
RenderMain(m, "", "")
}
default:
if nfs.ExistsFile(m, arg[2]) {
m.RenderDownload(arg[2])
}
}
}},
SERVE_PARSE: {Hand: func(m *ice.Message, arg ...string) {
m.Options(ice.HEIGHT, "480", ice.WIDTH, "320")
}},
SERVE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
if m.Option(ice.MSG_USERNAME) == "" && m.Config(tcp.LOCALHOST) == ice.TRUE && tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) {
aaa.UserRoot(m)
}
}},
DOMAIN: {Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 {
m.Config(tcp.LOCALHOST, ice.FALSE)
ice.Info.Domain = arg[0]
}
m.Echo(ice.Info.Domain)
}},
}, mdb.HashAction(
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,status,name,proto,host,port,dev",
tcp.LOCALHOST, ice.TRUE, LOGHEADERS, ice.FALSE,
nfs.PATH, kit.Dict(ice.PS, ice.USR_VOLCANOS),
ice.VOLCANOS, kit.Dict(nfs.PATH, ice.USR_VOLCANOS, INDEX, "page/index.html",
nfs.REPOS, "https://shylinux.com/x/volcanos", nfs.BRANCH, nfs.MASTER,
),
ice.INTSHELL, kit.Dict(nfs.PATH, ice.USR_INTSHELL, INDEX, ice.INDEX_SH,
nfs.REPOS, "https://shylinux.com/x/intshell", nfs.BRANCH, nfs.MASTER,
),
))},
PP(ice.INTSHELL): {Name: "/intshell/", Help: "命令行", Hand: func(m *ice.Message, arg ...string) {
mdb.SHORT, mdb.NAME, mdb.FIELD, "time,status,name,proto,host,port,dev", tcp.LOCALHOST, ice.TRUE, LOGHEADERS, ice.FALSE,
ice.INTSHELL, kit.Dict(nfs.PATH, ice.USR_INTSHELL, INDEX, ice.INDEX_SH, nfs.REPOS, "https://shylinux.com/x/intshell", nfs.BRANCH, nfs.MASTER),
ice.VOLCANOS, kit.Dict(nfs.PATH, ice.USR_VOLCANOS, INDEX, "page/index.html", nfs.REPOS, "https://shylinux.com/x/volcanos", nfs.BRANCH, nfs.MASTER),
), ServeAction())},
PP(ice.INTSHELL): {Name: "/intshell/", Help: "命令行", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
RenderIndex(m, ice.INTSHELL, arg...)
}},
PP(ice.VOLCANOS): {Name: "/volcanos/", Help: "浏览器", Hand: func(m *ice.Message, arg ...string) {
PP(ice.VOLCANOS): {Name: "/volcanos/", Help: "浏览器", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
RenderIndex(m, ice.VOLCANOS, arg...)
}},
PP(ice.PUBLISH): {Name: "/publish/", Help: "定制化", Hand: func(m *ice.Message, arg ...string) {
_share_local(aaa.UserRoot(m), ice.USR_PUBLISH, path.Join(arg...))
PP(ice.PUBLISH): {Name: "/publish/", Help: "定制化", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
_share_local(m, ice.USR_PUBLISH, path.Join(arg...))
}},
PP(ice.REQUIRE): {Name: "/require/shylinux.com/x/volcanos/proto.js", Help: "代码库", Hand: func(m *ice.Message, arg ...string) {
_share_repos(m, path.Join(arg[0], arg[1], arg[2]), arg[3:]...)
@ -384,12 +254,12 @@ func init() {
m.RenderDownload(p)
}},
PP(ice.REQUIRE, ice.USR): {Name: "/require/usr/", Help: "代码库", Hand: func(m *ice.Message, arg ...string) {
_share_local(aaa.UserRoot(m), ice.USR, path.Join(arg...))
_share_local(m, ice.USR, path.Join(arg...))
}},
PP(ice.REQUIRE, ice.SRC): {Name: "/require/src/", Help: "源代码", Hand: func(m *ice.Message, arg ...string) {
_share_local(aaa.UserRoot(m), ice.SRC, path.Join(arg...))
_share_local(m, ice.SRC, path.Join(arg...))
}},
PP(ice.HELP): {Name: "/help/", Help: "帮助", Hand: func(m *ice.Message, arg ...string) {
PP(ice.HELP): {Name: "/help/", Help: "帮助", Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 {
arg = append(arg, "tutor.shy")
}
@ -409,3 +279,14 @@ func init() {
return nil, nil
})
}
func ServeAction() ice.Actions {
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
for sub := range m.Target().Commands[m.CommandKey()].Actions {
if serveActions[sub] == ice.TRUE {
gdb.Watch(m, sub)
}
}
}}}
}
var serveActions = kit.DictList(SERVE_START, SERVE_REWRITE, SERVE_PARSE, SERVE_LOGIN, SERVE_CHECK, SERVE_RENDER, SERVE_STOP)

View File

@ -147,7 +147,26 @@ func init() {
m.EchoQRCode(msg.Option(mdb.LINK))
m.ProcessInner()
}},
}, mdb.HashAction(mdb.FIELD, "time,hash,userrole,username,usernick,river,storm,type,name,text", mdb.EXPIRE, "72h")), Hand: func(m *ice.Message, arg ...string) {
SERVE_PARSE: {Hand: func(m *ice.Message, arg ...string) {
if kit.Select("", arg, 0) != SHARE {
return
}
switch arg[1] {
case "local":
default:
m.Logs("refer", arg[0], arg[1])
m.Option(arg[0], arg[1])
}
}},
SERVE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
if m.Option(ice.MSG_USERNAME) == "" && m.Option(SHARE) != "" {
switch msg := m.Cmd(SHARE, m.Option(SHARE)); msg.Append(mdb.TYPE) {
case STORM, FIELD:
msg.Tables(func(value ice.Maps) { aaa.SessAuth(m, value) })
}
}
}},
}, mdb.HashAction(mdb.FIELD, "time,hash,userrole,username,usernick,river,storm,type,name,text", mdb.EXPIRE, "72h"), ServeAction(), aaa.WhiteAction()), Hand: func(m *ice.Message, arg ...string) {
if ctx.PodCmd(m, SHARE, arg) && m.Length() > 0 {
return
}

View File

@ -17,6 +17,66 @@ import (
"shylinux.com/x/websocket"
)
func _space_dial(m *ice.Message, dev, name string, arg ...string) {
msg := m.Cmd(SPIDE, dev)
host := msg.Append(kit.Keys(tcp.CLIENT, tcp.HOSTNAME))
proto := strings.Replace(msg.Append(kit.Keys(tcp.CLIENT, tcp.PROTOCOL)), ice.HTTP, "ws", 1)
uri := kit.ParseURL(kit.MergeURL(proto+"://"+host+PP(SPACE), mdb.TYPE, ice.Info.NodeType, mdb.NAME, name, SHARE, ice.Info.CtxShare, RIVER, ice.Info.CtxRiver, arg))
m.Go(func() {
ls := strings.Split(host, ice.DF)
args := kit.SimpleKV("type,name,host,port", proto, dev, ls[0], kit.Select(kit.Select("443", "80", proto == "ws"), ls, 1))
redial, _ := m.Configv(REDIAL).(ice.Map)
a, b, c := kit.Int(redial["a"]), kit.Int(redial["b"]), kit.Int(redial["c"])
for i := 0; i >= 0 && i < c; i++ {
msg := m.Spawn()
msg.Cmd(tcp.CLIENT, tcp.DIAL, args, func(s net.Conn) {
if s, _, e := websocket.NewClient(s, uri, nil, kit.Int(redial["r"]), kit.Int(redial["w"])); !msg.Warn(e) {
msg.Logs(mdb.CREATE, SPACE, dev, "retry", i, "uri", uri.String())
mdb.HashCreate(msg, kit.SimpleKV("", MASTER, dev, host), kit.Dict(mdb.TARGET, s))
defer mdb.HashRemove(msg, mdb.NAME, name)
if i = 0; _space_handle(msg, true, m.Target().Server().(*Frame), s, dev) {
i = -2
}
}
})
sleep := time.Duration(rand.Intn(a*(i+1))+b) * time.Millisecond
msg.Cost("order", i, "sleep", sleep, "reconnect", dev)
if time.Sleep(sleep); mdb.HashSelect(msg).Length() == 0 {
break
}
}
})
}
func _space_handle(m *ice.Message, safe bool, frame *Frame, c *websocket.Conn, name string) bool {
for {
_, b, e := c.ReadMessage()
if m.Warn(e, SPACE, name) {
break
}
msg := m.Spawn(b)
socket, source, target := c, kit.Simple(msg.Optionv(ice.MSG_SOURCE), name), kit.Simple(msg.Optionv(ice.MSG_TARGET))
msg.Log("recv", "%v<-%v %s %v", target, source, msg.Detailv(), msg.FormatMeta())
if len(target) == 0 {
if msg.Optionv(ice.MSG_HANDLE, ice.TRUE); safe { // 下行命令
gdb.Event(msg, SPACE_LOGIN)
} else { // 上行请求
msg.Option(ice.MSG_USERROLE, aaa.VOID)
}
msg.Go(func() { _space_exec(msg, source, target, c, name) })
} else if mdb.HashSelectDetail(msg, target[0], func(value ice.Map) {
if s, ok := value[mdb.TARGET].(*websocket.Conn); !m.Warn(!ok, ice.ErrNotValid, target[0]) { // 转发报文
socket, source, target = s, source, target[1:]
_space_echo(msg, source, target, socket, kit.Select("", target))
} else if msg.Option(ice.MSG_HANDLE) != ice.TRUE { // 下发失败
source, target = []string{}, kit.Revert(source)[1:]
}
}) {
} else if res, ok := frame.getSend(msg.Option(ice.MSG_TARGET)); !m.Warn(!ok || len(target) != 1) {
back(res, msg) // 接收响应
}
}
return false
}
func _space_domain(m *ice.Message) (link string) {
if link = ice.Info.Domain; link == "" {
m.Optionv(ice.MSG_OPTS, ice.MSG_USERNAME)
@ -36,116 +96,15 @@ func _space_domain(m *ice.Message) (link string) {
}
return tcp.PublishLocalhost(m, link)
}
func _space_dial(m *ice.Message, dev, name string, arg ...string) {
if strings.HasPrefix(dev, ice.HTTP) {
m.Cmd(SPIDE, mdb.CREATE, ice.DEV, dev)
dev = ice.DEV
}
msg := m.Cmd(SPIDE, dev)
host := msg.Append(kit.Keys(tcp.CLIENT, tcp.HOSTNAME))
proto := strings.Replace(msg.Append(kit.Keys(tcp.CLIENT, tcp.PROTOCOL)), ice.HTTP, "ws", 1)
uri := kit.MergeURL(proto+"://"+host+PP(SPACE), mdb.TYPE, ice.Info.NodeType, mdb.NAME, name, SHARE, ice.Info.CtxShare, RIVER, ice.Info.CtxRiver, arg)
u := kit.ParseURL(uri)
m.Go(func() {
frame := m.Target().Server().(*Frame)
ls := strings.Split(host, ice.DF)
args := kit.SimpleKV("type,name,host,port", proto, dev, ls[0], kit.Select("443", ls, 1))
redial, _ := m.Configv(REDIAL).(ice.Map)
a, b, c := kit.Int(redial["a"]), kit.Int(redial["b"]), kit.Int(redial["c"])
for i := 0; i >= 0 && i < c; i++ {
msg := m.Spawn()
msg.Cmd(tcp.CLIENT, tcp.DIAL, args, func(s net.Conn) {
if s, _, e := websocket.NewClient(s, u, nil, kit.Int(redial["r"]), kit.Int(redial["w"])); !msg.Warn(e) {
msg.Logs(mdb.CREATE, SPACE, dev, "retry", i, "uri", uri)
mdb.HashCreate(msg, kit.SimpleKV("", MASTER, dev, host), kit.Dict(mdb.TARGET, s))
defer mdb.HashRemove(msg, mdb.NAME, name)
if i = 0; _space_handle(msg, true, frame, s, dev) {
i = -2 // 关闭连接
}
}
})
// 断线重连
sleep := time.Duration(rand.Intn(a*(i+1))+b) * time.Millisecond
msg.Cost("order", i, "sleep", sleep, "reconnect", dev)
if time.Sleep(sleep); mdb.HashSelect(msg).Length() == 0 {
break
}
}
})
}
func _space_handle(m *ice.Message, safe bool, frame *Frame, c *websocket.Conn, name string) bool {
for {
_, b, e := c.ReadMessage()
if m.Warn(e, SPACE, name) {
break
}
socket, msg := c, m.Spawn(b)
target := kit.Simple(msg.Optionv(ice.MSG_TARGET))
source := kit.Simple(msg.Optionv(ice.MSG_SOURCE), name)
msg.Log("recv", "%v<-%v %s %v", target, source, msg.Detailv(), msg.FormatMeta())
if len(target) == 0 { // 执行命令
if msg.Optionv(ice.MSG_HANDLE, ice.TRUE); safe { // 下行命令
msg.Option(ice.MSG_USERROLE, kit.Select(msg.Option(ice.MSG_USERROLE), msg.Cmd(aaa.USER, msg.Option(ice.MSG_USERNAME)).Append(aaa.USERROLE)))
if msg.Option(ice.MSG_USERROLE) == aaa.VOID && ice.Info.UserName == aaa.TECH {
msg.Option(ice.MSG_USERROLE, aaa.TECH) // 演示空间
}
msg.Auth(aaa.USERROLE, msg.Option(ice.MSG_USERROLE), aaa.USERNAME, msg.Option(ice.MSG_USERNAME))
msg.Go(func() { _space_exec(msg, source, target, c, name) })
continue
}
// 上行请求
msg.Push(mdb.LINK, kit.MergePOD(_space_domain(msg), name))
_space_echo(msg, []string{}, kit.Revert(source)[1:], c, name)
continue
}
if mdb.HashSelectDetail(msg, target[0], func(value ice.Map) { // 转发命令
if s, ok := value[mdb.TARGET].(*websocket.Conn); ok {
socket, source, target = s, source, target[1:]
_space_echo(msg, source, target, socket, kit.Select("", target))
return // 转发报文
}
if msg.Warn(msg.Option(ice.MSG_HANDLE) == ice.TRUE, ice.ErrNotValid, "already handled") {
// 回复失败
} else { // 下发失败
msg.Warn(true, ice.ErrNotFound, target)
source, target = []string{}, kit.Revert(source)[1:]
}
}) {
continue
}
if res, ok := frame.getSend(msg.Option(ice.MSG_TARGET)); len(target) != 1 || !ok {
if msg.Warn(msg.Option(ice.MSG_HANDLE) == ice.TRUE, ice.ErrNotValid, target) {
// 回复失败
} else { // 下发失败
msg.Warn(true, ice.ErrNotFound, target)
source, target = []string{}, kit.Revert(source)[1:]
}
continue
} else { // 接收响应
m.Sleep30ms()
back(res, msg)
}
}
return false
}
func _space_exec(msg *ice.Message, source, target []string, c *websocket.Conn, name string) {
if aaa.Right(msg, msg.Detailv()) { // 执行命令
msg = msg.Cmd()
switch msg.Detailv()[0] {
case "pwd":
msg.Push(mdb.LINK, kit.MergePOD(_space_domain(msg), name))
default:
if aaa.Right(msg, msg.Detailv()) {
msg = msg.Cmd()
}
}
msg.Set(ice.MSG_OPTS)
_space_echo(msg, []string{}, kit.Revert(source)[1:], c, name)
msg.Cost(kit.Format("%v->%v %v %v", source, target, msg.Detailv(), msg.FormatSize()))
@ -163,59 +122,47 @@ func _space_echo(msg *ice.Message, source, target []string, c *websocket.Conn, n
}
func _space_send(m *ice.Message, space string, arg ...string) {
if space == "" || space == MYSELF || space == ice.Info.NodeName {
m.Cmdy(arg) // 本地命令
m.Cmdy(arg)
return
}
// 生成参数
for _, k := range kit.Simple(m.Optionv(ice.MSG_OPTS)) {
kit.Simple(m.Optionv(ice.MSG_OPTS), func(k string) {
switch k {
case ice.MSG_DETAIL, ice.MSG_CMDS, ice.MSG_SESSID:
default:
m.Optionv(k, m.Optionv(k))
}
}
})
m.Set(ice.MSG_DETAIL, arg...)
m.Optionv(ice.MSG_OPTS, m.Optionv(ice.MSG_OPTS))
m.Optionv(ice.MSG_OPTION, m.Optionv(ice.MSG_OPTS))
m.Set(ice.MSG_DETAIL, arg...)
// 发送命令
frame := m.Target().Server().(*Frame)
target, id := kit.Split(space, ice.PT, ice.PT), ""
target, id, f := kit.Split(space, ice.PT, ice.PT), "", m.Target().Server().(*Frame)
if m.Warn(!mdb.HashSelectDetail(m, target[0], func(value ice.Map) {
if socket, ok := value[mdb.TARGET].(*websocket.Conn); !m.Warn(!ok, ice.ErrNotFound, mdb.TARGET) {
id = frame.addSend(kit.Format(m.Target().ID()), m)
id = f.addSend(kit.Format(m.Target().ID()), m)
_space_echo(m, []string{id}, target[1:], socket, target[0])
}
}), ice.ErrNotFound, space) {
return
}
// 返回结果
m.Option(TIMEOUT, m.Config(kit.Keys(TIMEOUT, "c")))
call(m, m.Option("_async") == "", func(res *ice.Message) {
m.Cost(kit.Format("[%v]->%v %v %v", id, target, arg, m.Copy(res).FormatSize()))
frame.delSend(id)
call(m, m.Config(kit.Keys(TIMEOUT, "c")), func(res *ice.Message) {
m.Cost(kit.Format("[%v]->%v %v %v", f.delSend(id), target, arg, m.Copy(res).FormatSize()))
})
}
func _space_fork(m *ice.Message) {
buffer, _ := m.Configv(BUFFER).(ice.Map)
if s, e := websocket.Upgrade(m.W, m.R, nil, kit.Int(buffer["r"]), kit.Int(buffer["w"])); m.Assert(e) {
text := kit.Select(s.RemoteAddr().String(), m.Option(ice.MSG_USERADDR))
name := strings.ToLower(m.Option(mdb.NAME, kit.ReplaceAll(kit.Select(text, m.Option(mdb.NAME)), ".", "_", ":", "_")))
name := strings.ToLower(m.Option(mdb.NAME, kit.ReplaceAll(kit.Select(text, m.Option(mdb.NAME)), ice.PT, "_", ice.DF, "_")))
kind := kit.Select(WORKER, m.Option(mdb.TYPE))
args := append([]string{mdb.TYPE, kind, mdb.NAME, name}, m.OptionSimple(SHARE, RIVER, ice.MSG_USERUA)...)
m.Go(func() {
mdb.HashCreate(m, mdb.TEXT, kit.Select(text, m.Option(mdb.TEXT)), args, kit.Dict(mdb.TARGET, s))
defer mdb.HashRemove(m, mdb.NAME, name)
gdb.Event(m, SPACE_OPEN, args)
defer gdb.Event(m, SPACE_CLOSE, args)
switch kind {
case CHROME:
m.Go(func(msg *ice.Message) { msg.Sleep300ms(SPACE, name, cli.PWD, name) })
m.Go(func(msg *ice.Message) { msg.Sleep30ms(SPACE, name, cli.PWD, name) })
case WORKER:
gdb.Event(m, DREAM_START, args)
defer gdb.Event(m, DREAM_STOP, args)
@ -241,9 +188,10 @@ const (
REDIAL = "redial"
TIMEOUT = "timeout"
SPACE_OPEN = "space.open"
SPACE_CLOSE = "space.close"
SPACE_START = "space.start"
SPACE_OPEN = "space.open"
SPACE_LOGIN = "space.login"
SPACE_CLOSE = "space.close"
SPACE_STOP = "space.stop"
)
const SPACE = "space"
@ -251,26 +199,28 @@ const SPACE = "space"
func init() {
Index.MergeCommands(ice.Commands{
PP(SPACE): {Hand: func(m *ice.Message, arg ...string) { _space_fork(m) }},
SPACE: {Name: "space name cmd auto invite", Help: "空间站", Actions: ice.MergeActions(ice.Actions{
SPACE: {Name: "space name cmd auto", Help: "空间站", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { m.Conf("", mdb.HASH, "") }},
ice.CTX_EXIT: {Hand: func(m *ice.Message, arg ...string) { m.Conf("", mdb.HASH, "") }},
tcp.DIAL: {Name: "dial dev=ops name", Hand: func(m *ice.Message, arg ...string) {
_space_dial(m, m.Option(ice.DEV), kit.Select(ice.Info.NodeName, m.Option(mdb.NAME)), arg...)
}},
aaa.INVITE: {Help: "添加", Hand: func(m *ice.Message, arg ...string) {
for _, k := range []string{ice.MISC, ice.CORE, ice.BASE} {
m.Cmdy("web.code.publish", ice.CONTEXTS, k)
if strings.HasPrefix(m.Option(ice.DEV), ice.HTTP) {
m.Cmd(SPIDE, mdb.CREATE, ice.DEV, m.Option(ice.DEV))
m.Option(ice.DEV, ice.DEV)
}
m.EchoScript("shell", "# 共享环境", m.Option(ice.MSG_USERWEB))
m.EchoAnchor(m.Option(ice.MSG_USERWEB)).Echo(ice.NL)
m.EchoQRCode(m.Option(ice.MSG_USERWEB))
_space_dial(m, m.Option(ice.DEV), kit.Select(ice.Info.NodeName, m.Option(mdb.NAME)), arg...)
}},
mdb.REMOVE: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashModify(m, m.OptionSimple(mdb.NAME), mdb.STATUS, cli.STOP)
defer mdb.HashRemove(m, m.OptionSimple(mdb.NAME))
m.Cmd(SPACE, m.Option(mdb.NAME), ice.EXIT)
}},
OPEN: {Hand: func(m *ice.Message, arg ...string) { ProcessIframe(m, MergePod(m, m.Option(mdb.NAME)), arg...) }},
SPACE_LOGIN: {Hand: func(m *ice.Message, arg ...string) {
m.Option(ice.MSG_USERROLE, kit.Select(m.Option(ice.MSG_USERROLE), m.CmdAppend(aaa.USER, m.Option(ice.MSG_USERNAME), aaa.USERROLE)))
if m.Option(ice.MSG_USERROLE) == aaa.VOID && ice.Info.UserName == aaa.VOID {
m.Option(ice.MSG_USERROLE, aaa.TECH)
}
m.Auth(aaa.USERNAME, m.Option(ice.MSG_USERNAME), aaa.USERNICK, m.Option(ice.MSG_USERNICK), aaa.USERROLE, m.Option(ice.MSG_USERROLE))
}},
DREAM_TABLES: {Hand: func(m *ice.Message, arg ...string) {
switch m.Option(mdb.TYPE) {
case CHROME:
@ -287,19 +237,18 @@ func init() {
}
}},
DOMAIN: {Hand: func(m *ice.Message, arg ...string) { m.Echo(_space_domain(m)) }},
OPEN: {Hand: func(m *ice.Message, arg ...string) { ProcessIframe(m, MergePod(m, m.Option(mdb.NAME)), arg...) }},
}, mdb.HashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,type,name,text",
REDIAL, kit.Dict("a", 3000, "b", 1000, "c", 1000), TIMEOUT, kit.Dict("c", "180s"),
BUFFER, kit.Dict("r", ice.MOD_BUFS, "w", ice.MOD_BUFS),
), ctx.CmdAction(), DreamAction()), Hand: func(m *ice.Message, arg ...string) {
), SpaceAction(), DreamAction(), ctx.CmdAction(), aaa.WhiteAction()), Hand: func(m *ice.Message, arg ...string) {
if len(arg) > 0 && arg[0] == ctx.ACTION {
gdb.Event(m, DREAM_ACTION, arg)
return
}
if len(arg) > 1 {
} else if len(arg) > 1 {
_space_send(m, strings.ToLower(arg[0]), kit.Simple(kit.Split(arg[1]), arg[2:])...)
return
}
if mdb.HashSelect(m, arg...); len(arg) > 0 {
} else if mdb.HashSelect(m, arg...); len(arg) > 0 {
m.Sort("type,name,text")
}
if m.IsCliUA() {
@ -315,6 +264,18 @@ func init() {
}},
})
}
var spaceActions = kit.DictList(SPACE_START, SPACE_OPEN, SPACE_LOGIN, SPACE_CLOSE, SPACE_STOP)
func SpaceAction() ice.Actions {
return ice.Actions{ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
for sub := range m.Target().Commands[m.CommandKey()].Actions {
if spaceActions[sub] == ice.TRUE {
gdb.Watch(m, sub)
}
}
}}}
}
func Space(m *ice.Message, arg ice.Any) []string {
if arg == nil || arg == "" || kit.Format(arg) == ice.Info.NodeName {
return nil
@ -322,28 +283,20 @@ func Space(m *ice.Message, arg ice.Any) []string {
return []string{SPACE, kit.Format(arg)}
}
func call(m *ice.Message, sync bool, cb func(*ice.Message)) {
func call(m *ice.Message, timeout string, cb func(*ice.Message)) {
wait := make(chan bool, 2)
p := kit.Select("10s", m.Option(TIMEOUT))
t := time.AfterFunc(kit.Duration(p), func() {
t := time.AfterFunc(kit.Duration(timeout), func() {
m.Warn(true, ice.ErrNotValid, m.Detailv())
back(m, nil)
cb(nil)
m.Optionv("_cb", nil)
wait <- false
})
m.Optionv("_cb", func(res *ice.Message) {
if cb(res); sync {
wait <- true
t.Stop()
}
})
if sync {
<-wait
} else {
cb(res)
t.Stop()
}
wait <- true
})
<-wait
}
func back(m *ice.Message, res *ice.Message) {
switch cb := m.Optionv("_cb").(type) {

View File

@ -13,106 +13,103 @@ import (
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/base/tcp"
kit "shylinux.com/x/toolkits"
"shylinux.com/x/toolkits/logs"
"shylinux.com/x/toolkits/task"
)
type Frame struct {
*ice.Message
*http.Client
*http.Server
*http.ServeMux
send ice.Messages
lock task.Lock
send ice.Messages
}
func (frame *Frame) getSend(key string) (*ice.Message, bool) {
defer frame.lock.RLock()()
msg, ok := frame.send[key]
return msg, ok
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
f.send = ice.Messages{}
return f
}
func (frame *Frame) addSend(key string, msg *ice.Message) string {
defer frame.lock.Lock()()
frame.send[key] = msg
return key
}
func (frame *Frame) delSend(key string) {
defer frame.lock.Lock()()
delete(frame.send, key)
}
func (frame *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if _serve_main(frame.Message, w, r) {
frame.ServeMux.ServeHTTP(w, r)
}
}
func (frame *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
frame.send = ice.Messages{}
return frame
}
func (frame *Frame) Start(m *ice.Message, arg ...string) bool {
meta := logs.FileLineMeta("")
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
f.Message, f.Server = m, &http.Server{Handler: f}
list := map[*ice.Context]string{}
m.Travel(func(p *ice.Context, c *ice.Context) {
if f, ok := c.Server().(*Frame); ok {
if f.ServeMux != nil {
return
f, ok := c.Server().(*Frame)
if !ok || f.ServeMux != nil {
return
}
f.ServeMux = http.NewServeMux()
msg := m.Spawn(c)
if pf, ok := p.Server().(*Frame); ok && pf.ServeMux != nil {
route := ice.PS + c.Name + ice.PS
msg.Log(ROUTE, "%s <= %s", p.Name, route)
pf.Handle(route, http.StripPrefix(path.Dir(route), f))
list[c] = path.Join(list[p], route)
}
m.Confm(SERVE, kit.Keym(nfs.PATH), func(key string, value string) {
msg.Log(ROUTE, "%s <- %s <- %s", c.Name, key, value)
f.Handle(key, http.StripPrefix(key, http.FileServer(http.Dir(value))))
})
for key, cmd := range c.Commands {
if key[0] != '/' {
continue
}
f.ServeMux = http.NewServeMux()
msg := m.Spawn(c)
if pf, ok := p.Server().(*Frame); ok && pf.ServeMux != nil {
route := ice.PS + c.Name + ice.PS
msg.Log(ROUTE, "%s <= %s", p.Name, route, meta)
pf.Handle(route, http.StripPrefix(path.Dir(route), f))
list[c] = path.Join(list[p], route)
}
m.Confm(SERVE, kit.Keym(nfs.PATH), func(key string, value string) {
m.Log(ROUTE, "%s <- %s <- %s", c.Name, key, value, meta)
f.Handle(key, http.StripPrefix(key, http.FileServer(http.Dir(value))))
})
m.Travel(func(p *ice.Context, _c *ice.Context, key string, cmd *ice.Command) {
if c != _c || key[0] != '/' {
return
}
msg.Log(ROUTE, "%s <- %s", c.Name, key, meta)
ice.Info.Route[path.Join(list[c], key)] = ctx.FileURI(cmd.GetFileLine())
func(key string, cmd *ice.Command) {
msg.Log(ROUTE, "%s <- %s", c.Name, key)
f.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) {
m.TryCatch(msg.Spawn(), true, func(msg *ice.Message) { _serve_handle(key, cmd, msg, w, r) })
})
})
ice.Info.Route[path.Join(list[c], key)] = ctx.FileURI(cmd.GetFileLine())
}(key, cmd)
}
})
gdb.Event(m, SERVE_START, arg)
defer gdb.Event(m, SERVE_STOP)
frame.Message, frame.Server = m, &http.Server{Handler: frame}
switch cb := m.OptionCB("").(type) {
case func(http.Handler):
cb(frame)
cb(f)
default:
mdb.HashCreate(m, mdb.NAME, WEB, arg, m.OptionSimple(tcp.PROTO, ice.DEV), cli.STATUS, tcp.START)
m.Cmd(tcp.SERVER, tcp.LISTEN, mdb.TYPE, WEB, m.OptionSimple(mdb.NAME, tcp.HOST, tcp.PORT), func(l net.Listener) {
mdb.HashCreate(m, mdb.NAME, WEB, arg, m.OptionSimple(tcp.PROTO, ice.DEV), cli.STATUS, tcp.START)
defer mdb.HashModify(m, m.OptionSimple(mdb.NAME), cli.STATUS, tcp.STOP)
mdb.HashSelectTarget(m, m.Option(mdb.NAME), func() ice.Any { return l })
m.Warn(frame.Server.Serve(l)) // 启动服务
m.Warn(f.Server.Serve(l))
})
}
return true
}
func (frame *Frame) Close(m *ice.Message, arg ...string) bool {
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
return true
}
func (frame *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
return &Frame{}
}
func (f *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if _serve_main(f.Message, w, r) {
f.ServeMux.ServeHTTP(w, r)
}
}
func (f *Frame) getSend(key string) (*ice.Message, bool) {
defer f.lock.RLock()()
msg, ok := f.send[key]
return msg, ok
}
func (f *Frame) addSend(key string, msg *ice.Message) string {
defer f.lock.Lock()()
f.send[key] = msg
return key
}
func (f *Frame) delSend(key string) string {
defer f.lock.Lock()()
delete(f.send, key)
return key
}
const WEB = "web"
var Index = &ice.Context{Name: WEB, Help: "网络模块"}
func init() { ice.Index.Register(Index, &Frame{}, BROAD, SERVE, SPACE, DREAM, SHARE, CACHE, SPIDE, ROUTE) }
func init() {
ice.Index.Register(Index, &Frame{}, BROAD, SERVE, SPACE, DREAM, SHARE, CACHE, SPIDE, ROUTE)
}
func ApiAction(arg ...string) ice.Actions { return ice.Actions{kit.Select(ice.PS, arg, 0): {}} }
func P(arg ...string) string { return path.Join(ice.PS, path.Join(arg...)) }
func PP(arg ...string) string { return P(arg...) + ice.PS }

View File

@ -8,8 +8,8 @@ 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/lex"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/web"
kit "shylinux.com/x/toolkits"
)
@ -18,7 +18,17 @@ const POD = "pod"
func init() {
Index.MergeCommands(ice.Commands{
web.PP(POD): {Name: "/pod/", Help: "节点", Actions: ice.MergeActions(ctx.CmdAction(), aaa.WhiteAction()), Hand: func(m *ice.Message, arg ...string) {
POD: {Name: "pod", Help: "节点", Actions: ice.MergeActions(ice.Actions{
web.SERVE_PARSE: {Hand: func(m *ice.Message, arg ...string) {
switch kit.Select("", arg, 0) {
case CHAT:
for i := 1; i < len(arg)-1; i++ {
m.Logs("refer", arg[i], arg[i+1])
m.Option(arg[i], arg[i+1])
}
}
}},
}, ctx.CmdAction(), web.ServeAction(), web.ApiAction(), aaa.WhiteAction()), Hand: func(m *ice.Message, arg ...string) {
if web.OptionAgentIs(m, "curl", "wget") {
aaa.UserRoot(m).Cmdy(web.SHARE_LOCAL, ice.BIN_ICE_BIN, kit.Dict(ice.POD, kit.Select("", arg, 0)))
return
@ -41,4 +51,4 @@ func init() {
func RenderWebsite(m *ice.Message, pod string, dir string, arg ...string) *ice.Message {
return m.Echo(m.Cmdx(web.Space(m, pod), "web.chat.website", lex.PARSE, dir, arg)).RenderResult()
}
}

View File

@ -160,28 +160,6 @@ func init() {
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
m.Cmd(mdb.RENDER, mdb.CREATE, nfs.IML, m.PrefixKey())
m.Cmd(mdb.ENGINE, mdb.CREATE, nfs.IML, m.PrefixKey())
web.AddRewrite(func(w http.ResponseWriter, r *http.Request) bool {
if r.Method != http.MethodGet {
return false
}
if strings.HasSuffix(r.URL.Path, ice.PS) {
return false
}
if !strings.HasPrefix(r.Header.Get(web.UserAgent), "Mozilla") {
return false
}
if strings.HasPrefix(r.URL.Path, CHAT_WEBSITE) {
_website_render(m, w, r, kit.Ext(r.URL.Path), m.Cmdx(nfs.CAT, strings.Replace(r.URL.Path, CHAT_WEBSITE, SRC_WEBSITE, 1)), path.Base(r.URL.Path))
return true
}
if m.Cmd(WEBSITE, r.URL.Path, func(value ice.Maps) {
_website_render(m, w, r, value[mdb.TYPE], value[mdb.TEXT], path.Base(r.URL.Path))
}).Length() > 0 {
return true
}
return false
})
}},
lex.PARSE: {Hand: func(m *ice.Message, arg ...string) {
switch kit.Ext(arg[0]) {

View File

@ -159,7 +159,7 @@ func _install_trash(m *ice.Message, arg ...string) {
m.Cmd(cli.DAEMON, mdb.REMOVE, kit.Dict(mdb.HASH, value[mdb.HASH]))
}
})
m.Cmd(nfs.TRASH, kit.Path(ice.USR_LOCAL_DAEMON, m.Option(tcp.PORT), m.Option(nfs.PATH)))
nfs.Trash(m, kit.Path(ice.USR_LOCAL_DAEMON, m.Option(tcp.PORT), m.Option(nfs.PATH)))
}
func _install_service(m *ice.Message, arg ...string) {
arg = kit.Split(path.Base(arg[0]), "_-.")[:1]
@ -211,7 +211,7 @@ func init() {
gdb.DEBUG: {Name: "debug", Help: "调试", Hand: func(m *ice.Message, arg ...string) {
ctx.Process(m, XTERM, []string{mdb.TYPE, "gdb"}, arg...)
}},
nfs.TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
_install_trash(m, arg...)
}},
nfs.SOURCE: {Name: "source link path", Help: "源码", Hand: func(m *ice.Message, arg ...string) {
@ -250,8 +250,8 @@ func InstallAction(args ...ice.Any) ice.Actions {
cli.ORDER: {Name: "order", Help: "加载", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(INSTALL, cli.ORDER, m.Config(nfs.SOURCE), path.Join(_INSTALL, ice.BIN))
}},
nfs.TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.TRASH, m.Option(nfs.PATH))
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
nfs.Trash(m, m.Option(nfs.PATH))
}},
}
}

View File

@ -26,14 +26,11 @@ const PPROF = "pprof"
func init() {
Index.MergeCommands(ice.Commands{
PPROF: {Name: "pprof zone id auto", Help: "性能分析", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
web.AddRewrite(func(w http.ResponseWriter, r *http.Request) bool {
if p := r.URL.Path; strings.HasPrefix(p, "/debug/") {
r.URL.Path = strings.Replace(r.URL.Path, "/debug/", "/code/", -1)
m.Debug("rewrite %v -> %v", p, r.URL.Path)
}
return false
})
web.SERVE_REWRITE: {Hand: func(m *ice.Message, arg ...string) {
if strings.HasPrefix(arg[1], "/debug/") {
m.R.URL.Path = strings.Replace(m.R.URL.Path, "/debug/", "/code/", -1)
m.Debug("rewrite %v -> %v", arg[1], m.R.URL.Path)
}
}},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
@ -61,7 +58,7 @@ func init() {
m.Cmd(cli.DAEMON, m.Configv(PPROF), "-http="+p, m.Option(BINNARY), m.Option(nfs.FILE))
m.Echo("http://%s/ui/top", p).ProcessInner()
}},
}, mdb.ZoneAction(mdb.SHORT, mdb.ZONE, mdb.FIELD, "time,id,text,file", PPROF, kit.List(GO, "tool", PPROF))), Hand: func(m *ice.Message, arg ...string) {
}, mdb.ZoneAction(mdb.SHORT, mdb.ZONE, mdb.FIELD, "time,id,text,file", PPROF, kit.List(GO, "tool", PPROF)), web.ServeAction()), Hand: func(m *ice.Message, arg ...string) {
m.Fields(len(arg), "time,zone,count,binnary,service,seconds", mdb.ZoneField(m))
if mdb.ZoneSelect(m, arg...); len(arg) == 0 {
m.EchoAnchor(web.MergeLink(m, "/code/pprof/"))

View File

@ -120,8 +120,8 @@ func init() {
mdb.CREATE: {Name: "create file", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
_publish_file(m, m.Option(nfs.FILE))
}},
nfs.TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.TRASH, path.Join(ice.USR_PUBLISH, m.Option(nfs.PATH)))
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
nfs.Trash(m, path.Join(ice.USR_PUBLISH, m.Option(nfs.PATH)))
}},
}, aaa.RoleAction()), Hand: func(m *ice.Message, arg ...string) {
m.Option(nfs.DIR_ROOT, ice.USR_PUBLISH)

View File

@ -99,8 +99,8 @@ func init() {
m.Cmd("", DEVPACK)
}
}},
nfs.TRASH: {Name: "trash path", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.TRASH, arg[0])
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
nfs.Trash(m, arg[0])
}},
nfs.SCRIPT: {Name: "script file=hi/hi.js", Help: "脚本", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(nfs.DEFS, path.Join(m.Option(nfs.PATH), m.Option(nfs.FILE)), m.Cmdx("", TEMPLATE))

View File

@ -162,9 +162,9 @@ func init() {
_webpack_cache(m.Spawn(), _volcanos(m), true)
_webpack_build(m, _publish(m, WEBPACK, m.Option(mdb.NAME)))
}},
nfs.TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
if !strings.Contains(m.Option(nfs.PATH), "page/index") {
m.Cmd(nfs.TRASH, m.Option(nfs.PATH))
nfs.Trash(m, m.Option(nfs.PATH))
}
}},
}, mdb.HashAction(mdb.SHORT, nfs.PATH, mdb.FIELD, "time,path")), Hand: func(m *ice.Message, arg ...string) {

View File

@ -82,7 +82,7 @@ func WikiAction(dir string, ext ...string) ice.Actions {
return ice.Actions{ice.CTX_INIT: mdb.AutoConfig(nfs.PATH, dir, lex.REGEXP, kit.FileReg(ext...)),
web.UPLOAD: {Hand: func(m *ice.Message, arg ...string) { _wiki_upload(m, m.Option(nfs.PATH)) }},
nfs.SAVE: {Name: "save path text", Hand: func(m *ice.Message, arg ...string) { _wiki_save(m, m.Option(nfs.PATH), m.Option(mdb.TEXT)) }},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(nfs.TRASH, _wiki_path(m, m.Option(nfs.PATH))) }},
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) { nfs.Trash(m, _wiki_path(m, m.Option(nfs.PATH))) }},
mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {
case nfs.PATH:

View File

@ -147,6 +147,7 @@ func (m *Message) error(arg ...Any) {
}
m.Resultv(ErrWarn, kit.Simple(arg))
}
func (m *Message) IsOk() bool { return m.Result() == OK }
func (m *Message) IsErr(arg ...string) bool {
return len(arg) == 0 && m.Result(0) == ErrWarn || len(arg) > 0 && m.Result(1) == arg[0]
}

View File

@ -31,7 +31,7 @@ func _server_rewrite(m *ice.Message, p string, r *http.Request) {
m.Info("rewrite %v -> %v", p, r.URL.Path) // 访问服务
} else {
r.URL.Path = strings.Replace(r.URL.Path, "/x/", "/code/git/repos/", 1)
r.URL.Path = strings.Replace(r.URL.Path, "/x/", "/code/git/repository/", 1)
m.Info("rewrite %v -> %v", p, r.URL.Path) // 下载源码
}
}
@ -113,16 +113,13 @@ const SERVER = "server"
func init() {
Index.MergeCommands(ice.Commands{
web.WEB_LOGIN: {Hand: func(m *ice.Message, arg ...string) { m.Render(ice.RENDER_VOID) }},
"/repos/": {Name: "/repos/", Help: "代码库", Actions: ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
web.AddRewrite(func(p string, w http.ResponseWriter, r *http.Request) bool {
if strings.HasPrefix(p, "/x/") {
_server_rewrite(m, p, r)
}
return false
})
"repository": {Name: "repository", Help: "代码库", Actions: ice.MergeActions(ice.Actions{
web.SERVE_REWRITE: {Hand: func(m *ice.Message, arg ...string) {
if strings.HasPrefix(arg[1], "/x/") {
_server_rewrite(m, arg[1], m.R)
}
}},
}, Hand: func(m *ice.Message, arg ...string) {
}, web.ServeAction(), web.ApiAction()), Hand: func(m *ice.Message, arg ...string) {
if m.Option("go-get") == "1" { // 下载地址
p := web.MergeLink(m, "/x/"+path.Join(arg...))
m.RenderResult(kit.Format(`<meta name="%s" content="%s">`, "go-import", kit.Format(`%s git %s`, strings.Split(p, "://")[1], p)))
@ -164,9 +161,9 @@ func init() {
_git_cmd(m, PUSH, "--tags", remote, MASTER)
})
}},
nfs.TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
m.Assert(m.Option(nfs.PATH) != "")
m.Cmd(nfs.TRASH, path.Join(ice.USR_LOCAL_REPOS, m.Option(nfs.PATH)))
nfs.Trash(m, path.Join(ice.USR_LOCAL_REPOS, m.Option(nfs.PATH)))
}},
web.DREAM_INPUTS: {Hand: func(m *ice.Message, arg ...string) {
switch arg[0] {

View File

@ -306,8 +306,8 @@ func init() {
code.PUBLISH: {Name: "publish", Help: "发布", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(code.PUBLISH, ice.CONTEXTS, ice.MISC, ice.CORE)
}},
nfs.TRASH: {Name: "trash", Help: "删除", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.TRASH, mdb.CREATE, path.Join(_repos_path(m.Option(REPOS)), m.Option(nfs.FILE)))
nfs.TRASH: {Hand: func(m *ice.Message, arg ...string) {
nfs.Trash(m, path.Join(_repos_path(m.Option(REPOS)), m.Option(nfs.FILE)))
}},
code.BINPACK: {Name: "binpack", Help: "发布模式", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.LINK, ice.GO_SUM, path.Join(ice.SRC_RELEASE, ice.GO_SUM))