feat: incr sync version.

This commit is contained in:
Gordon
2024-06-24 17:48:33 +08:00
parent e8ccae6349
commit 88b8043224
308 changed files with 55952 additions and 59 deletions

View 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
}

View File

@@ -0,0 +1,7 @@
package msgtest
import "testing"
func Test_CreateConversations(t *testing.T) {
}

View 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)
}
}
}

View 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)
}

View 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)
}

View 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)
}

View 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
}
}

View 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() {}

View 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)
}

View 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
}

View 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) {
}

View 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
}