feat: incr sync version.
This commit is contained in:
38
go/chao-sdk-core/msgtest/config.go
Normal file
38
go/chao-sdk-core/msgtest/config.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package msgtest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
||||
)
|
||||
|
||||
// config here
|
||||
|
||||
// system
|
||||
var (
|
||||
TESTIP = "59.36.173.89"
|
||||
APIADDR = fmt.Sprintf("http://%v:10002", TESTIP)
|
||||
WSADDR = fmt.Sprintf("ws://%v:10001", TESTIP)
|
||||
SECRET = "openIM123"
|
||||
MANAGERUSERID = "openIMAdmin"
|
||||
|
||||
PLATFORMID = constant.WindowsPlatformID
|
||||
LogLevel = uint32(5)
|
||||
|
||||
REGISTERADDR = APIADDR + constant.UserRegister
|
||||
TOKENADDR = APIADDR + constant.GetUsersToken
|
||||
)
|
||||
|
||||
func GetConfig() *sdk_struct.IMConfig {
|
||||
var cf sdk_struct.IMConfig
|
||||
cf.ApiAddr = APIADDR
|
||||
cf.PlatformID = int32(PLATFORMID)
|
||||
cf.WsAddr = WSADDR
|
||||
cf.DataDir = "./"
|
||||
cf.LogLevel = LogLevel
|
||||
cf.IsExternalExtensions = true
|
||||
cf.IsLogStandardOutput = true
|
||||
cf.LogFilePath = ""
|
||||
return &cf
|
||||
|
||||
}
|
||||
7
go/chao-sdk-core/msgtest/conversation_test.go
Normal file
7
go/chao-sdk-core/msgtest/conversation_test.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package msgtest
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_CreateConversations(t *testing.T) {
|
||||
|
||||
}
|
||||
38
go/chao-sdk-core/msgtest/message_test.go
Normal file
38
go/chao-sdk-core/msgtest/message_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package msgtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/msgtest/module"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/msgtest/sdk_user_simulator"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/ccontext"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_SimulateMultiOnline(t *testing.T) {
|
||||
ctx := ccontext.WithOperationID(context.Background(), "TEST_ROOT")
|
||||
userIDList := []string{"1", "2"}
|
||||
metaManager := module.NewMetaManager(APIADDR, SECRET, MANAGERUSERID)
|
||||
userManager := metaManager.NewUserManager()
|
||||
serverTime, err := metaManager.GetServerTime()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
offset := serverTime - utils.GetCurrentTimestampByMill()
|
||||
sdk_user_simulator.SetServerTimeOffset(offset)
|
||||
for _, userID := range userIDList {
|
||||
token, err := userManager.GetToken(userID, int32(PLATFORMID))
|
||||
if err != nil {
|
||||
log.ZError(ctx, "get token failed, err: %v", err, "userID", userID)
|
||||
continue
|
||||
}
|
||||
err = sdk_user_simulator.InitSDKAndLogin(userID, token)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "login failed, err: %v", err, "userID", userID)
|
||||
} else {
|
||||
log.ZDebug(ctx, "login success, userID: %v", "userID", userID)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
51
go/chao-sdk-core/msgtest/module/api_msg_sender.go
Normal file
51
go/chao-sdk-core/msgtest/module/api_msg_sender.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
||||
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
type ApiMsgSender struct {
|
||||
*MetaManager
|
||||
}
|
||||
|
||||
type SendMsgReq struct {
|
||||
RecvID string `json:"recvID" binding:"required_if" message:"recvID is required if sessionType is SingleChatType or NotificationChatType"`
|
||||
SendMsg
|
||||
}
|
||||
|
||||
type SendMsg struct {
|
||||
SendID string `json:"sendID" binding:"required"`
|
||||
GroupID string `json:"groupID" binding:"required_if=SessionType 2|required_if=SessionType 3"`
|
||||
SenderNickname string `json:"senderNickname"`
|
||||
SenderFaceURL string `json:"senderFaceURL"`
|
||||
SenderPlatformID int32 `json:"senderPlatformID"`
|
||||
Content map[string]interface{} `json:"content" binding:"required" swaggerignore:"true"`
|
||||
ContentType int32 `json:"contentType" binding:"required"`
|
||||
SessionType int32 `json:"sessionType" binding:"required"`
|
||||
IsOnlineOnly bool `json:"isOnlineOnly"`
|
||||
NotOfflinePush bool `json:"notOfflinePush"`
|
||||
OfflinePushInfo *sdkws.OfflinePushInfo `json:"offlinePushInfo"`
|
||||
}
|
||||
|
||||
func (a *ApiMsgSender) SendMsg(sendID, recvID string, index int) error {
|
||||
content := fmt.Sprintf("this is test msg user %s to user %s, index: %d", sendID, recvID, index)
|
||||
text := sdk_struct.TextElem{Content: content}
|
||||
req := &SendMsgReq{
|
||||
RecvID: recvID,
|
||||
SendMsg: SendMsg{
|
||||
SendID: sendID,
|
||||
SenderPlatformID: constant.WindowsPlatformID,
|
||||
ContentType: constant.Text,
|
||||
SessionType: constant.SingleChatType,
|
||||
Content: map[string]interface{}{"content": utils.StructToJsonString(text)},
|
||||
},
|
||||
}
|
||||
var resp msg.SendMsgResp
|
||||
return a.postWithCtx(constant.SendMsgRouter, req, &resp)
|
||||
}
|
||||
18
go/chao-sdk-core/msgtest/module/friend_manager.go
Normal file
18
go/chao-sdk-core/msgtest/module/friend_manager.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/protocol/relation"
|
||||
)
|
||||
|
||||
type TestFriendManager struct {
|
||||
*MetaManager
|
||||
}
|
||||
|
||||
func (t *TestFriendManager) ImportFriends(ownerUserID string, friendUserIDs []string) error {
|
||||
req := &relation.ImportFriendReq{
|
||||
OwnerUserID: ownerUserID,
|
||||
FriendUserIDs: friendUserIDs,
|
||||
}
|
||||
return t.postWithCtx(constant.ImportFriendListRouter, &req, nil)
|
||||
}
|
||||
75
go/chao-sdk-core/msgtest/module/group_manager.go
Normal file
75
go/chao-sdk-core/msgtest/module/group_manager.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/protocol/group"
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
)
|
||||
|
||||
type TestGroupManager struct {
|
||||
*MetaManager
|
||||
}
|
||||
|
||||
func (t *TestGroupManager) GenGroupID(prefix string) string {
|
||||
return fmt.Sprintf("%s_test_group_id_%d", prefix, time.Now().UnixNano())
|
||||
}
|
||||
|
||||
func (t *TestGroupManager) CreateGroup(groupID string, groupName string, ownerUserID string, userIDs []string) error {
|
||||
const batch = 2000
|
||||
var memberUserIDs []string
|
||||
if len(userIDs) > batch {
|
||||
memberUserIDs = userIDs[:batch]
|
||||
} else {
|
||||
memberUserIDs = userIDs
|
||||
}
|
||||
req := &group.CreateGroupReq{
|
||||
MemberUserIDs: memberUserIDs,
|
||||
OwnerUserID: ownerUserID,
|
||||
GroupInfo: &sdkws.GroupInfo{
|
||||
GroupID: groupID,
|
||||
GroupName: groupName,
|
||||
GroupType: constant.WorkingGroup,
|
||||
CreatorUserID: ownerUserID,
|
||||
},
|
||||
}
|
||||
resp := &group.CreateGroupResp{}
|
||||
if err := t.postWithCtx(constant.CreateGroupRouter, &req, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(userIDs) > batch {
|
||||
num := len(userIDs) / batch
|
||||
if len(userIDs)%batch != 0 {
|
||||
num++
|
||||
}
|
||||
for i := 1; i < num; i++ {
|
||||
start := batch * i
|
||||
end := batch*i + batch
|
||||
if len(userIDs) < end {
|
||||
end = len(userIDs)
|
||||
}
|
||||
req := map[string]any{
|
||||
"groupID": groupID,
|
||||
"invitedUserIDs": userIDs[start:end],
|
||||
"reason": "test",
|
||||
}
|
||||
resp := struct{}{}
|
||||
if err := t.postWithCtx(constant.RouterGroup+"/invite_user_to_group", req, &resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestGroupManager) InviteUserToGroup(ctx context.Context, groupID string, invitedUserIDs []string) error {
|
||||
req := &group.InviteUserToGroupReq{
|
||||
GroupID: groupID,
|
||||
InvitedUserIDs: invitedUserIDs,
|
||||
}
|
||||
resp := &group.InviteUserToGroupResp{}
|
||||
return t.postWithCtx(constant.InviteUserToGroupRouter, &req, &resp)
|
||||
}
|
||||
140
go/chao-sdk-core/msgtest/module/manager.go
Normal file
140
go/chao-sdk-core/msgtest/module/manager.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/internal/util"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/sdkerrs"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
||||
authPB "github.com/openimsdk/protocol/auth"
|
||||
"github.com/openimsdk/protocol/msg"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
ManagerUserID = "openIMAdmin"
|
||||
)
|
||||
|
||||
type MetaManager struct {
|
||||
managerUserID string
|
||||
apiAddr string
|
||||
secret string
|
||||
token string
|
||||
}
|
||||
|
||||
func NewMetaManager(apiAddr, secret, managerUserID string) *MetaManager {
|
||||
return &MetaManager{
|
||||
managerUserID: managerUserID,
|
||||
apiAddr: apiAddr,
|
||||
secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MetaManager) NewUserManager() *TestUserManager {
|
||||
return &TestUserManager{m}
|
||||
}
|
||||
|
||||
func (m *MetaManager) NewGroupMananger() *TestGroupManager {
|
||||
return &TestGroupManager{m}
|
||||
}
|
||||
|
||||
func (m *MetaManager) NewFriendManager() *TestFriendManager {
|
||||
return &TestFriendManager{m}
|
||||
}
|
||||
|
||||
func (m *MetaManager) NewApiMsgSender() *ApiMsgSender {
|
||||
return &ApiMsgSender{m}
|
||||
}
|
||||
|
||||
func (m *MetaManager) apiPost(ctx context.Context, route string, req, resp any) (err error) {
|
||||
operationID, _ := ctx.Value("operationID").(string)
|
||||
if operationID == "" {
|
||||
err := sdkerrs.ErrArgs.Wrap("call api operationID is empty")
|
||||
return err
|
||||
}
|
||||
reqBody, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return sdkerrs.ErrSdkInternal.Wrap("json.Marshal(req) failed " + err.Error())
|
||||
}
|
||||
reqUrl := m.apiAddr + route
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, reqUrl, bytes.NewReader(reqBody))
|
||||
if err != nil {
|
||||
return sdkerrs.ErrSdkInternal.Wrap("sdk http.NewRequestWithContext failed " + err.Error())
|
||||
}
|
||||
log.ZDebug(ctx, "ApiRequest", "url", reqUrl, "body", string(reqBody))
|
||||
request.ContentLength = int64(len(reqBody))
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
request.Header.Set("operationID", operationID)
|
||||
if m.token != "" {
|
||||
request.Header.Set("token", m.token)
|
||||
}
|
||||
response, err := new(http.Client).Do(request)
|
||||
if err != nil {
|
||||
return sdkerrs.ErrNetwork.Wrap("ApiPost http.Client.Do failed " + err.Error())
|
||||
}
|
||||
defer response.Body.Close()
|
||||
respBody, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "ApiResponse", err, "type", "read body", "status", response.Status)
|
||||
return sdkerrs.ErrSdkInternal.Wrap("io.ReadAll(ApiResponse) failed " + err.Error())
|
||||
}
|
||||
log.ZDebug(ctx, "ApiResponse", "url", reqUrl, "status", response.Status, "body", string(respBody))
|
||||
var baseApi util.ApiResponse
|
||||
if err := json.Unmarshal(respBody, &baseApi); err != nil {
|
||||
return sdkerrs.ErrSdkInternal.Wrap(fmt.Sprintf("api %s json.Unmarshal(%q, %T) failed %s", m.apiAddr, string(respBody), &baseApi, err.Error()))
|
||||
}
|
||||
if baseApi.ErrCode != 0 {
|
||||
err := sdkerrs.New(baseApi.ErrCode, baseApi.ErrMsg, baseApi.ErrDlt)
|
||||
return err
|
||||
}
|
||||
if resp == nil || len(baseApi.Data) == 0 || string(baseApi.Data) == "null" {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(baseApi.Data, resp); err != nil {
|
||||
return sdkerrs.ErrSdkInternal.Wrap(fmt.Sprintf("json.Unmarshal(%q, %T) failed %s", string(baseApi.Data), resp, err.Error()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MetaManager) postWithCtx(route string, req, resp any) error {
|
||||
return m.apiPost(m.buildCtx(), route, req, resp)
|
||||
}
|
||||
|
||||
func (m *MetaManager) buildCtx() context.Context {
|
||||
return mcontext.NewCtx(utils.OperationIDGenerator())
|
||||
}
|
||||
|
||||
func (m *MetaManager) getToken(userID string, platformID int32) (string, error) {
|
||||
req := authPB.UserTokenReq{PlatformID: platformID, UserID: userID, Secret: m.secret}
|
||||
resp := authPB.UserTokenResp{}
|
||||
err := m.postWithCtx(constant.GetUsersToken, &req, &resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.Token, nil
|
||||
}
|
||||
|
||||
func (m *MetaManager) initToken() error {
|
||||
token, err := m.getToken(m.managerUserID, constant.AdminPlatformID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.token = token
|
||||
return nil
|
||||
}
|
||||
func (m *MetaManager) GetServerTime() (int64, error) {
|
||||
req := msg.GetServerTimeReq{}
|
||||
resp := msg.GetServerTimeResp{}
|
||||
err := m.postWithCtx(constant.GetServerTimeRouter, &req, &resp)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
return resp.ServerTime, nil
|
||||
}
|
||||
}
|
||||
183
go/chao-sdk-core/msgtest/module/msg_sender.go
Normal file
183
go/chao-sdk-core/msgtest/module/msg_sender.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/internal/interaction"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/ccontext"
|
||||
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/common"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
)
|
||||
|
||||
type SendMsgUser struct {
|
||||
longConnMgr *interaction.LongConnMgr
|
||||
userID string
|
||||
pushMsgAndMaxSeqCh chan common.Cmd2Value
|
||||
recvPushMsgCallback func(msg *sdkws.MsgData)
|
||||
failedMessageMap map[string]error
|
||||
cancelFunc context.CancelFunc
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (b SendMsgUser) GetUserID() string {
|
||||
return b.userID
|
||||
}
|
||||
|
||||
func WithRecvPushMsgCallback(callback func(msg *sdkws.MsgData)) func(core *SendMsgUser) {
|
||||
return func(core *SendMsgUser) {
|
||||
core.recvPushMsgCallback = callback
|
||||
}
|
||||
}
|
||||
|
||||
func newIMconfig(platformID int32, apiAddr, wsAddr string) sdk_struct.IMConfig {
|
||||
return sdk_struct.IMConfig{
|
||||
PlatformID: platformID,
|
||||
ApiAddr: apiAddr,
|
||||
WsAddr: wsAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func newUserCtx(userID, token string, imConfig sdk_struct.IMConfig) context.Context {
|
||||
return ccontext.WithInfo(context.Background(), &ccontext.GlobalConfig{
|
||||
UserID: userID,
|
||||
Token: token,
|
||||
IMConfig: imConfig})
|
||||
}
|
||||
|
||||
func NewUser(userID, token string, imConfig sdk_struct.IMConfig, opts ...func(core *SendMsgUser)) *SendMsgUser {
|
||||
pushMsgAndMaxSeqCh := make(chan common.Cmd2Value, 1000)
|
||||
ctx := newUserCtx(userID, token, imConfig)
|
||||
longConnMgr := interaction.NewLongConnMgr(ctx, &ConnListner{}, nil, pushMsgAndMaxSeqCh, nil)
|
||||
core := &SendMsgUser{
|
||||
pushMsgAndMaxSeqCh: pushMsgAndMaxSeqCh,
|
||||
longConnMgr: longConnMgr,
|
||||
userID: userID,
|
||||
failedMessageMap: make(map[string]error),
|
||||
ctx: ctx,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(core)
|
||||
}
|
||||
baseCtx, cancel := context.WithCancel(ctx)
|
||||
core.cancelFunc = cancel
|
||||
go core.recvPushMsg(baseCtx)
|
||||
go core.longConnMgr.Run(baseCtx)
|
||||
return core
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) Close(ctx context.Context) {
|
||||
b.longConnMgr.Close(ctx)
|
||||
b.cancelFunc()
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) SendMsgWithContext(userID string, index int) error {
|
||||
newCtx := mcontext.SetOperationID(b.ctx, utils.OperationIDGenerator())
|
||||
return b.SendSingleMsg(newCtx, userID, index)
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) SendGroupMsgWithContext(groupID string, index int) error {
|
||||
newCtx := mcontext.SetOperationID(b.ctx, utils.OperationIDGenerator())
|
||||
return b.SendGroupMsg(newCtx, groupID, index)
|
||||
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) SendSingleMsg(ctx context.Context, userID string, index int) error {
|
||||
return b.sendMsg(ctx, userID, "", index, constant.SingleChatType, fmt.Sprintf("this is test msg user %s to user %s, index: %d", b.userID, userID, index))
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) BatchSendSingleMsg(ctx context.Context, userID string, index int) error {
|
||||
content := fmt.Sprintf("this is test msg user %s to user %s, index: %d", b.userID, userID, index)
|
||||
err := b.sendMsg(ctx, userID, "", index, constant.SingleChatType, content)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "send msg failed", err, "userID", userID, "index", index, "content", content)
|
||||
b.failedMessageMap[content] = err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) SendGroupMsg(ctx context.Context, groupID string, index int) error {
|
||||
return b.sendMsg(ctx, "", groupID, index, constant.SuperGroupChatType, fmt.Sprintf("this is test msg user %s to group %s, index: %d", b.userID, groupID, index))
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) BatchSendGroupMsg(ctx context.Context, groupID string, index int) error {
|
||||
content := fmt.Sprintf("this is test msg user %s to group %s, index: %d", b.userID, groupID, index)
|
||||
err := b.sendMsg(ctx, "", groupID, index, constant.SuperGroupChatType, content)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "send msg failed", err, "groupID", groupID, "index", index, "content", content)
|
||||
b.failedMessageMap[content] = err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) sendMsg(ctx context.Context, userID, groupID string, index int, sesstionType int32, content string) error {
|
||||
var resp sdkws.UserSendMsgResp
|
||||
text := sdk_struct.TextElem{Content: content}
|
||||
clientMsgID := utils.GetMsgID(b.userID)
|
||||
msg := &sdkws.MsgData{
|
||||
SendID: b.userID,
|
||||
GroupID: groupID,
|
||||
RecvID: userID,
|
||||
SessionType: sesstionType,
|
||||
ContentType: constant.Text,
|
||||
SenderNickname: b.userID,
|
||||
Content: []byte(utils.StructToJsonString(text)),
|
||||
CreateTime: time.Now().UnixMilli(),
|
||||
SenderPlatformID: constant.AdminPlatformID,
|
||||
ClientMsgID: clientMsgID,
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
if err := b.longConnMgr.SendReqWaitResp(ctx, msg, constant.SendMsg, &resp); err != nil {
|
||||
b.failedMessageMap[clientMsgID] = err
|
||||
|
||||
return err
|
||||
}
|
||||
if resp.SendTime-now > 1500 {
|
||||
log.ZWarn(ctx, "msg recv resp is too slow", nil, "sendTime", resp.SendTime, "now", now)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) recvPushMsg(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case cmd := <-b.pushMsgAndMaxSeqCh:
|
||||
switch cmd.Cmd {
|
||||
case constant.CmdPushMsg:
|
||||
pushMsgs := cmd.Value.(*sdkws.PushMessages)
|
||||
for _, push := range pushMsgs.Msgs {
|
||||
for _, msg := range push.Msgs {
|
||||
if b.recvPushMsgCallback == nil {
|
||||
b.defaultRecvPushMsgCallback(msg)
|
||||
} else {
|
||||
b.recvPushMsgCallback(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SendMsgUser) defaultRecvPushMsgCallback(msg *sdkws.MsgData) {
|
||||
}
|
||||
|
||||
type ConnListner struct {
|
||||
}
|
||||
|
||||
func (c *ConnListner) OnConnecting() {}
|
||||
func (c *ConnListner) OnConnectSuccess() {}
|
||||
func (c *ConnListner) OnConnectFailed(errCode int32, errMsg string) {
|
||||
// log.ZError(context.Background(), "connect failed", nil, "errCode", errCode, "errMsg", errMsg)
|
||||
}
|
||||
func (c *ConnListner) OnKickedOffline() {}
|
||||
func (c *ConnListner) OnUserTokenExpired() {}
|
||||
43
go/chao-sdk-core/msgtest/module/user_manager.go
Normal file
43
go/chao-sdk-core/msgtest/module/user_manager.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/protocol/sdkws"
|
||||
userPB "github.com/openimsdk/protocol/user"
|
||||
)
|
||||
|
||||
type TestUserManager struct {
|
||||
*MetaManager
|
||||
}
|
||||
|
||||
func (t *TestUserManager) GenUserIDs(num int) (userIDs []string) {
|
||||
for i := 0; i < num; i++ {
|
||||
userIDs = append(userIDs, fmt.Sprintf("testv3new_%d_%d", time.Now().UnixNano(), i))
|
||||
}
|
||||
return userIDs
|
||||
}
|
||||
|
||||
func (t *TestUserManager) GenUserIDsWithPrefix(num int, prefix string) (userIDs []string) {
|
||||
for i := 0; i < num; i++ {
|
||||
userIDs = append(userIDs, fmt.Sprintf("%s_testv3new_%d_%d", prefix, time.Now().UnixNano(), i))
|
||||
}
|
||||
return userIDs
|
||||
}
|
||||
|
||||
func (t *TestUserManager) RegisterUsers(userIDs ...string) error {
|
||||
var users []*sdkws.UserInfo
|
||||
for _, userID := range userIDs {
|
||||
users = append(users, &sdkws.UserInfo{UserID: userID, Nickname: userID})
|
||||
}
|
||||
return t.postWithCtx(constant.UserRegister, &userPB.UserRegisterReq{
|
||||
Secret: t.secret,
|
||||
Users: users,
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (t *TestUserManager) GetToken(userID string, platformID int32) (string, error) {
|
||||
return t.getToken(userID, platformID)
|
||||
}
|
||||
301
go/chao-sdk-core/msgtest/pressure_test.go
Normal file
301
go/chao-sdk-core/msgtest/pressure_test.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package msgtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/openim-sdk-core/v3/msgtest/module"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
||||
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
const (
|
||||
TenThousandGroupUserNum = 10000
|
||||
ThousandGroupUserNum = 1000
|
||||
HundredGroupUserNum = 100
|
||||
FiftyGroupUserNum = 50
|
||||
|
||||
TenThousandGroupNum = 2
|
||||
ThousandGroupNum = 5
|
||||
HundredGroupNum = 50
|
||||
FiftyGroupNum = 100
|
||||
|
||||
FastenedUserPrefix = "fastened_user_prefix"
|
||||
RecvMsgPrefix = "recv_msg_prefix"
|
||||
)
|
||||
|
||||
var (
|
||||
totalOnlineUserNum int // 总在线用户数
|
||||
friendMsgSenderNum int // 好友消息发送者数
|
||||
NotFriendMsgSenderNum int // 非好友消息发送者数
|
||||
groupMsgSenderNum int // 群消息发送者数
|
||||
msgSenderNumEvreyUser int // 每个用户的消息数
|
||||
fastenedUserNum int // 固定用户数
|
||||
|
||||
recvMsgUserNum int // 消息接收者数, 抽样账号
|
||||
|
||||
)
|
||||
|
||||
func InitWithFlag() {
|
||||
flag.IntVar(&totalOnlineUserNum, "t", 100000, "total online user num")
|
||||
flag.IntVar(&friendMsgSenderNum, "f", 100, "friend msg sender num")
|
||||
flag.IntVar(&NotFriendMsgSenderNum, "n", 100, "not friend msg sender num")
|
||||
flag.IntVar(&groupMsgSenderNum, "g", 100, "group msg sender num")
|
||||
flag.IntVar(&msgSenderNumEvreyUser, "m", 100, "msg sender num evrey user")
|
||||
|
||||
flag.IntVar(&recvMsgUserNum, "r", 20, "recv msg user num")
|
||||
flag.IntVar(&fastenedUserNum, "u", 300, "fastened user num")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
InitWithFlag()
|
||||
|
||||
if err := log.InitFromConfig("sdk.log", "sdk", 4,
|
||||
true, false, "./chat_log", 2, 24, "v1.0.0"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PressureFull(t *testing.T) {
|
||||
flag.Parse()
|
||||
if friendMsgSenderNum+NotFriendMsgSenderNum+groupMsgSenderNum > totalOnlineUserNum {
|
||||
t.Fatal("sender num > total online user num")
|
||||
}
|
||||
|
||||
p := NewPressureTester()
|
||||
// gen userIDs
|
||||
userIDs, fastenedUserIDs, recvMsgUserIDs := p.genUserIDs()
|
||||
|
||||
// register
|
||||
if err := p.registerUsers(userIDs, fastenedUserIDs, recvMsgUserIDs); err != nil {
|
||||
t.Fatalf("register users failed, err: %v", err)
|
||||
}
|
||||
// init users
|
||||
p.initUserConns(userIDs, fastenedUserIDs)
|
||||
|
||||
// create groups
|
||||
err := p.createTestGroups(userIDs, fastenedUserIDs, recvMsgUserIDs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// import friends
|
||||
if err := p.importFriends(p.friendSenderUserIDs, fastenedUserIDs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p.pressureSendMsg()
|
||||
// send msg test
|
||||
}
|
||||
|
||||
func Test_InitUserConn(t *testing.T) {
|
||||
flag.Parse()
|
||||
p := NewPressureTester()
|
||||
userNum := 10
|
||||
// gen userIDs
|
||||
userIDs := p.userManager.GenUserIDs(userNum)
|
||||
// register
|
||||
if err := p.registerUsers(userIDs, nil, nil); err != nil {
|
||||
t.Fatalf("register users failed, err: %v", err)
|
||||
}
|
||||
// init users
|
||||
p.initUserConns(userIDs, nil)
|
||||
}
|
||||
|
||||
type PressureTester struct {
|
||||
friendManager *module.TestFriendManager
|
||||
userManager *module.TestUserManager
|
||||
groupManager *module.TestGroupManager
|
||||
msgSender map[string]*module.SendMsgUser
|
||||
groupMsgSender map[string]*module.SendMsgUser
|
||||
|
||||
groupSenderUserIDs, friendSenderUserIDs, notfriendSenderUserIDs []string
|
||||
recvMsgUserIDs []string
|
||||
|
||||
tenThousandGroupIDs, thousandGroupIDs, hundredGroupUserIDs, fiftyGroupUserIDs []string
|
||||
}
|
||||
|
||||
func NewPressureTester() *PressureTester {
|
||||
metaManager := module.NewMetaManager(APIADDR, SECRET, MANAGERUSERID)
|
||||
return &PressureTester{friendManager: metaManager.NewFriendManager(), userManager: metaManager.NewUserManager(), groupManager: metaManager.NewGroupMananger(),
|
||||
msgSender: make(map[string]*module.SendMsgUser), groupMsgSender: make(map[string]*module.SendMsgUser)}
|
||||
}
|
||||
|
||||
func (p *PressureTester) genUserIDs() (userIDs, fastenedUserIDs, recvMsgUserIDs []string) {
|
||||
userIDs = p.userManager.GenUserIDs(totalOnlineUserNum - fastenedUserNum) // 在线用户
|
||||
fastenedUserIDs = p.userManager.GenUserIDsWithPrefix(fastenedUserNum, FastenedUserPrefix) // 指定300用户
|
||||
recvMsgUserIDs = p.userManager.GenUserIDsWithPrefix(recvMsgUserNum, RecvMsgPrefix) // 抽样用户完整SDK
|
||||
return
|
||||
}
|
||||
|
||||
func (p *PressureTester) registerUsers(userIDs []string, fastenedUserIDs []string, recvMsgUserIDs []string) error {
|
||||
for i := 0; i < len(userIDs); i += 1000 {
|
||||
end := i + 1000
|
||||
if end > len(userIDs) {
|
||||
end = len(userIDs)
|
||||
}
|
||||
userIDsSlice := userIDs[i:end]
|
||||
if err := p.userManager.RegisterUsers(userIDsSlice...); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(userIDsSlice) < 1000 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(fastenedUserIDs) != 0 {
|
||||
if err := p.userManager.RegisterUsers(fastenedUserIDs...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(recvMsgUserIDs) != 0 {
|
||||
if err := p.userManager.RegisterUsers(recvMsgUserIDs...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PressureTester) initUserConns(userIDs []string, fastenedUserIDs []string) {
|
||||
for i, userID := range userIDs {
|
||||
token, err := p.userManager.GetToken(userID, int32(PLATFORMID))
|
||||
if err != nil {
|
||||
log.ZError(context.Background(), "get token failed", err, "userID", userID, "platformID", PLATFORMID)
|
||||
continue
|
||||
}
|
||||
user := module.NewUser(userID, token, sdk_struct.IMConfig{WsAddr: WSADDR, ApiAddr: APIADDR, PlatformID: int32(PLATFORMID)})
|
||||
if 0 <= i && i < friendMsgSenderNum {
|
||||
p.msgSender[userID] = user
|
||||
p.friendSenderUserIDs = append(p.friendSenderUserIDs, userID)
|
||||
} else if friendMsgSenderNum <= i && i < friendMsgSenderNum+NotFriendMsgSenderNum {
|
||||
p.msgSender[userID] = user
|
||||
p.notfriendSenderUserIDs = append(p.notfriendSenderUserIDs, userID)
|
||||
}
|
||||
}
|
||||
if len(fastenedUserIDs) != 0 {
|
||||
for _, userID := range fastenedUserIDs {
|
||||
token, err := p.userManager.GetToken(userID, int32(PLATFORMID))
|
||||
if err != nil {
|
||||
log.ZError(context.Background(), "get token failed", err, "userID", userID, "platformID", PLATFORMID)
|
||||
continue
|
||||
}
|
||||
user := module.NewUser(userID, token, sdk_struct.IMConfig{WsAddr: WSADDR, ApiAddr: APIADDR, PlatformID: int32(PLATFORMID)})
|
||||
p.msgSender[userID] = user
|
||||
p.groupSenderUserIDs = append(p.groupSenderUserIDs, userID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PressureTester) createTestGroups(userIDs, fastenedUserIDs, recvMsgUserIDs []string) (err error) {
|
||||
// create ten thousand group
|
||||
for i := 1; i <= TenThousandGroupNum; i++ {
|
||||
groupID := p.groupManager.GenGroupID(fmt.Sprintf("tenThousandGroup_%d", i))
|
||||
err = p.groupManager.CreateGroup(groupID, "tenThousandGroup", userIDs[0], append(userIDs[(i-1)*TenThousandGroupUserNum:i*TenThousandGroupUserNum-1], fastenedUserIDs...))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.tenThousandGroupIDs = append(p.tenThousandGroupIDs, groupID)
|
||||
}
|
||||
// create two thousand group
|
||||
exclude := TenThousandGroupNum * TenThousandGroupUserNum
|
||||
for i := 1; i <= ThousandGroupNum; i++ {
|
||||
groupID := p.groupManager.GenGroupID(fmt.Sprintf("thousandGroup_%d", i))
|
||||
err = p.groupManager.CreateGroup(groupID, "thousandGroup", userIDs[0], append(userIDs[exclude+(i-1)*ThousandGroupUserNum:exclude+i*ThousandGroupUserNum-1], fastenedUserIDs...))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.thousandGroupIDs = append(p.thousandGroupIDs, groupID)
|
||||
}
|
||||
// create five hundred group
|
||||
exclude += exclude + ThousandGroupNum*ThousandGroupUserNum
|
||||
for i := 1; i <= HundredGroupNum; i++ {
|
||||
groupID := p.groupManager.GenGroupID(fmt.Sprintf("hundredGroup_%d", i))
|
||||
err = p.groupManager.CreateGroup(groupID, "hundredGroup", userIDs[0], append(fastenedUserIDs[0:80], recvMsgUserIDs...))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.hundredGroupUserIDs = append(p.hundredGroupUserIDs, groupID)
|
||||
}
|
||||
// create fifty group
|
||||
exclude += exclude + HundredGroupNum*HundredGroupUserNum
|
||||
for i := 1; i <= FiftyGroupNum; i++ {
|
||||
groupID := p.groupManager.GenGroupID(fmt.Sprintf("fiftyGroup_%d", i))
|
||||
err = p.groupManager.CreateGroup(groupID, "fiftyGroup", userIDs[0], append(fastenedUserIDs[0:30], recvMsgUserIDs...))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.fiftyGroupUserIDs = append(p.fiftyGroupUserIDs, groupID)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *PressureTester) sendMsgs2Users(senderIDs, recvIDs []string, num int, duration time.Duration) {
|
||||
var wg sync.WaitGroup
|
||||
for _, senderID := range senderIDs {
|
||||
for _, recvID := range recvIDs {
|
||||
wg.Add(1)
|
||||
go func(senderID, recvID string) {
|
||||
defer wg.Done()
|
||||
for i := 0; i < num; i++ {
|
||||
if user, ok := p.msgSender[senderID]; ok {
|
||||
user.SendMsgWithContext(recvID, i)
|
||||
}
|
||||
time.Sleep(duration)
|
||||
}
|
||||
}(senderID, recvID)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (p *PressureTester) sendMsgs2Groups(senderIDs, groupIDs []string, num int, duration time.Duration) {
|
||||
var wg sync.WaitGroup
|
||||
for _, senderID := range senderIDs {
|
||||
for _, groupID := range groupIDs {
|
||||
wg.Add(1)
|
||||
go func(senderID, groupID string) {
|
||||
defer wg.Done()
|
||||
for i := 0; i < num; i++ {
|
||||
if user, ok := p.groupMsgSender[senderID]; ok {
|
||||
user.SendGroupMsgWithContext(groupID, i)
|
||||
}
|
||||
time.Sleep(duration)
|
||||
}
|
||||
}(senderID, groupID)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (p *PressureTester) pressureSendMsg() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(3)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
p.sendMsgs2Users(p.friendSenderUserIDs, p.recvMsgUserIDs, msgSenderNumEvreyUser, time.Second)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
p.sendMsgs2Users(p.notfriendSenderUserIDs, p.recvMsgUserIDs, msgSenderNumEvreyUser, time.Second)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
totalGroupIDs := append(append(p.tenThousandGroupIDs, p.thousandGroupIDs...), append(p.hundredGroupUserIDs, p.fiftyGroupUserIDs...)...)
|
||||
p.sendMsgs2Groups(p.groupSenderUserIDs, totalGroupIDs, msgSenderNumEvreyUser, time.Second)
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (p *PressureTester) importFriends(friendSenderUserIDs, recvMsgUserIDs []string) error {
|
||||
for _, recvMsgUserID := range recvMsgUserIDs {
|
||||
if err := p.friendManager.ImportFriends(recvMsgUserID, friendSenderUserIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
252
go/chao-sdk-core/msgtest/sdk_user_simulator/listener.go
Normal file
252
go/chao-sdk-core/msgtest/sdk_user_simulator/listener.go
Normal file
@@ -0,0 +1,252 @@
|
||||
package sdk_user_simulator
|
||||
|
||||
import (
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
||||
)
|
||||
|
||||
type conversationCallBack struct {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnSyncServerFailed() {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnNewConversation(conversationList string) {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnConversationChanged(conversationList string) {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnTotalUnreadMessageCountChanged(totalUnreadCount int32) {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnRecvMessageExtensionsChanged(msgID string, reactionExtensionList string) {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnRecvMessageExtensionsDeleted(msgID string, reactionExtensionKeyList string) {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnSyncServerProgress(progress int) {
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnSyncServerStart() {
|
||||
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnSyncServerFinish() {
|
||||
|
||||
}
|
||||
|
||||
func (c *conversationCallBack) OnConversationUserInputStatusChanged(change string) {
|
||||
|
||||
}
|
||||
|
||||
type userCallback struct {
|
||||
}
|
||||
|
||||
func (c userCallback) OnUserStatusChanged(statusMap string) {
|
||||
|
||||
}
|
||||
|
||||
func (userCallback) OnSelfInfoUpdated(callbackData string) {
|
||||
|
||||
}
|
||||
func (userCallback) OnUserCommandAdd(callbackData string) {
|
||||
|
||||
}
|
||||
func (userCallback) OnUserCommandUpdate(callbackData string) {
|
||||
|
||||
}
|
||||
func (userCallback) OnUserCommandDelete(callbackData string) {
|
||||
|
||||
}
|
||||
|
||||
type SingleMessage struct {
|
||||
SendID string
|
||||
ClientMsgID string
|
||||
Delay int64
|
||||
}
|
||||
type MsgListenerCallBak struct {
|
||||
userID string
|
||||
GroupDelay map[string][]*SingleMessage
|
||||
SingleDelay map[string][]*SingleMessage
|
||||
}
|
||||
|
||||
func NewMsgListenerCallBak(userID string) *MsgListenerCallBak {
|
||||
return &MsgListenerCallBak{userID: userID,
|
||||
GroupDelay: make(map[string][]*SingleMessage),
|
||||
SingleDelay: make(map[string][]*SingleMessage)}
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvNewMessage(message string) {
|
||||
var sm sdk_struct.MsgStruct
|
||||
utils.JsonStringToStruct(message, &sm)
|
||||
switch sm.SessionType {
|
||||
case constant.SingleChatType:
|
||||
m.SingleDelay[sm.SendID] =
|
||||
append(m.SingleDelay[sm.SendID], &SingleMessage{SendID: sm.SendID, ClientMsgID: sm.ClientMsgID, Delay: GetRelativeServerTime() - sm.SendTime})
|
||||
case constant.SuperGroupChatType:
|
||||
m.GroupDelay[sm.GroupID] =
|
||||
append(m.GroupDelay[sm.GroupID], &SingleMessage{SendID: sm.SendID, ClientMsgID: sm.ClientMsgID, Delay: GetRelativeServerTime() - sm.SendTime})
|
||||
default:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvC2CReadReceipt(msgReceiptList string) {
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnMsgDeleted(s string) {}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvOfflineNewMessage(message string) {
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvMessageExtensionsAdded(msgID string, reactionExtensionList string) {
|
||||
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvGroupReadReceipt(groupMsgReceiptList string) {
|
||||
}
|
||||
func (m *MsgListenerCallBak) OnNewRecvMessageRevoked(messageRevoked string) {
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvMessageExtensionsChanged(msgID string, reactionExtensionList string) {
|
||||
|
||||
}
|
||||
func (m *MsgListenerCallBak) OnRecvMessageExtensionsDeleted(msgID string, reactionExtensionKeyList string) {
|
||||
}
|
||||
|
||||
func (m *MsgListenerCallBak) OnRecvOnlineOnlyMessage(message string) {
|
||||
|
||||
}
|
||||
|
||||
type testFriendListener struct {
|
||||
}
|
||||
|
||||
func (testFriendListener) OnFriendApplicationAdded(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testFriendListener) OnFriendApplicationDeleted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnFriendApplicationAccepted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnFriendApplicationRejected(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnFriendAdded(callbackInfo string) {
|
||||
}
|
||||
|
||||
func (testFriendListener) OnFriendDeleted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnBlackAdded(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testFriendListener) OnBlackDeleted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnFriendInfoChanged(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnSuccess() {
|
||||
|
||||
}
|
||||
|
||||
func (testFriendListener) OnError(code int32, msg string) {
|
||||
|
||||
}
|
||||
|
||||
type testGroupListener struct {
|
||||
}
|
||||
|
||||
func (testGroupListener) OnJoinedGroupAdded(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testGroupListener) OnJoinedGroupDeleted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testGroupListener) OnGroupMemberAdded(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testGroupListener) OnGroupMemberDeleted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testGroupListener) OnGroupApplicationAdded(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testGroupListener) OnGroupApplicationDeleted(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testGroupListener) OnGroupInfoChanged(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testGroupListener) OnGroupMemberInfoChanged(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testGroupListener) OnGroupApplicationAccepted(callbackInfo string) {
|
||||
|
||||
}
|
||||
func (testGroupListener) OnGroupApplicationRejected(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
func (testGroupListener) OnGroupDismissed(callbackInfo string) {
|
||||
|
||||
}
|
||||
|
||||
type testConnListener struct {
|
||||
}
|
||||
|
||||
func (t *testConnListener) OnUserTokenInvalid(errMsg string) {}
|
||||
|
||||
func (t *testConnListener) OnUserTokenExpired() {
|
||||
|
||||
}
|
||||
func (t *testConnListener) OnConnecting() {
|
||||
|
||||
}
|
||||
|
||||
func (t *testConnListener) OnConnectSuccess() {
|
||||
|
||||
}
|
||||
|
||||
func (t *testConnListener) OnConnectFailed(ErrCode int32, ErrMsg string) {
|
||||
|
||||
}
|
||||
|
||||
func (t *testConnListener) OnKickedOffline() {
|
||||
|
||||
}
|
||||
|
||||
func (t *testConnListener) OnSelfInfoUpdated(info string) {
|
||||
|
||||
}
|
||||
func (t *testConnListener) OnUserCommandAdd(info string) {
|
||||
|
||||
}
|
||||
func (t *testConnListener) OnUserCommandUpdate(info string) {
|
||||
|
||||
}
|
||||
func (t *testConnListener) OnUserCommandDelete(info string) {
|
||||
|
||||
}
|
||||
func (t *testConnListener) OnSuccess() {
|
||||
|
||||
}
|
||||
|
||||
func (t *testConnListener) OnError(code int32, msg string) {
|
||||
|
||||
}
|
||||
121
go/chao-sdk-core/msgtest/sdk_user_simulator/user.go
Normal file
121
go/chao-sdk-core/msgtest/sdk_user_simulator/user.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package sdk_user_simulator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/open_im_sdk"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/ccontext"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
||||
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"go.etcd.io/etcd/api/v3/version"
|
||||
)
|
||||
|
||||
var (
|
||||
UserMessageMap = make(map[string]*MsgListenerCallBak)
|
||||
timeOffset int64
|
||||
)
|
||||
|
||||
var (
|
||||
TESTIP = "125.124.195.201"
|
||||
APIADDR = fmt.Sprintf("http://%v:10002", TESTIP)
|
||||
WSADDR = fmt.Sprintf("ws://%v:10001", TESTIP)
|
||||
SECRET = "openIM123"
|
||||
PLATFORMID = constant.WindowsPlatformID
|
||||
LogLevel = uint32(5)
|
||||
)
|
||||
|
||||
func SetServerTimeOffset(offset int64) {
|
||||
timeOffset = offset
|
||||
}
|
||||
func GetRelativeServerTime() int64 {
|
||||
return utils.GetCurrentTimestampByMill() + timeOffset
|
||||
}
|
||||
|
||||
func InitSDKAndLogin(userID, token string) error {
|
||||
userForSDK := open_im_sdk.NewLoginMgr()
|
||||
var cf sdk_struct.IMConfig
|
||||
cf.ApiAddr = APIADDR
|
||||
cf.PlatformID = int32(PLATFORMID)
|
||||
cf.WsAddr = WSADDR
|
||||
cf.DataDir = "./"
|
||||
cf.LogLevel = LogLevel
|
||||
cf.IsExternalExtensions = true
|
||||
cf.IsLogStandardOutput = true
|
||||
cf.LogFilePath = ""
|
||||
var testConnListener testConnListener
|
||||
userForSDK.InitSDK(cf, &testConnListener)
|
||||
if err := log.InitFromConfig(userID+"_open-im-sdk-core", "", int(LogLevel), true, false, cf.DataDir, 0, 24, version.Version); err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := ccontext.WithOperationID(userForSDK.BaseCtx(), utils.OperationIDGenerator())
|
||||
SetListener(userForSDK, userID)
|
||||
err := userForSDK.Login(ctx, userID, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetListener(userForSDK *open_im_sdk.LoginMgr, userID string) {
|
||||
var testConversation conversationCallBack
|
||||
userForSDK.SetConversationListener(&testConversation)
|
||||
|
||||
var testUser userCallback
|
||||
userForSDK.SetUserListener(testUser)
|
||||
|
||||
msgCallBack := NewMsgListenerCallBak(userID)
|
||||
UserMessageMap[userID] = msgCallBack
|
||||
userForSDK.SetAdvancedMsgListener(msgCallBack)
|
||||
|
||||
var friendListener testFriendListener
|
||||
userForSDK.SetFriendListener(friendListener)
|
||||
|
||||
var groupListener testGroupListener
|
||||
userForSDK.SetGroupListener(groupListener)
|
||||
}
|
||||
func CheckMessageDelay(singleMessageCount map[string]int, groupMessageCount map[string]int) {
|
||||
ctx := context.Background()
|
||||
log.ZDebug(ctx, "chat checking....")
|
||||
var sAllDelay, gAllDelay int64
|
||||
var sAllPercent, gAllPercent float64
|
||||
for userID, bak := range UserMessageMap {
|
||||
delay, percent := calculate(singleMessageCount, bak.SingleDelay)
|
||||
sAllDelay += delay
|
||||
sAllPercent += percent
|
||||
log.ZDebug(ctx, fmt.Sprintf("single chat %v delay %v ms,success rate %v/100", userID, delay,
|
||||
percent))
|
||||
gDelay, gPercent := calculate(groupMessageCount, bak.GroupDelay)
|
||||
gAllDelay += gDelay
|
||||
gAllPercent += gPercent
|
||||
log.ZDebug(ctx, fmt.Sprintf("group chat %v delay %v ms,success rate %v/100", userID, gDelay, gPercent))
|
||||
}
|
||||
log.ZDebug(ctx, fmt.Sprintf("single chat all delay %v ms,success rate %v/100", sAllDelay/int64(len(UserMessageMap)), sAllPercent/float64(len(UserMessageMap))))
|
||||
log.ZDebug(ctx, fmt.Sprintf("group chat all delay %v ms,success rate %v/100", gAllDelay/int64(len(UserMessageMap)), gAllPercent/float64(len(UserMessageMap))))
|
||||
log.ZDebug(ctx, fmt.Sprintf("all chat all delay %v ms,success rate %v/100", (sAllDelay+gAllDelay)/2, (sAllPercent+gAllPercent)/float64(2)))
|
||||
|
||||
log.ZDebug(ctx, "chat checking end....")
|
||||
|
||||
}
|
||||
|
||||
func calculate(singleMessageCount map[string]int, data map[string][]*SingleMessage) (delay int64, percent float64) {
|
||||
var allDelay int64
|
||||
var SuccessRate float64
|
||||
var successCount int
|
||||
for sendIDOrGroupID, messages := range data {
|
||||
if count, ok := singleMessageCount[sendIDOrGroupID]; ok {
|
||||
SuccessRate += float64(len(messages)) / float64(count)
|
||||
successCount++
|
||||
}
|
||||
var singleUserOrGroupDelay int64
|
||||
for _, message := range messages {
|
||||
singleUserOrGroupDelay += message.Delay
|
||||
}
|
||||
allDelay += singleUserOrGroupDelay / int64(len(messages))
|
||||
|
||||
}
|
||||
return allDelay / int64(len(data)), SuccessRate / float64(successCount) * 100
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user