diff --git a/base/aaa/sess.go b/base/aaa/sess.go index c8ddb7a4..91d18fec 100644 --- a/base/aaa/sess.go +++ b/base/aaa/sess.go @@ -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"))), ) } diff --git a/base/nfs/trash.go b/base/nfs/trash.go index c6de0bf9..ddceb21e 100644 --- a/base/nfs/trash.go +++ b/base/nfs/trash.go @@ -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) +} diff --git a/base/tcp/port.go b/base/tcp/port.go index 0ced6b53..5ff0dae3 100644 --- a/base/tcp/port.go +++ b/base/tcp/port.go @@ -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 { diff --git a/base/web/_story.go b/base/web/_story.go deleted file mode 100644 index 37be85ca..00000000 --- a/base/web/_story.go +++ /dev/null @@ -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) -} diff --git a/base/web/dream.go b/base/web/dream.go index 9d1b81f0..bade7fbd 100644 --- a/base/web/dream.go +++ b/base/web/dream.go @@ -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) diff --git a/base/web/serve.go b/base/web/serve.go index ff3f90d5..16166c63 100644 --- a/base/web/serve.go +++ b/base/web/serve.go @@ -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) diff --git a/base/web/share.go b/base/web/share.go index 869518f4..798f26c1 100644 --- a/base/web/share.go +++ b/base/web/share.go @@ -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 } diff --git a/base/web/space.go b/base/web/space.go index 132b16f8..52ad2568 100644 --- a/base/web/space.go +++ b/base/web/space.go @@ -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) { diff --git a/base/web/web.go b/base/web/web.go index d5f07069..7ece141e 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -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 } diff --git a/core/chat/pod.go b/core/chat/pod.go index 68fa4cd7..e6a63198 100644 --- a/core/chat/pod.go +++ b/core/chat/pod.go @@ -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() -} \ No newline at end of file +} diff --git a/core/chat/website.go b/core/chat/website.go index bb6fde15..4f4afa4a 100644 --- a/core/chat/website.go +++ b/core/chat/website.go @@ -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]) { diff --git a/core/code/install.go b/core/code/install.go index 2c546853..453e13b8 100644 --- a/core/code/install.go +++ b/core/code/install.go @@ -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)) }}, } } diff --git a/core/code/pprof.go b/core/code/pprof.go index f6bcf9d0..88eb5d8c 100644 --- a/core/code/pprof.go +++ b/core/code/pprof.go @@ -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/")) diff --git a/core/code/publish.go b/core/code/publish.go index 95bbf02b..f42be20d 100644 --- a/core/code/publish.go +++ b/core/code/publish.go @@ -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) diff --git a/core/code/vimer.go b/core/code/vimer.go index b2e52550..c6673dfd 100644 --- a/core/code/vimer.go +++ b/core/code/vimer.go @@ -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)) diff --git a/core/code/webpack.go b/core/code/webpack.go index 0196107e..0458a63a 100644 --- a/core/code/webpack.go +++ b/core/code/webpack.go @@ -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) { diff --git a/core/wiki/wiki.go b/core/wiki/wiki.go index ea60dd76..df62ec9b 100644 --- a/core/wiki/wiki.go +++ b/core/wiki/wiki.go @@ -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: diff --git a/logs.go b/logs.go index 4d86d945..d06d3700 100644 --- a/logs.go +++ b/logs.go @@ -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] } diff --git a/misc/git/server.go b/misc/git/server.go index b6551e9c..fbfd17e2 100644 --- a/misc/git/server.go +++ b/misc/git/server.go @@ -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(``, "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] { diff --git a/misc/git/status.go b/misc/git/status.go index 143397b0..af97c628 100644 --- a/misc/git/status.go +++ b/misc/git/status.go @@ -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))