package imapi import ( "context" "sync" "time" "git.imall.cloud/openim/chat/pkg/botstruct" "git.imall.cloud/openim/chat/pkg/eerrs" "git.imall.cloud/openim/protocol/auth" "git.imall.cloud/openim/protocol/constant" "git.imall.cloud/openim/protocol/group" "git.imall.cloud/openim/protocol/relation" "git.imall.cloud/openim/protocol/sdkws" "git.imall.cloud/openim/protocol/user" wrapperspb "git.imall.cloud/openim/protocol/wrapperspb" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" ) type CallerInterface interface { ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) ImportFriend(ctx context.Context, ownerUserID string, friendUserID []string) error GetUserToken(ctx context.Context, userID string, platform int32) (string, error) GetAdminTokenCache(ctx context.Context, userID string) (string, error) GetAdminTokenServer(ctx context.Context, userID string) (string, error) InviteToGroup(ctx context.Context, userID string, groupIDs []string) error UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string, userType int32, userFlag string) error UpdateUserInfoEx(ctx context.Context, userID string, ex string) error GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) AddNotificationAccount(ctx context.Context, req *user.AddNotificationAccountReq) error UpdateNotificationAccount(ctx context.Context, req *user.UpdateNotificationAccountInfoReq) error ForceOffLine(ctx context.Context, userID string) error RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error FindGroupInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) UserRegisterCount(ctx context.Context, start int64, end int64) (map[string]int64, int64, error) OnlineUserCount(ctx context.Context) (*OnlineUserCountResp, error) OnlineUserCountTrend(ctx context.Context, req *OnlineUserCountTrendReq) (*OnlineUserCountTrendResp, error) UserSendMsgCount(ctx context.Context, req *UserSendMsgCountReq) (*UserSendMsgCountResp, error) UserSendMsgCountTrend(ctx context.Context, req *UserSendMsgCountTrendReq) (*UserSendMsgCountTrendResp, error) UserSendMsgQuery(ctx context.Context, req *UserSendMsgQueryReq) (*UserSendMsgQueryResp, error) FriendUserIDs(ctx context.Context, userID string) ([]string, error) AccountCheckSingle(ctx context.Context, userID string) (bool, error) SendSimpleMsg(ctx context.Context, req *SendSingleMsgReq, key string) error } type authToken struct { token string expired time.Time } type Caller struct { imApi string imSecret string defaultIMUserID string tokenCache map[string]*authToken lock sync.RWMutex } func New(imApi string, imSecret string, defaultIMUserID string) CallerInterface { return &Caller{ imApi: imApi, imSecret: imSecret, defaultIMUserID: defaultIMUserID, tokenCache: make(map[string]*authToken), lock: sync.RWMutex{}, } } func (c *Caller) ImportFriend(ctx context.Context, ownerUserID string, friendUserIDs []string) error { if len(friendUserIDs) == 0 { return nil } _, err := importFriend.Call(ctx, c.imApi, &relation.ImportFriendReq{ OwnerUserID: ownerUserID, FriendUserIDs: friendUserIDs, }) return err } func (c *Caller) ImAdminTokenWithDefaultAdmin(ctx context.Context) (string, error) { return c.GetAdminTokenCache(ctx, c.defaultIMUserID) } func (c *Caller) GetAdminTokenCache(ctx context.Context, userID string) (string, error) { c.lock.RLock() t, ok := c.tokenCache[userID] c.lock.RUnlock() if ok && t.expired.After(time.Now()) { return t.token, nil } c.lock.Lock() defer c.lock.Unlock() t, ok = c.tokenCache[userID] if ok && t.expired.After(time.Now()) { return t.token, nil } token, err := c.GetAdminTokenServer(ctx, userID) if err != nil { return "", err } c.tokenCache[userID] = &authToken{token: token, expired: time.Now().Add(time.Minute * 4)} return token, nil } func (c *Caller) GetAdminTokenServer(ctx context.Context, userID string) (string, error) { resp, err := getAdminToken.Call(ctx, c.imApi, &auth.GetAdminTokenReq{ Secret: c.imSecret, UserID: userID, }) if err != nil { return "", err } log.ZDebug(ctx, "get im admin token from server", "userID", userID, "token", resp.Token) return resp.Token, nil } func (c *Caller) GetUserToken(ctx context.Context, userID string, platformID int32) (string, error) { resp, err := getuserToken.Call(ctx, c.imApi, &auth.GetUserTokenReq{ PlatformID: platformID, UserID: userID, }) if err != nil { return "", err } return resp.Token, nil } func (c *Caller) InviteToGroup(ctx context.Context, userID string, groupIDs []string) error { for _, groupID := range groupIDs { _, _ = inviteToGroup.Call(ctx, c.imApi, &group.InviteUserToGroupReq{ GroupID: groupID, Reason: "", InvitedUserIDs: []string{userID}, }) } return nil } func (c *Caller) UpdateUserInfo(ctx context.Context, userID string, nickName string, faceURL string, userType int32, userFlag string) error { _, err := updateUserInfo.Call(ctx, c.imApi, &user.UpdateUserInfoReq{UserInfo: &sdkws.UserInfo{ UserID: userID, Nickname: nickName, FaceURL: faceURL, UserType: userType, UserFlag: userFlag, }}) return err } func (c *Caller) UpdateUserInfoEx(ctx context.Context, userID string, ex string) error { _, err := updateUserInfoEx.Call(ctx, c.imApi, &user.UpdateUserInfoExReq{ UserInfo: &sdkws.UserInfoWithEx{ UserID: userID, Ex: &wrapperspb.StringValue{Value: ex}, }, }) return err } func (c *Caller) GetUserInfo(ctx context.Context, userID string) (*sdkws.UserInfo, error) { resp, err := c.GetUsersInfo(ctx, []string{userID}) if err != nil { return nil, err } if len(resp) == 0 { return nil, errs.ErrRecordNotFound.WrapMsg("record not found") } return resp[0], nil } func (c *Caller) GetUsersInfo(ctx context.Context, userIDs []string) ([]*sdkws.UserInfo, error) { resp, err := getUserInfo.Call(ctx, c.imApi, &user.GetDesignateUsersReq{ UserIDs: userIDs, }) if err != nil { return nil, err } return resp.UsersInfo, nil } func (c *Caller) RegisterUser(ctx context.Context, users []*sdkws.UserInfo) error { _, err := registerUser.Call(ctx, c.imApi, &user.UserRegisterReq{ Users: users, }) return err } func (c *Caller) ForceOffLine(ctx context.Context, userID string) error { for id := range constant.PlatformID2Name { _, _ = forceOffLine.Call(ctx, c.imApi, &auth.ForceLogoutReq{ PlatformID: int32(id), UserID: userID, }) } return nil } func (c *Caller) FindGroupInfo(ctx context.Context, groupIDs []string) ([]*sdkws.GroupInfo, error) { resp, err := getGroupsInfo.Call(ctx, c.imApi, &group.GetGroupsInfoReq{ GroupIDs: groupIDs, }) if err != nil { return nil, err } return resp.GroupInfos, nil } func (c *Caller) UserRegisterCount(ctx context.Context, start int64, end int64) (map[string]int64, int64, error) { resp, err := registerUserCount.Call(ctx, c.imApi, &user.UserRegisterCountReq{ Start: start, End: end, }) if err != nil { return nil, 0, err } return resp.Count, resp.Total, nil } // OnlineUserCount 获取在线人数统计 func (c *Caller) OnlineUserCount(ctx context.Context) (*OnlineUserCountResp, error) { return onlineUserCount.Call(ctx, c.imApi, &OnlineUserCountReq{}) } // OnlineUserCountTrend 获取在线人数走势统计 func (c *Caller) OnlineUserCountTrend(ctx context.Context, req *OnlineUserCountTrendReq) (*OnlineUserCountTrendResp, error) { return onlineUserCountTrend.Call(ctx, c.imApi, req) } // UserSendMsgCount 获取用户发送消息统计 func (c *Caller) UserSendMsgCount(ctx context.Context, req *UserSendMsgCountReq) (*UserSendMsgCountResp, error) { return userSendMsgCount.Call(ctx, c.imApi, req) } // UserSendMsgCountTrend 获取用户发送消息走势统计 func (c *Caller) UserSendMsgCountTrend(ctx context.Context, req *UserSendMsgCountTrendReq) (*UserSendMsgCountTrendResp, error) { return userSendMsgCountTrend.Call(ctx, c.imApi, req) } // UserSendMsgQuery 获取用户发送消息查询列表 func (c *Caller) UserSendMsgQuery(ctx context.Context, req *UserSendMsgQueryReq) (*UserSendMsgQueryResp, error) { return userSendMsgQuery.Call(ctx, c.imApi, req) } func (c *Caller) FriendUserIDs(ctx context.Context, userID string) ([]string, error) { resp, err := friendUserIDs.Call(ctx, c.imApi, &relation.GetFriendIDsReq{UserID: userID}) if err != nil { return nil, err } return resp.FriendIDs, nil } // return true when isUserNotExist. func (c *Caller) AccountCheckSingle(ctx context.Context, userID string) (bool, error) { resp, err := accountCheck.Call(ctx, c.imApi, &user.AccountCheckReq{CheckUserIDs: []string{userID}}) if err != nil { return false, err } if resp.Results[0].AccountStatus == constant.Registered { return false, eerrs.ErrAccountAlreadyRegister.Wrap() } return true, nil } func (c *Caller) SendSimpleMsg(ctx context.Context, req *SendSingleMsgReq, key string) error { _, err := sendSimpleMsg.CallWithQuery(ctx, c.imApi, req, map[string]string{botstruct.Key: key}) return err } func (c *Caller) AddNotificationAccount(ctx context.Context, req *user.AddNotificationAccountReq) error { _, err := addNotificationAccount.Call(ctx, c.imApi, req) return err } func (c *Caller) UpdateNotificationAccount(ctx context.Context, req *user.UpdateNotificationAccountInfoReq) error { _, err := updateNotificationAccount.Call(ctx, c.imApi, req) return err }