diff --git a/core/plugin_core.go b/core/plugin_core.go index 452f93b..b437801 100644 --- a/core/plugin_core.go +++ b/core/plugin_core.go @@ -589,6 +589,9 @@ func initPlugin(data string, uuid string) (*common.Function, []func(), error) { vm.Set("genUuid", func() string { return utils.GenUUID() }) + vm.Set("genUUID", func() string { + return utils.GenUUID() + }) vm.Set("UUID", func() string { return uuid }) diff --git a/core/plugin_utils.go b/core/plugin_utils.go index 577fcf2..f703256 100644 --- a/core/plugin_utils.go +++ b/core/plugin_utils.go @@ -364,6 +364,7 @@ func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func( vm.Set("crypto", &Crypto{ vm: vm, }) + vm.Set("createNickName", CreateNickName) } func EncryptPlugin(script string) string { diff --git a/core/plugin_web_response.go b/core/plugin_web_response.go index 9d1d860..051a0dc 100644 --- a/core/plugin_web_response.go +++ b/core/plugin_web_response.go @@ -8,7 +8,6 @@ import ( "github.com/dop251/goja" "github.com/gin-gonic/gin" "github.com/goccy/go-json" - "github.com/gorilla/websocket" ) type Response struct { @@ -27,11 +26,10 @@ type Response struct { isJson bool status int isRedirect bool - conn *websocket.Conn + conn *WsConn } func (r *Response) Send(gv goja.Value) *Response { - gve := gv.Export() switch gve := gve.(type) { case string: @@ -46,7 +44,7 @@ func (r *Response) Send(gv goja.Value) *Response { } } if r.conn != nil { - r.conn.WriteMessage(1, []byte(r.content)) + r.conn.WriteMessage(1, []byte(r.content), nil) r.content = "" return r } @@ -58,14 +56,20 @@ func (r *Response) SendStatus(st int) *Response { return r } -func (r *Response) Json(ps ...interface{}) *Response { +func (r *Response) Json(ps ...interface{}) interface{} { var status int64 = 200 var data interface{} + var pattern map[string]interface{} if len(ps) == 1 { data = ps[0] } else { - status = ps[0].(int64) - data = ps[1] + if v, ok := ps[1].(map[string]interface{}); ok { + data = ps[0] + pattern = v + } else { + status = ps[0].(int64) + data = ps[1] + } } d, err := json.Marshal(data) f := string(d) @@ -77,9 +81,9 @@ func (r *Response) Json(ps ...interface{}) *Response { r.content += fmt.Sprint(data) } if r.conn != nil { - r.conn.WriteMessage(1, d) + _, result := r.conn.WriteMessage(1, d, pattern) r.content = "" - return r + return result } return r } diff --git a/core/websocket.go b/core/websocket.go index af5d0b6..36d7c17 100644 --- a/core/websocket.go +++ b/core/websocket.go @@ -1,9 +1,16 @@ package core import ( + "encoding/json" + "fmt" "net/http" "strings" + "sync" + "sync/atomic" + "time" + "github.com/buger/jsonparser" + "github.com/cdle/sillyplus/utils" "github.com/dop251/goja" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" @@ -19,6 +26,62 @@ func IsWebSocketRequest(req *http.Request) bool { return true } +type WsPattern struct { + Value map[string]interface{} + Chan chan map[string]interface{} +} + +type WsConn struct { + conn *websocket.Conn + patterns sync.Map + Key int64 + sync.RWMutex +} + +func (wc *WsConn) Close() error { + return wc.conn.Close() +} + +func (wc *WsConn) WriteMessage(messageType int, data []byte, pattern map[string]interface{}) (error, map[string]interface{}) { + var res map[string]interface{} + wp := &WsPattern{} + var timeout int + if pattern != nil { + if v, ok := pattern["$timeout"]; ok { + timeout = utils.Int(v) + delete(pattern, "$timeout") + } // + wp.Value = pattern + key := atomic.AddInt64(&wc.Key, 1) + wp.Chan = make(chan map[string]interface{}, 1) + defer func() { + close(wp.Chan) + wc.patterns.Delete(key) + }() + wc.patterns.Store(key, wp) + } + var err error + func() { + wc.Lock() + defer wc.Unlock() + err = wc.conn.WriteMessage(messageType, data) + }() + if pattern != nil { + if timeout == 0 { + timeout = 5000 + } + select { + case res = <-wp.Chan: + case <-time.After(time.Millisecond * time.Duration(timeout)): + } + } + return err, res +} + +// func (wc *WsConn) WriteMessage(messageType int, data []byte) error { +// return wc.conn.WriteMessage(messageType, data) +// } + func handleWebsocket(c *gin.Context) { for _, function := range Functions { if len(function.Https) != 0 { @@ -34,14 +97,6 @@ func handleWebsocket(c *gin.Context) { var res = &Response{ c: c, } - req._event = "connect" - function.Handle(&Faker{ - Type: "websocket", - }, func(vm *goja.Runtime) { - vm.Set("res", res) - vm.Set("req", req) - }) - // message var upGrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true @@ -52,9 +107,63 @@ func handleWebsocket(c *gin.Context) { c.Writer.Write([]byte(err.Error())) return } - res.conn = ws + wc := &WsConn{} + res.conn = wc + req._event = "connect" + wc.conn = ws + go function.Handle(&Faker{ + Type: "websocket", + }, func(vm *goja.Runtime) { + vm.Set("res", res) + vm.Set("req", req) + }) + // message for { _, data, err := ws.ReadMessage() + wc.patterns.Range(func(key, value any) bool { + wp := value.(*WsPattern) + matched := false + // fmt.Println("wp.Value", wp.Value) + for k, v := range wp.Value { + value, _, _, err := jsonparser.Get(data, strings.Split(k, ".")...) + // fmt.Println("k, v", k, v, "key path", strings.Split(k, "."), "data:", string(data), err) + if err != nil { + // fmt.Println("err1", err) + return true + } + if string(value) != fmt.Sprint(v) { + return true + } + matched = true + // v2 := v + // fmt.Println("v2 := v", v2, string(value)) + // err = json.Unmarshal(value, &v2) + // if err != nil { + // fmt.Println("err2", err) + // return true + // } + // if v != v2 { + // fmt.Println("err3", err) + // return true + // } else { + // matched = true + // } + } + // fmt.Println("matched", matched) + if matched { + var result = map[string]interface{}{} + err := json.Unmarshal(data, &result) + if err == nil { + select { + case wp.Chan <- result: + default: + } + } else { + // fmt.Println("err3", err) + } + } + return true + }) if err != nil { // disconnect req._event = "disconnect" for _, f2 := range Functions { @@ -78,7 +187,7 @@ func handleWebsocket(c *gin.Context) { function = f2 } } - function.Handle(&Faker{ + go function.Handle(&Faker{ Type: "websocket", }, func(vm *goja.Runtime) { vm.Set("res", res)