update ws

This commit is contained in:
Star 2024-10-16 18:08:06 +08:00
parent 4412bfc727
commit ea04fd82c8
3 changed files with 143 additions and 70 deletions

160
http.go
View File

@ -2,6 +2,7 @@ package http
import (
_ "embed"
"encoding/json"
"net/http"
"reflect"
"strings"
@ -275,14 +276,14 @@ func (hc *Http) Connect(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
// ws.onPing = opt.Func("onPing")
// ws.onPong = opt.Func("onPong")
ws.onMessage = opt.Func("onMessage")
ws.onJSONMessage = opt.Func("onJSONMessage")
ws.pingInterval = opt.Int64("pingInterval")
ws.reconnectInterval = opt.Int64("reconnectInterval")
if ws.reconnectInterval == 0 && (ws.onMessage != nil || ws.onJSONMessage != nil) {
if ws.reconnectInterval == 0 && ws.onMessage != nil {
ws.reconnectInterval = 1000
}
}
// fmt.Println(u.BMagenta("WS"), "start")
if err := ws.connect(vm); err == nil {
if ws.pingInterval > 0 {
// fmt.Println(u.BMagenta("WS"), "start ping")
@ -290,10 +291,7 @@ func (hc *Http) Connect(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
// ws.sleep(time.Duration(ws.pingInterval) * time.Millisecond)
for {
if ws.conn != nil {
// fmt.Println(u.BMagenta("WS"), "ping")
ws.writeLock.Lock()
ws.conn.WriteMessage(websocket.PingMessage, []byte{'P'})
ws.writeLock.Unlock()
ws.writeMessage(websocket.PingMessage, nil)
}
if !ws.running {
break
@ -310,30 +308,17 @@ func (hc *Http) Connect(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
ws.pingStopChan <- true
}
if ws.onMessage != nil || ws.onJSONMessage != nil {
if ws.onMessage != nil {
// fmt.Println(u.BMagenta("WS"), "start onMessage")
go func() {
for {
for {
if ws.conn != nil {
if ws.onJSONMessage != nil {
var obj interface{}
err := ws.conn.ReadJSON(&obj)
if err != nil {
break
}
_, _ = ws.onJSONMessage(ws.this, vm.ToValue(obj))
} else {
typ, buf, err := ws.conn.ReadMessage()
if err != nil {
break
}
if typ == websocket.TextMessage {
_, _ = ws.onMessage(ws.this, vm.ToValue(string(buf)))
} else {
_, _ = ws.onMessage(ws.this, vm.ToValue(buf))
}
typ, data, err := readWSMessage(ws.conn)
if err != nil {
break
}
_, _ = ws.onMessage(ws.this, vm.ToValue(typ), vm.ToValue(data))
}
}
// fmt.Println(u.BMagenta("WS"), "stop onMessage")
@ -377,8 +362,11 @@ type WS struct {
onError goja.Callable
// onPing goja.Callable
// onPong goja.Callable
pingTimes int64
pongTimes int64
lastPingTime int64
lastPongTime int64
onMessage goja.Callable
onJSONMessage goja.Callable
pingInterval int64
reconnectInterval int64
}
@ -437,6 +425,15 @@ func (ws *WS) connect(vm *goja.Runtime) error {
// })
// return err
// }
ws.pingTimes = 0
ws.pongTimes = 0
ws.lastPingTime = 0
ws.lastPongTime = 0
conn.SetPongHandler(func(appData string) error {
ws.pongTimes++
ws.lastPongTime = time.Now().UnixMilli()
return nil
})
conn.SetCloseHandler(func(code int, text string) error {
// fmt.Println(u.BMagenta("WS"), "onClose")
if ws.onClose != nil {
@ -462,48 +459,111 @@ func (ws *WS) connect(vm *goja.Runtime) error {
return nil
}
func (ws *WS) Read(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
typ, buf, err := ws.conn.ReadMessage()
if err != nil {
panic(vm.NewGoError(err))
}
if typ == websocket.TextMessage {
return vm.ToValue(string(buf))
} else {
return vm.ToValue(buf)
}
func (ws *WS) PingCount(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
return vm.ToValue(gojs.Map{
"pingTimes": ws.pingTimes,
"pongTimes": ws.pongTimes,
"lastPingTime": ws.lastPingTime,
"lastPongTime": ws.lastPongTime,
})
}
func (ws *WS) ReadJSON(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
var obj interface{}
err := ws.conn.ReadJSON(&obj)
func (ws *WS) Read(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
typ, data, err := readWSMessage(ws.conn)
if err != nil {
panic(vm.NewGoError(err))
}
return vm.ToValue(obj)
return vm.ToValue(gojs.Map{
"type": typ,
"data": data,
})
}
func readWSMessage(client *websocket.Conn) (string, any, error) {
msgType := "close"
var msgData any
typ, data, err := client.ReadMessage()
if err == nil && typ != websocket.CloseMessage {
switch typ {
case websocket.TextMessage:
if err2 := json.Unmarshal(data, &msgData); err2 != nil {
msgData = string(data)
msgType = "text"
} else {
msgType = "json"
}
case websocket.BinaryMessage:
if err2 := json.Unmarshal(data, &msgData); err2 != nil {
msgData = data
msgType = "binary"
} else {
msgType = "json"
}
case websocket.PingMessage:
msgData = string(data)
msgType = "ping"
case websocket.PongMessage:
msgData = string(data)
msgType = "pong"
}
}
return msgType, msgData, err
}
func (ws *WS) writeMessage(typ int, msg []byte) error {
ws.writeLock.Lock()
defer ws.writeLock.Unlock()
if typ == websocket.PingMessage {
ws.pingTimes++
ws.lastPingTime = time.Now().UnixMilli()
}
return ws.conn.WriteMessage(typ, msg)
}
func (ws *WS) Write(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
var err error
ws.writeLock.Lock()
if args.Arguments[0].ExportType().Kind() == reflect.String {
err = ws.conn.WriteMessage(websocket.TextMessage, args.Bytes(0))
} else {
err = ws.conn.WriteMessage(websocket.BinaryMessage, args.Bytes(0))
switch args.Any(0).(type) {
case []byte:
err = ws.writeMessage(websocket.BinaryMessage, args.Bytes(0))
case string:
err = ws.writeMessage(websocket.TextMessage, args.Bytes(0))
default:
err = ws.writeMessage(websocket.TextMessage, u.JsonBytes(args.Any(0)))
}
ws.writeLock.Unlock()
if err != nil {
panic(vm.NewGoError(err))
}
return nil
}
func (ws *WS) WriteJSON(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(1)
ws.writeLock.Lock()
err := ws.conn.WriteJSON(args.Any(0))
ws.writeLock.Unlock()
func (ws *WS) Ping(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
err := ws.writeMessage(websocket.PingMessage, nil)
if err != nil {
panic(vm.NewGoError(err))
}
return nil
}
func (ws *WS) WriteMessage(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
args := gojs.MakeArgs(&argsIn, vm).Check(2)
var err error
switch args.Str(0) {
case "text":
err = ws.writeMessage(websocket.TextMessage, args.Bytes(1))
case "binary":
err = ws.writeMessage(websocket.BinaryMessage, args.Bytes(1))
case "ping":
err = ws.writeMessage(websocket.PingMessage, args.Bytes(1))
case "pong":
err = ws.writeMessage(websocket.PongMessage, args.Bytes(1))
case "close":
err = ws.writeMessage(websocket.CloseMessage, args.Bytes(1))
case "json":
err = ws.writeMessage(websocket.TextMessage, u.JsonBytes(args.Any(1)))
default:
err = ws.writeMessage(websocket.TextMessage, args.Bytes(1))
}
if err != nil {
panic(vm.NewGoError(err))
}

24
http.ts
View File

@ -59,16 +59,28 @@ interface WSConfig {
compress: boolean
onOpen: () => void
onClose: (code: number, data: string) => void
onMessage: (data: any) => void
onJSONMessage: (data: any) => void
onMessage: (type: string, data: any) => void
pingInterval: number
reconnectInterval: number
}
interface WS {
read(): any
readJSON(): any
read: () => WSMessage
write(data: any): void
writeJSON(data: any): void
writeMessage(type: string, data: any): void
ping: () => void
pingCount: () => PingCount
close(): void
}
}
interface PingCount {
pingTimes: number
pongTimes: number
lastPingTime: number
lastPongTime: number
}
interface WSMessage {
type: string
data: string | Object
}

View File

@ -6,20 +6,21 @@ function main() { }
function testSync() {
let conn = http.connect("http://127.0.0.1:18001/ws")
conn.write('111')
if (conn.read() !== '111') {
return false
let r1 = conn.read().data
if (r1 !== 111) {
return r1
}
conn.write(new Uint8Array([0x01, 0x02, 0x03]))
let r2 = conn.read()
let r2 = conn.read().data
if (r2[0] != 1 || r2[1] != 2 || r2[2] != 3) {
return false
return r2
}
conn.writeJSON({ name: 'Tom' })
let r3 = conn.readJSON()
conn.write({ name: 'Tom' })
let r3 = conn.read().data
if (r3.name != 'Tom') {
return false
return r3
}
conn.close()
return true
@ -42,22 +43,22 @@ function testAsync() {
onPong: function (data) {
console.info("onPong", data)
},
onJSONMessage: function (data) {
onMessage: function (type, data) {
// console.info("onJSONMessage", data)
asyncResult += data.name
},
})
asyncConn = conn
conn.writeJSON({ name: 'Tom1' })
conn.writeJSON({ name: 'Tom2' })
conn.writeJSON({ name: 'Tom3' })
conn.write({ name: 'Tom1' })
conn.write({ name: 'Tom2' })
conn.write({ name: 'Tom3' })
}
function testAsync2() {
asyncConn.writeJSON({ name: 'Tom4' })
asyncConn.writeJSON({ name: 'Tom5' })
asyncConn.writeJSON({ name: 'Tom6' })
asyncConn.write({ name: 'Tom4' })
asyncConn.write({ name: 'Tom5' })
asyncConn.write({ name: 'Tom6' })
}
function closeAsync() {