Files
servicebase/pkg/common/netease/ImClient.go
2025-11-28 13:59:36 +08:00

1086 lines
34 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package Netease
import (
"context"
"encoding/json"
"fmt"
"strings"
"gitea.ddegame.cn/open/servicebase/pkg/common"
"gitea.ddegame.cn/open/servicebase/pkg/common/HyTools"
yunxin "gitea.ddegame.cn/open/servicebase/pkg/common/netease/dto"
"gitea.ddegame.cn/open/servicebase/pkg/htools"
"gitea.ddegame.cn/open/servicebase/pkg/log"
"github.com/pkg/errors"
"github.com/spf13/cast"
"math/rand"
"strconv"
"time"
"github.com/anxpp/beego/logs"
"github.com/spf13/viper"
)
type ImClient struct {
AppKey string
AppSecret string
}
type CreateImRes struct {
Code int
Desc string
}
type BroadcastNotificationReq struct {
FromAccountId string `json:"from_account_id"`
Content string `json:"content"`
TargetOs []string `json:"target_os"`
}
func NewImClient() *ImClient {
fmt.Printf("NewImClient: %s\n", viper.GetString("netease.im.key"))
key := viper.GetString("netease.im.key")
secret := viper.GetString("netease.im.secret")
return &ImClient{AppKey: key, AppSecret: secret}
}
// 生成云信header
func (client *ImClient) generateHeader() map[string]string {
nonce := randNumber()
t := time.Now()
currentTime := strconv.FormatInt(t.UTC().Unix(), 10)
result := make(map[string]string)
result["AppKey"] = client.AppKey
result["Nonce"] = nonce
result["CurTime"] = currentTime
result["CheckSum"] = client.generateCheckSum(nonce, currentTime)
result["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8"
return result
}
func (client *ImClient) generateJsonHeader() map[string]string {
nonce := randNumber()
t := time.Now()
currentTime := strconv.FormatInt(t.UTC().Unix(), 10)
result := make(map[string]string)
result["AppKey"] = client.AppKey
result["Nonce"] = nonce
result["CurTime"] = currentTime
result["CheckSum"] = client.generateCheckSum(nonce, currentTime)
result["Content-Type"] = "application/json"
return result
}
// 生成云信签名
func (client *ImClient) generateCheckSum(nonce, currentTime string) string {
waitSignStr := client.AppSecret + nonce + currentTime
result := HyTools.StringToSHA1(waitSignStr)
return result
}
// 创建云信账户
// imService.CreateImUser(common.SYNC_DATA_USER_ID,"数据同步",common.PHOTO_DOMAIN_URL+"assets/sys/guanfanggonggao.png")
func (client *ImClient) CreateImUser(userId, nickName, avatar string) error {
url := "https://api.netease.im/nimserver/user/create.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := HyTools.NewStringBuilder()
sb.Append("accid=" + userId)
sb.Append("&")
sb.Append("token=123456")
sb.Append("&")
sb.Append("name=" + nickName)
sb.Append("&")
sb.Append("icon=" + avatar)
res, err := HyTools.HttpDo(httpMethod, url, header, sb.ToString())
if err != nil {
// {"desc":"already register","code":414}
logs.Info("YunXin_SignUp_Fail_AccID_%s:"+err.Error(), userId)
return err
} else {
var resDTO CreateImRes
json.Unmarshal([]byte(res), &resDTO)
if resDTO.Code != 200 {
logs.Info("YunXin_SignUp_Fail_AccID_%s:"+resDTO.Desc, userId)
} else {
logs.Info("YunXin_SignUp_Success_AccID_%s:"+res, userId)
}
}
var body map[string]any
if errJson := json.Unmarshal([]byte(res), &body); errJson != nil {
return errJson
}
if int(body["code"].(float64)) != 200 {
return errors.New(body["desc"].(string))
}
return err
}
// 查询用户信息
func (client *ImClient) GetImUserInfo(userId string) error {
url := "https://api.netease.im/nimserver/user/getUinfos.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := HyTools.NewStringBuilder()
accids := []string{userId}
byteData, _ := json.Marshal(accids)
sb.Append("accids=" + string(byteData))
res, err := HyTools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info("#" + "查询云信用户信息结果:" + res + "#")
var body map[string]any
if errJson := json.Unmarshal([]byte(res), &body); errJson != nil {
return errJson
}
if int(body["code"].(float64)) != 200 {
return errors.New(body["desc"].(string))
}
return err
}
// 更新云信信息
func (client *ImClient) UpdateImUserInfo(accid, nickName, avatar string) error {
url := "https://api.netease.im/nimserver/user/updateUinfo.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
sb.Append("accid=" + accid)
sb.Append("&")
sb.Append("name=" + nickName)
sb.Append("&")
sb.Append("icon=" + avatar)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "云信更新用户信息结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 更新云信用户扩展信息
func (client *ImClient) UpdateImUserExt(accid, ext string) error {
url := "https://api.netease.im/nimserver/user/updateUinfo.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
sb.Append("accid=" + accid)
sb.Append("&")
sb.Append("ex=" + ext)
logs.Info("update_im_user userID[%s] ext:%s", accid, ext)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING+"云信更新用户ext%s信息结果:"+res+common.LOG_QUOTE_STRING, ext)
return err
}
// 封禁云信帐号
func (client *ImClient) BlockImUser(accid string) error {
url := "https://api.netease.im/nimserver/user/block.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
sb.Append("accid=" + accid)
sb.Append("&")
sb.Append("needkick=true")
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "封禁云信帐号结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 解禁云信帐号
func (client *ImClient) UnBlockImUser(accid string) error {
url := "https://api.netease.im/nimserver/user/unblock.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
sb.Append("accid=" + accid)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "解禁云信帐号结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 创建云信聊天室
func (client *ImClient) CreateChatroom(ownerUserId string, roomName string) (chatroomModel NeteaseChatroomDTO) {
logs.Info("CreateChatroom ownerUserId=%s roomName=%s", ownerUserId, roomName)
url := "https://api.netease.im/nimserver/chatroom/create.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
sb.Append("creator=" + ownerUserId)
sb.Append("&")
sb.Append("name=" + roomName)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
if err != nil {
logs.Info(common.LOG_QUOTE_STRING + "云信创建聊天室请求失败:" + err.Error() + common.LOG_QUOTE_STRING)
return
}
logs.Info(common.LOG_QUOTE_STRING + "云信创建聊天室结果:" + res + common.LOG_QUOTE_STRING)
var createRes CreateChatroomResponse
err1 := json.Unmarshal([]byte(res), &createRes)
if err1 != nil {
logs.Info(common.LOG_QUOTE_STRING + "创建聊天室失败,解析结果错误:" + res + common.LOG_QUOTE_STRING)
panic(err1)
}
if createRes.Code != 200 {
logs.Info(common.LOG_QUOTE_STRING + "创建Im聊天室失败:code= " + strconv.Itoa(createRes.Code) + common.LOG_QUOTE_STRING)
panic(errors.New("创建云信Im聊天室失败"))
}
chatroomModel = createRes.Chatroom
return
}
// IM发送消息
func (client *ImClient) SendMsg(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/msg/sendMsg.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "云信IM发消息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "云信IM发消息结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 添加机器人
func (client *ImClient) AddRobot(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/chatroom/addRobot.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "添加机器人:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "添加机器人:" + res + common.LOG_QUOTE_STRING)
return err
}
// 移除机器人
func (client *ImClient) RemoveRobot(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/chatroom/removeRobot.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "移除机器人:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "移除机器人:" + res + common.LOG_QUOTE_STRING)
return err
}
// 发送聊天室消息
func (client *ImClient) SendChatroomMsg(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/chatroom/sendMsg.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "聊天室发消息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "聊天室发消息结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 获取在线成员信息
func (client *ImClient) GetChatroomMembers(parameters map[string]string) (imResponse ImResponse, err error) {
url := "https://api.netease.im/nimserver/chatroom/queryMembers.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
body := generateBodyData(parameters)
logs.Info(common.LOG_QUOTE_STRING + "获取在线成员请求:" + body + common.LOG_QUOTE_STRING)
res, err1 := htools.HttpDo(httpMethod, url, header, body)
if err1 != nil {
logs.Error(common.LOG_QUOTE_STRING + "获取在线成员失败:" + err1.Error() + common.LOG_QUOTE_STRING)
err = err1
return
}
logs.Info(common.LOG_QUOTE_STRING + "获取在线成员结果:" + res + common.LOG_QUOTE_STRING)
var response ImResponse
if err2 := json.Unmarshal([]byte(res), &response); err2 != nil {
logs.Error(common.LOG_QUOTE_STRING + "获取在线成员解析失败:" + err2.Error() + common.LOG_QUOTE_STRING)
err = err2
return
}
imResponse = response
return
}
// 分页获取聊天室在线用户列表
func (client *ImClient) GetChatroomOnlineUserListByPage(parameters map[string]string) (imResponse ImResponse, err error) {
url := "https://api.netease.im/nimserver/chatroom/membersByPage.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
body := generateBodyData(parameters)
logs.Info(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表:" + body + common.LOG_QUOTE_STRING)
res, err1 := htools.HttpDo(httpMethod, url, header, body)
if err1 != nil {
logs.Error(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表失败:" + err1.Error() + common.LOG_QUOTE_STRING)
err = err1
return
}
logs.Info(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表结果:" + res + common.LOG_QUOTE_STRING)
var response ImResponse
if err2 := json.Unmarshal([]byte(res), &response); err2 != nil {
logs.Error(common.LOG_QUOTE_STRING + "分页获取聊天室在线列表失败:" + err2.Error() + common.LOG_QUOTE_STRING)
err = err2
return
}
imResponse = response
return
}
// 更新聊天室房间信息
func (client *ImClient) UpdateRoomInfo(request yunxin.UpdateRoomInfoRequest) (err error) {
url := "https://api.netease.im/nimserver/chatroom/update.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
sb.Append("roomid=" + request.Roomid)
sb.Append("&")
sb.Append("name=")
sb.Append("&")
sb.Append("announcement=")
sb.Append("&")
sb.Append("ext=")
sb.Append("&")
sb.Append("notifyExt=" + request.NotifyExt)
logs.Info(common.LOG_QUOTE_STRING + "更新聊天室信息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, httpErr := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "更新聊天室信息结果:" + res + common.LOG_QUOTE_STRING)
if httpErr != nil {
logs.Info(common.LOG_QUOTE_STRING + "更新聊天室信息失败:" + httpErr.Error() + common.LOG_QUOTE_STRING)
err = httpErr
return
}
resMap := make(map[string]any)
jsonErr := json.Unmarshal([]byte(res), &resMap)
if jsonErr != nil {
logs.Info(common.LOG_QUOTE_STRING + "解析更新房间信息结果失败:" + jsonErr.Error() + common.LOG_QUOTE_STRING)
err = jsonErr
return
}
code := resMap["code"].(float64)
codeStr := htools.Float64ToString(code)
if codeStr != "200" {
logs.Info(common.LOG_QUOTE_STRING + "更新房间信息结果失败: code=" + codeStr + common.LOG_QUOTE_STRING)
err = errors.New("更新失败 code=" + codeStr)
return
}
return
}
// 聊天室临时禁言
func (client *ImClient) ChatroomMuteUser(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/chatroom/temporaryMute.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "聊天室临时禁言请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "聊天室临时禁言结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 切换聊天室状态
func (client *ImClient) ChangeChatroomStat(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/chatroom/toggleCloseStat.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
requestId := HyTools.GetUUID()
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态请求:requestId " + requestId + " body " + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
if len(res) == 0 {
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态结果:失败 res为空 requestId " + requestId + common.LOG_QUOTE_STRING)
return errors.New("操作失败")
}
if err != nil {
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态结果:失败 返回error requestId " + requestId + "error " + err.Error() + common.LOG_QUOTE_STRING)
return err
}
var resData struct {
Code int `json:"code"`
Desc string `json:"desc"`
}
_ = json.Unmarshal([]byte(res), &resData)
if resData.Code != 200 {
if resData.Code != 417 { // 重复操作 直接忽略
logs.Info(fmt.Sprintf(common.LOG_QUOTE_STRING+"聊天室切换聊天室开关状态结果:失败 code[%d] requestId "+requestId+" desc[%s] "+common.LOG_QUOTE_STRING, resData.Code, resData.Desc))
return errors.New("操作失败")
}
}
logs.Info(common.LOG_QUOTE_STRING + "聊天室切换聊天室开关状态结果: requestId " + requestId + " response " + res + common.LOG_QUOTE_STRING)
return err
}
// 设置聊天室成员角色
func (client *ImClient) SetChatroomMemberRole(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/chatroom/setMemberRole.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "设置聊天室成员角色请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "设置聊天室成员角色结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 发送广播消息
func (client *ImClient) SendBroadCastMsg(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/msg/broadcastMsg.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "发送广播请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "发送广播结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 发送全员广播 V2
func (client *ImClient) SendBroadCastMsgV2(req BroadcastNotificationReq) error {
url := "https://open.yunxinapi.com/im/v2/broadcast_notification"
httpMethod := common.HTTP_METHOD_POST
header := client.generateJsonHeader()
bodyStr := HyTools.JsonStr(req)
logs.Info(common.LOG_QUOTE_STRING + "发送广播请求V2:" + bodyStr + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, bodyStr)
logs.Info(common.LOG_QUOTE_STRING + "发送广播结果V2:" + res + common.LOG_QUOTE_STRING)
return err
}
// 踢出用户登录 V2 https://{endpoint}/im/v2/accounts/{account_id}/actions/kick
func (client *ImClient) KickOutUserV2(userId string) error {
url := "https://open.yunxinapi.com/im/v2/accounts/" + userId + "/actions/kick"
httpMethod := common.HTTP_METHOD_POST
header := client.generateJsonHeader()
req := make(map[string]any, 3)
req["type"] = 1
req["device_id_list"] = []string{}
req["kick_notify_extension"] = ""
bodyStr := HyTools.JsonStr(req)
logs.Info(common.LOG_QUOTE_STRING + "发送踢下线请求V2:" + bodyStr + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, bodyStr)
logs.Info(common.LOG_QUOTE_STRING + "发送踢下线结果V2:" + res + common.LOG_QUOTE_STRING)
return err
}
// 设置/取消 拉黑 静音
func (client *ImClient) SetSpecialRelation(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/user/setSpecialRelation.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "设置/取消 拉黑请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "设置/取消 拉黑结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 发送自定义系统通知
func (client *ImClient) BatchSendMsg(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/msg/sendBatchMsg.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "云信IM批量发消息请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "云信IM批量发消息结果:" + res + common.LOG_QUOTE_STRING)
return err
}
// 批量发送消息
func (client *ImClient) SendAttachMsg(parameters map[string]string) error {
url := "https://api.netease.im/nimserver/msg/sendAttachMsg.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
logs.Info(common.LOG_QUOTE_STRING + "云信IM发系统通知请求:" + sb.ToString() + common.LOG_QUOTE_STRING)
res, err := htools.HttpDo(httpMethod, url, header, sb.ToString())
logs.Info(common.LOG_QUOTE_STRING + "云信IM发系统通知结果:" + res + common.LOG_QUOTE_STRING)
if parameters["to"] == "b260b07ff3d1411f926e2d767cb9d6f3" {
log.Info("完成给老板发接单消息")
}
return err
}
// CreateChatGroup 创建群组
func (client *ImClient) CreateChatGroup(ctx context.Context, ownerUserId string, groupName string, inviteMem []string) (string, error) {
url := "https://open.yunxinapi.com/im/v2.1/teams"
httpMethod := common.HTTP_METHOD_POST
header := client.generateJsonHeader()
reqBody := &CreateChatGroupReq{
OwnerAccountID: ownerUserId,
TeamType: 1,
Name: groupName,
MembersLimit: 3000,
InviteAccountIDs: inviteMem,
InviteMsg: "管理",
Configuration: &TeamConfiguration{
JoinMode: 1,
},
AntispamConfiguration: nil,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return "", errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
// {"desc":"already register","code":414}
logs.Info("YunXin_CreateChatGroup_Fail_AccID_%s:"+err.Error(), ownerUserId)
return "", errors.WithStack(err)
}
log.InfoF("create group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return "", errors.WithStack(err)
}
if body.Code != 200 {
return "", errors.Errorf("YunXin_CreateChatGroup code(%d) not 200,msg: %s", body.Code, body.Msg)
}
if len(body.Data.FailedList) > 0 {
var errInfo []string
for _, member := range body.Data.FailedList {
errInfo = append(errInfo, fmt.Sprintf("account: %s ,code: %d ,msg: %s", member.AccountID, member.ErrorCode, member.ErrorMsg))
}
return "", errors.Errorf("YunXin_CreateChatGroup err: %s", strings.Join(errInfo, ";"))
}
return cast.ToString(body.Data.TeamInfo.TeamID), nil
}
// 创建云信账户
// 创建高级群,创建时即可通过设置群成员列表邀请用户入群。
// 建群成功会返回 tid网易云信服务器产生群唯一标识该字段需要保存以便于加人与踢人等后续操作。
// 如果创建时邀请的成员中存在加群数量超过限制的情况,会返回 faccid加群失败成员的 IM 账号)。
// 每个用户可创建的群数量有限制,限制值由 IM 套餐的群组配置决定,具体可前往 网易云信控制台 查看。
func (client *ImClient) CreateProGroup(tname, owner, announcement, avatar, msg string) (string, error) {
url := "https://api.netease.im/nimserver/team/create.action"
httpMethod := common.HTTP_METHOD_POST
header := client.generateHeader()
sb := HyTools.NewStringBuilder()
sb.Append("tname=" + tname)
sb.Append("&")
sb.Append("owner=" + owner)
sb.Append("&")
sb.Append("announcement=" + announcement)
sb.Append("&")
sb.Append("msg=" + msg)
sb.Append("&")
sb.Append("icon=" + avatar)
sb.Append("&")
sb.Append("members=[]")
sb.Append("&")
sb.Append("joinmode=" + "0")
sb.Append("&")
sb.Append("beinvitemode=" + "1")
sb.Append("&")
sb.Append("invitemode=" + "1") // 邀请权限即谁可以邀请他人入群0群主和管理员默认。1所有人
sb.Append("&")
sb.Append("teamMemberLimit=" + "3000") // 最大群成员数(包含群主),[2200(默认)]
sb.Append("&")
sb.Append("isNotifyCloseOnline=" + "0") // 是否关闭群通知消息在线发送0否。1
sb.Append("&")
sb.Append("isNotifyClosePersistent=" + "0") // 是否关闭存储离线/漫游/历史的群通知消息0否。1
res, err := HyTools.HttpDo(httpMethod, url, header, sb.ToString())
// code Integer 状态码
// tid Long 网易云信服务器产生,群唯一标识
// faccid String 入群失败的账号accid列表格式为 JSONArray如果创建时邀请的成员中存在加群数量超过限制的情况会返回入群失败的 accid 以及附言msg
if err != nil {
// {"desc":"already register","code":414}
log.Info("CreateProGroup %s:" + err.Error())
return "", err
} else {
var resDTO CreateImRes
json.Unmarshal([]byte(res), &resDTO)
if resDTO.Code != 200 {
log.Info("CreateProGroup_%s:" + resDTO.Desc)
} else {
log.Info("CreateProGroup_%s:" + res)
}
}
var body map[string]any
if errJson := json.Unmarshal([]byte(res), &body); errJson != nil {
return "", errJson
}
if int(body["code"].(float64)) != 200 {
return "", errors.New(body["desc"].(string))
}
return body["tid"].(string), nil
}
// GroupUpdate 更新群组
func (client *ImClient) GroupUpdate(ctx context.Context, id, operator_id, name, announcement, icon string) error {
url := "https://open.yunxinapi.com/im/v2.1/teams/" + id
httpMethod := common.HTTP_METHOD_PATCH
header := client.generateJsonHeader()
reqBody := map[string]any{
"operator_id": operator_id,
"team_type": 1,
"name": name,
"announcement": announcement,
// "intro": intro,
// "members_limit": members_limit,
// "join_mode": join_mode, 通过 SDK 侧操作申请入群的验证方式。 0默认无需验证直接入群。 1需要群主或管理员验证通过才能入群。 2不允许任何人申请入群。
// "agree_mode": agree_mode, 邀请入群时是否需要被邀请人的同意。0默认需要被邀请人同意才能入群。1不需要被邀请人同意直接入群。
// "invite_mode": invite_mode, 邀请权限即谁可以邀请他人入群。0默认群主和管理员。1所有人。
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupUpdate %s:"+err.Error(), operator_id)
return errors.WithStack(err)
}
log.InfoF("update group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupUpdate code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupTransfer 转让群组
func (client *ImClient) GroupTransfer(ctx context.Context, id, new_owner, extension string) error {
url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + "/actions/transfer_owner"
httpMethod := common.HTTP_METHOD_PATCH
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"new_owner_account_id": new_owner,
"leave": 2,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupTransfer %s:"+err.Error(), id)
return errors.WithStack(err)
}
log.InfoF("GroupTransfer group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupTransfer code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupManagerAdd
func (client *ImClient) GroupManagerAdd(ctx context.Context, id, operator_id, extension string, managers []string) error {
url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + "/actions/add_manager"
httpMethod := common.HTTP_METHOD_POST
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"managers": managers,
"operator_id": operator_id,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupManagerAdd %s:"+err.Error(), operator_id)
return errors.WithStack(err)
}
log.InfoF("GroupManagerAdd group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupManagerAdd code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupManagerRemove
func (client *ImClient) GroupManagerRemove(ctx context.Context, id, operator_id, extension string, managers []string) error {
url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + "/actions/remove_manager"
httpMethod := common.HTTP_METHOD_DELETE
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"managers": managers,
"operator_id": operator_id,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupManagerRemove %s:"+err.Error(), operator_id)
return errors.WithStack(err)
}
log.InfoF("GroupManagerRemove group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupManagerRemove code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupRemove
func (client *ImClient) GroupRemove(ctx context.Context, id, operator_id, extension string) error {
url := "https://open.yunxinapi.com/im/v2.1/teams/" + id
httpMethod := common.HTTP_METHOD_DELETE
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"operator_id": operator_id,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupRemove %s:"+err.Error(), operator_id)
return errors.WithStack(err)
}
log.InfoF("GroupRemove group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupRemove code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupMemberKick
func (client *ImClient) GroupMemberKick(ctx context.Context, tid, operator_id, extension string, members []string) error {
url := "https://open.yunxinapi.com/im/v2/team_members/actions/kick_member"
httpMethod := common.HTTP_METHOD_DELETE
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"operator_id": operator_id,
"team_id": tid,
"kick_account_ids": members,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupMemberKick %s:"+err.Error(), operator_id)
return errors.WithStack(err)
}
log.InfoF("GroupMemberKick group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupMemberKick code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupMemberLeave
func (client *ImClient) GroupMemberLeave(ctx context.Context, tid, account_id, extension string) error {
url := "https://open.yunxinapi.com/im/v2/team_members/actions/leave"
httpMethod := common.HTTP_METHOD_DELETE
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"account_id": account_id,
"team_id": tid,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupMemberLeave %s:"+err.Error(), tid)
return errors.WithStack(err)
}
log.InfoF("GroupMemberLeave group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupMemberLeave code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// GroupMemberJoin
func (client *ImClient) GroupMemberJoin(ctx context.Context, tid, operator_id, msg, extension string, invite_account_ids []string) error {
url := "https://open.yunxinapi.com/im/v2/team_members"
httpMethod := common.HTTP_METHOD_POST
header := client.generateJsonHeader()
reqBody := map[string]any{
"team_type": 1,
"operator_id": operator_id,
"team_id": tid,
"msg": msg,
"invite_account_ids": invite_account_ids,
"extension": extension,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return errors.WithStack(err)
}
res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes))
if err != nil {
log.InfoF("GroupMemberJoin %s:"+err.Error(), tid)
return errors.WithStack(err)
}
log.InfoF("GroupMemberJoin group chat resp: %s", res)
var body BaseRes[CreateChatGroupRsp]
err = json.Unmarshal([]byte(res), &body)
if err != nil {
return errors.WithStack(err)
}
if body.Code != 200 {
return errors.Errorf("GroupMemberJoin code(%d) not 200,msg: %s", body.Code, body.Msg)
}
return nil
}
// ================ 私有方法 ========================
func generateBodyData(parameters map[string]string) string {
sb := htools.NewStringBuilder()
parametersCount := len(parameters)
i := 0
for k, v := range parameters {
sb.Append(k + "=" + v)
if i < parametersCount-1 {
sb.Append("&")
}
i++
}
return sb.ToString()
}
func randNumber() string {
str := "0123456789"
bytes := []byte(str)
var result []byte
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 4; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}