mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-05-15 06:25:58 +08:00
feat: Integrate Comprehensive E2E Testing for GoChat (#1906)
* feat: create e2e test readme Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> * feat: fix markdown file * feat: add openim make lint * feat: add git chglog pull request * feat: add git chglog pull request * fix: fix openim api err code * fix: fix openim api err code * fix: fix openim api err code * feat: Improve CICD * feat: Combining GitHub and Google Workspace for Effective Project Management' * feat: fix openim tools error code * feat: fix openim tools error code * feat: add openim error handle * feat: add openim error handle * feat: optimize tim white prom code return err * feat: fix openim tools error code * style: format openim server code style * feat: add openim optimize commit code * feat: add openim optimize commit code * feat: add openim auto format code * feat: add openim auto format code * feat: add openim auto format code * feat: add openim auto format code * feat: add openim auto format code * feat: format openim code * feat: Some of the notes were translated * feat: Some of the notes were translated * feat: update openim server code * feat: optimize openim reset code * feat: optimize openim reset code --------- Signed-off-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com>
This commit is contained in:
@@ -91,13 +91,7 @@ type Client struct {
|
||||
// }
|
||||
|
||||
// ResetClient updates the client's state with new connection and context information.
|
||||
func (c *Client) ResetClient(
|
||||
ctx *UserConnContext,
|
||||
conn LongConn,
|
||||
isBackground, isCompress bool,
|
||||
longConnServer LongConnServer,
|
||||
token string,
|
||||
) {
|
||||
func (c *Client) ResetClient(ctx *UserConnContext, conn LongConn, isBackground, isCompress bool, longConnServer LongConnServer, token string) {
|
||||
c.w = new(sync.Mutex)
|
||||
c.conn = conn
|
||||
c.PlatformID = utils.StringToInt(ctx.GetPlatformID())
|
||||
@@ -112,9 +106,11 @@ func (c *Client) ResetClient(
|
||||
c.token = token
|
||||
}
|
||||
|
||||
// pingHandler handles ping messages and sends pong responses.
|
||||
func (c *Client) pingHandler(_ string) error {
|
||||
_ = c.conn.SetReadDeadline(pongWait)
|
||||
if err := c.conn.SetReadDeadline(pongWait); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.writePongMsg()
|
||||
}
|
||||
|
||||
@@ -141,7 +137,8 @@ func (c *Client) readMessage() {
|
||||
}
|
||||
|
||||
log.ZDebug(c.ctx, "readMessage", "messageType", messageType)
|
||||
if c.closed.Load() { // 连接刚置位已经关闭,但是协程还没退出的场景
|
||||
if c.closed.Load() {
|
||||
// The scenario where the connection has just been closed, but the coroutine has not exited
|
||||
c.closedErr = ErrConnClosed
|
||||
return
|
||||
}
|
||||
@@ -185,11 +182,11 @@ func (c *Client) handleMessage(message []byte) error {
|
||||
|
||||
err := c.longConnServer.Decode(message, binaryReq)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.longConnServer.Validate(binaryReq); err != nil {
|
||||
return errs.Wrap(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if binaryReq.SendID != c.UserID {
|
||||
@@ -239,7 +236,7 @@ func (c *Client) setAppBackgroundStatus(ctx context.Context, req *Req) ([]byte,
|
||||
}
|
||||
|
||||
c.IsBackground = isBackground
|
||||
// todo callback
|
||||
// TODO: callback
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -273,7 +270,7 @@ func (c *Client) replyMessage(ctx context.Context, binaryReq *Req, err error, re
|
||||
}
|
||||
|
||||
if binaryReq.ReqIdentifier == WsLogoutMsg {
|
||||
return errors.New("user logout")
|
||||
return errs.Wrap(errors.New("user logout"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -316,17 +313,21 @@ func (c *Client) writeBinaryMsg(resp Resp) error {
|
||||
|
||||
encodedBuf, err := c.longConnServer.Encode(resp)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
return err
|
||||
}
|
||||
|
||||
c.w.Lock()
|
||||
defer c.w.Unlock()
|
||||
|
||||
_ = c.conn.SetWriteDeadline(writeWait)
|
||||
err = c.conn.SetWriteDeadline(writeWait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.IsCompress {
|
||||
resultBuf, compressErr := c.longConnServer.CompressWithPool(encodedBuf)
|
||||
if compressErr != nil {
|
||||
return errs.Wrap(compressErr)
|
||||
return compressErr
|
||||
}
|
||||
return c.conn.WriteMessage(MessageBinary, resultBuf)
|
||||
}
|
||||
@@ -344,7 +345,7 @@ func (c *Client) writePongMsg() error {
|
||||
|
||||
err := c.conn.SetWriteDeadline(writeWait)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return c.conn.WriteMessage(PongMessage, nil)
|
||||
|
||||
@@ -17,7 +17,6 @@ package msggateway
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
@@ -46,12 +45,15 @@ func NewGzipCompressor() *GzipCompressor {
|
||||
func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) {
|
||||
gzipBuffer := bytes.Buffer{}
|
||||
gz := gzip.NewWriter(&gzipBuffer)
|
||||
|
||||
if _, err := gz.Write(rawData); err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
return nil, errs.Wrap(err, "GzipCompressor.Compress: writing to gzip writer failed")
|
||||
}
|
||||
|
||||
if err := gz.Close(); err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
return nil, errs.Wrap(err, "GzipCompressor.Compress: closing gzip writer failed")
|
||||
}
|
||||
|
||||
return gzipBuffer.Bytes(), nil
|
||||
}
|
||||
|
||||
@@ -63,10 +65,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) {
|
||||
gz.Reset(&gzipBuffer)
|
||||
|
||||
if _, err := gz.Write(rawData); err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error writing data")
|
||||
}
|
||||
if err := gz.Close(); err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error closing gzip writer")
|
||||
}
|
||||
return gzipBuffer.Bytes(), nil
|
||||
}
|
||||
@@ -75,32 +77,36 @@ func (g *GzipCompressor) DeCompress(compressedData []byte) ([]byte, error) {
|
||||
buff := bytes.NewBuffer(compressedData)
|
||||
reader, err := gzip.NewReader(buff)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "NewReader failed")
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DeCompress: NewReader creation failed")
|
||||
}
|
||||
compressedData, err = io.ReadAll(reader)
|
||||
decompressedData, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "ReadAll failed")
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DeCompress: reading from gzip reader failed")
|
||||
}
|
||||
_ = reader.Close()
|
||||
return compressedData, nil
|
||||
if err = reader.Close(); err != nil {
|
||||
// Even if closing the reader fails, we've successfully read the data,
|
||||
// so we return the decompressed data and an error indicating the close failure.
|
||||
return decompressedData, errs.Wrap(err, "GzipCompressor.DeCompress: closing gzip reader failed")
|
||||
}
|
||||
return decompressedData, nil
|
||||
}
|
||||
|
||||
func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, error) {
|
||||
reader := gzipReaderPool.Get().(*gzip.Reader)
|
||||
if reader == nil {
|
||||
return nil, errs.Wrap(errors.New("NewReader failed"))
|
||||
}
|
||||
defer gzipReaderPool.Put(reader)
|
||||
|
||||
err := reader.Reset(bytes.NewReader(compressedData))
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "NewReader failed")
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed")
|
||||
}
|
||||
|
||||
compressedData, err = io.ReadAll(reader)
|
||||
decompressedData, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "ReadAll failed")
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed")
|
||||
}
|
||||
_ = reader.Close()
|
||||
return compressedData, nil
|
||||
if err = reader.Close(); err != nil {
|
||||
// Similar to DeCompress, return the data and error for close failure.
|
||||
return decompressedData, errs.Wrap(err, "GzipCompressor.DecompressWithPool: closing pooled gzip reader failed")
|
||||
}
|
||||
return decompressedData, nil
|
||||
}
|
||||
|
||||
@@ -37,10 +37,16 @@ func TestCompressDecompress(t *testing.T) {
|
||||
|
||||
// compress
|
||||
dest, err := compressor.CompressWithPool(src)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// decompress
|
||||
res, err := compressor.DecompressWithPool(dest)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// check
|
||||
@@ -60,10 +66,16 @@ func TestCompressDecompressWithConcurrency(t *testing.T) {
|
||||
|
||||
// compress
|
||||
dest, err := compressor.CompressWithPool(src)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// decompress
|
||||
res, err := compressor.DecompressWithPool(dest)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// check
|
||||
@@ -99,6 +111,7 @@ func BenchmarkDecompress(b *testing.B) {
|
||||
|
||||
compressor := NewGzipCompressor()
|
||||
comdata, err := compressor.Compress(src)
|
||||
|
||||
assert.Equal(b, nil, err)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
||||
@@ -37,7 +37,7 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) {
|
||||
enc := gob.NewEncoder(&buff)
|
||||
err := enc.Encode(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "GobEncoder.Encode failed")
|
||||
}
|
||||
return buff.Bytes(), nil
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error {
|
||||
dec := gob.NewDecoder(buff)
|
||||
err := dec.Decode(decodeData)
|
||||
if err != nil {
|
||||
return errs.Wrap(err)
|
||||
return errs.Wrap(err, "GobEncoder.Decode failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,14 +23,7 @@ import (
|
||||
|
||||
// RunWsAndServer run ws server.
|
||||
func RunWsAndServer(rpcPort, wsPort, prometheusPort int) error {
|
||||
fmt.Println(
|
||||
"start rpc/msg_gateway server, port: ",
|
||||
rpcPort,
|
||||
wsPort,
|
||||
prometheusPort,
|
||||
", OpenIM version: ",
|
||||
config.Version,
|
||||
)
|
||||
fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version)
|
||||
longServer, err := NewWsServer(
|
||||
WithPort(wsPort),
|
||||
WithMaxConnNum(int64(config.Config.LongConnSvr.WebsocketMaxConnNum)),
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
package msggateway
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
@@ -72,7 +74,8 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er
|
||||
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
// The upgrader.Upgrade method usually returns enough error messages to diagnose problems that may occur during the upgrade
|
||||
return errs.Wrap(err, "GenerateLongConn: WebSocket upgrade failed")
|
||||
}
|
||||
d.conn = conn
|
||||
return nil
|
||||
@@ -96,7 +99,16 @@ func (d *GWebSocket) SetReadDeadline(timeout time.Duration) error {
|
||||
}
|
||||
|
||||
func (d *GWebSocket) SetWriteDeadline(timeout time.Duration) error {
|
||||
return d.conn.SetWriteDeadline(time.Now().Add(timeout))
|
||||
// TODO add error
|
||||
if timeout <= 0 {
|
||||
return errs.Wrap(errors.New("timeout must be greater than 0"))
|
||||
}
|
||||
|
||||
// TODO SetWriteDeadline Future add error handling
|
||||
if err := d.conn.SetWriteDeadline(time.Now().Add(timeout)); err != nil {
|
||||
return errs.Wrap(err, "GWebSocket.SetWriteDeadline failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Response, error) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/OpenIMSDK/protocol/push"
|
||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -119,10 +120,10 @@ func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDi
|
||||
func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) {
|
||||
req := sdkws.GetMaxSeqReq{}
|
||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "GetSeq: error unmarshaling request")
|
||||
}
|
||||
if err := g.validate.Struct(&req); err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "GetSeq: validation failed")
|
||||
}
|
||||
resp, err := g.msgRpcClient.GetMaxSeq(context, &req)
|
||||
if err != nil {
|
||||
@@ -130,28 +131,37 @@ func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error)
|
||||
}
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "GetSeq: error marshaling response")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (g GrpcHandler) SendMessage(context context.Context, data *Req) ([]byte, error) {
|
||||
msgData := sdkws.MsgData{}
|
||||
// SendMessage handles the sending of messages through gRPC. It unmarshals the request data,
|
||||
// validates the message, and then sends it using the message RPC client.
|
||||
func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error) {
|
||||
// Unmarshal the message data from the request.
|
||||
var msgData sdkws.MsgData
|
||||
if err := proto.Unmarshal(data.Data, &msgData); err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "error unmarshalling message data")
|
||||
}
|
||||
|
||||
// Validate the message data structure.
|
||||
if err := g.validate.Struct(&msgData); err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "message data validation failed")
|
||||
}
|
||||
|
||||
req := msg.SendMsgReq{MsgData: &msgData}
|
||||
resp, err := g.msgRpcClient.SendMsg(context, &req)
|
||||
|
||||
resp, err := g.msgRpcClient.SendMsg(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "error marshaling response")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
@@ -162,7 +172,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
|
||||
}
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "error marshaling response")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
@@ -170,7 +180,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
|
||||
func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([]byte, error) {
|
||||
req := sdkws.PullMessageBySeqsReq{}
|
||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||
return nil, err
|
||||
return nil, errs.Wrap(err, "error unmarshaling request")
|
||||
}
|
||||
if err := g.validate.Struct(data); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -88,6 +88,7 @@ type WsServer struct {
|
||||
Encoder
|
||||
MessageHandler
|
||||
}
|
||||
|
||||
type kickHandler struct {
|
||||
clientOK bool
|
||||
oldClients []*Client
|
||||
@@ -129,7 +130,9 @@ func (ws *WsServer) UnRegister(c *Client) {
|
||||
}
|
||||
|
||||
func (ws *WsServer) Validate(s any) error {
|
||||
//?question?
|
||||
if s == nil {
|
||||
return errs.Wrap(errors.New("input cannot be nil"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -276,7 +279,7 @@ func (ws *WsServer) registerClient(client *Client) {
|
||||
log.ZDebug(client.ctx, "user exist", "userID", client.UserID, "platformID", client.PlatformID)
|
||||
if clientOK {
|
||||
ws.clients.Set(client.UserID, client)
|
||||
// 已经有同平台的连接存在
|
||||
// There is already a connection to the platform
|
||||
log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID", client.PlatformID, "old remote addr", getRemoteAdders(oldClients))
|
||||
ws.onlineUserConnNum.Add(1)
|
||||
} else {
|
||||
|
||||
@@ -19,15 +19,15 @@ import "time"
|
||||
type (
|
||||
Option func(opt *configs)
|
||||
configs struct {
|
||||
// 长连接监听端口
|
||||
// Long connection listening port
|
||||
port int
|
||||
// 长连接允许最大链接数
|
||||
// Maximum number of connections allowed for long connection
|
||||
maxConnNum int64
|
||||
// 连接握手超时时间
|
||||
// Connection handshake timeout
|
||||
handshakeTimeout time.Duration
|
||||
// 允许消息最大长度
|
||||
// Maximum length allowed for messages
|
||||
messageMaxMsgLength int
|
||||
// websocket write buffer, default: 4096, 4kb.
|
||||
// Websocket write buffer, default: 4096, 4kb.
|
||||
writeBufferSize int
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user