diff --git a/README.md b/README.md index e0962c6..3d345a0 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ func main() { √ - 关系链管理 + 关系链管理 添加单个好友 @@ -288,6 +288,21 @@ func main() { √ + + + 拉取好友 + + SNS.PullFriends + + + + √ + 拉取单个指定好友 @@ -338,6 +353,19 @@ func main() { 支持分页拉取所有黑名单。 √ + + + 拉取黑名单 + + SNS.PullBlacklist + + + + √ + 校验黑名单 @@ -641,7 +669,7 @@ func main() { √ - 群组管理 + 群组管理 拉取App中的所有群组ID @@ -657,6 +685,14 @@ func main() { 本方法由“拉取App中的所有群组ID(FetchGroupIds)”拓展而来 √ + + + 续拉取App中的所有群组 + + Group.PullGroups + 本方法由“拉取App中的所有群组(FetchGroups)”拓展而来 + √ + 创建群组 @@ -899,7 +935,7 @@ func main() { √ - 最近联系人 + 最近联系人 拉取会话列表 @@ -907,6 +943,19 @@ func main() { 支持分页拉取会话列表。 √ + + + 拉取会话列表 + + RecentContact.PullSessions + + + + √ + 删除单个会话 diff --git a/account/api.go b/account/api.go index b161c94..f89d93a 100644 --- a/account/api.go +++ b/account/api.go @@ -8,7 +8,6 @@ package account import ( - "errors" "fmt" "github.com/dobyte/tencent-im/internal/core" @@ -121,10 +120,10 @@ func (a *api) ImportAccount(account *Account) (err error) { // https://cloud.tencent.com/document/product/269/4919 func (a *api) ImportAccounts(userIds ...string) (failUserIds []string, err error) { if c := len(userIds); c == 0 { - err = errors.New("the account is not set") + err = core.NewError(enum.InvalidParamsCode, "the userid is not set") return } else if c > batchImportAccountsLimit { - err = errors.New(fmt.Sprintf("the number of imported accounts cannot exceed %d", batchImportAccountsLimit)) + err = core.NewError(enum.InvalidParamsCode, fmt.Sprintf("the number of imported accounts cannot exceed %d", batchImportAccountsLimit)) return } @@ -166,10 +165,10 @@ func (a *api) DeleteAccount(userId string) (err error) { // https://cloud.tencent.com/document/product/269/36443 func (a *api) DeleteAccounts(userIds ...string) (results []*DeleteResult, err error) { if c := len(userIds); c == 0 { - err = errors.New("the account is not set") + err = core.NewError(enum.InvalidParamsCode, "the userid is not set") return } else if c > batchDeleteAccountsLimit { - err = errors.New(fmt.Sprintf("the number of deleted accounts cannot exceed %d", batchDeleteAccountsLimit)) + err = core.NewError(enum.InvalidParamsCode, fmt.Sprintf("the number of deleted accounts cannot exceed %d", batchDeleteAccountsLimit)) return } @@ -219,10 +218,10 @@ func (a *api) CheckAccount(userId string) (bool, error) { // https://cloud.tencent.com/document/product/269/38417 func (a *api) CheckAccounts(userIds ...string) (results []*CheckResult, err error) { if c := len(userIds); c == 0 { - err = errors.New("the account is not set") + err = core.NewError(enum.InvalidParamsCode, "the account is not set") return } else if c > batchCheckAccountsLimit { - err = errors.New(fmt.Sprintf("the number of checked accounts cannot exceed %d", batchCheckAccountsLimit)) + err = core.NewError(enum.InvalidParamsCode, fmt.Sprintf("the number of checked accounts cannot exceed %d", batchCheckAccountsLimit)) return } diff --git a/account/types.go b/account/types.go index 0312086..3bc6478 100644 --- a/account/types.go +++ b/account/types.go @@ -21,13 +21,13 @@ type ( // 批量导入账号(参数) importAccountsReq struct { - UserIds []string `json:"UserIds"` // (必填)用户名,单个用户名长度不超过32字节,单次最多导入100个用户名 + UserIds []string `json:"Accounts"` // (必填)用户名,单个用户名长度不超过32字节,单次最多导入100个用户名 } // 批量导入账号(响应) importAccountsResp struct { types.ActionBaseResp - FailUserIds []string `json:"FailUserIds"` // 导入失败的帐号列表 + FailUserIds []string `json:"FailAccounts"` // 导入失败的帐号列表 } // 账号项 diff --git a/example/main.go b/example/main.go index 1c9fcb8..a6eb526 100644 --- a/example/main.go +++ b/example/main.go @@ -28,9 +28,9 @@ func main() { FaceUrl: "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png", }); err != nil { if e, ok := err.(im.Error); ok { - fmt.Println(fmt.Sprintf("import accout failed, code:%d, message:%s.", e.Code(), e.Message())) + fmt.Println(fmt.Sprintf("import account failed, code:%d, message:%s.", e.Code(), e.Message())) } else { - fmt.Println(fmt.Sprintf("import accout failed:%s.", err.Error())) + fmt.Println(fmt.Sprintf("import account failed:%s.", err.Error())) } } diff --git a/group/api.go b/group/api.go index b15da56..7822d61 100644 --- a/group/api.go +++ b/group/api.go @@ -8,6 +8,8 @@ package group import ( + "fmt" + "github.com/dobyte/tencent-im/internal/conv" "github.com/dobyte/tencent-im/internal/core" "github.com/dobyte/tencent-im/internal/enum" @@ -40,6 +42,8 @@ const ( commandDeleteGroupMsgBySender = "delete_group_msg_by_sender" commandGetGroupSimpleMsg = "group_msg_get_simple" commandGetOnlineMemberNum = "get_online_member_num" + + batchGetGroupsLimit = 50 // 批量获取群组限制 ) type API interface { @@ -55,6 +59,12 @@ type API interface { // https://cloud.tencent.com/document/product/269/1614 FetchGroups(limit int, next int, groupTypeAndFilter ...interface{}) (ret *FetchGroupsRet, err error) + // PullGroups 续拉取App中的所有群组 + // 本方法由“拉取App中的所有群组(FetchGroups)”拓展而来 + // 点击查看详细文档: + // https://cloud.tencent.com/document/product/269/1614 + PullGroups(arg *PullGroupsArg, fn func(ret *FetchGroupsRet)) (err error) + // CreateGroup 创建群组 // App 管理员可以通过该接口创建群组。 // 点击查看详细文档: @@ -264,6 +274,11 @@ func (a *api) FetchGroupIds(limit int, next int, groupType ...GroupType) (ret *F // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/1614 func (a *api) FetchGroups(limit int, next int, groupTypeAndFilter ...interface{}) (ret *FetchGroupsRet, err error) { + if limit > batchGetGroupsLimit { + err = core.NewError(enum.InvalidParamsCode, fmt.Sprintf("the number of groups id cannot exceed %d", batchGetGroupsLimit)) + return + } + var ( resp *FetchGroupIdsRet filter *Filter @@ -288,17 +303,41 @@ func (a *api) FetchGroups(limit int, next int, groupTypeAndFilter ...interface{} return } + ret = &FetchGroupsRet{Next: resp.Next, Total: resp.Total, HasMore: resp.HasMore} + if len(resp.List) > 0 { - var groups []*Group - if groups, err = a.GetGroups(resp.List, filter); err != nil { + if ret.List, err = a.GetGroups(resp.List, filter); err != nil { + return + } + } + + return +} + +// PullGroups 续拉取App中的所有群组 +// 本方法由“拉取App中的所有群组(FetchGroups)”拓展而来 +// 点击查看详细文档: +// https://cloud.tencent.com/document/product/269/1614 +func (a *api) PullGroups(arg *PullGroupsArg, fn func(ret *FetchGroupsRet)) (err error) { + var ( + limit = arg.Limit + groupType = arg.GroupType + filter = arg.Filter + next int + ret *FetchGroupsRet + ) + + for ret == nil || ret.HasMore { + ret, err = a.FetchGroups(limit, next, groupType, filter) + if err != nil { return } - ret = &FetchGroupsRet{ - Total: resp.Total, - Next: resp.Next, - HasMore: resp.HasMore, - List: groups, + fn(ret) + + if ret.HasMore { + next = ret.Next + break } } @@ -401,74 +440,80 @@ func (a *api) GetGroup(groupId string, filter ...*Filter) (group *Group, err err // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/1616 func (a *api) GetGroups(groupIds []string, filters ...*Filter) (groups []*Group, err error) { - if len(groupIds) > 0 { - req := &getGroupsReq{GroupIds: groupIds} - resp := &getGroupsResp{} - - if len(filters) > 0 { - if filter := filters[0]; filter != nil { - req.ResponseFilter = &responseFilter{ - GroupBaseInfoFilter: filter.GetAllBaseInfoFilterFields(), - MemberInfoFilter: filter.GetAllMemberInfoFilterFields(), - GroupCustomDataFilter: filter.GetAllGroupCustomDataFilterFields(), - MemberCustomDataFilter: filter.GetAllMemberCustomDataFilterFields(), - } + if c := len(groupIds); c == 0 { + err = core.NewError(enum.InvalidParamsCode, "the group's id is not set") + return + } else if c > batchGetGroupsLimit { + err = core.NewError(enum.InvalidParamsCode, fmt.Sprintf("the number of group's id cannot exceed %d", batchGetGroupsLimit)) + return + } + + req := &getGroupsReq{GroupIds: groupIds} + resp := &getGroupsResp{} + + if len(filters) > 0 { + if filter := filters[0]; filter != nil { + req.ResponseFilter = &responseFilter{ + GroupBaseInfoFilter: filter.GetAllBaseInfoFilterFields(), + MemberInfoFilter: filter.GetAllMemberInfoFilterFields(), + GroupCustomDataFilter: filter.GetAllGroupCustomDataFilterFields(), + MemberCustomDataFilter: filter.GetAllMemberCustomDataFilterFields(), } } + } - if err = a.client.Post(serviceGroup, commandGetGroups, req, resp); err != nil { - return - } + if err = a.client.Post(serviceGroup, commandGetGroups, req, resp); err != nil { + return + } - groups = make([]*Group, 0, len(resp.GroupInfos)) - for _, item := range resp.GroupInfos { - group := NewGroup() - group.setError(item.ErrorCode, item.ErrorInfo) - if group.err == nil { - group.id = item.GroupId - group.name = item.Name - group.types = item.Type - group.owner = item.OwnerUserId - group.avatar = item.FaceUrl - group.memberNum = item.MemberNum - group.maxMemberNum = item.MaxMemberNum - group.applyJoinOption = item.ApplyJoinOption - group.createTime = item.CreateTime - group.lastInfoTime = item.LastInfoTime - group.lastMsgTime = item.LastMsgTime - group.shutUpStatus = item.ShutUpAllMember - group.nextMsgSeq = item.NextMsgSeq - - if item.AppDefinedData != nil && len(item.AppDefinedData) > 0 { - for _, v := range item.AppDefinedData { - group.SetCustomData(v.Key, v.Value) - } + groups = make([]*Group, 0, len(resp.GroupInfos)) + for _, item := range resp.GroupInfos { + group := NewGroup() + group.setError(item.ErrorCode, item.ErrorInfo) + if group.err == nil { + group.id = item.GroupId + group.name = item.Name + group.types = item.Type + group.owner = item.OwnerUserId + group.avatar = item.FaceUrl + group.memberNum = item.MemberNum + group.maxMemberNum = item.MaxMemberNum + group.applyJoinOption = item.ApplyJoinOption + group.createTime = item.CreateTime + group.lastInfoTime = item.LastInfoTime + group.lastMsgTime = item.LastMsgTime + group.shutUpStatus = item.ShutUpAllMember + group.nextMsgSeq = item.NextMsgSeq + + if item.AppDefinedData != nil && len(item.AppDefinedData) > 0 { + for _, v := range item.AppDefinedData { + group.SetCustomData(v.Key, v.Value) } + } - if item.MemberList != nil && len(item.MemberList) > 0 { - for _, m := range item.MemberList { - member := &Member{ - userId: m.UserId, - role: m.Role, - joinTime: m.JoinTime, - nameCard: m.NameCard, - msgSeq: m.MsgSeq, - msgFlag: MsgFlag(m.MsgFlag), - lastSendMsgTime: m.LastSendMsgTime, - } + if item.MemberList != nil && len(item.MemberList) > 0 { + for _, m := range item.MemberList { + member := &Member{ + userId: m.UserId, + role: m.Role, + joinTime: m.JoinTime, + nameCard: m.NameCard, + msgSeq: m.MsgSeq, + msgFlag: MsgFlag(m.MsgFlag), + lastSendMsgTime: m.LastSendMsgTime, + } - if m.AppMemberDefinedData != nil && len(m.AppMemberDefinedData) > 0 { - for _, v := range m.AppMemberDefinedData { - member.SetCustomData(v.Key, v.Value) - } + if m.AppMemberDefinedData != nil && len(m.AppMemberDefinedData) > 0 { + for _, v := range m.AppMemberDefinedData { + member.SetCustomData(v.Key, v.Value) } - - group.AddMembers(member) } - } - groups = append(groups, group) + group.AddMembers(member) + } } + + groups = append(groups, group) } } diff --git a/group/group.go b/group/group.go index 4580bcb..8093c55 100644 --- a/group/group.go +++ b/group/group.go @@ -72,18 +72,18 @@ type Group struct { func NewGroup(id ...string) *Group { group := &Group{} if len(id) > 0 { - group.SetId(id[0]) + group.SetGroupId(id[0]) } return group } -// SetId 设置群ID -func (g *Group) SetId(id string) { +// SetGroupId 设置群ID +func (g *Group) SetGroupId(id string) { g.id = id } -// GetId 获取群ID -func (g *Group) GetId() string { +// GetGroupId 获取群ID +func (g *Group) GetGroupId() string { return g.id } diff --git a/group/types.go b/group/types.go index 76fb695..6676212 100644 --- a/group/types.go +++ b/group/types.go @@ -12,17 +12,17 @@ import "github.com/dobyte/tencent-im/internal/types" type ( // 拉取App中的所有群组(请求) fetchGroupIdsReq struct { - Limit int `json:"Limit,omitempty"` - Next int `json:"Next"` - GroupType string `json:"GroupType,omitempty"` + Limit int `json:"Limit,omitempty"` // (选填)本次获取的群组 ID 数量的上限,不得超过 10000。如果不填,默认为最大值 10000 + Next int `json:"Next,omitempty"` // (选填)群太多时分页拉取标志,第一次填0,以后填上一次返回的值,返回的 Next 为0代表拉完了 + GroupType string `json:"GroupType,omitempty"` // (选填)如果仅需要返回特定群组形态的群组,可以通过 GroupType 进行过滤,但此时返回的 TotalCount 的含义就变成了 App 中属于该群组形态的群组总数。不填为获取所有类型的群组。 } // 拉取App中的所有群组(响应) fetchGroupIdsResp struct { types.ActionBaseResp - Next int `json:"Next"` - TotalCount int `json:"TotalCount"` - GroupIdList []groupIdItem `json:"GroupIdList"` + Next int `json:"Next"` // 分页拉取的标志 + TotalCount int `json:"TotalCount"` // App 当前的群组总数。 + GroupIdList []groupIdItem `json:"GroupIdList"` // 获取到的群组 ID 的集合 } // FetchGroupIdsRet 拉取App中的所有群组ID返回 @@ -41,6 +41,13 @@ type ( List []*Group // 群组列表 } + // PullGroupsArg 续拉取群信息(参数) + PullGroupsArg struct { + Limit int // 分页限制 + GroupType GroupType // 群组类型 + Filter *Filter // 过滤器 + } + // 群ID groupIdItem struct { GroupId string `json:"GroupId"` // 群ID @@ -103,7 +110,7 @@ type ( // 获取群详细资料(请求) getGroupsReq struct { - GroupIds []string `json:"GroupIds"` + GroupIds []string `json:"GroupIdList"` ResponseFilter *responseFilter `json:"ResponseFilter,omitempty"` } @@ -298,7 +305,7 @@ type ( Random uint32 `json:"Random"` // (必填)无符号32位整数 MsgPriority string `json:"MsgPriority,omitempty"` // (选填)消息的优先级 FromUserId string `json:"From_Account,omitempty"` // (选填)消息来源帐号 - MsgBody []types.MsgBody `json:"MsgBody"` // (必填)消息体 + MsgBody []*types.MsgBody `json:"MsgBody"` // (必填)消息体 OnlineOnlyFlag int `json:"MsgOnlineOnlyFlag,omitempty"` // (选填)1表示消息仅发送在线成员,默认0表示发送所有成员,AVChatRoom(直播群)不支持该参数 SendMsgControl []string `json:"SendMsgControl,omitempty"` // (选填)消息发送权限,NoLastMsg 只对单条消息有效,表示不更新最近联系人会话;NoUnread 不计未读,只对单条消息有效。(如果该消息 MsgOnlineOnlyFlag 设置为1,则不允许使用该字段。) ForbidCallbackControl []string `json:"ForbidCallbackControl,omitempty"` // (选填)消息回调禁止开关,只对单条消息有效 @@ -383,10 +390,10 @@ type ( // 消息信息 messageItem struct { - FromUserId string `json:"From_Account"` // (必填)消息来源帐号 - MsgBody []types.MsgBody `json:"MsgBody"` // (必填)消息体 - SendTime int64 `json:"SendTime"` // (必填)消息发送时间 - Random uint32 `json:"Random,omitempty"` // (选填)无符号32位整数 + FromUserId string `json:"From_Account"` // (必填)消息来源帐号 + MsgBody []*types.MsgBody `json:"MsgBody"` // (必填)消息体 + SendTime int64 `json:"SendTime"` // (必填)消息发送时间 + Random uint32 `json:"Random,omitempty"` // (选填)无符号32位整数 } // 导入群消息(请求) diff --git a/im.go b/im.go index 6001822..161e946 100644 --- a/im.go +++ b/im.go @@ -86,17 +86,17 @@ func (i *im) GetUserSig() UserSig { return UserSig{UserSig: userSig, ExpireAt: expireAt} } -// SNS 获取关系链管理接口 +// SNS 获取关系链管理接口ok func (i *im) SNS() sns.API { return sns.NewAPI(i.client) } -// Mute 获取全局禁言管理接口 +// Mute 获取全局禁言管理接口ok func (i *im) Mute() mute.API { return mute.NewAPI(i.client) } -// Push 获取全员推送接口 +// Push 获取全员推送接口ok func (i *im) Push() push.API { return push.NewAPI(i.client) } @@ -106,27 +106,27 @@ func (i *im) Group() group.API { return group.NewAPI(i.client) } -// Account 获取账号管理接口 +// Account 获取账号管理接口ok func (i *im) Account() account.API { return account.NewAPI(i.client) } -// Profile 获取资料管理接口 +// Profile 获取资料管理接口ok func (i *im) Profile() profile.API { return profile.NewAPI(i.client) } -// Private 获取私聊消息接口 +// Private 获取私聊消息接口ok func (i *im) Private() private.API { return private.NewAPI(i.client) } -// Operation 获取运营管理接口 +// Operation 获取运营管理接口ok func (i *im) Operation() operation.API { return operation.NewAPI(i.client) } -// RecentContact 获取最近联系人接口 +// RecentContact 获取最近联系人接口ok func (i *im) RecentContact() recentcontact.API { return recentcontact.NewAPI(i.client) } diff --git a/im_test.go b/im_test.go index 6816cf3..9c6d5ec 100644 --- a/im_test.go +++ b/im_test.go @@ -21,20 +21,22 @@ import ( "github.com/dobyte/tencent-im/private" "github.com/dobyte/tencent-im/profile" "github.com/dobyte/tencent-im/push" + "github.com/dobyte/tencent-im/recentcontact" "github.com/dobyte/tencent-im/sns" ) const ( - assistant = "assistant" - test1 = "test1" - test2 = "test2" - test3 = "test3" - test4 = "test4" - test5 = "test5" - test6 = "test6" - test7 = "test7" - test8 = "test8" - test9 = "test9" + assistant = "assistant" + accountPrefix = "test" + test1 = "test1" + test2 = "test2" + test3 = "test3" + test4 = "test4" + test5 = "test5" + test6 = "test6" + test7 = "test7" + test8 = "test8" + test9 = "test9" ) func NewIM() im.IM { @@ -45,6 +47,29 @@ func NewIM() im.IM { }) } +// 处理错误 +func handleError(t *testing.T, callName string, err error) { + if e, ok := err.(im.Error); ok { + t.Fatalf("call %s failed, code:%d, message:%s.", callName, e.Code(), e.Message()) + } else { + t.Fatalf("call %s failed, err:%s.", callName, e.Error()) + } +} + +func testUserIds() []string { + return []string{ + test1, + test2, + test3, + test4, + test5, + test6, + test7, + test8, + test9, + } +} + // func NewIM() im.IM { // return im.NewIM(im.Options{ // AppId: 0, @@ -181,7 +206,7 @@ func TestIm_Account_QueryAccountsOnlineStatus(t *testing.T) { } // 全员推送 -func TestIm_Push_Push(t *testing.T) { +func TestIm_Push_PushMessage(t *testing.T) { message := push.NewMessage() message.SetSender(assistant) message.SetLifeTime(5000) @@ -199,7 +224,7 @@ func TestIm_Push_Push(t *testing.T) { taskId, err := NewIM().Push().PushMessage(message) if err != nil { - t.Fatal(err) + handleError(t, "push.PushMessage", err) } t.Log(taskId) @@ -211,7 +236,7 @@ func TestIm_Push_SetAttrNames(t *testing.T) { 0: "age", 1: "city", }); err != nil { - t.Fatal(err) + handleError(t, "push.SetAttrNames", err) } t.Log("Success") @@ -221,7 +246,7 @@ func TestIm_Push_SetAttrNames(t *testing.T) { func TestIm_Push_GetAttrNames(t *testing.T) { ret, err := NewIM().Push().GetAttrNames() if err != nil { - t.Fatal(err) + handleError(t, "push.GetAttrNames", err) } t.Log(ret) @@ -231,7 +256,7 @@ func TestIm_Push_GetAttrNames(t *testing.T) { func TestIm_Push_GetUserAttrs(t *testing.T) { ret, err := NewIM().Push().GetUserAttrs(test1) if err != nil { - t.Fatal(err) + handleError(t, "push.GetUserAttrs", err) } t.Log(ret) @@ -246,7 +271,7 @@ func TestIm_Push_SetUserAttrs(t *testing.T) { }, }) if err != nil { - t.Fatal(err) + handleError(t, "push.SetUserAttrs", err) } t.Log("Success") @@ -258,7 +283,7 @@ func TestIm_Push_DeleteUserAttrs(t *testing.T) { test1: {"age", "city"}, }) if err != nil { - t.Fatal(err) + handleError(t, "push.DeleteUserAttrs", err) } t.Log("Success") @@ -268,7 +293,7 @@ func TestIm_Push_DeleteUserAttrs(t *testing.T) { func TestIm_Push_GetUserTags(t *testing.T) { ret, err := NewIM().Push().GetUserTags(test1) if err != nil { - t.Fatal(err) + handleError(t, "push.GetUserTags", err) } t.Log(ret) @@ -280,7 +305,7 @@ func TestIm_Push_AddUserTags(t *testing.T) { test1: {"chengdu"}, }) if err != nil { - t.Fatal(err) + handleError(t, "push.AddUserTags", err) } t.Log("Success") @@ -292,7 +317,7 @@ func TestIm_Push_DeleteUserTags(t *testing.T) { test1: {"chengdu"}, }) if err != nil { - t.Fatal(err) + handleError(t, "push.DeleteUserTags", err) } t.Log("Success") @@ -302,7 +327,7 @@ func TestIm_Push_DeleteUserTags(t *testing.T) { func TestIm_Push_DeleteUserAllTags(t *testing.T) { err := NewIM().Push().DeleteUserAllTags(test1, test2) if err != nil { - t.Fatal(err) + handleError(t, "push.DeleteUserAllTags", err) } t.Log("Success") @@ -312,13 +337,14 @@ func TestIm_Push_DeleteUserAllTags(t *testing.T) { func TestIm_Profile_SetProfile(t *testing.T) { p := profile.NewProfile() p.SetUserId(assistant) + p.SetNickname("小助手") p.SetAvatar("http://www.qq.com") p.SetGender(profile.GenderTypeMale) p.SetLocation(1, 23, 7465, 92) p.SetLanguage(20) if err := NewIM().Profile().SetProfile(p); err != nil { - t.Fatal(err) + handleError(t, "profile.SetProfile", err) } t.Log("Success") @@ -336,7 +362,7 @@ func TestIm_Profile_GetProfile(t *testing.T) { profile.StandardAttrLanguage, }) if err != nil { - t.Fatal(err) + handleError(t, "profile.GetProfiles", err) } for _, p := range profiles { @@ -353,30 +379,35 @@ func TestIm_Profile_GetProfile(t *testing.T) { func TestIm_Operation_GetOperationData(t *testing.T) { data, err := NewIM().Operation().GetOperationData() if err != nil { - t.Fatal(err) + handleError(t, "operation.GetOperationData", err) } - t.Log(data) + t.Log(data[0].AppId) + t.Log(data[0].AppName) + t.Log(data[0].ActiveUserNum) + t.Log("Success") } // 拉取运营数据 func TestIm_Operation_GetHistoryData(t *testing.T) { - files, err := NewIM().Operation().GetHistoryData(operation.ChatTypeC2C, time.Date(2021, time.August, 22, 14, 0, 0, 0, time.Local)) + files, err := NewIM().Operation().GetHistoryData(operation.ChatTypeC2C, time.Date(2021, time.November, 4, 14, 0, 0, 0, time.Local)) if err != nil { - t.Fatal(err) + handleError(t, "operation.GetHistoryData", err) } t.Log(files) + t.Log("Success") } // 获取服务器IP地址 func TestIm_Operation_GetIpList(t *testing.T) { ips, err := NewIM().Operation().GetIPList() if err != nil { - t.Fatal(err) + handleError(t, "operation.GetIPList", err) } t.Log(ips) + t.Log("Success") } // 设置全局禁言 @@ -384,7 +415,7 @@ func TestIm_Mute_SetNoSpeaking(t *testing.T) { var privateMuteTime uint = 400 var groupMuteTime uint = 200 if err := NewIM().Mute().SetNoSpeaking(assistant, &privateMuteTime, &groupMuteTime); err != nil { - t.Fatal(err) + handleError(t, "mute.SetNoSpeaking", err) } t.Log("Success") @@ -394,7 +425,7 @@ func TestIm_Mute_SetNoSpeaking(t *testing.T) { func TestIm_Mute_GetNoSpeaking(t *testing.T) { ret, err := NewIM().Mute().GetNoSpeaking(assistant) if err != nil { - t.Fatal(err) + handleError(t, "mute.GetNoSpeaking", err) } t.Log(ret.PrivateMuteTime) @@ -403,29 +434,28 @@ func TestIm_Mute_GetNoSpeaking(t *testing.T) { // 添加好友 func TestIm_SNS_AddFriends(t *testing.T) { - friends := make([]*sns.Friend, 0) + var ( + userIds = testUserIds() + friends = make([]*sns.Friend, 0, len(userIds)) + friend *sns.Friend + ) - var friend *sns.Friend - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) + for _, userId := range userIds { friend = sns.NewFriend(userId) friend.SetAddSource("android") friends = append(friends, friend) - userIds = append(userIds, userId) } failUserIds, err := NewIM().Account().ImportAccounts(userIds...) if err != nil { - t.Fatal(err) + handleError(t, "account.ImportAccounts", err) } t.Log(failUserIds) - results, err := NewIM().SNS().AddFriends("assistant", true, false, friends...) + results, err := NewIM().SNS().AddFriends(assistant, true, false, friends...) if err != nil { - t.Fatal(err) + handleError(t, "sns.AddFriends", err) } t.Log(results) @@ -433,16 +463,15 @@ func TestIm_SNS_AddFriends(t *testing.T) { // 导入好友 func TestIm_SNS_ImportFriends(t *testing.T) { - friends := make([]*sns.Friend, 0) - - var friend *sns.Friend - var userIds []string - var userId string - var now = time.Now().Unix() - for i := 20; i < 30; i++ { - userId = "test" + strconv.Itoa(i) - friend = sns.NewFriend() - friend.SetUserId(userId) + var ( + userIds = testUserIds() + friends = make([]*sns.Friend, 0, len(userIds)) + friend *sns.Friend + now = time.Now().Unix() + ) + + for _, userId := range userIds { + friend = sns.NewFriend(userId) friend.SetAddSource("android") friend.SetGroup("测试组") friend.SetAddWording("测试一下") @@ -450,35 +479,53 @@ func TestIm_SNS_ImportFriends(t *testing.T) { friend.SetRemark("测试好友") friend.SetRemarkTime(now) friends = append(friends, friend) - userIds = append(userIds, userId) } failUserIds, err := NewIM().Account().ImportAccounts(userIds...) if err != nil { - t.Fatal(err) + handleError(t, "account.ImportAccounts", err) } t.Log(failUserIds) - results, err := NewIM().SNS().ImportFriends("assistant", friends...) + results, err := NewIM().SNS().ImportFriends(assistant, friends...) if err != nil { - t.Fatal(err) + handleError(t, "sns.ImportFriends", err) } t.Log(results) + t.Log("Success") +} + +// 更新单个好友 +func TestIm_SNS_UpdateFriend(t *testing.T) { + friend := sns.NewFriend(test1) + friend.SetAddSource("android") // 忽略更新 + friend.SetGroup("测试组") + friend.SetAddWording("更新单个好友") // 忽略更新 + friend.SetAddTime(time.Now().Unix()) // 忽略更新 + friend.SetRemark("更新单个好友") + friend.SetRemarkTime(time.Now().Unix()) // 忽略更新 + + err := NewIM().SNS().UpdateFriend(assistant, friend) + if err != nil { + handleError(t, "sns.UpdateFriend", err) + } + + t.Log("Success") } // 更新好友 func TestIm_SNS_UpdateFriends(t *testing.T) { - friends := make([]*sns.Friend, 0) - - var friend *sns.Friend - var userIds []string - var userId string - var now = time.Now().Unix() - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - friend = sns.NewFriend(userId) + var ( + total = 10 + friends = make([]*sns.Friend, 0, total) + friend *sns.Friend + now = time.Now().Unix() + ) + + for i := 0; i < total; i++ { + friend = sns.NewFriend(accountPrefix + strconv.Itoa(i)) friend.SetAddSource("android") friend.SetGroup("测试组") friend.SetAddWording("测试一下") @@ -486,46 +533,35 @@ func TestIm_SNS_UpdateFriends(t *testing.T) { friend.SetRemark("测试好友") friend.SetRemarkTime(now) friends = append(friends, friend) - userIds = append(userIds, userId) } - failUserIds, err := NewIM().Account().ImportAccounts(userIds...) + results, err := NewIM().SNS().UpdateFriends(assistant, friends...) if err != nil { - t.Fatal(err) - } - - t.Log(failUserIds) - - results, err := NewIM().SNS().UpdateFriends("assistant", friends...) - if err != nil { - t.Fatal(err) + handleError(t, "sns.UpdateFriends", err) } t.Log(results) + t.Log("Success") } // 删除好友 func TestIm_SNS_DeleteFriends(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() - results, err := NewIM().SNS().DeleteFriends("assistant", false, userIds...) + results, err := NewIM().SNS().DeleteFriends(assistant, false, userIds...) if err != nil { - t.Fatal(err) + handleError(t, "sns.DeleteFriends", err) } t.Log(results) + t.Log("Success") } // 删除所有好友 func TestIm_SNS_DeleteAllFriends(t *testing.T) { - err := NewIM().SNS().DeleteAllFriends("assistant") + err := NewIM().SNS().DeleteAllFriends(assistant) if err != nil { - t.Fatal(err) + handleError(t, "sns.DeleteAllFriends", err) } t.Log("Success") @@ -533,31 +569,22 @@ func TestIm_SNS_DeleteAllFriends(t *testing.T) { // 校验好友 func TestIm_SNS_CheckFriends(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() - results, err := NewIM().SNS().CheckFriends("assistant", sns.CheckTypeSingle, userIds...) + results, err := NewIM().SNS().CheckFriends(assistant, sns.CheckTypeSingle, userIds...) if err != nil { - t.Fatal(err) + handleError(t, "sns.CheckFriends", err) } t.Log(results) + t.Log("Success") } // 拉取指定好友 func TestIm_SNS_GetFriends(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() - friends, err := NewIM().SNS().GetFriends("assistant", []string{ + friends, err := NewIM().SNS().GetFriends(assistant, []string{ sns.FriendAttrAddSource, sns.FriendAttrRemark, sns.FriendAttrRemarkTime, // 此Tag无效,GetFriends内部忽略了 @@ -568,7 +595,7 @@ func TestIm_SNS_GetFriends(t *testing.T) { sns.StandardAttrBirthday, }, userIds...) if err != nil { - t.Fatal(err) + handleError(t, "sns.GetFriends", err) } // 第一种获取方式 @@ -587,8 +614,8 @@ func TestIm_SNS_GetFriends(t *testing.T) { // 第二种获取方式 for _, friend := range friends { - if err := friend.GetError(); err != nil { - t.Log(fmt.Sprintf("获取账号%s失败", friend.GetUserId())) + if err = friend.GetError(); err != nil { + t.Log(fmt.Sprintf("获取账号%s失败:%s", friend.GetUserId(), err.Error())) } else { t.Log(friend.GetUserId()) t.Log(friend.GetAddSource()) @@ -613,26 +640,27 @@ func TestIm_SNS_FetchFriends(t *testing.T) { customSequence = 0 ) - for ret == nil || !ret.IsOver { - ret, err = s.FetchFriends("assistant", startIndex, standardSequence, customSequence) + for ret == nil || ret.HasMore { + ret, err = s.FetchFriends(assistant, startIndex, standardSequence, customSequence) if err != nil { - t.Error(err) - return + handleError(t, "sns.FetchFriends", err) } - startIndex = ret.NextStartIndex + startIndex = ret.StartIndex standardSequence = ret.StandardSequence customSequence = ret.CustomSequence - t.Log("下一个开始点:", ret.NextStartIndex) - t.Log("是否拉取完毕:", ret.IsOver) + t.Log("下一个开始点:", ret.StartIndex) t.Log("标准排序:", ret.StandardSequence) t.Log("自定义排序:", ret.CustomSequence) - t.Log("好友总数:", ret.FriendNum) + t.Log("好友总数:", ret.Total) + t.Log("是否还有数据:", ret.HasMore) t.Log("好友列表:") fmt.Println() - for _, friend := range ret.Friends { - if friend.IsValid() { + for _, friend := range ret.List { + if err = friend.GetError(); err != nil { + t.Log(fmt.Sprintf("获取账号%s失败:%s", friend.GetUserId(), err.Error())) + } else { t.Log(friend.GetUserId()) t.Log(friend.GetAddSource()) t.Log(friend.GetRemark()) @@ -646,38 +674,61 @@ func TestIm_SNS_FetchFriends(t *testing.T) { } } +// 续拉取好友 +func TestIm_SNS_PullFriends(t *testing.T) { + err := NewIM().SNS().PullFriends(assistant, func(ret *sns.FetchFriendsRet) { + t.Log("下一个开始点:", ret.StartIndex) + t.Log("标准排序:", ret.StandardSequence) + t.Log("自定义排序:", ret.CustomSequence) + t.Log("好友总数:", ret.Total) + t.Log("是否还有数据:", ret.HasMore) + t.Log("好友列表:") + fmt.Println() + for _, friend := range ret.List { + if err := friend.GetError(); err != nil { + t.Log(fmt.Sprintf("获取账号%s失败:%s", friend.GetUserId(), err.Error())) + } else { + t.Log(friend.GetUserId()) + t.Log(friend.GetAddSource()) + t.Log(friend.GetRemark()) + t.Log(friend.GetRemarkTime()) + t.Log(friend.GetGroup()) + t.Log(friend.GetNickname()) + t.Log(friend.GetBirthday()) + fmt.Println() + } + } + }) + if err != nil { + handleError(t, "sns.PullFriends", err) + } + t.Log("Success") +} + // 添加黑名单 func TestIm_SNS_AddBlacklist(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() - results, err := NewIM().SNS().AddBlacklist("assistant", userIds...) + results, err := NewIM().SNS().AddBlacklist(assistant, userIds...) if err != nil { - t.Fatal(err) + handleError(t, "sns.AddBlacklist", err) } t.Log(results) + t.Log("Success") } // 删除黑名单 func TestIm_SNS_DeleteBlacklist(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 5; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() - results, err := NewIM().SNS().DeleteBlacklist("assistant", userIds...) + results, err := NewIM().SNS().DeleteBlacklist(assistant, userIds...) if err != nil { - t.Fatal(err) + handleError(t, "sns.DeleteBlacklist", err) } t.Log(results) + t.Log("Success") } // 拉取黑名单 @@ -691,40 +742,56 @@ func TestIm_SNS_FetchBlacklist(t *testing.T) { standardSequence = 0 ) - for ret == nil || !ret.IsOver { - ret, err = s.FetchBlacklist("assistant", startIndex, maxLimited, standardSequence) + for ret == nil || ret.HasMore { + ret, err = s.FetchBlacklist(assistant, startIndex, maxLimited, standardSequence) if err != nil { - t.Error(err) - return + handleError(t, "sns.FetchBlacklist", err) } - startIndex = ret.NextStartIndex + startIndex = ret.StartIndex standardSequence = ret.StandardSequence t.Log("下一个开始点:", startIndex) t.Log("标准排序:", standardSequence) t.Log("黑名单列表:") fmt.Println() - for _, blacklist := range ret.Blacklists { + for _, blacklist := range ret.List { t.Log(blacklist.UserId) t.Log(blacklist.Time) fmt.Println() } } + + t.Log("Success") +} + +// 续拉取黑名单 +func TestIm_SNS_PullBlacklist(t *testing.T) { + err := NewIM().SNS().PullBlacklist(assistant, 2, func(ret *sns.FetchBlacklistRet) { + t.Log("下一个开始点:", ret.StartIndex) + t.Log("标准排序:", ret.StandardSequence) + t.Log("黑名单列表:") + fmt.Println() + for _, blacklist := range ret.List { + t.Log(blacklist.UserId) + t.Log(blacklist.Time) + fmt.Println() + } + }) + if err != nil { + handleError(t, "sns.PullBlacklist", err) + } + + t.Log("Success") } // 校验黑名单 func TestIm_SNS_CheckBlacklist(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() - results, err := NewIM().SNS().CheckBlacklist("assistant", sns.BlacklistCheckTypeSingle, userIds...) + results, err := NewIM().SNS().CheckBlacklist(assistant, sns.BlacklistCheckTypeSingle, userIds...) if err != nil { - t.Fatal(err) + handleError(t, "sns.CheckBlacklist", err) } for _, result := range results { @@ -743,33 +810,31 @@ func TestIm_SNS_CheckBlacklist(t *testing.T) { } fmt.Println() } + + t.Log("Success") } // 添加分组 func TestIm_SNS_AddGroups(t *testing.T) { - var userIds []string - var userId string - for i := 0; i < 10; i++ { - userId = "test" + strconv.Itoa(i) - userIds = append(userIds, userId) - } + var userIds = testUserIds() _, results, err := NewIM().SNS().AddGroups("assistant", []string{ - "测试3", - "测试4", + "测试5", + "测试6", }, userIds) if err != nil { - t.Fatal(err) + handleError(t, "sns.AddGroups", err) } t.Log(results) + t.Log("Success") } // 删除分组 func TestIm_SNS_DeleteGroups(t *testing.T) { _, err := NewIM().SNS().DeleteGroups("assistant", "测试3", "测试4") if err != nil { - t.Fatal(err) + handleError(t, "sns.DeleteGroups", err) } t.Log("Success") @@ -780,19 +845,16 @@ func TestIm_SNS_GetGroups(t *testing.T) { var ( err error lastSequence int - groupNames = []string{ - "测试1", - "测试2", - } - results []*sns.GroupResult + results []*sns.GroupResult ) - lastSequence, results, err = NewIM().SNS().GetGroups("assistant", lastSequence, true, groupNames...) + lastSequence, results, err = NewIM().SNS().GetGroups("assistant", lastSequence, true, "测试1", "测试2") if err != nil { - t.Fatal(err) + handleError(t, "sns.GetGroups", err) } t.Log(results) + t.Log("Success") } // 发送单聊消息 @@ -816,11 +878,12 @@ func TestIm_Private_SendMessage(t *testing.T) { ret, err := NewIM().Private().SendMessage(message) if err != nil { - t.Fatal(err) + handleError(t, "private.SendMessage", err) } t.Log(ret.MsgKey) t.Log(ret.MsgTime) + t.Log("Success") } // 批量发单聊消息 @@ -834,7 +897,7 @@ func TestIm_Private_SendMessages(t *testing.T) { ret, err := NewIM().Private().SendMessages(message) if err != nil { - t.Fatal(err) + handleError(t, "private.SendMessages", err) } t.Log(ret.MsgKey) @@ -854,7 +917,7 @@ func TestIm_Private_ImportMessage(t *testing.T) { err := NewIM().Private().ImportMessage(message) if err != nil { - t.Fatal(err) + handleError(t, "private.ImportMessage", err) } t.Log("Success") @@ -867,31 +930,30 @@ func TestIm_Private_FetchMessages(t *testing.T) { p = NewIM().Private() ret *private.FetchMessagesRet arg = &private.FetchMessagesArg{ - FromUserId: "test1", - ToUserId: "assistant", + FromUserId: test1, + ToUserId: assistant, MaxLimited: 5, MinTime: time.Now().Add(-20 * time.Hour).Unix(), MaxTime: time.Now().Unix(), } ) - for ret == nil || !ret.IsOver { + for ret == nil || ret.HasMore { ret, err = p.FetchMessages(arg) if err != nil { - t.Error(err) - return + handleError(t, "private.FetchMessages", err) } - if !ret.IsOver { + if ret.HasMore { arg.LastMsgKey = ret.LastMsgKey arg.MaxTime = ret.LastMsgTime } - t.Log(ret.IsOver) + t.Log(ret.HasMore) t.Log(ret.LastMsgKey) t.Log(ret.LastMsgTime) - t.Log(ret.MsgCount) - t.Log(ret.MsgList) + t.Log(ret.Count) + t.Log(ret.List) fmt.Println() } } @@ -905,15 +967,15 @@ func TestIm_Private_PullMessages(t *testing.T) { MinTime: time.Now().Add(-30 * time.Hour).Unix(), MaxTime: time.Now().Unix(), }, func(ret *private.FetchMessagesRet) { - t.Log(ret.IsOver) + t.Log(ret.HasMore) t.Log(ret.LastMsgKey) t.Log(ret.LastMsgTime) - t.Log(ret.MsgCount) - t.Log(ret.MsgList) + t.Log(ret.Count) + t.Log(ret.List) fmt.Println() }) if err != nil { - t.Fatal(err) + handleError(t, "private.PullMessages", err) } t.Log("Success") @@ -921,9 +983,9 @@ func TestIm_Private_PullMessages(t *testing.T) { // 撤销消息 func TestIm_Private_RevokeMessage(t *testing.T) { - err := NewIM().Private().RevokeMessage("assistant", "test1", "31906_833502_1572869830") + err := NewIM().Private().RevokeMessage(assistant, test1, "31906_833502_1572869830") if err != nil { - t.Fatal(err) + handleError(t, "private.RevokeMessage", err) } t.Log("Success") @@ -931,9 +993,9 @@ func TestIm_Private_RevokeMessage(t *testing.T) { // 设置单聊消息已读 func TestIm_Private_SetMessageRead(t *testing.T) { - err := NewIM().Private().SetMessageRead("assistant", "test1") + err := NewIM().Private().SetMessageRead(assistant, test1) if err != nil { - t.Fatal(err) + handleError(t, "private.SetMessageRead", err) } t.Log("Success") @@ -941,9 +1003,9 @@ func TestIm_Private_SetMessageRead(t *testing.T) { // 获取未读消息数 func TestIm_Private_GetUnreadMessageNum(t *testing.T) { - ret, err := NewIM().Private().GetUnreadMessageNum("assistant", "test1", "test2") + ret, err := NewIM().Private().GetUnreadMessageNum(assistant, test1, test2) if err != nil { - t.Fatal(err) + handleError(t, "private.GetUnreadMessageNum", err) } t.Log(ret.Total) @@ -958,20 +1020,19 @@ func TestIm_Group_CreateGroup(t *testing.T) { g.SetType(group.TypeLiveRoom) g.SetMaxMemberNum(30) g.SetAvatar("http://www.baidu.com") - // g.SetId("test_group1") + g.SetGroupId("test_group2") g.SetIntroduction("这是一个测试群") g.SetNotification("这是一个测试群公告") for i := 1; i < 10; i++ { - member := group.NewMember() - member.SetUserId("test" + strconv.Itoa(i)) + member := group.NewMember(accountPrefix + strconv.Itoa(i)) member.SetJoinTime(time.Now()) g.AddMembers(member) } groupId, err := NewIM().Group().CreateGroup(g) if err != nil { - t.Fatal(err) + handleError(t, "group.CreateGroup", err) } t.Log(groupId) @@ -981,7 +1042,7 @@ func TestIm_Group_CreateGroup(t *testing.T) { func TestIm_Group_DestroyGroup(t *testing.T) { err := NewIM().Group().DestroyGroup("test_group1") if err != nil { - t.Fatal(err) + handleError(t, "group.DestroyGroup", err) } t.Log("Success") @@ -995,7 +1056,7 @@ func TestIm_Group_GetGroup(t *testing.T) { } if g != nil { - t.Log(g.GetId()) + t.Log(g.GetGroupId()) t.Log(g.GetName()) t.Log(g.GetType()) t.Log(g.GetOwner()) @@ -1016,7 +1077,7 @@ func TestIm_Group_GetGroups(t *testing.T) { if err = g.GetError(); err != nil { t.Error(err) } else { - t.Log(g.GetId()) + t.Log(g.GetGroupId()) t.Log(g.GetName()) t.Log(g.GetType()) t.Log(g.GetOwner()) @@ -1069,7 +1130,7 @@ func TestIm_Group_UpdateGroup(t *testing.T) { g.SetType(group.TypePublic) g.SetMaxMemberNum(30) g.SetAvatar("http://www.baidu.com") - g.SetId("test_group1") + g.SetGroupId("test_group1") g.SetIntroduction("这是一个测试群") g.SetNotification("这是一个测试群公告") @@ -1114,7 +1175,7 @@ func TestIm_Group_FetchGroupMembers(t *testing.T) { func TestIm_Group_FetchGroupIds(t *testing.T) { ret, err := NewIM().Group().FetchGroupIds(3, 7964653962) if err != nil { - t.Fatal(err) + handleError(t, "group.FetchGroupIds", err) } t.Log(ret.Total) @@ -1125,9 +1186,9 @@ func TestIm_Group_FetchGroupIds(t *testing.T) { // 拉取App中的所有群组 func TestIm_Group_FetchGroups(t *testing.T) { - ret, err := NewIM().Group().FetchGroups(3, 7964653962) + ret, err := NewIM().Group().FetchGroups(50, 7964653962) if err != nil { - t.Fatal(err) + handleError(t, "group.FetchGroups", err) } t.Log(ret.Total) @@ -1135,12 +1196,32 @@ func TestIm_Group_FetchGroups(t *testing.T) { t.Log(ret.HasMore) for _, g := range ret.List { - t.Log(g.GetId()) + t.Log(g.GetGroupId()) t.Log(g.GetOwner()) t.Log(g.GetName()) } } +// 续拉取App中的所有群组 +func TestIm_Group_PullGroups(t *testing.T) { + err := NewIM().Group().PullGroups(&group.PullGroupsArg{ + Limit: 50, + }, func(ret *group.FetchGroupsRet) { + t.Log(ret.Total) + t.Log(ret.Next) + t.Log(ret.HasMore) + + for _, g := range ret.List { + t.Log(g.GetGroupId()) + t.Log(g.GetOwner()) + t.Log(g.GetName()) + } + }) + if err != nil { + handleError(t, "group.PullGroups", err) + } +} + // 修改群成员资料 func TestIm_Group_UpdateGroupMember(t *testing.T) { member := group.NewMember(test1) @@ -1355,3 +1436,38 @@ func TestIm_Group_FetchMessages(t *testing.T) { t.Log(ret) } + +// 拉取会话列表 +func TestIm_RecentContact_FetchSessions(t *testing.T) { + ret, err := NewIM().RecentContact().FetchSessions(&recentcontact.FetchSessionsArg{ + UserId: assistant, + }) + if err != nil { + handleError(t, "recentcontact.FetchSessions", err) + } + + t.Log(ret) + t.Log("Success") +} + +// 拉取会话列表 +func TestIm_RecentContact_PullSessions(t *testing.T) { + err := NewIM().RecentContact().PullSessions(&recentcontact.PullSessionsArg{ + UserId: assistant, + }, func(ret *recentcontact.FetchSessionsRet) { + t.Log(ret) + }) + if err != nil { + handleError(t, "recentcontact.PullSessions", err) + } + t.Log("Success") +} + +// 删除单个会话 +func TestIm_RecentContact_DeleteSession(t *testing.T) { + err := NewIM().RecentContact().DeleteSession(assistant, test1, recentcontact.SessionTypeC2C, true) + if err != nil { + handleError(t, "recentcontact.DeleteSession", err) + } + t.Log("Success") +} diff --git a/internal/entity/mesage.go b/internal/entity/mesage.go index b37597a..b880377 100644 --- a/internal/entity/mesage.go +++ b/internal/entity/mesage.go @@ -22,11 +22,11 @@ var ( ) type Message struct { - sender string // 发送方UserId - lifeTime int // 消息离线保存时长(单位:秒),最长为7天(604800秒) - random uint32 // 消息随机数,由随机函数产生 - body []types.MsgBody // 消息体 - offlinePush *offlinePush // 推送实体 + sender string // 发送方UserId + lifeTime int // 消息离线保存时长(单位:秒),最长为7天(604800秒) + random uint32 // 消息随机数,由随机函数产生 + body []*types.MsgBody // 消息体 + offlinePush *offlinePush // 推送实体 } // SetSender 设置发送方UserId @@ -66,7 +66,7 @@ func (m *Message) GetRandom() uint32 { // AddContent 添加消息内容(添加会累加之前的消息内容) func (m *Message) AddContent(msgContent ...interface{}) { if m.body == nil { - m.body = make([]types.MsgBody, 0) + m.body = make([]*types.MsgBody, 0) } if len(msgContent) > 0 { @@ -93,7 +93,7 @@ func (m *Message) AddContent(msgContent ...interface{}) { msgType = "" } - m.body = append(m.body, types.MsgBody{ + m.body = append(m.body, &types.MsgBody{ MsgType: msgType, MsgContent: content, }) @@ -110,7 +110,7 @@ func (m *Message) SetContent(msgContent ...interface{}) { } // GetBody 获取消息体 -func (m *Message) GetBody() []types.MsgBody { +func (m *Message) GetBody() []*types.MsgBody { return m.body } diff --git a/internal/enum/code.go b/internal/enum/code.go index 3c694c5..6ee9e94 100644 --- a/internal/enum/code.go +++ b/internal/enum/code.go @@ -8,7 +8,9 @@ package enum const ( - SuccessCode = 0 // 成功 - InvalidParamsCode = -1 // 无效参数(自定义) - InvalidResponseCode = -2 // 无效响应(自定义) + SuccessActionStatus = "OK" // 成功状态 + FailActionStatus = "FAIL" // 失败状态 + SuccessCode = 0 // 成功 + InvalidParamsCode = -1 // 无效参数(自定义) + InvalidResponseCode = -2 // 无效响应(自定义) ) diff --git a/internal/enum/enum.go b/internal/enum/enum.go index 5de0732..963846c 100644 --- a/internal/enum/enum.go +++ b/internal/enum/enum.go @@ -12,9 +12,6 @@ import ( ) const ( - SuccessActionStatus = "OK" - FailActionStatus = "FAIL" - // 消息类型 MsgText = "TIMTextElem" // 消息元素 MsgLocation = "TIMLocationElem" // 地理位置消息元素 diff --git a/internal/types/types.go b/internal/types/types.go index 2b22a90..2ece00c 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -90,6 +90,7 @@ type ( // MsgSoundContent 语音消息元素 MsgSoundContent struct { + UUID string `json:"UUID"` // (必填)语音的唯一标识,类型为 String。客户端用于索引语音的键值。无法通过该字段下载相应的语音。若需要获取该语音,请升级 IM SDK 版本至4.X。 Url string `json:"Url"` // (必填)语音下载地址,可通过该 URL 地址直接下载相应语音 Size int `json:"Size"` // (必填)语音数据大小,单位:字节。 Second int `json:"Second"` // (必填)语音时长,单位:秒。 @@ -98,27 +99,30 @@ type ( // MsgImageContent 图像消息元素 MsgImageContent struct { - UUID string `json:"UUID"` // (必填)图片序列号。后台用于索引图片的键值。 - ImageFormat int `json:"ImageFormat"` // (必填)图片格式。JPG = 1,GIF = 2,PNG = 3,BMP = 4,其他 = 255。 - ImageInfos []ImageInfo `json:"ImageInfoArray"` // (必填)原图、缩略图或者大图下载信息。 + UUID string `json:"UUID"` // (必填)图片序列号。后台用于索引图片的键值。 + ImageFormat int `json:"ImageFormat"` // (必填)图片格式。JPG = 1,GIF = 2,PNG = 3,BMP = 4,其他 = 255。 + ImageInfos []*ImageInfo `json:"ImageInfoArray"` // (必填)原图、缩略图或者大图下载信息。 } // MsgFileContent 文件消息元素 MsgFileContent struct { Url string `json:"Url"` // (必填)文件下载地址,可通过该 URL 地址直接下载相应文件 - Size int `json:"FileSize"` // (必填)文件数据大小,单位:字节 - Name string `json:"FileName"` // (必填)文件名称 + UUID string `json:"UUID"` // (必填)文件的唯一标识,客户端用于索引文件的键值。 + FileSize int `json:"FileSize"` // (必填)文件数据大小,单位:字节 + FileName string `json:"FileName"` // (必填)文件名称 DownloadFlag int `json:"Download_Flag"` // (必填)文件下载方式标记。目前 Download_Flag 取值只能为2,表示可通过Url字段值的 URL 地址直接下载文件。 } // MsgVideoContent 视频消息元素 MsgVideoContent struct { + VideoUUID string `json:"VideoUUID"` // (必填)视频的唯一标识,客户端用于索引视频的键值。 VideoUrl string `json:"VideoUrl"` // (必填)视频下载地址。可通过该 URL 地址直接下载相应视频 VideoSize int `json:"VideoSize"` // (必填)视频数据大小,单位:字节 VideoSecond int `json:"VideoSecond"` // (必填)视频时长,单位:秒 VideoFormat string `json:"VideoFormat"` // (必填)视频格式,例如 mp4 VideoDownloadFlag int `json:"VideoDownloadFlag"` // (必填)视频下载方式标记。目前 VideoDownloadFlag 取值只能为2,表示可通过VideoUrl字段值的 URL 地址直接下载视频。 ThumbUrl string `json:"ThumbUrl"` // (必填)视频缩略图下载地址。可通过该 URL 地址直接下载相应视频缩略图。 + ThumbUUID string `json:"ThumbUUID"` // (必填)视频缩略图的唯一标识,客户端用于索引视频缩略图的键值。 ThumbSize int `json:"ThumbSize"` // (必填)缩略图大小,单位:字节 ThumbWidth int `json:"ThumbWidth"` // (必填)缩略图宽度 ThumbHeight int `json:"ThumbHeight"` // (必填)缩略图高度 diff --git a/private/api.go b/private/api.go index dd443af..45a2b1b 100644 --- a/private/api.go +++ b/private/api.go @@ -246,12 +246,9 @@ func (a *api) FetchMessages(arg *FetchMessagesArg) (ret *FetchMessagesRet, err e ret = &FetchMessagesRet{ LastMsgKey: resp.LastMsgKey, LastMsgTime: resp.LastMsgTime, - MsgCount: resp.MsgCount, - MsgList: resp.MsgList, - } - - if resp.Complete == 1 { - ret.IsOver = true + Count: resp.MsgCount, + List: resp.MsgList, + HasMore: resp.Complete != 1, } return @@ -281,7 +278,7 @@ func (a *api) PullMessages(arg *PullMessagesArg, fn func(ret *FetchMessagesRet)) } ) - for ret == nil || !ret.IsOver { + for ret == nil || ret.HasMore { ret, err = a.FetchMessages(req) if err != nil { return @@ -289,7 +286,7 @@ func (a *api) PullMessages(arg *PullMessagesArg, fn func(ret *FetchMessagesRet)) fn(ret) - if !ret.IsOver { + if ret.HasMore { req.LastMsgKey = ret.LastMsgKey req.MaxTime = ret.LastMsgTime } diff --git a/private/types.go b/private/types.go index 3b3b89d..5e34271 100644 --- a/private/types.go +++ b/private/types.go @@ -18,7 +18,7 @@ type ( MsgSeq int `json:"MsgSeq,omitempty"` // (选填)消息序列号,后台会根据该字段去重及进行同秒内消息的排序,详细规则请看本接口的功能说明。若不填该字段,则由后台填入随机数。 MsgRandom uint32 `json:"MsgRandom"` // (必填)消息随机数,后台用于同一秒内的消息去重。请确保该字段填的是随机数 MsgTimeStamp int64 `json:"MsgTimeStamp,omitempty"` // (选填)消息时间戳,UNIX 时间戳(单位:秒) - MsgBody []types.MsgBody `json:"MsgBody"` // (必填)消息内容,具体格式请参考 消息格式描述(注意,一条消息可包括多种消息元素,MsgBody 为 Array 类型) + MsgBody []*types.MsgBody `json:"MsgBody"` // (必填)消息内容,具体格式请参考 消息格式描述(注意,一条消息可包括多种消息元素,MsgBody 为 Array 类型) SyncOtherMachine int `json:"SyncOtherMachine,omitempty"` // (选填)消息是否同步到在线终端和漫游上 1:把消息同步到 From_Account 在线终端和漫游上;2:消息不同步至 From_Account; 若不填写默认情况下会将消息存 From_Account 漫游 CustomData string `json:"CloudCustomData,omitempty"` // (选填)消息回调禁止开关,只对本条消息有效, SendMsgControl []string `json:"SendMsgControl,omitempty"` // (选填)消息发送控制选项,是一个 String 数组,只对本条消息有效。 @@ -45,7 +45,7 @@ type ( ToUserIds []string `json:"To_Account"` // (必填)消息接收方UserID MsgSeq int `json:"MsgSeq,omitempty"` // (选填)消息序列号,后台会根据该字段去重及进行同秒内消息的排序,详细规则请看本接口的功能说明。若不填该字段,则由后台填入随机数。 MsgRandom uint32 `json:"MsgRandom"` // (必填)消息随机数,后台用于同一秒内的消息去重。请确保该字段填的是随机数 - MsgBody []types.MsgBody `json:"MsgBody"` // (必填)消息内容,具体格式请参考 消息格式描述(注意,一条消息可包括多种消息元素,MsgBody 为 Array 类型) + MsgBody []*types.MsgBody `json:"MsgBody"` // (必填)消息内容,具体格式请参考 消息格式描述(注意,一条消息可包括多种消息元素,MsgBody 为 Array 类型) SyncOtherMachine int `json:"SyncOtherMachine,omitempty"` // (选填)消息是否同步到在线终端和漫游上 1:把消息同步到 From_Account 在线终端和漫游上;2:消息不同步至 From_Account; 若不填写默认情况下会将消息存 From_Account 漫游 CustomData string `json:"CloudCustomData,omitempty"` // (选填)消息回调禁止开关,只对本条消息有效, SendMsgControl []string `json:"SendMsgControl,omitempty"` // (选填)消息发送控制选项,是一个 String 数组,只对本条消息有效。 @@ -73,14 +73,14 @@ type ( // 导入消息(请求) importMessageReq struct { - FromUserId string `json:"From_Account,omitempty"` // (选填)消息发送方UserID(用于指定发送消息方帐号) - ToUserId string `json:"To_Account"` // (必填)消息接收方UserID - MsgSeq int `json:"MsgSeq,omitempty"` // (选填)消息序列号,后台会根据该字段去重及进行同秒内消息的排序,详细规则请看本接口的功能说明。若不填该字段,则由后台填入随机数。 - MsgRandom uint32 `json:"MsgRandom"` // (必填)消息随机数,后台用于同一秒内的消息去重。请确保该字段填的是随机数 - MsgTimeStamp int64 `json:"MsgTimeStamp,omitempty"` // (选填)消息时间戳,UNIX 时间戳(单位:秒) - MsgBody []types.MsgBody `json:"MsgBody"` // (必填)消息内容,具体格式请参考 消息格式描述(注意,一条消息可包括多种消息元素,MsgBody 为 Array 类型) - SyncFromOldSystem int `json:"SyncFromOldSystem,omitempty"` // (选填)消息是否同步到在线终端和漫游上 1:把消息同步到 From_Account 在线终端和漫游上;2:消息不同步至 From_Account; 若不填写默认情况下会将消息存 From_Account 漫游 - CustomData string `json:"CloudCustomData,omitempty"` // (选填)消息回调禁止开关,只对本条消息有效, + FromUserId string `json:"From_Account,omitempty"` // (选填)消息发送方UserID(用于指定发送消息方帐号) + ToUserId string `json:"To_Account"` // (必填)消息接收方UserID + MsgSeq int `json:"MsgSeq,omitempty"` // (选填)消息序列号,后台会根据该字段去重及进行同秒内消息的排序,详细规则请看本接口的功能说明。若不填该字段,则由后台填入随机数。 + MsgRandom uint32 `json:"MsgRandom"` // (必填)消息随机数,后台用于同一秒内的消息去重。请确保该字段填的是随机数 + MsgTimeStamp int64 `json:"MsgTimeStamp,omitempty"` // (选填)消息时间戳,UNIX 时间戳(单位:秒) + MsgBody []*types.MsgBody `json:"MsgBody"` // (必填)消息内容,具体格式请参考 消息格式描述(注意,一条消息可包括多种消息元素,MsgBody 为 Array 类型) + SyncFromOldSystem int `json:"SyncFromOldSystem,omitempty"` // (选填)消息是否同步到在线终端和漫游上 1:把消息同步到 From_Account 在线终端和漫游上;2:消息不同步至 From_Account; 若不填写默认情况下会将消息存 From_Account 漫游 + CustomData string `json:"CloudCustomData,omitempty"` // (选填)消息回调禁止开关,只对本条消息有效, } // FetchMessagesArg 拉取消息参数 @@ -96,20 +96,20 @@ type ( // 拉取消息参数(响应) fetchMessagesResp struct { types.ActionBaseResp - Complete int `json:"Complete"` // 是否全部拉取,0表示未全部拉取,需要续拉,1表示已全部拉取 - LastMsgTime int64 `json:"LastMsgTime"` // 本次拉取到的消息里的最后一条消息的时间 - LastMsgKey string `json:"LastMsgKey"` // 本次拉取到的消息里的最后一条消息的标识 - MsgCount int `json:"MsgCnt"` // 本次拉取到的消息条数 - MsgList []MessageItem `json:"MsgList"` // 消息列表 + Complete int `json:"Complete"` // 是否全部拉取,0表示未全部拉取,需要续拉,1表示已全部拉取 + LastMsgTime int64 `json:"LastMsgTime"` // 本次拉取到的消息里的最后一条消息的时间 + LastMsgKey string `json:"LastMsgKey"` // 本次拉取到的消息里的最后一条消息的标识 + MsgCount int `json:"MsgCnt"` // 本次拉取到的消息条数 + MsgList []*MessageItem `json:"MsgList"` // 消息列表 } // FetchMessagesRet 消息结果 FetchMessagesRet struct { - IsOver bool // 是否拉取结束 - LastMsgTime int64 // 本次拉取到的消息里的最后一条消息的时间 - LastMsgKey string // 本次拉取到的消息里的最后一条消息的标识 - MsgCount int // 本次拉取到的消息条数 - MsgList []MessageItem // 消息列表 + LastMsgTime int64 // 本次拉取到的消息里的最后一条消息的时间 + LastMsgKey string // 本次拉取到的消息里的最后一条消息的标识 + Count int // 本次拉取到的消息条数 + HasMore bool // 是否还有更多数据 + List []*MessageItem // 消息列表 } // MessageItem 消息项 diff --git a/push/api.go b/push/api.go index ed0f351..32127b9 100644 --- a/push/api.go +++ b/push/api.go @@ -74,13 +74,13 @@ type API interface { // 管理员给用户设置属性。每次最多只能给100个用户设置属性。使用前请先 设置应用属性名称 。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45938 - SetUserAttrs(attrs map[string]map[string]interface{}) (err error) + SetUserAttrs(userAttrs map[string]map[string]interface{}) (err error) // DeleteUserAttrs 删除用户属性 // 管理员给用户删除属性。注意每次最多只能给100个用户删除属性。使用前请先 设置应用属性名称。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45939 - DeleteUserAttrs(attrs map[string][]string) (err error) + DeleteUserAttrs(userAttrs map[string][]string) (err error) // GetUserTags 获取用户标签 // 获取用户标签(必须以管理员帐号调用)。每次最多只能获取100个用户的标签。 @@ -95,13 +95,13 @@ type API interface { // 单个标签最大长度为50字节。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45941 - AddUserTags(tags map[string][]string) (err error) + AddUserTags(userTags map[string][]string) (err error) // DeleteUserTags 删除用户标签 // 管理员给用户删除标签。注意每次最多只能给100个用户删除标签。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45942 - DeleteUserTags(tags map[string][]string) (err error) + DeleteUserTags(userTags map[string][]string) (err error) // DeleteUserAllTags 删除用户所有标签 // 管理员给用户删除所有标签。注意每次最多只能给100个用户删除所有标签。 @@ -234,8 +234,8 @@ func (a *api) GetUserAttrs(userIds ...string) (attrs map[string]map[string]inter // 管理员给用户设置属性。每次最多只能给100个用户设置属性。使用前请先 设置应用属性名称 。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45938 -func (a *api) SetUserAttrs(attrs map[string]map[string]interface{}) (err error) { - if c := len(attrs); c == 0 { +func (a *api) SetUserAttrs(userAttrs map[string]map[string]interface{}) (err error) { + if c := len(userAttrs); c == 0 { err = core.NewError(enum.InvalidParamsCode, "the attributes is not set") return } else if c > batchSetUserAttrsLimit { @@ -243,8 +243,8 @@ func (a *api) SetUserAttrs(attrs map[string]map[string]interface{}) (err error) return } - req := &setUserAttrsReq{Attrs: make([]*userAttrItem, 0, len(attrs))} - for userId, attrs := range attrs { + req := &setUserAttrsReq{Attrs: make([]*userAttrItem, 0, len(userAttrs))} + for userId, attrs := range userAttrs { req.Attrs = append(req.Attrs, &userAttrItem{ UserId: userId, Attrs: attrs, @@ -262,8 +262,8 @@ func (a *api) SetUserAttrs(attrs map[string]map[string]interface{}) (err error) // 管理员给用户删除属性。注意每次最多只能给100个用户删除属性。使用前请先 设置应用属性名称。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45939 -func (a *api) DeleteUserAttrs(attrs map[string][]string) (err error) { - if c := len(attrs); c == 0 { +func (a *api) DeleteUserAttrs(userAttrs map[string][]string) (err error) { + if c := len(userAttrs); c == 0 { err = core.NewError(enum.InvalidParamsCode, "the attributes is not set") return } else if c > batchDeleteUserAttrsLimit { @@ -271,8 +271,8 @@ func (a *api) DeleteUserAttrs(attrs map[string][]string) (err error) { return } - req := &deleteUserAttrsReq{Attrs: make([]deleteUserAttr, 0, len(attrs))} - for userId, attrs := range attrs { + req := &deleteUserAttrsReq{Attrs: make([]deleteUserAttr, 0, len(userAttrs))} + for userId, attrs := range userAttrs { req.Attrs = append(req.Attrs, deleteUserAttr{ UserId: userId, Attrs: attrs, @@ -323,8 +323,8 @@ func (a *api) GetUserTags(userIds ...string) (tags map[string][]string, err erro // 单个标签最大长度为50字节。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45941 -func (a *api) AddUserTags(tags map[string][]string) (err error) { - if c := len(tags); c == 0 { +func (a *api) AddUserTags(userTags map[string][]string) (err error) { + if c := len(userTags); c == 0 { err = core.NewError(enum.InvalidParamsCode, "the tags of user is not set") return } else if c > batchAddUserTagsLimit { @@ -332,8 +332,8 @@ func (a *api) AddUserTags(tags map[string][]string) (err error) { return } - req := &addUserTagsReq{Tags: make([]*userTag, 0, len(tags))} - for userId, tags := range tags { + req := &addUserTagsReq{Tags: make([]*userTag, 0, len(userTags))} + for userId, tags := range userTags { req.Tags = append(req.Tags, &userTag{ UserId: userId, Tags: tags, @@ -351,8 +351,8 @@ func (a *api) AddUserTags(tags map[string][]string) (err error) { // 管理员给用户删除标签。注意每次最多只能给100个用户删除标签。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/45942 -func (a *api) DeleteUserTags(tags map[string][]string) (err error) { - if c := len(tags); c == 0 { +func (a *api) DeleteUserTags(userTags map[string][]string) (err error) { + if c := len(userTags); c == 0 { err = core.NewError(enum.InvalidParamsCode, "the tags of user is not set") return } else if c > batchDeleteUserTagsLimit { @@ -360,8 +360,8 @@ func (a *api) DeleteUserTags(tags map[string][]string) (err error) { return } - req := &deleteUserTagsReq{Tags: make([]*userTag, 0, len(tags))} - for userId, tags := range tags { + req := &deleteUserTagsReq{Tags: make([]*userTag, 0, len(userTags))} + for userId, tags := range userTags { req.Tags = append(req.Tags, &userTag{ UserId: userId, Tags: tags, diff --git a/push/types.go b/push/types.go index eb8f087..217d514 100644 --- a/push/types.go +++ b/push/types.go @@ -23,7 +23,7 @@ type ( FromUserId string `json:"From_Account,omitempty"` // (选填)消息推送方帐号 Condition *condition `json:"Condition,omitempty"` // (选填)推送条件 MsgRandom uint32 `json:"MsgRandom"` // (必填)消息随机数,由随机函数产生 - MsgBody []types.MsgBody `json:"MsgBody"` // (必填)消息内容 + MsgBody []*types.MsgBody `json:"MsgBody"` // (必填)消息内容 MsgLifeTime int `json:"MsgLifeTime,omitempty"` // (选填)消息离线存储时间,单位秒,最多保存7天(604800秒)。默认为0,表示不离线存储 OfflinePushInfo *types.OfflinePushInfo `json:"OfflinePushInfo,omitempty"` // (选填)离线推送信息配置 } diff --git a/recentcontact/api.go b/recentcontact/api.go index 3bf01f1..af6840a 100644 --- a/recentcontact/api.go +++ b/recentcontact/api.go @@ -25,6 +25,13 @@ type API interface { // https://cloud.tencent.com/document/product/269/62118 FetchSessions(arg *FetchSessionsArg) (ret *FetchSessionsRet, err error) + // PullSessions 续拉取会话列表 + // 本API是借助"拉取会话列表"API进行扩展实现 + // 支持分页拉取会话列表 + // 点击查看详细文档: + // https://cloud.tencent.com/document/product/269/62118 + PullSessions(arg *PullSessionsArg, fn func(ret *FetchSessionsRet)) (err error) + // DeleteSession 删除单个会话 // 删除指定会话,支持同步清理漫游消息。 // 点击查看详细文档: @@ -76,11 +83,43 @@ func (a *api) FetchSessions(arg *FetchSessionsArg) (ret *FetchSessionsRet, err e StartIndex: resp.StartIndex, TopTimeStamp: resp.TopTimeStamp, TopStartIndex: resp.TopStartIndex, - Sessions: resp.Sessions, + List: resp.Sessions, + HasMore: resp.CompleteFlag == 0, } - if resp.CompleteFlag == 1 { - ret.IsOver = true + return +} + +// PullSessions 续拉取会话列表 +// 本API是借助"拉取会话列表"API进行扩展实现 +// 支持分页拉取会话列表 +// 点击查看详细文档: +// https://cloud.tencent.com/document/product/269/62118 +func (a *api) PullSessions(arg *PullSessionsArg, fn func(ret *FetchSessionsRet)) (err error) { + var ( + ret *FetchSessionsRet + req = &FetchSessionsArg{ + UserId: arg.UserId, + IsAllowTopSession: arg.IsAllowTopSession, + IsReturnEmptySession: arg.IsReturnEmptySession, + IsAllowTopSessionPaging: arg.IsAllowTopSessionPaging, + } + ) + + for ret == nil || ret.HasMore { + ret, err = a.FetchSessions(req) + if err != nil { + return + } + + fn(ret) + + if ret.HasMore { + req.TimeStamp = ret.TimeStamp + req.StartIndex = ret.StartIndex + req.TopTimeStamp = ret.TopTimeStamp + req.TopStartIndex = ret.TopStartIndex + } } return diff --git a/recentcontact/types.go b/recentcontact/types.go index c171a32..f045de4 100644 --- a/recentcontact/types.go +++ b/recentcontact/types.go @@ -21,14 +21,22 @@ type FetchSessionsArg struct { IsAllowTopSessionPaging bool // (选填)是否支持置顶会话分页 } +// PullSessionsArg 续拉取会话列表(参数) +type PullSessionsArg struct { + UserId string // (必填)请求拉取该用户的会话列表 + IsAllowTopSession bool // (选填)是否支持置顶会话 + IsReturnEmptySession bool // (选填)是否返回空会话 + IsAllowTopSessionPaging bool // (选填)是否支持置顶会话分页 +} + // FetchSessionsRet 拉取会话列表(返回) type FetchSessionsRet struct { - IsOver bool // 是否拉完了数据 TimeStamp int // 普通会话下一页拉取的起始时间,分页拉取时通过请求包的 TimeStamp 字段带给移动通信后台 StartIndex int // 普通会话下一页拉取的起始位置,分页拉取时通过请求包的 StartIndex 字段带给移动通信后台 TopTimeStamp int // 置顶会话下一页拉取的起始时间,分页拉取时通过请求包的 TopTimeStamp 字段带给移动通信后台 TopStartIndex int // 置顶会话下一页拉取的起始位置,分页拉取时通过请求包的 TopStartIndex 字段带给移动通信后台 - Sessions []*SessionItem // 会话对象数组 + HasMore bool // 是否拉完了数据 + List []*SessionItem // 会话对象数组 } // fetchSessionsReq 拉取会话列表(请求) diff --git a/sns/api.go b/sns/api.go index 2f6b327..ee0c2e9 100644 --- a/sns/api.go +++ b/sns/api.go @@ -136,6 +136,15 @@ type API interface { // https://cloud.tencent.com/document/product/269/1647 FetchFriends(userId string, startIndex int, sequence ...int) (ret *FetchFriendsRet, err error) + // PullFriends 续拉取好友 + // 本API是借助"拉取好友"API进行扩展实现 + // 分页拉取全量好友数据。 + // 不支持资料数据的拉取。 + // 不需要指定请求拉取的字段,默认返回全量的标配好友数据和自定义好友数据。 + // 点击查看详细文档: + // https://cloud.tencent.com/document/product/269/1647 + PullFriends(userId string, fn func(ret *FetchFriendsRet)) (err error) + // AddBlacklist 添加黑名单 // 添加黑名单,支持批量添加黑名单。 // 点击查看详细文档: @@ -152,7 +161,14 @@ type API interface { // 支持分页拉取所有黑名单。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/3722 - FetchBlacklist(userId string, startIndex, maxLimited, lastSequence int) (ret *FetchBlacklistRet, err error) + FetchBlacklist(userId string, maxLimited int, startIndexAndSequence ...int) (ret *FetchBlacklistRet, err error) + + // PullBlacklist 拉取黑名单 + // 本API是借助"拉取黑名单"API进行扩展实现 + // 支持分页拉取所有黑名单。 + // 点击查看详细文档: + // https://cloud.tencent.com/document/product/269/3722 + PullBlacklist(userId string, maxLimited int, fn func(ret *FetchBlacklistRet)) (err error) // CheckBlacklist 校验黑名单 // 点击查看详细文档: @@ -198,11 +214,9 @@ func (a *api) AddFriend(userId string, isBothAdd, isForceAdd bool, friend *Frien return } - if results != nil && len(results) > 0 { - for _, result := range results { - if result.UserId == friend.GetUserId() && result.ResultCode != enum.SuccessCode { - return core.NewError(result.ResultCode, result.ResultInfo) - } + for _, result := range results { + if result.UserId == friend.GetUserId() && result.ResultCode != enum.SuccessCode { + return core.NewError(result.ResultCode, result.ResultInfo) } } @@ -272,11 +286,9 @@ func (a *api) ImportFriend(userId string, friend *Friend) (err error) { return } - if results != nil && len(results) > 0 { - for _, result := range results { - if result.UserId == friend.GetUserId() && result.ResultCode != enum.SuccessCode { - return core.NewError(result.ResultCode, result.ResultInfo) - } + for _, result := range results { + if result.UserId == friend.GetUserId() && result.ResultCode != enum.SuccessCode { + return core.NewError(result.ResultCode, result.ResultInfo) } } @@ -345,11 +357,9 @@ func (a *api) UpdateFriend(userId string, friend *Friend) (err error) { return } - if results != nil && len(results) > 0 { - for _, result := range results { - if result.UserId == friend.GetUserId() && result.ResultCode != enum.SuccessCode { - return core.NewError(result.ResultCode, result.ResultInfo) - } + for _, result := range results { + if result.UserId == friend.GetUserId() && result.ResultCode != enum.SuccessCode { + return core.NewError(result.ResultCode, result.ResultInfo) } } @@ -610,12 +620,10 @@ func (a *api) FetchFriends(userId string, startIndex int, sequence ...int) (ret ret = &FetchFriendsRet{ StandardSequence: resp.StandardSequence, CustomSequence: resp.CustomSequence, - FriendNum: resp.FriendNum, - NextStartIndex: resp.NextStartIndex, - } - - if resp.CompleteFlag != 0 { - ret.IsOver = true + StartIndex: resp.NextStartIndex, + Total: resp.FriendNum, + HasMore: resp.CompleteFlag == 0, + List: make([]*Friend, 0, len(resp.Friends)), } for _, item := range resp.Friends { @@ -623,7 +631,40 @@ func (a *api) FetchFriends(userId string, startIndex int, sequence ...int) (ret for _, v := range item.Values { friend.SetAttr(v.Tag, v.Value) } - ret.Friends = append(ret.Friends, friend) + ret.List = append(ret.List, friend) + } + + return +} + +// PullFriends 续拉取好友 +// 本API是借助"拉取好友"API进行扩展实现 +// 分页拉取全量好友数据。 +// 不支持资料数据的拉取。 +// 不需要指定请求拉取的字段,默认返回全量的标配好友数据和自定义好友数据。 +// 点击查看详细文档: +// https://cloud.tencent.com/document/product/269/1647 +func (a *api) PullFriends(userId string, fn func(ret *FetchFriendsRet)) (err error) { + var ( + ret *FetchFriendsRet + startIndex int + standardSequence int + customSequence int + ) + + for ret == nil || ret.HasMore { + ret, err = a.FetchFriends(userId, startIndex, standardSequence, customSequence) + if err != nil { + return + } + + fn(ret) + + if ret.HasMore { + startIndex = ret.StartIndex + standardSequence = ret.StandardSequence + customSequence = ret.CustomSequence + } } return @@ -683,8 +724,17 @@ func (a *api) DeleteBlacklist(userId string, deletedUserIds ...string) (results // 支持分页拉取所有黑名单。 // 点击查看详细文档: // https://cloud.tencent.com/document/product/269/3722 -func (a *api) FetchBlacklist(userId string, startIndex, maxLimited, lastSequence int) (ret *FetchBlacklistRet, err error) { - req := &fetchBlacklistReq{UserId: userId, StartIndex: startIndex, MaxLimited: maxLimited, LastSequence: lastSequence} +func (a *api) FetchBlacklist(userId string, maxLimited int, startIndexAndSequence ...int) (ret *FetchBlacklistRet, err error) { + req := &fetchBlacklistReq{UserId: userId, MaxLimited: maxLimited} + + if len(startIndexAndSequence) > 0 { + req.StartIndex = startIndexAndSequence[0] + } + + if len(startIndexAndSequence) > 1 { + req.LastSequence = startIndexAndSequence[1] + } + resp := &fetchBlacklistResp{} if err = a.client.Post(service, commandGetBlackList, req, resp); err != nil { @@ -692,13 +742,39 @@ func (a *api) FetchBlacklist(userId string, startIndex, maxLimited, lastSequence } ret = &FetchBlacklistRet{ - NextStartIndex: resp.StartIndex, + StartIndex: resp.StartIndex, StandardSequence: resp.CurrentSequence, - Blacklists: resp.Blacklists, + List: resp.Blacklists, + HasMore: resp.StartIndex != 0, } - if resp.StartIndex == 0 { - ret.IsOver = true + return +} + +// PullBlacklist 拉取黑名单 +// 本API是借助"拉取黑名单"API进行扩展实现 +// 支持分页拉取所有黑名单。 +// 点击查看详细文档: +// https://cloud.tencent.com/document/product/269/3722 +func (a *api) PullBlacklist(userId string, maxLimited int, fn func(ret *FetchBlacklistRet)) (err error) { + var ( + ret *FetchBlacklistRet + startIndex = 0 + standardSequence = 0 + ) + + for ret == nil || ret.HasMore { + ret, err = a.FetchBlacklist(userId, maxLimited, startIndex, standardSequence) + if err != nil { + return + } + + fn(ret) + + if ret.HasMore { + startIndex = ret.StartIndex + standardSequence = ret.StandardSequence + } } return diff --git a/sns/friend.go b/sns/friend.go index 3fc13a2..0f5543f 100644 --- a/sns/friend.go +++ b/sns/friend.go @@ -25,12 +25,12 @@ type Friend struct { customAttrs map[string]interface{} } -func NewFriend(account ...string) *Friend { +func NewFriend(userId ...string) *Friend { f := new(Friend) f.customAttrs = make(map[string]interface{}) - if len(account) > 0 { - f.SetUserId(account[0]) + if len(userId) > 0 { + f.SetUserId(userId[0]) } return f diff --git a/sns/types.go b/sns/types.go index d9bbd2b..98a9908 100644 --- a/sns/types.go +++ b/sns/types.go @@ -172,10 +172,10 @@ type ( FetchFriendsRet struct { StandardSequence int // 标准排序 CustomSequence int // 自定义排序 - FriendNum int // 好友总数 - IsOver bool // 是否没有数据了 - NextStartIndex int // 分页接口下一页的起始位置 - Friends []*Friend // 好友列表 + StartIndex int // 分页接口下一页的起始位置 + Total int // 好友总数 + HasMore bool // 是否还有更多数据 + List []*Friend // 好友列表 } // 添加黑名单(请求) @@ -215,18 +215,18 @@ type ( // 拉取黑名单(响应) fetchBlacklistResp struct { types.ActionBaseResp - ErrorDisplay string `json:"ErrorDisplay"` // 详细的客户端展示信息 - StartIndex int `json:"StartIndex"` // 下页拉取的起始位置,0表示已拉完 - CurrentSequence int `json:"CurrentSequence"` // 黑名单最新的 Seq - Blacklists []Blacklist `json:"BlackListItem"` // 黑名单对象数组 + ErrorDisplay string `json:"ErrorDisplay"` // 详细的客户端展示信息 + StartIndex int `json:"StartIndex"` // 下页拉取的起始位置,0表示已拉完 + CurrentSequence int `json:"CurrentSequence"` // 黑名单最新的 Seq + Blacklists []*Blacklist `json:"BlackListItem"` // 黑名单对象数组 } // FetchBlacklistRet 拉取黑名单结果 FetchBlacklistRet struct { - StandardSequence int // 标准排序 - IsOver bool // 是否没有数据了 - NextStartIndex int // 分页接口下一页的起始位置 - Blacklists []Blacklist // 黑名单列表 + StandardSequence int // 标准排序 + StartIndex int // 分页接口下一页的起始位置 + HasMore bool // 是否还有数据 + List []*Blacklist // 黑名单列表 } // Blacklist 黑名单