From 78be157b5de8111e8485e2a2fceb102444b8d237 Mon Sep 17 00:00:00 2001 From: shaoying Date: Sun, 22 Sep 2019 15:51:04 +0800 Subject: [PATCH] add web.wss --- src/contexts/cli/version.go | 2 +- src/contexts/ctx/core.go | 7 ++- src/contexts/ctx/type.go | 1 + src/contexts/web/web.go | 121 +++++++++++++++++++++++++++++++++++- src/examples/chat/chat.go | 1 + src/plugin/love/index.shy | 7 +++ src/toolkit/core.go | 6 ++ usr/librarys/chat.js | 12 +++- usr/librarys/context.js | 27 ++++++++ usr/librarys/example.js | 11 ++++ 10 files changed, 188 insertions(+), 7 deletions(-) diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go index 853eabf5..e98a94b8 100644 --- a/src/contexts/cli/version.go +++ b/src/contexts/cli/version.go @@ -4,5 +4,5 @@ var version = struct { host string self int }{ - "2019-09-22 09:30:17", "mac", 632, + "2019-09-22 15:44:02", "mac", 660, } diff --git a/src/contexts/ctx/core.go b/src/contexts/ctx/core.go index 09e48ade..84566cbd 100644 --- a/src/contexts/ctx/core.go +++ b/src/contexts/ctx/core.go @@ -1,10 +1,10 @@ package ctx import ( - "runtime" "errors" "fmt" "io" + "runtime" "strings" "time" "toolkit" @@ -382,7 +382,10 @@ func (m *Message) Call(cb func(msg *Message) (sub *Message), arg ...interface{}) if m == nil { return m } - if m.callback = cb; len(arg) > 0 || len(m.Meta["detail"]) > 0 { + if m.callback = cb; len(arg) > 0 && kit.Format(arg[0]) == "skip" { + return m + } + if len(arg) > 0 || len(m.Meta["detail"]) > 0 { m.Log("call", m.Format("detail", "option")) m.Cmd(arg...) } diff --git a/src/contexts/ctx/type.go b/src/contexts/ctx/type.go index 753b2a4f..17b9c704 100644 --- a/src/contexts/ctx/type.go +++ b/src/contexts/ctx/type.go @@ -70,6 +70,7 @@ type Message struct { Hand bool Meta map[string][]string Data map[string]interface{} + Sync chan bool callback func(msg *Message) (sub *Message) freeback []func(msg *Message) (done bool) diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index c846084d..e9a343cb 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -1,6 +1,7 @@ package web import ( + "github.com/gorilla/websocket" "github.com/skip2/go-qrcode" "contexts/ctx" @@ -119,7 +120,8 @@ func (web *WEB) Login(msg *ctx.Message, w http.ResponseWriter, r *http.Request) return false } if relay.Appends("username") { - msg.Log("info", "login: %s", msg.Option("username", relay.Append("username"))) + name := msg.Cmdx("ssh._route", msg.Conf("runtime", "work.route"), "_check", "work", "create", relay.Append("username"), msg.Conf("runtime", "node.route")) + msg.Log("info", "login: %s", msg.Option("username", name)) http.SetCookie(w, &http.Cookie{Name: "sessid", Value: msg.Option("sessid", msg.Cmdx("aaa.user", "session", "select")), Path: "/"}) } if role := relay.Append("userrole"); role != "" { @@ -425,6 +427,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", "toolkit": &ctx.Config{Name: "toolkit", Value: map[string]interface{}{ "time": map[string]interface{}{"cmd": "time"}, }, Help: "工具列表"}, + "wss": &ctx.Config{Name: "wss", Value: map[string]interface{}{}, Help: ""}, }, Commands: map[string]*ctx.Command{ "_init": &ctx.Command{Name: "_init", Help: "post请求", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { @@ -1081,6 +1084,122 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", }) return }}, + + "/wss": &ctx.Command{Name: "/wss", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + r := m.Optionv("request").(*http.Request) + w := m.Optionv("response").(http.ResponseWriter) + + if s, e := websocket.Upgrade(w, r, nil, 4096, 4096); m.Assert(e) { + h := kit.Hashs("uniq") + p := make(chan *ctx.Message, 10) + meta := map[string]interface{}{ + "create_time": m.Time(), + "create_user": m.Option("username"), + "agent": r.Header.Get("User-Agent"), + "sessid": m.Option("sessid"), + "socket": s, + "channel": p, + } + m.Conf("wss", []string{m.Option("username"), h}, meta) + m.Conf("wss", h, meta) + + what := m + m.Log("info", "wss conn %v", h) + m.Gos(m.Spawn(), func(msg *ctx.Message) { + for { + if t, b, e := s.ReadMessage(); e == nil { + var data interface{} + if e := json.Unmarshal(b, &data); e == nil { + m.Log("info", "wss recv %s %d msg %v", h, t, data) + } else { + m.Log("warn", "wss recv %s %d msg %v", h, t, e) + } + + what.Optionv("data", data) + what.Back(what) + } else { + m.Log("warn", "wss recv %s %d msg %v", h, t, e) + close(p) + break + } + } + }) + + for what = range p { + s.WriteJSON(what.Meta) + } + + s.Close() + m.Conf("wss", h, "") + m.Conf("wss", []string{m.Option("username"), h}, "") + m.Log("warn", "wss close %s", h) + } + return + }}, + "wss": &ctx.Command{Name: "wss", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + if len(arg) == 0 { + m.Confm("wss", func(key string, value map[string]interface{}) { + if value["agent"] == nil { + return + } + m.Push("key", m.Cmdx("aaa.short", key)) + m.Push("create_time", value["create_time"]) + m.Push("create_user", value["create_user"]) + m.Push("sessid", kit.Format(value["sessid"])[:6]) + m.Push("agent", value["agent"]) + }) + m.Table() + return + } + + list := []string{} + if strings.Contains(arg[0], ".") { + vs := strings.SplitN(arg[0], ".", 2) + m.Confm("wss", vs[0], func(key string, value map[string]interface{}) { + if vs[1] == "*" || strings.Contains(kit.Format(value["agent"]), vs[1]) { + list = append(list, key) + } + }) + } else { + if len(arg[0]) != 32 { + arg[0] = m.Cmdx("aaa.short", arg[0]) + } + list = append(list, arg[0]) + } + + if len(arg) == 1 { + m.Cmdy(".config", "wss", arg[0]) + return + } + + for _, v := range list { + if p, ok := m.Confv("wss", []string{v, "channel"}).(chan *ctx.Message); ok { + if arg[1] == "sync" { + m.Meta["detail"] = arg[2:] + p <- m + m.CallBack(true, func(msg *ctx.Message) *ctx.Message { + if data, ok := m.Optionv("data").(map[string]interface{}); ok { + res := kit.Trans(data["result"]) + m.Log("info", "result: %v", res) + if len(res) > 0 { + m.Result(res) + } + } + + m.Push("time", m.Time()) + m.Push("key", m.Cmdx("aaa.short", v)) + m.Push("action", kit.Format(arg[2:])) + m.Push("result", kit.Format(m.Meta["result"])) + return nil + }, "skip") + } else { + m.Meta["detail"] = arg[1:] + p <- m + } + } + } + return + }}, }, } diff --git a/src/examples/chat/chat.go b/src/examples/chat/chat.go index f80b658d..ba54479a 100644 --- a/src/examples/chat/chat.go +++ b/src/examples/chat/chat.go @@ -195,6 +195,7 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心", if !m.Options("sessid") || !m.Options("username") { return } + m.Short("river") // 自动入群 if m.Options("river") { diff --git a/src/plugin/love/index.shy b/src/plugin/love/index.shy index 42c4b8bc..077e089c 100644 --- a/src/plugin/love/index.shy +++ b/src/plugin/love/index.shy @@ -48,3 +48,10 @@ fun media "娱乐" private \ end end +kit wss "推送" private "web.wss" \ + text "" name wss imports plugin_wss \ + text "" name cmd \ + button "推送" \ + button "返回" click Last \ + exports wss key + diff --git a/src/toolkit/core.go b/src/toolkit/core.go index 46af428a..cf1360fd 100644 --- a/src/toolkit/core.go +++ b/src/toolkit/core.go @@ -317,6 +317,12 @@ func Map(v interface{}, random string, args ...interface{}) map[string]interface fun(i, val) } } + case func(string, []interface{}): + for k, v := range value { + if val, ok := v.([]interface{}); ok { + fun(k, val) + } + } case func(string, map[string]interface{}): switch random { case "%": diff --git a/usr/librarys/chat.js b/usr/librarys/chat.js index ff6f8403..ba200f83 100644 --- a/usr/librarys/chat.js +++ b/usr/librarys/chat.js @@ -280,7 +280,7 @@ var page = Page({check: true, ], 0) }, Core: function(event, line, args, cbs) { - var plugin = event.Plugin || {}, engine = { + var plugin = event.Plugin || page.plugin && page.plugin.Plugin || {}, engine = { share: function(args) { typeof cbs == "function" && cbs(ctx.Share({"group": option.dataset.group, "name": option.dataset.name, "cmds": [ river, line.storm, line.action, args[1]||"", @@ -347,12 +347,12 @@ var page = Page({check: true, }, _run: function() { var meta = plugin && plugin.target && plugin.target.Meta || {} - field.Pane.Run([meta.river||river, meta.storm||storm, meta.action||index].concat(args), function(msg) { + field.Pane.Run([meta.river||river, meta.storm||storm, meta.action].concat(args), function(msg) { engine._msg(msg), typeof cbs == "function" && cbs(msg) }) }, } - if (args.length > 0 && engine[args[0]] && engine[args[0]](args)) {return} + if (args.length > 0 && engine[args[0]] && engine[args[0]](args)) {typeof cbs == "function" && cbs(line); return} event.shiftKey? engine._msg(): engine._run() }, Show: function() {var pane = field.Pane @@ -469,12 +469,17 @@ var page = Page({check: true, "返回": function(event, value) { page.plugin && page.plugin.Plugin.Last() }, + "推送": function(event, value) { + if (page.socket) {return} + page.socket = page.WSS() + }, }, Button: [["layout", "聊天", "办公", "工作", "最高", "最宽", "最大"], "", "刷新", "清屏", "并行", "串行", "", ["display", "表格", "编辑", "绘图"], "", "添加", "删除", "加参", "减参", "", "执行", "下载", "清空", "返回", + "", "推送", ], } }, @@ -636,5 +641,6 @@ var page = Page({check: true, }) page.river.Pane.Show(), page.pane = page.action, page.plugin = kit.Selector(page.action, "fieldset")[0] page.action.Pane.Layout(ctx.Search("layout")? ctx.Search("layout"): kit.device.isMobile? "办公": "工作") + page.socket = page.WSS() }, }) diff --git a/usr/librarys/context.js b/usr/librarys/context.js index 39f0a059..4d53d181 100644 --- a/usr/librarys/context.js +++ b/usr/librarys/context.js @@ -204,6 +204,33 @@ ctx = context = { xhr.setRequestHeader("Accept", "application/json") xhr.send(args.join("&")) }, + WSS: function(cb) { + var s = new WebSocket("ws://"+location.host+"/wss") + s.onopen = function(event) { + kit.Log(event) + } + s.onmessage = function(event) { + var msg = JSON.parse(event.data) + + try { + var msg = JSON.parse(event.data||'{}') + } catch (e) { + var msg = {"result": [event.data]} + } + + msg.event = event, msg.reply = function(sub) { + s.send(JSON.stringify(sub||msg)) + } + typeof cb == "function" && cb(msg) + } + s.onerror = function(event) { + kit.Log(event) + } + s.onclose = function(event) { + kit.Log(event) + } + return s + }, Upload: function(file, cb, detail) { var data = new FormData() data.append("upload", file) diff --git a/usr/librarys/example.js b/usr/librarys/example.js index 90650127..ab95136e 100644 --- a/usr/librarys/example.js +++ b/usr/librarys/example.js @@ -437,6 +437,17 @@ function Page(page) { } return typeof page[args[0]] == "function" && kit._call(page[args[0]], args.slice(1)) }, + WSS: function(cb) { + return ctx.WSS(cb || (function(m) { + if (m.detail) { + page.action.Pane.Core(event, m, ["_cmd", m.detail], function(msg) { + m.reply(msg) + }) + } else { + page.ontoast(m.result.join("")) + } + })) + }, initToast: function() {}, initLogin: function(page, field, option, output) {