first commit

This commit is contained in:
Yangtao
2025-11-18 17:48:20 +08:00
commit 6e56cab848
196 changed files with 65809 additions and 0 deletions

View File

@ -0,0 +1,767 @@
package Netease
import (
"context"
"encoding/json"
"fmt"
"servicebase/pkg/common"
"servicebase/pkg/common/HyTools"
yunxin "servicebase/pkg/common/netease/dto"
"servicebase/pkg/htools"
"servicebase/pkg/log"
"strings"
"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 {
// {"code":200,"info":{"token":"123456","accid":"b8af4bebe2064435974ba2340d852055","name":"b8af4bebe2064435974ba2340d852055"}}
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]interface{}
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())
// #查询云信用户信息结果:{"desc":"b8af4bebe2064435974ba2340d852055not register","code":414}#
// {"code":200,"uinfos":[{"icon":"https://xzphoto.meetalk.tech/upload/6bba4098-6ea8-4758-8193-19abed540c0b.0","accid":"2251bae8a0514e6892f0374f5dd260d4","name":"弦乐","gender":0}]}
logs.Info("#" + "查询云信用户信息结果:" + res + "#")
var body map[string]interface{}
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
}
// {"valid":true,"ext":"","creator":"1b94b5e7af8a45ed9fda27d28165d4c9","name":"32452345","muted":false,"roomid":11142139973,"queuelevel":0}
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]interface{})
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
}
//{"desc":"parameter roomid should be long","code":414}
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
}
// ================ 私有方法 ========================
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)
}

View File

@ -0,0 +1,124 @@
package Netease
import (
"context"
"testing"
)
// 测试获取IM用户信息
func TestImClient_GetImUserInfo(t *testing.T) {
type fields struct {
AppKey string
AppSecret string
}
type args struct {
userId string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "test",
fields: fields{
AppKey: "543b1a440b940b170fccdf494839efc01",
AppSecret: "41134093938f1",
},
args: args{
// 2251bae8a0514e6892f0374f5dd260d4
// b8af4bebe2064435974ba2340d852055
userId: "fcda23bc00e641f5ae17492503b566ed",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := &ImClient{
AppKey: tt.fields.AppKey,
AppSecret: tt.fields.AppSecret,
}
if err := client.GetImUserInfo(tt.args.userId); (err != nil) != tt.wantErr {
t.Errorf("GetImUserInfo() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
// 测试注册IM用户
func TestImClient_CreateImUser(t *testing.T) {
type fields struct {
AppKey string
AppSecret string
}
type args struct {
userId string
nickname string
avatar string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "test",
fields: fields{
AppKey: "543b1a440b940b170fccdf494839efc01",
AppSecret: "41134093938f1",
},
args: args{
// 2251bae8a0514e6892f0374f5dd260d4
// b8af4bebe2064435974ba2340d852055
userId: "fcda23bc00e641f5ae17492503b566ed",
nickname: "杏",
avatar: "https://photo-app.ddegame.cn/upload/19986a27-3bae-49f7-9643-cd18cda87557.jpg",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client := &ImClient{
AppKey: tt.fields.AppKey,
AppSecret: tt.fields.AppSecret,
}
if err := client.CreateImUser(tt.args.userId, tt.args.nickname, tt.args.avatar); (err != nil) != tt.wantErr {
t.Errorf("GetImUserInfo() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
// 测试注册IM用户
func TestImClient_CreateImUserOne(t *testing.T) {
client := &ImClient{
AppKey: "543b1a440b940b170fccdf494839efc01",
AppSecret: "41134093938f1",
}
client.CreateImUser("fcda23bc00e641f5ae17492503b566ed", "杏", "https://photo-app.ddegame.cn/upload/19986a27-3bae-49f7-9643-cd18cda87557.jpg")
}
func TestImClient_CreateChatGroup(t *testing.T) {
client := &ImClient{
AppKey: "543b1a440b940b170fccdf494839efc01",
AppSecret: "41134093938f1",
}
groupId, err := client.CreateChatGroup(context.Background(), "e1fbefbbd77a402e8c2101a0ebe15f5d", "测试群", []string{"e1fbefbbd77a402e8c2101a0ebe15f5d"})
if err != nil {
t.Error(err)
}
println(groupId)
}
func init() {
// viper.SetConfigName("dev.yaml")
// viper.AddConfigPath("../../../configs/admin/")
// viper.SetConfigType("yaml")
// _ = viper.ReadInConfig()
// log.Init()
// datasource.InitMySQlMaster()
}

View File

@ -0,0 +1,33 @@
package Netease
type ImResponse struct {
Code int `json:"code"`
Desc interface{} `json:"desc"`
}
// 获取聊天室在线列表返回对象
type GetChatroomMemberResponse struct {
Data []ChatroomMemberDTO `json:"data"`
}
// 聊天室会员
type ChatroomMemberDTO struct {
RoomId int `json:"roomid"`
AccId string `json:"accid"`
OnlineStat bool `json:"onlineStat"`
}
// 创建聊天室返回结果
type CreateChatroomResponse struct {
Code int `json:"code"`
Chatroom NeteaseChatroomDTO `json:"chatroom"`
}
// 聊天室会员
type NeteaseChatroomDTO struct {
RoomId int `json:"roomid"`
Valid bool `json:"valid"`
RoomName string `json:"name"`
Ext string `json:"ext"`
Creator string `json:"creator"`
}

View File

@ -0,0 +1,10 @@
package yunxin
// 聊天室在线成员对象
type ImChatroomOnlineMember struct {
MessageRoomId int `json:"roomid"`
UserId string `json:"accid"`
EnterTime int64 `json:"enterTime"`
Type string `json:"type"`
OnlineStat bool `json:"onlineStat"`
}

View File

@ -0,0 +1,9 @@
package yunxin
// IM用户扩展信息 会话列表用户数据从IM信息获取
type ImUserExtData struct {
VipLevel string // Vip等级
AvatarDecoration string // 头饰
GroupType string
VipConfig string // json字符串dto.UserVipConfigDTO
}

View File

@ -0,0 +1,7 @@
package yunxin
// 更新聊天室信息请求对象
type UpdateRoomInfoRequest struct {
Roomid string `json:"roomid"` // 房间ID
NotifyExt string `json:"notifyExt" // 扩展信息`
}

38
pkg/common/netease/req.go Normal file
View File

@ -0,0 +1,38 @@
package Netease
// CreateChatGroupReq 创建群组请求
// https://doc.yunxin.163.com/messaging2/server-apis/DIwODUwMTE?platform=server
type CreateChatGroupReq struct {
OwnerAccountID string `json:"owner_account_id"` // M 群主(创建者)的 IM 账号 ID。
TeamType int `json:"team_type"` // M 1高级群。2超大群。
Name string `json:"name"` // M 长度上限 64 位字符。
Icon string `json:"icon,omitempty"` // O 群组头像的 URL 地址,例如 "https://netease/xxx.png",长度上限 1024 位字符。
Announcement string `json:"announcement,omitempty"` // O 群组公告,长度上限 1024 位字符。
Intro string `json:"intro,omitempty"` // O群组简介长度上限 512 位字符。
MembersLimit int `json:"members_limit"` // O 群组成员数上限(包含群主),默认为 200。可设置范围的为[2 ~ 200]。
ServerExtension string `json:"server_extension,omitempty"` // O 自定义群组扩展字段,第三方可以跟据此属性自定义扩展自己的群属性,建议封装成 JSONObject 格式,{key:value}。长度上限 1024 位字符。 对应 SDK 的 serverExtension 字段。
CustomerExtension string `json:"customer_extension,omitempty"` // O 客户端自定义扩展字段,仅服务器 API 可以设置SDK 仅负责透传,不解析内容。 对应 SDK 的 customerExtension 字段。
Extension string `json:"extension,omitempty"` // M 创建群组时邀请入群的成员列表。
InviteAccountIDs []string `json:"invite_account_ids,omitempty"` // M 邀请入群的附言,长度上限 150 位字符。
InviteMsg string `json:"invite_msg,omitempty"`
Configuration *TeamConfiguration `json:"configuration,omitempty"`
AntispamConfiguration *AntispamConfig `json:"antispam_configuration,omitempty"`
}
type TeamConfiguration struct {
JoinMode int `json:"join_mode"` // 通过 SDK 侧操作申请入群的验证方式。 0默认无需验证直接入群。 1需要群主或管理员验证通过才能入群。 2不允许任何人申请入群。
AgreeMode int `json:"agree_mode"` // 邀请入群时是否需要被邀请人的同意。 0默认需要被邀请人同意才能入群。 1不需要被邀请人同意直接入群。
InviteMode int `json:"invite_mode"` // 邀请权限,即谁可以邀请他人入群。 0默认群主和管理员。 1所有人。
UpdateTeamInfoMode int `json:"update_team_info_mode"`
UpdateExtensionMode int `json:"update_extension_mode"`
}
type AntispamConfig struct {
Enabled bool `json:"enabled"`
BusinessIDMap *BusinessIDMap `json:"business_id_map,omitempty"`
}
type BusinessIDMap struct {
Type int `json:"type"`
AntispamBusinessID string `json:"antispam_business_id"`
}

35
pkg/common/netease/rsp.go Normal file
View File

@ -0,0 +1,35 @@
package Netease
type CreateChatGroupRsp struct {
FailedList []*FailedMember `json:"failed_list,omitempty"`
TeamInfo *TeamInfo `json:"team_info"`
}
type FailedMember struct {
AccountID string `json:"account_id"`
ErrorCode int `json:"error_code"`
ErrorMsg string `json:"error_msg"`
}
type TeamInfo struct {
TeamID int64 `json:"team_id"`
OwnerAccountID string `json:"owner_account_id"`
Name string `json:"name"`
Icon string `json:"icon,omitempty"`
Announcement string `json:"announcement,omitempty"`
Intro string `json:"intro,omitempty"`
MembersLimit int `json:"members_limit"`
MemberCount int `json:"member_count"`
ServerExtension string `json:"server_extension,omitempty"`
CustomerExtension string `json:"customer_extension,omitempty"`
CreateTime int64 `json:"create_time"`
UpdateTime int64 `json:"update_time"`
TeamType int `json:"team_type"`
Configuration *TeamConfiguration `json:"configuration,omitempty"`
}
type BaseRes[T any] struct {
Code int
Msg string
Data T
}