我有一个前端应用程序,它连接到WebSocket并尝试提供json-rpc2以从服务器调用客户端。在使用“github.com/gorilla/websocket”编写的服务器应用程序中,创建*rpc.Client
的最佳方法是什么?我尝试使用*websocket.Conn
的UnderlyingConn()
: jsonrpc2.NewClient(conn.UnderlyingConn())
,但它不起作用。
package jsonrpc2ws
import (
"github.com/powerman/rpc-codec/jsonrpc2"
"github.com/gorilla/websocket"
"encoding/json"
"io"
"sync"
)
func NewClient(ws *websocket.Conn) *jsonrpc2.Client {
c := &client{
ws:ws,
}
c.initRead()
c.initWrite()
return jsonrpc2.NewClient(c)
}
type client struct {
w *io.PipeWriter
r *io.PipeReader
ws *websocket.Conn
err error // io error
mu sync.Mutex // protects err
}
func (x *client) error() (err error) {
x.mu.Lock()
err = x.err
x.mu.Unlock()
return
}
func (x *client) setError (err error) {
x.mu.Lock()
if x.err != nil {
x.err = err
}
x.mu.Unlock()
}
func (x *client) initRead(){
var w *io.PipeWriter
x.r, w = io.Pipe()
go func(){
_,b,err := x.ws.ReadMessage()
for ; x.error() == nil && err == nil; _,b,err = x.ws.ReadMessage(){
_,err = w.Write(b)
}
x.setError(err)
w.Close()
} ()
}
func (x *client) initWrite(){
var r *io.PipeReader
r,x.w = io.Pipe()
go func(){
dec := json.NewDecoder(r)
var b json.RawMessage
err := dec.Decode(&b)
for ; x.error() == nil && err == nil; err = dec.Decode(&b){
err = x.ws.WriteMessage(websocket.TextMessage, b)
}
x.setError(err)
r.Close()
} ()
}
func (x *client) Write(p []byte) (int, error){
if x.error() != nil {
return 0, x.error()
}
return x.w.Write(p)
}
func (x *client) Read(p []byte) (int, error){
if x.error() != nil {
return 0, x.error()
}
return x.r.Read(p)
}
func (x *client) Close() error{
x.ws.Close()
x.w.Close()
x.r.Close()
return nil
}
nhooyr.io/websocket
包的Net.Conn
包装器。
https://pkg.go.dev/nhooyr.io/websocket#NetConn
这是用于通过WebSockets隧道传输任意协议的库。虽然该库的少数用户需要此功能,但正确实现它很棘手,因此在库中提供了此功能。请参见https://github.com/nhooyr/websocket/issues/100以获取更多详细信息。nhooyr/websocket
包对我有用,实际上被golang包推荐。
*rpc.Client
代替。 - fpawel