refactor: 3.7.0 code conventions. (#2148)
* Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * feat: add code lint * feat: add code lint * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * Script Refactoring * feat: code format * Script Refactoring * Script Refactoring * Script Refactoring * Adjust MinIO configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: config change. * refactor: webhooks update. * Adjust configuration settings * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * feat: s3 api addr * refactor: webhooks update. * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * Adjust configuration settings * refactor: webhooks update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * refactor: kafka update. * refactor: kafka update. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Simplify the Docker Compose configuration, remove unnecessary environment variables, and eliminate the gateway service. * Windows can compile and run. * Windows can compile and run. * refactor: kafka update. * feat: msg cache split * refactor: webhooks update * refactor: webhooks update * refactor: friends update * refactor: group update * refactor: third update * refactor: api update * refactor: crontab update * refactor: msggateway update * mage * mage * refactor: all module update. * check * refactor: all module update. * load config * load config * load config * load config * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * refactor: all module update. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update tools * update tools * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * update protocol * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: all module update. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * Optimize Docker configuration and script. * refactor: api remove token auth by redis directly. * Code Refactoring * refactor: websocket auth change to call rpc of auth. * refactor: kick online user and remove token change to call auth rpc. * refactor: kick online user and remove token change to call auth rpc. * refactor: remove msggateway redis. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor webhook * refactor: cmd update. * refactor: cmd update. * fix: runtime: goroutine stack exceeds * refactor: cmd update. * refactor notification * refactor notification * refactor * refactor: cmd update. * refactor: cmd update. * refactor * refactor * refactor * protojson * protojson * protojson * go mod * wrapperspb * refactor: cmd update. * refactor: cmd update. * refactor: cmd update. * refactor: context update. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: websocket update info. * refactor: api name change. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: update file * refactor * refactor * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * refactor: debug info. * fix: callback update. * fix: callback update. * refactor * fix: update message. * fix: msg cache timeout. * refactor * refactor * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: push update. * fix: websocket handle error remove when upgrade error. --------- Co-authored-by: skiffer-git <44203734@qq.com> Co-authored-by: Xinwei Xiong (cubxxw) <3293172751nss@gmail.com> Co-authored-by: withchao <993506633@qq.com>
This commit is contained in:
+11
-117
@@ -18,21 +18,17 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/mcontext"
|
||||
cbapi "github.com/openimsdk/open-im-server/v3/pkg/callbackstruct"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/http"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
)
|
||||
|
||||
func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, isAppBackground bool, connID string) error {
|
||||
if !globalConfig.Callback.CallbackUserOnline.Enable {
|
||||
return nil
|
||||
}
|
||||
func (ws *WsServer) webhookAfterUserOnline(ctx context.Context, after *config.AfterConfig, userID string, platformID int, isAppBackground bool, connID string) {
|
||||
req := cbapi.CallbackUserOnlineReq{
|
||||
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
|
||||
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
|
||||
CallbackCommand: cbapi.CallbackUserOnlineCommand,
|
||||
CallbackCommand: cbapi.CallbackAfterUserOnlineCommand,
|
||||
OperationID: mcontext.GetOperationID(ctx),
|
||||
PlatformID: platformID,
|
||||
Platform: constant.PlatformIDToName(platformID),
|
||||
@@ -43,21 +39,14 @@ func CallbackUserOnline(ctx context.Context, globalConfig *config.GlobalConfig,
|
||||
IsAppBackground: isAppBackground,
|
||||
ConnID: connID,
|
||||
}
|
||||
resp := cbapi.CommonCallbackResp{}
|
||||
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, &req, &resp, globalConfig.Callback.CallbackUserOnline); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
ws.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CommonCallbackResp{}, after)
|
||||
}
|
||||
|
||||
func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int, connID string) error {
|
||||
if !globalConfig.Callback.CallbackUserOffline.Enable {
|
||||
return nil
|
||||
}
|
||||
func (ws *WsServer) webhookAfterUserOffline(ctx context.Context, after *config.AfterConfig, userID string, platformID int, connID string) {
|
||||
req := &cbapi.CallbackUserOfflineReq{
|
||||
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
|
||||
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
|
||||
CallbackCommand: cbapi.CallbackUserOfflineCommand,
|
||||
CallbackCommand: cbapi.CallbackAfterUserOfflineCommand,
|
||||
OperationID: mcontext.GetOperationID(ctx),
|
||||
PlatformID: platformID,
|
||||
Platform: constant.PlatformIDToName(platformID),
|
||||
@@ -67,21 +56,14 @@ func CallbackUserOffline(ctx context.Context, globalConfig *config.GlobalConfig,
|
||||
Seq: time.Now().UnixMilli(),
|
||||
ConnID: connID,
|
||||
}
|
||||
resp := &cbapi.CallbackUserOfflineResp{}
|
||||
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
ws.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CallbackUserOfflineResp{}, after)
|
||||
}
|
||||
|
||||
func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig, userID string, platformID int) error {
|
||||
if !globalConfig.Callback.CallbackUserKickOff.Enable {
|
||||
return nil
|
||||
}
|
||||
func (ws *WsServer) webhookAfterUserKickOff(ctx context.Context, after *config.AfterConfig, userID string, platformID int) {
|
||||
req := &cbapi.CallbackUserKickOffReq{
|
||||
UserStatusCallbackReq: cbapi.UserStatusCallbackReq{
|
||||
UserStatusBaseCallback: cbapi.UserStatusBaseCallback{
|
||||
CallbackCommand: cbapi.CallbackUserKickOffCommand,
|
||||
CallbackCommand: cbapi.CallbackAfterUserKickOffCommand,
|
||||
OperationID: mcontext.GetOperationID(ctx),
|
||||
PlatformID: platformID,
|
||||
Platform: constant.PlatformIDToName(platformID),
|
||||
@@ -90,93 +72,5 @@ func CallbackUserKickOff(ctx context.Context, globalConfig *config.GlobalConfig,
|
||||
},
|
||||
Seq: time.Now().UnixMilli(),
|
||||
}
|
||||
resp := &cbapi.CommonCallbackResp{}
|
||||
if err := http.CallBackPostReturn(ctx, globalConfig.Callback.CallbackUrl, req, resp, globalConfig.Callback.CallbackUserOffline); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
ws.webhookClient.AsyncPost(ctx, req.GetCallbackCommand(), req, &cbapi.CommonCallbackResp{}, after)
|
||||
}
|
||||
|
||||
// func callbackUserOnline(operationID, userID string, platformID int, token string, isAppBackground bool, connID
|
||||
// string) cbApi.CommonCallbackResp {
|
||||
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
||||
// if !config.Config.Callback.CallbackUserOnline.WithEnable {
|
||||
// return callbackResp
|
||||
// }
|
||||
// callbackUserOnlineReq := cbApi.CallbackUserOnlineReq{
|
||||
// Token: token,
|
||||
// UserStatusCallbackReq: cbApi.UserStatusCallbackReq{
|
||||
// UserStatusBaseCallback: cbApi.UserStatusBaseCallback{
|
||||
// CallbackCommand: constant.CallbackUserOnlineCommand,
|
||||
// OperationID: operationID,
|
||||
// PlatformID: int32(platformID),
|
||||
// Platform: constant.PlatformIDToName(platformID),
|
||||
// },
|
||||
// UserID: userID,
|
||||
// },
|
||||
// Seq: int(time.Now().UnixNano() / 1e6),
|
||||
// IsAppBackground: isAppBackground,
|
||||
// ConnID: connID,
|
||||
// }
|
||||
// callbackUserOnlineResp := &cbApi.CallbackUserOnlineResp{CommonCallbackResp: &callbackResp}
|
||||
// if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, constant.CallbackUserOnlineCommand,
|
||||
// callbackUserOnlineReq, callbackUserOnlineResp, config.Config.Callback.CallbackUserOnline.CallbackTimeOut); err != nil
|
||||
// {
|
||||
// callbackResp.ErrCode = http2.StatusInternalServerError
|
||||
// callbackResp.ErrMsg = err.Error()
|
||||
// }
|
||||
// return callbackResp
|
||||
//}
|
||||
//func callbackUserOffline(operationID, userID string, platformID int, connID string) cbApi.CommonCallbackResp {
|
||||
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
||||
// if !config.Config.Callback.CallbackUserOffline.WithEnable {
|
||||
// return callbackResp
|
||||
// }
|
||||
// callbackOfflineReq := cbApi.CallbackUserOfflineReq{
|
||||
// UserStatusCallbackReq: cbApi.UserStatusCallbackReq{
|
||||
// UserStatusBaseCallback: cbApi.UserStatusBaseCallback{
|
||||
// CallbackCommand: constant.CallbackUserOfflineCommand,
|
||||
// OperationID: operationID,
|
||||
// PlatformID: int32(platformID),
|
||||
// Platform: constant.PlatformIDToName(platformID),
|
||||
// },
|
||||
// UserID: userID,
|
||||
// },
|
||||
// Seq: int(time.Now().UnixNano() / 1e6),
|
||||
// ConnID: connID,
|
||||
// }
|
||||
// callbackUserOfflineResp := &cbApi.CallbackUserOfflineResp{CommonCallbackResp: &callbackResp}
|
||||
// if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, constant.CallbackUserOfflineCommand,
|
||||
// callbackOfflineReq, callbackUserOfflineResp, config.Config.Callback.CallbackUserOffline.CallbackTimeOut); err != nil
|
||||
// {
|
||||
// callbackResp.ErrCode = http2.StatusInternalServerError
|
||||
// callbackResp.ErrMsg = err.Error()
|
||||
// }
|
||||
// return callbackResp
|
||||
//}
|
||||
//func callbackUserKickOff(operationID string, userID string, platformID int) cbApi.CommonCallbackResp {
|
||||
// callbackResp := cbApi.CommonCallbackResp{OperationID: operationID}
|
||||
// if !config.Config.Callback.CallbackUserKickOff.WithEnable {
|
||||
// return callbackResp
|
||||
// }
|
||||
// callbackUserKickOffReq := cbApi.CallbackUserKickOffReq{
|
||||
// UserStatusCallbackReq: cbApi.UserStatusCallbackReq{
|
||||
// UserStatusBaseCallback: cbApi.UserStatusBaseCallback{
|
||||
// CallbackCommand: constant.CallbackUserKickOffCommand,
|
||||
// OperationID: operationID,
|
||||
// PlatformID: int32(platformID),
|
||||
// Platform: constant.PlatformIDToName(platformID),
|
||||
// },
|
||||
// UserID: userID,
|
||||
// },
|
||||
// Seq: int(time.Now().UnixNano() / 1e6),
|
||||
// }
|
||||
// callbackUserKickOffResp := &cbApi.CallbackUserKickOffResp{CommonCallbackResp: &callbackResp}
|
||||
// if err := http.CallBackPostReturn(ctx, config.Config.Callback.CallbackUrl, constant.CallbackUserKickOffCommand,
|
||||
// callbackUserKickOffReq, callbackUserKickOffResp, config.Config.Callback.CallbackUserOffline.CallbackTimeOut); err !=
|
||||
// nil {
|
||||
// callbackResp.ErrCode = http2.StatusInternalServerError
|
||||
// callbackResp.ErrMsg = err.Error()
|
||||
// }
|
||||
// return callbackResp
|
||||
//}
|
||||
|
||||
@@ -16,28 +16,27 @@ package msggateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/OpenIMSDK/tools/apiresp"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/mcontext"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/msgprocessor"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrConnClosed = errors.New("conn has closed")
|
||||
ErrNotSupportMessageProtocol = errors.New("not support message protocol")
|
||||
ErrClientClosed = errors.New("client actively close the connection")
|
||||
ErrPanic = errors.New("panic error")
|
||||
ErrConnClosed = errs.New("conn has closed")
|
||||
ErrNotSupportMessageProtocol = errs.New("not support message protocol")
|
||||
ErrClientClosed = errs.New("client actively close the connection")
|
||||
ErrPanic = errs.New("panic error")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -75,32 +74,20 @@ type Client struct {
|
||||
token string
|
||||
}
|
||||
|
||||
// function not used
|
||||
// func newClient(ctx *UserConnContext, conn LongConn, isCompress bool) *Client {
|
||||
// return &Client{
|
||||
// w: new(sync.Mutex),
|
||||
// conn: conn,
|
||||
// PlatformID: utils.StringToInt(ctx.GetPlatformID()),
|
||||
// IsCompress: isCompress,
|
||||
// UserID: ctx.GetUserID(),
|
||||
// ctx: ctx,
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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, longConnServer LongConnServer) {
|
||||
c.w = new(sync.Mutex)
|
||||
c.conn = conn
|
||||
c.PlatformID = utils.StringToInt(ctx.GetPlatformID())
|
||||
c.IsCompress = isCompress
|
||||
c.IsBackground = isBackground
|
||||
c.PlatformID = stringutil.StringToInt(ctx.GetPlatformID())
|
||||
c.IsCompress = ctx.GetCompression()
|
||||
c.IsBackground = ctx.GetBackground()
|
||||
c.UserID = ctx.GetUserID()
|
||||
c.ctx = ctx
|
||||
c.longConnServer = longConnServer
|
||||
c.IsBackground = false
|
||||
c.closed.Store(false)
|
||||
c.closedErr = nil
|
||||
c.token = token
|
||||
c.token = ctx.GetToken()
|
||||
}
|
||||
|
||||
func (c *Client) pingHandler(_ string) error {
|
||||
@@ -126,6 +113,7 @@ func (c *Client) readMessage() {
|
||||
c.conn.SetPingHandler(c.pingHandler)
|
||||
|
||||
for {
|
||||
log.ZDebug(c.ctx, "readMessage")
|
||||
messageType, message, returnErr := c.conn.ReadMessage()
|
||||
if returnErr != nil {
|
||||
log.ZWarn(c.ctx, "readMessage", returnErr, "messageType", messageType)
|
||||
@@ -187,7 +175,7 @@ func (c *Client) handleMessage(message []byte) error {
|
||||
}
|
||||
|
||||
if binaryReq.SendID != c.UserID {
|
||||
return errs.Wrap(errors.New("exception conn userID not same to req userID"), binaryReq.String())
|
||||
return errs.New("exception conn userID not same to req userID", "binaryReq", binaryReq.String())
|
||||
}
|
||||
|
||||
ctx := mcontext.WithMustInfoCtx(
|
||||
@@ -267,7 +255,7 @@ func (c *Client) replyMessage(ctx context.Context, binaryReq *Req, err error, re
|
||||
}
|
||||
|
||||
if binaryReq.ReqIdentifier == WsLogoutMsg {
|
||||
return errs.Wrap(errors.New("user logout"))
|
||||
return errs.New("user logout", "operationID", binaryReq.OperationID).Wrap()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -34,6 +34,7 @@ type Compressor interface {
|
||||
DeCompress(compressedData []byte) ([]byte, error)
|
||||
DecompressWithPool(compressedData []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type GzipCompressor struct {
|
||||
compressProtocol string
|
||||
}
|
||||
@@ -47,11 +48,11 @@ func (g *GzipCompressor) Compress(rawData []byte) ([]byte, error) {
|
||||
gz := gzip.NewWriter(&gzipBuffer)
|
||||
|
||||
if _, err := gz.Write(rawData); err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.Compress: writing to gzip writer failed")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.Compress: writing to gzip writer failed")
|
||||
}
|
||||
|
||||
if err := gz.Close(); err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.Compress: closing gzip writer failed")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.Compress: closing gzip writer failed")
|
||||
}
|
||||
|
||||
return gzipBuffer.Bytes(), nil
|
||||
@@ -65,10 +66,10 @@ func (g *GzipCompressor) CompressWithPool(rawData []byte) ([]byte, error) {
|
||||
gz.Reset(&gzipBuffer)
|
||||
|
||||
if _, err := gz.Write(rawData); err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error writing data")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.CompressWithPool: error writing data")
|
||||
}
|
||||
if err := gz.Close(); err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.CompressWithPool: error closing gzip writer")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.CompressWithPool: error closing gzip writer")
|
||||
}
|
||||
return gzipBuffer.Bytes(), nil
|
||||
}
|
||||
@@ -77,16 +78,16 @@ 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, "GzipCompressor.DeCompress: NewReader creation failed")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.DeCompress: NewReader creation failed")
|
||||
}
|
||||
decompressedData, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DeCompress: reading from gzip reader failed")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.DeCompress: reading from gzip reader failed")
|
||||
}
|
||||
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, errs.WrapMsg(err, "GzipCompressor.DeCompress: closing gzip reader failed")
|
||||
}
|
||||
return decompressedData, nil
|
||||
}
|
||||
@@ -97,16 +98,16 @@ func (g *GzipCompressor) DecompressWithPool(compressedData []byte) ([]byte, erro
|
||||
|
||||
err := reader.Reset(bytes.NewReader(compressedData))
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.DecompressWithPool: resetting gzip reader failed")
|
||||
}
|
||||
|
||||
decompressedData, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed")
|
||||
return nil, errs.WrapMsg(err, "GzipCompressor.DecompressWithPool: reading from pooled gzip reader failed")
|
||||
}
|
||||
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, errs.WrapMsg(err, "GzipCompressor.DecompressWithPool: closing pooled gzip reader failed")
|
||||
}
|
||||
return decompressedData, nil
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ const (
|
||||
Compression = "compression"
|
||||
GzipCompressionProtocol = "gzip"
|
||||
BackgroundStatus = "isBackground"
|
||||
MsgResp = "isMsgResp"
|
||||
SendResponse = "isMsgResp"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
package msggateway
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/tools/utils/encrypt"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"github.com/openimsdk/tools/utils/timeutil"
|
||||
)
|
||||
|
||||
type UserConnContext struct {
|
||||
@@ -54,7 +57,7 @@ func (c *UserConnContext) Value(key any) any {
|
||||
case constant.ConnID:
|
||||
return c.GetConnID()
|
||||
case constant.OpUserPlatform:
|
||||
return constant.PlatformIDToName(utils.StringToInt(c.GetPlatformID()))
|
||||
return constant.PlatformIDToName(stringutil.StringToInt(c.GetPlatformID()))
|
||||
case constant.RemoteAddr:
|
||||
return c.RemoteAddr
|
||||
default:
|
||||
@@ -69,7 +72,7 @@ func newContext(respWriter http.ResponseWriter, req *http.Request) *UserConnCont
|
||||
Path: req.URL.Path,
|
||||
Method: req.Method,
|
||||
RemoteAddr: req.RemoteAddr,
|
||||
ConnID: utils.Md5(req.RemoteAddr + "_" + strconv.Itoa(int(utils.GetCurrentTimestampByMill()))),
|
||||
ConnID: encrypt.Md5(req.RemoteAddr + "_" + strconv.Itoa(int(timeutil.GetCurrentTimestampByMill()))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +136,32 @@ func (c *UserConnContext) GetToken() string {
|
||||
return c.Req.URL.Query().Get(Token)
|
||||
}
|
||||
|
||||
func (c *UserConnContext) GetCompression() bool {
|
||||
compression, exists := c.Query(Compression)
|
||||
if exists && compression == GzipCompressionProtocol {
|
||||
return true
|
||||
} else {
|
||||
compression, exists := c.GetHeader(Compression)
|
||||
if exists && compression == GzipCompressionProtocol {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *UserConnContext) ShouldSendResp() bool {
|
||||
errResp, exists := c.Query(SendResponse)
|
||||
if exists {
|
||||
b, err := strconv.ParseBool(errResp)
|
||||
if err != nil {
|
||||
return false
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *UserConnContext) SetToken(token string) {
|
||||
c.Req.URL.RawQuery = Token + "=" + token
|
||||
}
|
||||
@@ -144,3 +173,23 @@ func (c *UserConnContext) GetBackground() bool {
|
||||
}
|
||||
return b
|
||||
}
|
||||
func (c *UserConnContext) ParseEssentialArgs() error {
|
||||
_, exists := c.Query(Token)
|
||||
if !exists {
|
||||
return servererrs.ErrConnArgsErr.WrapMsg("token is empty")
|
||||
}
|
||||
_, exists = c.Query(WsUserID)
|
||||
if !exists {
|
||||
return servererrs.ErrConnArgsErr.WrapMsg("sendID is empty")
|
||||
}
|
||||
platformIDStr, exists := c.Query(PlatformID)
|
||||
if !exists {
|
||||
return servererrs.ErrConnArgsErr.WrapMsg("platformID is empty")
|
||||
}
|
||||
_, err := strconv.Atoi(platformIDStr)
|
||||
if err != nil {
|
||||
return servererrs.ErrConnArgsErr.WrapMsg("platformID is not int")
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
type Encoder interface {
|
||||
@@ -35,9 +35,8 @@ func NewGobEncoder() *GobEncoder {
|
||||
func (g *GobEncoder) Encode(data any) ([]byte, error) {
|
||||
buff := bytes.Buffer{}
|
||||
enc := gob.NewEncoder(&buff)
|
||||
err := enc.Encode(data)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "GobEncoder.Encode failed")
|
||||
if err := enc.Encode(data); err != nil {
|
||||
return nil, errs.WrapMsg(err, "GobEncoder.Encode failed", "action", "encode")
|
||||
}
|
||||
return buff.Bytes(), nil
|
||||
}
|
||||
@@ -45,9 +44,8 @@ func (g *GobEncoder) Encode(data any) ([]byte, error) {
|
||||
func (g *GobEncoder) Decode(encodeData []byte, decodeData any) error {
|
||||
buff := bytes.NewBuffer(encodeData)
|
||||
dec := gob.NewDecoder(buff)
|
||||
err := dec.Decode(decodeData)
|
||||
if err != nil {
|
||||
return errs.Wrap(err, "GobEncoder.Decode failed")
|
||||
if err := dec.Decode(decodeData); err != nil {
|
||||
return errs.WrapMsg(err, "GobEncoder.Decode failed", "action", "decode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
|
||||
package msggateway
|
||||
|
||||
import "github.com/OpenIMSDK/tools/apiresp"
|
||||
import (
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
func httpError(ctx *UserConnContext, err error) {
|
||||
log.ZWarn(ctx, "ws connection error", err)
|
||||
apiresp.HttpError(ctx.RespWriter, err)
|
||||
}
|
||||
|
||||
@@ -16,38 +16,30 @@ package msggateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/protocol/msggateway"
|
||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/mcontext"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/startrpc"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/msggateway"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func (s *Server) InitServer(config *config.GlobalConfig, disCov discoveryregistry.SvcDiscoveryRegistry, server *grpc.Server) error {
|
||||
rdb, err := cache.NewRedis(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgModel := cache.NewMsgCacheModel(rdb, config)
|
||||
func (s *Server) InitServer(ctx context.Context, config *Config, disCov discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
|
||||
s.LongConnServer.SetDiscoveryRegistry(disCov, config)
|
||||
s.LongConnServer.SetCacheHandler(msgModel)
|
||||
msggateway.RegisterMsgGatewayServer(server, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Start(conf *config.GlobalConfig) error {
|
||||
return startrpc.Start(
|
||||
s.rpcPort,
|
||||
conf.RpcRegisterName.OpenImMessageGatewayName,
|
||||
s.prometheusPort,
|
||||
func (s *Server) Start(ctx context.Context, index int, conf *Config) error {
|
||||
return startrpc.Start(ctx, &conf.ZookeeperConfig, &conf.MsgGateway.Prometheus, conf.MsgGateway.ListenIP,
|
||||
conf.MsgGateway.RPC.RegisterIP,
|
||||
conf.MsgGateway.RPC.Ports, index,
|
||||
conf.Share.RpcRegisterName.MessageGateway,
|
||||
&conf.Share,
|
||||
conf,
|
||||
s.InitServer,
|
||||
)
|
||||
@@ -57,7 +49,7 @@ type Server struct {
|
||||
rpcPort int
|
||||
prometheusPort int
|
||||
LongConnServer LongConnServer
|
||||
config *config.GlobalConfig
|
||||
config *Config
|
||||
pushTerminal map[int]struct{}
|
||||
}
|
||||
|
||||
@@ -65,7 +57,7 @@ func (s *Server) SetLongConnServer(LongConnServer LongConnServer) {
|
||||
s.LongConnServer = LongConnServer
|
||||
}
|
||||
|
||||
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *config.GlobalConfig) *Server {
|
||||
func NewServer(rpcPort int, proPort int, longConnServer LongConnServer, conf *Config) *Server {
|
||||
s := &Server{
|
||||
rpcPort: rpcPort,
|
||||
prometheusPort: proPort,
|
||||
@@ -89,8 +81,8 @@ func (s *Server) GetUsersOnlineStatus(
|
||||
ctx context.Context,
|
||||
req *msggateway.GetUsersOnlineStatusReq,
|
||||
) (*msggateway.GetUsersOnlineStatusResp, error) {
|
||||
if !authverify.IsAppManagerUid(ctx, s.config) {
|
||||
return nil, errs.ErrNoPermission.Wrap("only app manager")
|
||||
if !authverify.IsAppManagerUid(ctx, s.config.Share.IMAdminUserID) {
|
||||
return nil, errs.ErrNoPermission.WrapMsg("only app manager")
|
||||
}
|
||||
var resp msggateway.GetUsersOnlineStatusResp
|
||||
for _, userID := range req.UserIDs {
|
||||
@@ -122,11 +114,9 @@ func (s *Server) GetUsersOnlineStatus(
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (s *Server) OnlineBatchPushOneMsg(
|
||||
ctx context.Context,
|
||||
req *msggateway.OnlineBatchPushOneMsgReq,
|
||||
) (*msggateway.OnlineBatchPushOneMsgResp, error) {
|
||||
panic("implement me")
|
||||
func (s *Server) OnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq) (*msggateway.OnlineBatchPushOneMsgResp, error) {
|
||||
// todo implement
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msggateway.OnlineBatchPushOneMsgReq,
|
||||
@@ -158,7 +148,7 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msgga
|
||||
(client.IsBackground && client.PlatformID != constant.IOSPlatformID) {
|
||||
err := client.PushMessage(ctx, req.MsgData)
|
||||
if err != nil {
|
||||
userPlatform.ResultCode = int64(errs.ErrPushMsgErr.Code())
|
||||
userPlatform.ResultCode = int64(servererrs.ErrPushMsgErr.Code())
|
||||
resp = append(resp, userPlatform)
|
||||
} else {
|
||||
if _, ok := s.pushTerminal[client.PlatformID]; ok {
|
||||
@@ -167,7 +157,7 @@ func (s *Server) SuperGroupOnlineBatchPushOneMsg(ctx context.Context, req *msgga
|
||||
}
|
||||
}
|
||||
} else {
|
||||
userPlatform.ResultCode = int64(errs.ErrIOSBackgroundPushErr.Code())
|
||||
userPlatform.ResultCode = int64(servererrs.ErrIOSBackgroundPushErr.Code())
|
||||
resp = append(resp, userPlatform)
|
||||
}
|
||||
}
|
||||
@@ -187,7 +177,7 @@ func (s *Server) KickUserOffline(
|
||||
for _, v := range req.KickUserIDList {
|
||||
clients, _, ok := s.LongConnServer.GetUserPlatformCons(v, int(req.PlatformID))
|
||||
if !ok {
|
||||
log.ZInfo(ctx, "conn not exist", "userID", v, "platformID", req.PlatformID)
|
||||
log.ZDebug(ctx, "conn not exist", "userID", v, "platformID", req.PlatformID)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -203,10 +193,7 @@ func (s *Server) KickUserOffline(
|
||||
return &msggateway.KickUserOfflineResp{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) MultiTerminalLoginCheck(
|
||||
ctx context.Context,
|
||||
req *msggateway.MultiTerminalLoginCheckReq,
|
||||
) (*msggateway.MultiTerminalLoginCheckResp, error) {
|
||||
func (s *Server) MultiTerminalLoginCheck(ctx context.Context, req *msggateway.MultiTerminalLoginCheckReq) (*msggateway.MultiTerminalLoginCheckResp, error) {
|
||||
if oldClients, userOK, clientOK := s.LongConnServer.GetUserPlatformCons(req.UserID, int(req.PlatformID)); userOK {
|
||||
tempUserCtx := newTempContext()
|
||||
tempUserCtx.SetToken(req.Token)
|
||||
|
||||
+31
-10
@@ -15,22 +15,43 @@
|
||||
package msggateway
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
// RunWsAndServer run ws server.
|
||||
func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort int) error {
|
||||
fmt.Println("start rpc/msg_gateway server, port: ", rpcPort, wsPort, prometheusPort, ", OpenIM version: ", config.Version)
|
||||
type Config struct {
|
||||
MsgGateway config.MsgGateway
|
||||
ZookeeperConfig config.ZooKeeper
|
||||
Share config.Share
|
||||
WebhooksConfig config.Webhooks
|
||||
}
|
||||
|
||||
// Start run ws server.
|
||||
func Start(ctx context.Context, index int, conf *Config) error {
|
||||
log.CInfo(ctx, "MSG-GATEWAY server is initializing", "rpcPorts", conf.MsgGateway.RPC.Ports,
|
||||
"wsPort", conf.MsgGateway.LongConnSvr.Ports, "prometheusPorts", conf.MsgGateway.Prometheus.Ports)
|
||||
wsPort, err := datautil.GetElemByIndex(conf.MsgGateway.LongConnSvr.Ports, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prometheusPort, err := datautil.GetElemByIndex(conf.MsgGateway.Prometheus.Ports, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rpcPort, err := datautil.GetElemByIndex(conf.MsgGateway.RPC.Ports, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
longServer, err := NewWsServer(
|
||||
conf,
|
||||
WithPort(wsPort),
|
||||
WithMaxConnNum(int64(conf.LongConnSvr.WebsocketMaxConnNum)),
|
||||
WithHandshakeTimeout(time.Duration(conf.LongConnSvr.WebsocketTimeout)*time.Second),
|
||||
WithMessageMaxMsgLength(conf.LongConnSvr.WebsocketMaxMsgLen),
|
||||
WithWriteBufferSize(conf.LongConnSvr.WebsocketWriteBufferSize),
|
||||
WithMaxConnNum(int64(conf.MsgGateway.LongConnSvr.WebsocketMaxConnNum)),
|
||||
WithHandshakeTimeout(time.Duration(conf.MsgGateway.LongConnSvr.WebsocketTimeout)*time.Second),
|
||||
WithMessageMaxMsgLength(conf.MsgGateway.LongConnSvr.WebsocketMaxMsgLen),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -39,7 +60,7 @@ func RunWsAndServer(conf *config.GlobalConfig, rpcPort, wsPort, prometheusPort i
|
||||
hubServer := NewServer(rpcPort, prometheusPort, longServer, conf)
|
||||
netDone := make(chan error)
|
||||
go func() {
|
||||
err = hubServer.Start(conf)
|
||||
err = hubServer.Start(ctx, index, conf)
|
||||
netDone <- err
|
||||
}()
|
||||
return hubServer.LongConnServer.Run(netDone)
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
package msggateway
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"encoding/json"
|
||||
"github.com/openimsdk/tools/apiresp"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
)
|
||||
|
||||
type LongConn interface {
|
||||
@@ -75,7 +76,7 @@ func (d *GWebSocket) GenerateLongConn(w http.ResponseWriter, r *http.Request) er
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
// 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")
|
||||
return errs.WrapMsg(err, "GenerateLongConn: WebSocket upgrade failed")
|
||||
}
|
||||
d.conn = conn
|
||||
return nil
|
||||
@@ -86,7 +87,7 @@ func (d *GWebSocket) WriteMessage(messageType int, message []byte) error {
|
||||
return d.conn.WriteMessage(messageType, message)
|
||||
}
|
||||
|
||||
//func (d *GWebSocket) setSendConn(sendConn *websocket.Conn) {
|
||||
// func (d *GWebSocket) setSendConn(sendConn *websocket.Conn) {
|
||||
// d.sendConn = sendConn
|
||||
//}
|
||||
|
||||
@@ -99,24 +100,24 @@ func (d *GWebSocket) SetReadDeadline(timeout time.Duration) error {
|
||||
}
|
||||
|
||||
func (d *GWebSocket) SetWriteDeadline(timeout time.Duration) error {
|
||||
// TODO add error
|
||||
if timeout <= 0 {
|
||||
return errs.Wrap(errors.New("timeout must be greater than 0"))
|
||||
return errs.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 errs.WrapMsg(err, "GWebSocket.SetWriteDeadline failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *GWebSocket) Dial(urlStr string, requestHeader http.Header) (*http.Response, error) {
|
||||
conn, httpResp, err := websocket.DefaultDialer.Dial(urlStr, requestHeader)
|
||||
if err == nil {
|
||||
d.conn = conn
|
||||
if err != nil {
|
||||
return httpResp, errs.WrapMsg(err, "GWebSocket.Dial failed", "url", urlStr)
|
||||
}
|
||||
return httpResp, err
|
||||
d.conn = conn
|
||||
return httpResp, nil
|
||||
}
|
||||
|
||||
func (d *GWebSocket) IsNil() bool {
|
||||
@@ -144,6 +145,34 @@ func (d *GWebSocket) SetPingHandler(handler PingPongHandler) {
|
||||
d.conn.SetPingHandler(handler)
|
||||
}
|
||||
|
||||
//func (d *GWebSocket) CheckSendConnDiffNow() bool {
|
||||
// return d.conn == d.sendConn
|
||||
//}
|
||||
func (d *GWebSocket) RespondWithError(err error, w http.ResponseWriter, r *http.Request) error {
|
||||
if err := d.GenerateLongConn(w, r); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(apiresp.ParseError(err))
|
||||
if err != nil {
|
||||
_ = d.Close()
|
||||
return errs.WrapMsg(err, "json marshal failed")
|
||||
}
|
||||
|
||||
if err := d.WriteMessage(MessageText, data); err != nil {
|
||||
_ = d.Close()
|
||||
return errs.WrapMsg(err, "WriteMessage failed")
|
||||
}
|
||||
_ = d.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *GWebSocket) RespondWithSuccess() error {
|
||||
data, err := json.Marshal(apiresp.ParseError(nil))
|
||||
if err != nil {
|
||||
_ = d.Close()
|
||||
return errs.WrapMsg(err, "json marshal failed")
|
||||
}
|
||||
|
||||
if err := d.WriteMessage(MessageText, data); err != nil {
|
||||
_ = d.Close()
|
||||
return errs.WrapMsg(err, "WriteMessage failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,15 +18,15 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/msg"
|
||||
"github.com/OpenIMSDK/protocol/push"
|
||||
"github.com/OpenIMSDK/protocol/sdkws"
|
||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/protocol/push"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/utils/jsonutil"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -46,7 +46,7 @@ func (r *Req) String() string {
|
||||
tReq.SendID = r.SendID
|
||||
tReq.OperationID = r.OperationID
|
||||
tReq.MsgIncr = r.MsgIncr
|
||||
return utils.StructToJsonString(tReq)
|
||||
return jsonutil.StructToJsonString(tReq)
|
||||
}
|
||||
|
||||
var reqPool = sync.Pool{
|
||||
@@ -86,7 +86,7 @@ func (r *Resp) String() string {
|
||||
tResp.OperationID = r.OperationID
|
||||
tResp.ErrCode = r.ErrCode
|
||||
tResp.ErrMsg = r.ErrMsg
|
||||
return utils.StructToJsonString(tResp)
|
||||
return jsonutil.StructToJsonString(tResp)
|
||||
}
|
||||
|
||||
type MessageHandler interface {
|
||||
@@ -106,30 +106,30 @@ type GrpcHandler struct {
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
func NewGrpcHandler(validate *validator.Validate, client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) *GrpcHandler {
|
||||
msgRpcClient := rpcclient.NewMessageRpcClient(client, config)
|
||||
pushRpcClient := rpcclient.NewPushRpcClient(client, config)
|
||||
func NewGrpcHandler(validate *validator.Validate, client discovery.SvcDiscoveryRegistry, rpcRegisterName *config.RpcRegisterName) *GrpcHandler {
|
||||
msgRpcClient := rpcclient.NewMessageRpcClient(client, rpcRegisterName.Msg)
|
||||
pushRpcClient := rpcclient.NewPushRpcClient(client, rpcRegisterName.Push)
|
||||
return &GrpcHandler{
|
||||
msgRpcClient: &msgRpcClient,
|
||||
pushClient: &pushRpcClient, validate: validate,
|
||||
}
|
||||
}
|
||||
|
||||
func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error) {
|
||||
func (g GrpcHandler) GetSeq(ctx context.Context, data *Req) ([]byte, error) {
|
||||
req := sdkws.GetMaxSeqReq{}
|
||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||
return nil, errs.Wrap(err, "GetSeq: error unmarshaling request")
|
||||
return nil, errs.WrapMsg(err, "GetSeq: error unmarshaling request", "action", "unmarshal", "dataType", "GetMaxSeqReq")
|
||||
}
|
||||
if err := g.validate.Struct(&req); err != nil {
|
||||
return nil, errs.Wrap(err, "GetSeq: validation failed")
|
||||
return nil, errs.WrapMsg(err, "GetSeq: validation failed", "action", "validate", "dataType", "GetMaxSeqReq")
|
||||
}
|
||||
resp, err := g.msgRpcClient.GetMaxSeq(context, &req)
|
||||
resp, err := g.msgRpcClient.GetMaxSeq(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "GetSeq: error marshaling response")
|
||||
return nil, errs.WrapMsg(err, "GetSeq: error marshaling response", "action", "marshal", "dataType", "GetMaxSeqResp")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
@@ -137,19 +137,16 @@ func (g GrpcHandler) GetSeq(context context.Context, data *Req) ([]byte, error)
|
||||
// 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, errs.Wrap(err, "error unmarshalling message data")
|
||||
return nil, errs.WrapMsg(err, "SendMessage: error unmarshaling message data", "action", "unmarshal", "dataType", "MsgData")
|
||||
}
|
||||
|
||||
// Validate the message data structure.
|
||||
if err := g.validate.Struct(&msgData); err != nil {
|
||||
return nil, errs.Wrap(err, "message data validation failed")
|
||||
return nil, errs.WrapMsg(err, "SendMessage: message data validation failed", "action", "validate", "dataType", "MsgData")
|
||||
}
|
||||
|
||||
req := msg.SendMsgReq{MsgData: &msgData}
|
||||
|
||||
resp, err := g.msgRpcClient.SendMsg(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -157,7 +154,7 @@ func (g GrpcHandler) SendMessage(ctx context.Context, data *Req) ([]byte, error)
|
||||
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "error marshaling response")
|
||||
return nil, errs.WrapMsg(err, "SendMessage: error marshaling response", "action", "marshal", "dataType", "SendMsgResp")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
@@ -170,7 +167,7 @@ func (g GrpcHandler) SendSignalMessage(context context.Context, data *Req) ([]by
|
||||
}
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "error marshaling response")
|
||||
return nil, errs.WrapMsg(err, "error marshaling response", "action", "marshal", "dataType", "SendMsgResp")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
@@ -178,10 +175,10 @@ 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, errs.Wrap(err, "error unmarshaling request")
|
||||
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "PullMessageBySeqsReq")
|
||||
}
|
||||
if err := g.validate.Struct(data); err != nil {
|
||||
return nil, errs.Wrap(err, "validation failed")
|
||||
return nil, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "PullMessageBySeqsReq")
|
||||
}
|
||||
resp, err := g.msgRpcClient.PullMessageBySeqList(context, &req)
|
||||
if err != nil {
|
||||
@@ -189,7 +186,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
|
||||
}
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "error marshaling response")
|
||||
return nil, errs.WrapMsg(err, "error marshaling response", "action", "marshal", "dataType", "PullMessageBySeqsResp")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
@@ -197,7 +194,7 @@ func (g GrpcHandler) PullMessageBySeqList(context context.Context, data *Req) ([
|
||||
func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, error) {
|
||||
req := push.DelUserPushTokenReq{}
|
||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||
return nil, errs.Wrap(err, "error unmarshaling request")
|
||||
return nil, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "DelUserPushTokenReq")
|
||||
}
|
||||
resp, err := g.pushClient.DelUserPushToken(context, &req)
|
||||
if err != nil {
|
||||
@@ -205,7 +202,7 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err
|
||||
}
|
||||
c, err := proto.Marshal(resp)
|
||||
if err != nil {
|
||||
return nil, errs.Wrap(err, "error marshaling response")
|
||||
return nil, errs.WrapMsg(err, "error marshaling response", "action", "marshal", "dataType", "DelUserPushTokenResp")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
@@ -213,31 +210,10 @@ func (g GrpcHandler) UserLogout(context context.Context, data *Req) ([]byte, err
|
||||
func (g GrpcHandler) SetUserDeviceBackground(_ context.Context, data *Req) ([]byte, bool, error) {
|
||||
req := sdkws.SetAppBackgroundStatusReq{}
|
||||
if err := proto.Unmarshal(data.Data, &req); err != nil {
|
||||
return nil, false, errs.Wrap(err, "error unmarshaling request")
|
||||
return nil, false, errs.WrapMsg(err, "error unmarshaling request", "action", "unmarshal", "dataType", "SetAppBackgroundStatusReq")
|
||||
}
|
||||
if err := g.validate.Struct(data); err != nil {
|
||||
return nil, false, errs.Wrap(err, "validation failed")
|
||||
return nil, false, errs.WrapMsg(err, "validation failed", "action", "validate", "dataType", "SetAppBackgroundStatusReq")
|
||||
}
|
||||
return nil, req.IsBackground, nil
|
||||
}
|
||||
|
||||
// func (g GrpcHandler) call[T any](ctx context.Context, data Req, m proto.Message, rpc func(ctx context.Context, req
|
||||
// proto.Message)) ([]byte, error) {
|
||||
// if err := proto.Unmarshal(data.Data, m); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// if err := g.validate.Struct(m); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// rpc(ctx, m)
|
||||
// req := msg.SendMsgReq{MsgData: &msgData}
|
||||
// resp, err := g.notification.Msg.SendMsg(context, &req)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// c, err := proto.Marshal(resp)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return c, nil
|
||||
//}
|
||||
|
||||
+114
-191
@@ -16,29 +16,25 @@ package msggateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/webhook"
|
||||
pbAuth "github.com/openimsdk/protocol/auth"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/OpenIMSDK/protocol/constant"
|
||||
"github.com/OpenIMSDK/protocol/msggateway"
|
||||
"github.com/OpenIMSDK/tools/apiresp"
|
||||
"github.com/OpenIMSDK/tools/discoveryregistry"
|
||||
"github.com/OpenIMSDK/tools/errs"
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/OpenIMSDK/tools/utils"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/db/cache"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/prommetrics"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/servererrs"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/rpcclient"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/openimsdk/protocol/constant"
|
||||
"github.com/openimsdk/protocol/msggateway"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/stringutil"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
@@ -48,8 +44,7 @@ type LongConnServer interface {
|
||||
GetUserAllCons(userID string) ([]*Client, bool)
|
||||
GetUserPlatformCons(userID string, platform int) ([]*Client, bool, bool)
|
||||
Validate(s any) error
|
||||
SetCacheHandler(cache cache.MsgModel)
|
||||
SetDiscoveryRegistry(client discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig)
|
||||
SetDiscoveryRegistry(client discovery.SvcDiscoveryRegistry, config *Config)
|
||||
KickUserConn(client *Client) error
|
||||
UnRegister(c *Client)
|
||||
SetKickHandlerInfo(i *kickHandler)
|
||||
@@ -58,15 +53,8 @@ type LongConnServer interface {
|
||||
MessageHandler
|
||||
}
|
||||
|
||||
// bufferPool is unused
|
||||
// var bufferPool = sync.Pool{
|
||||
// New: func() any {
|
||||
// return make([]byte, 1024)
|
||||
// },
|
||||
// }
|
||||
|
||||
type WsServer struct {
|
||||
globalConfig *config.GlobalConfig
|
||||
msgGatewayConfig *Config
|
||||
port int
|
||||
wsMaxConnNum int64
|
||||
registerChan chan *Client
|
||||
@@ -79,12 +67,13 @@ type WsServer struct {
|
||||
handshakeTimeout time.Duration
|
||||
writeBufferSize int
|
||||
validate *validator.Validate
|
||||
cache cache.MsgModel
|
||||
userClient *rpcclient.UserRpcClient
|
||||
disCov discoveryregistry.SvcDiscoveryRegistry
|
||||
authClient *rpcclient.Auth
|
||||
disCov discovery.SvcDiscoveryRegistry
|
||||
Compressor
|
||||
Encoder
|
||||
MessageHandler
|
||||
webhookClient *webhook.Client
|
||||
}
|
||||
|
||||
type kickHandler struct {
|
||||
@@ -93,9 +82,10 @@ type kickHandler struct {
|
||||
newClient *Client
|
||||
}
|
||||
|
||||
func (ws *WsServer) SetDiscoveryRegistry(disCov discoveryregistry.SvcDiscoveryRegistry, config *config.GlobalConfig) {
|
||||
ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, config)
|
||||
u := rpcclient.NewUserRpcClient(disCov, config)
|
||||
func (ws *WsServer) SetDiscoveryRegistry(disCov discovery.SvcDiscoveryRegistry, config *Config) {
|
||||
ws.MessageHandler = NewGrpcHandler(ws.validate, disCov, &config.Share.RpcRegisterName)
|
||||
u := rpcclient.NewUserRpcClient(disCov, config.Share.RpcRegisterName.User, config.Share.IMAdminUserID)
|
||||
ws.authClient = rpcclient.NewAuth(disCov, config.Share.RpcRegisterName.Auth)
|
||||
ws.userClient = &u
|
||||
ws.disCov = disCov
|
||||
}
|
||||
@@ -107,30 +97,17 @@ func (ws *WsServer) SetUserOnlineStatus(ctx context.Context, client *Client, sta
|
||||
}
|
||||
switch status {
|
||||
case constant.Online:
|
||||
err := CallbackUserOnline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID())
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "CallbackUserOnline err", err)
|
||||
}
|
||||
ws.webhookAfterUserOnline(ctx, &ws.msgGatewayConfig.WebhooksConfig.AfterUserOnline, client.UserID, client.PlatformID, client.IsBackground, client.ctx.GetConnID())
|
||||
case constant.Offline:
|
||||
err := CallbackUserOffline(ctx, ws.globalConfig, client.UserID, client.PlatformID, client.ctx.GetConnID())
|
||||
if err != nil {
|
||||
log.ZWarn(ctx, "CallbackUserOffline err", err)
|
||||
}
|
||||
ws.webhookAfterUserOffline(ctx, &ws.msgGatewayConfig.WebhooksConfig.AfterUserOffline, client.UserID, client.PlatformID, client.ctx.GetConnID())
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *WsServer) SetCacheHandler(cache cache.MsgModel) {
|
||||
ws.cache = cache
|
||||
}
|
||||
|
||||
func (ws *WsServer) UnRegister(c *Client) {
|
||||
ws.unregisterChan <- c
|
||||
}
|
||||
|
||||
func (ws *WsServer) Validate(s any) error {
|
||||
if s == nil {
|
||||
return errs.Wrap(errors.New("input cannot be nil"))
|
||||
}
|
||||
func (ws *WsServer) Validate(_ any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -142,14 +119,14 @@ func (ws *WsServer) GetUserPlatformCons(userID string, platform int) ([]*Client,
|
||||
return ws.clients.Get(userID, platform)
|
||||
}
|
||||
|
||||
func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer, error) {
|
||||
func NewWsServer(msgGatewayConfig *Config, opts ...Option) (*WsServer, error) {
|
||||
var config configs
|
||||
for _, o := range opts {
|
||||
o(&config)
|
||||
}
|
||||
v := validator.New()
|
||||
return &WsServer{
|
||||
globalConfig: globalConfig,
|
||||
msgGatewayConfig: msgGatewayConfig,
|
||||
port: config.port,
|
||||
wsMaxConnNum: config.maxConnNum,
|
||||
writeBufferSize: config.writeBufferSize,
|
||||
@@ -166,6 +143,7 @@ func NewWsServer(globalConfig *config.GlobalConfig, opts ...Option) (*WsServer,
|
||||
clients: newUserMap(),
|
||||
Compressor: NewGzipCompressor(),
|
||||
Encoder: NewGobEncoder(),
|
||||
webhookClient: webhook.NewWebhookClient(msgGatewayConfig.WebhooksConfig.URL),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -176,7 +154,7 @@ func (ws *WsServer) Run(done chan error) error {
|
||||
shutdownDone = make(chan struct{}, 1)
|
||||
)
|
||||
|
||||
server := http.Server{Addr: ":" + utils.IntToString(ws.port), Handler: nil}
|
||||
server := http.Server{Addr: ":" + stringutil.IntToString(ws.port), Handler: nil}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
@@ -196,9 +174,9 @@ func (ws *WsServer) Run(done chan error) error {
|
||||
go func() {
|
||||
http.HandleFunc("/", ws.wsHandler)
|
||||
err := server.ListenAndServe()
|
||||
defer close(netDone)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
netErr = errs.Wrap(err, "ws start err", server.Addr)
|
||||
close(netDone)
|
||||
netErr = errs.WrapMsg(err, "ws start err", server.Addr)
|
||||
}
|
||||
}()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
@@ -208,7 +186,7 @@ func (ws *WsServer) Run(done chan error) error {
|
||||
case err = <-done:
|
||||
sErr := server.Shutdown(ctx)
|
||||
if sErr != nil {
|
||||
return errs.Wrap(sErr, "shutdown err")
|
||||
return errs.WrapMsg(sErr, "shutdown err")
|
||||
}
|
||||
close(shutdownDone)
|
||||
if err != nil {
|
||||
@@ -223,7 +201,7 @@ func (ws *WsServer) Run(done chan error) error {
|
||||
var concurrentRequest = 3
|
||||
|
||||
func (ws *WsServer) sendUserOnlineInfoToOtherNode(ctx context.Context, client *Client) error {
|
||||
conns, err := ws.disCov.GetConns(ctx, ws.globalConfig.RpcRegisterName.OpenImMessageGatewayName)
|
||||
conns, err := ws.disCov.GetConns(ctx, ws.msgGatewayConfig.Share.RpcRegisterName.MessageGateway)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -279,7 +257,8 @@ func (ws *WsServer) registerClient(client *Client) {
|
||||
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))
|
||||
log.ZInfo(client.ctx, "repeat login", "userID", client.UserID, "platformID",
|
||||
client.PlatformID, "old remote addr", getRemoteAdders(oldClients))
|
||||
ws.onlineUserConnNum.Add(1)
|
||||
} else {
|
||||
ws.clients.Set(client.UserID, client)
|
||||
@@ -288,13 +267,14 @@ func (ws *WsServer) registerClient(client *Client) {
|
||||
}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
if ws.globalConfig.Envs.Discovery == "zookeeper" {
|
||||
if ws.msgGatewayConfig.Share.Env == "zookeeper" {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_ = ws.sendUserOnlineInfoToOtherNode(client.ctx, client)
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -331,7 +311,7 @@ func (ws *WsServer) KickUserConn(client *Client) error {
|
||||
}
|
||||
|
||||
func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Client, newClient *Client) {
|
||||
switch ws.globalConfig.MultiLoginPolicy {
|
||||
switch ws.msgGatewayConfig.MsgGateway.MultiLoginPolicy {
|
||||
case constant.DefalutNotKick:
|
||||
case constant.PCAndOther:
|
||||
if constant.PlatformIDToClass(newClient.PlatformID) == constant.TerminalPC {
|
||||
@@ -349,57 +329,13 @@ func (ws *WsServer) multiTerminalLoginChecker(clientOK bool, oldClients []*Clien
|
||||
log.ZWarn(c.ctx, "KickOnlineMessage", err)
|
||||
}
|
||||
}
|
||||
m, err := ws.cache.GetTokensWithoutError(
|
||||
newClient.ctx,
|
||||
newClient.UserID,
|
||||
newClient.PlatformID,
|
||||
ctx := mcontext.WithMustInfoCtx(
|
||||
[]string{newClient.ctx.GetOperationID(), newClient.ctx.GetUserID(),
|
||||
constant.PlatformIDToName(newClient.PlatformID), newClient.ctx.GetConnID()},
|
||||
)
|
||||
if err != nil && err != redis.Nil {
|
||||
log.ZWarn(
|
||||
newClient.ctx,
|
||||
"get token from redis err",
|
||||
err,
|
||||
"userID",
|
||||
newClient.UserID,
|
||||
"platformID",
|
||||
newClient.PlatformID,
|
||||
)
|
||||
return
|
||||
}
|
||||
if m == nil {
|
||||
log.ZWarn(
|
||||
newClient.ctx,
|
||||
"m is nil",
|
||||
errors.New("m is nil"),
|
||||
"userID",
|
||||
newClient.UserID,
|
||||
"platformID",
|
||||
newClient.PlatformID,
|
||||
)
|
||||
return
|
||||
}
|
||||
log.ZDebug(
|
||||
newClient.ctx,
|
||||
"get token from redis",
|
||||
"userID",
|
||||
newClient.UserID,
|
||||
"platformID",
|
||||
newClient.PlatformID,
|
||||
"tokenMap",
|
||||
m,
|
||||
)
|
||||
|
||||
for k := range m {
|
||||
if k != newClient.ctx.GetToken() {
|
||||
m[k] = constant.KickedToken
|
||||
}
|
||||
}
|
||||
log.ZDebug(newClient.ctx, "set token map is ", "token map", m, "userID",
|
||||
newClient.UserID, "token", newClient.ctx.GetToken())
|
||||
err = ws.cache.SetTokenMapByUidPid(newClient.ctx, newClient.UserID, newClient.PlatformID, m)
|
||||
if err != nil {
|
||||
log.ZWarn(newClient.ctx, "SetTokenMapByUidPid err", err, "userID", newClient.UserID, "platformID", newClient.PlatformID)
|
||||
return
|
||||
if _, err := ws.authClient.InvalidateToken(ctx, newClient.token, newClient.UserID, newClient.PlatformID); err != nil {
|
||||
log.ZWarn(newClient.ctx, "InvalidateToken err", err, "userID", newClient.UserID,
|
||||
"platformID", newClient.PlatformID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,107 +349,94 @@ func (ws *WsServer) unregisterClient(client *Client) {
|
||||
}
|
||||
ws.onlineUserConnNum.Add(-1)
|
||||
ws.SetUserOnlineStatus(client.ctx, client, constant.Offline)
|
||||
log.ZInfo(client.ctx, "user offline", "close reason", client.closedErr, "online user Num", ws.onlineUserNum.Load(), "online user conn Num",
|
||||
log.ZInfo(client.ctx, "user offline", "close reason", client.closedErr, "online user Num",
|
||||
ws.onlineUserNum.Load(), "online user conn Num",
|
||||
ws.onlineUserConnNum.Load(),
|
||||
)
|
||||
}
|
||||
|
||||
func (ws *WsServer) ParseWSArgs(r *http.Request) (args *WSArgs, err error) {
|
||||
var v WSArgs
|
||||
defer func() {
|
||||
args = &v
|
||||
}()
|
||||
query := r.URL.Query()
|
||||
v.MsgResp, _ = strconv.ParseBool(query.Get(MsgResp))
|
||||
if ws.onlineUserConnNum.Load() >= ws.wsMaxConnNum {
|
||||
return nil, errs.ErrConnOverMaxNumLimit.Wrap("over max conn num limit")
|
||||
// validateRespWithRequest checks if the response matches the expected userID and platformID.
|
||||
func (ws *WsServer) validateRespWithRequest(ctx *UserConnContext, resp *pbAuth.ParseTokenResp) error {
|
||||
userID := ctx.GetUserID()
|
||||
platformID := stringutil.StringToInt32(ctx.GetPlatformID())
|
||||
if resp.UserID != userID {
|
||||
return servererrs.ErrTokenInvalid.WrapMsg(fmt.Sprintf("token uid %s != userID %s", resp.UserID, userID))
|
||||
}
|
||||
if v.Token = query.Get(Token); v.Token == "" {
|
||||
return nil, errs.ErrConnArgsErr.Wrap("token is empty")
|
||||
if resp.PlatformID != platformID {
|
||||
return servererrs.ErrTokenInvalid.WrapMsg(fmt.Sprintf("token platform %d != platformID %d", resp.PlatformID, platformID))
|
||||
}
|
||||
if v.UserID = query.Get(WsUserID); v.UserID == "" {
|
||||
return nil, errs.ErrConnArgsErr.Wrap("sendID is empty")
|
||||
}
|
||||
platformIDStr := query.Get(PlatformID)
|
||||
if platformIDStr == "" {
|
||||
return nil, errs.ErrConnArgsErr.Wrap("platformID is empty")
|
||||
}
|
||||
platformID, err := strconv.Atoi(platformIDStr)
|
||||
if err != nil {
|
||||
return nil, errs.ErrConnArgsErr.Wrap("platformID is not int")
|
||||
}
|
||||
v.PlatformID = platformID
|
||||
if err = authverify.WsVerifyToken(v.Token, v.UserID, ws.globalConfig.Secret, platformID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if query.Get(Compression) == GzipCompressionProtocol {
|
||||
v.Compression = true
|
||||
}
|
||||
if r.Header.Get(Compression) == GzipCompressionProtocol {
|
||||
v.Compression = true
|
||||
}
|
||||
m, err := ws.cache.GetTokensWithoutError(context.Background(), v.UserID, platformID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, ok := m[v.Token]; ok {
|
||||
switch v {
|
||||
case constant.NormalToken:
|
||||
case constant.KickedToken:
|
||||
return nil, errs.ErrTokenKicked.Wrap()
|
||||
default:
|
||||
return nil, errs.ErrTokenUnknown.Wrap(fmt.Sprintf("token status is %d", v))
|
||||
}
|
||||
} else {
|
||||
return nil, errs.ErrTokenNotExist.Wrap()
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
type WSArgs struct {
|
||||
Token string
|
||||
UserID string
|
||||
PlatformID int
|
||||
Compression bool
|
||||
MsgResp bool
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WsServer) wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Create a new connection context
|
||||
connContext := newContext(w, r)
|
||||
args, pErr := ws.ParseWSArgs(r)
|
||||
var wsLongConn *GWebSocket
|
||||
if args.MsgResp {
|
||||
wsLongConn = newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize)
|
||||
if err := wsLongConn.GenerateLongConn(w, r); err != nil {
|
||||
httpError(connContext, err)
|
||||
return
|
||||
}
|
||||
data, err := json.Marshal(apiresp.ParseError(pErr))
|
||||
if err != nil {
|
||||
_ = wsLongConn.Close()
|
||||
return
|
||||
}
|
||||
if err := wsLongConn.WriteMessage(MessageText, data); err != nil {
|
||||
_ = wsLongConn.Close()
|
||||
return
|
||||
}
|
||||
if pErr != nil {
|
||||
_ = wsLongConn.Close()
|
||||
return
|
||||
|
||||
// Check if the current number of online user connections exceeds the maximum limit
|
||||
if ws.onlineUserConnNum.Load() >= ws.wsMaxConnNum {
|
||||
// If it exceeds the maximum connection number, return an error via HTTP and stop processing
|
||||
httpError(connContext, servererrs.ErrConnOverMaxNumLimit.WrapMsg("over max conn num limit"))
|
||||
return
|
||||
}
|
||||
|
||||
// Parse essential arguments (e.g., user ID, Token)
|
||||
err := connContext.ParseEssentialArgs()
|
||||
if err != nil {
|
||||
// If there's an error during parsing, return an error via HTTP and stop processing
|
||||
|
||||
httpError(connContext, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Call the authentication client to parse the Token obtained from the context
|
||||
resp, err := ws.authClient.ParseToken(connContext, connContext.GetToken())
|
||||
if err != nil {
|
||||
// If there's an error parsing the Token, decide whether to send the error message via WebSocket based on the context flag
|
||||
shouldSendError := connContext.ShouldSendResp()
|
||||
if shouldSendError {
|
||||
// Create a WebSocket connection object and attempt to send the error message via WebSocket
|
||||
wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize)
|
||||
if err := wsLongConn.RespondWithError(err, w, r); err == nil {
|
||||
// If the error message is successfully sent via WebSocket, stop processing
|
||||
return
|
||||
}
|
||||
}
|
||||
// If sending via WebSocket is not required or fails, return the error via HTTP and stop processing
|
||||
httpError(connContext, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate the authentication response matches the request (e.g., user ID and platform ID)
|
||||
err = ws.validateRespWithRequest(connContext, resp)
|
||||
if err != nil {
|
||||
// If validation fails, return an error via HTTP and stop processing
|
||||
httpError(connContext, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Create a WebSocket long connection object
|
||||
wsLongConn := newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize)
|
||||
if err := wsLongConn.GenerateLongConn(w, r); err != nil {
|
||||
//If the creation of the long connection fails, the error is handled internally during the handshake process.
|
||||
log.ZWarn(connContext, "long connection fails", err)
|
||||
return
|
||||
} else {
|
||||
if pErr != nil {
|
||||
httpError(connContext, pErr)
|
||||
return
|
||||
}
|
||||
wsLongConn = newGWebSocket(WebSocket, ws.handshakeTimeout, ws.writeBufferSize)
|
||||
if err := wsLongConn.GenerateLongConn(w, r); err != nil {
|
||||
httpError(connContext, err)
|
||||
return
|
||||
// Check if a normal response should be sent via WebSocket
|
||||
shouldSendSuccessResp := connContext.ShouldSendResp()
|
||||
if shouldSendSuccessResp {
|
||||
// Attempt to send a success message through WebSocket
|
||||
if err := wsLongConn.RespondWithSuccess(); err != nil {
|
||||
// If the success message is successfully sent, end further processing
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve a client object from the client pool, reset its state, and associate it with the current WebSocket long connection
|
||||
client := ws.clientPool.Get().(*Client)
|
||||
client.ResetClient(connContext, wsLongConn, connContext.GetBackground(), args.Compression, ws, args.Token)
|
||||
client.ResetClient(connContext, wsLongConn, ws)
|
||||
|
||||
// Register the client with the server and start message processing
|
||||
ws.registerChan <- client
|
||||
go client.readMessage()
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenIMSDK/tools/log"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/utils/datautil"
|
||||
)
|
||||
|
||||
type UserMap struct {
|
||||
@@ -54,6 +55,7 @@ func (u *UserMap) Get(key string, platformID int) ([]*Client, bool, bool) {
|
||||
return nil, userExisted, false
|
||||
}
|
||||
|
||||
// Set adds a client to the map.
|
||||
func (u *UserMap) Set(key string, v *Client) {
|
||||
allClients, existed := u.m.Load(key)
|
||||
if existed {
|
||||
@@ -63,6 +65,7 @@ func (u *UserMap) Set(key string, v *Client) {
|
||||
u.m.Store(key, oldClients)
|
||||
} else {
|
||||
log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client_user_id", v.UserID)
|
||||
|
||||
var clients []*Client
|
||||
clients = append(clients, v)
|
||||
u.m.Store(key, clients)
|
||||
@@ -98,14 +101,10 @@ func (u *UserMap) delete(key string, connRemoteAddr string) (isDeleteUser bool)
|
||||
return false
|
||||
}
|
||||
|
||||
func (u *UserMap) deleteClients(key string, clientsToDelete []*Client) (isDeleteUser bool) {
|
||||
// Convert the slice of clients to delete into a map for efficient lookup.
|
||||
deleteMap := make(map[string]struct{})
|
||||
for _, client := range clientsToDelete {
|
||||
deleteMap[client.ctx.GetRemoteAddr()] = struct{}{}
|
||||
}
|
||||
|
||||
// Load the current clients associated with the key.
|
||||
func (u *UserMap) deleteClients(key string, clients []*Client) (isDeleteUser bool) {
|
||||
m := datautil.SliceToMapAny(clients, func(c *Client) (string, struct{}) {
|
||||
return c.ctx.GetRemoteAddr(), struct{}{}
|
||||
})
|
||||
allClients, existed := u.m.Load(key)
|
||||
if !existed {
|
||||
// If the key doesn't exist, return false.
|
||||
@@ -116,7 +115,7 @@ func (u *UserMap) deleteClients(key string, clientsToDelete []*Client) (isDelete
|
||||
oldClients := allClients.([]*Client)
|
||||
var remainingClients []*Client
|
||||
for _, client := range oldClients {
|
||||
if _, shouldBeDeleted := deleteMap[client.ctx.GetRemoteAddr()]; !shouldBeDeleted {
|
||||
if _, shouldBeDeleted := m[client.ctx.GetRemoteAddr()]; !shouldBeDeleted {
|
||||
remainingClients = append(remainingClients, client)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user