package agora import ( "bytes" "encoding/base64" "encoding/json" "fmt" "git.hilo.cn/hilo-common/mylogrus" "git.hilo.cn/hilo-common/resource/config" rtctokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/RtcTokenBuilder" "io/ioutil" "net/http" "strconv" "time" ) const urlBase = "https://api.agora.io/v1/apps/" //建立MatchConfirm func CreateAgora(channelId string, expireTimestamp uint32, agoraId1 uint32, agoraId2 uint32) (string, string, uint32, string, uint32, error) { appId := config.GetAgoraAppId() appCertificate := config.GetAgoraAppCertificate() //channelId := strings.Replace(uuid.NewV4().String(), "-", "", -1) //expireTimeInSeconds := uint32(60) //currentTimestamp := uint32(time.Now().UTC().Unix()) //expireTimestamp := currentTimestamp + expireTimeInSeconds token1, err := rtctokenbuilder.BuildTokenWithUID(appId, appCertificate, channelId, agoraId1, rtctokenbuilder.RoleAttendee, expireTimestamp) if err != nil { mylogrus.MyLog.Printf("Fail to obtain token for user 1 %v", err.Error()) return "", "", 0, "", 0, err } token2, err := rtctokenbuilder.BuildTokenWithUID(appId, appCertificate, channelId, agoraId2, rtctokenbuilder.RoleAttendee, expireTimestamp) if err != nil { mylogrus.MyLog.Printf("Fail to obtain token for user 2 %v", err.Error()) return "", "", 0, "", 0, err } return channelId, token1, agoraId1, token2, agoraId2, nil } //创建群组的声网通道,token有效时长:一个星期, 参数:userId uint32, channelId,业务保证唯一性。返回:channelId, token, err func CreateGroupAgora(channelId string, uid uint32) (string, string, error) { appId := config.GetAgoraAppId() appCertificate := config.GetAgoraAppCertificate() //channelId := strings.Replace(uuid.NewV4().String(), "-", "", -1) expireTimeInSeconds := uint32(60 * 60 * 24 * 7) //一个星期 currentTimestamp := uint32(time.Now().UTC().Unix()) expireTimestamp := currentTimestamp + expireTimeInSeconds token, err := rtctokenbuilder.BuildTokenWithUID(appId, appCertificate, channelId, uid, rtctokenbuilder.RoleAttendee, expireTimestamp) if err != nil { mylogrus.MyLog.Printf("Fail to obtain token for user 1 %v", err.Error()) return "", "", err } return channelId, token, nil } // 生成RESTful API 凭证 func createCredential() string { customerKey := config.GetAgoraCustomerKey() customerSecret := config.GetAgoraCustomerSecret() // 拼接客户 ID 和客户密钥并使用 base64 进行编码 plainCredentials := customerKey + ":" + customerSecret base64Credentials := base64.StdEncoding.EncodeToString([]byte(plainCredentials)) mylogrus.MyLog.Infof("agora customerKey :%s customerSecret:%s encodeString:%s", customerKey, customerSecret, base64Credentials) return base64Credentials } type AcquireResourceBody struct { ResourceId string `json:"resourceId"` } type StartResourceBody struct { Sid string `json:"sid"` ResourceId string `json:"resourceId"` } type FileListItem struct { Filename string `json:"filename"` TrackType string `json:"trackType"` Uid string `json:"uid"` MixedAllUser bool `json:"mixedAllUser"` IsPlayable bool `json:"isPlayable"` SliceStartTime int64 `json:"sliceStartTime"` } type ServerResponse struct { FileListMode string `json:"fileListMode"` FileList []FileListItem `json:"fileList"` UploadingStatus string `json:"uploadingStatus"` } type StopResponseBody struct { ResourceId string `json:"resourceId"` Sid string `json:"sid"` ServerResponse ServerResponse `json:"serverResponse"` } func generateUid() uint32 { // 1609430400就是2021-01-01 00:00:00 return uint32(time.Now().Unix() - 1609430400) } func GetRecordPathPrefix() string { return "nextvideo/agoraRecording/" } //获取资源Id func acquireResourceId(cname string) (string, uint32, error) { appId := config.GetAgoraAppId() url := urlBase + appId + "/cloud_recording/acquire" clientRequest := make(map[string]interface{}) clientRequest["resourceExpiredHour"] = 24 clientRequest["scene"] = 2 // 申请延时转码资源 params := make(map[string]interface{}) params["cname"] = cname uid := generateUid() params["uid"] = strconv.FormatUint(uint64(uid), 10) params["clientRequest"] = clientRequest bytesData, err := json.Marshal(params) if err != nil { return "", 0, err } reader := bytes.NewReader(bytesData) //mylogrus.MyLog.Infof("agora api:acquire url:%v, param:%v", url, string(bytesData)) client := &http.Client{} req, err := http.NewRequest("POST", url, reader) if err != nil { mylogrus.MyLog.Errorf("agora api:acquire request err:%v", err) return "", 0, err // handle error } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora api:acquire do err:%v", err) return "", 0, err } defer resp.Body.Close() mylogrus.MyLog.Infof("req header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return "", 0, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Infof("agora api:acquire resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora api:acquire resp err:%v", err) return "", 0, err } var resourceBody AcquireResourceBody if err := json.Unmarshal(body, &resourceBody); err != nil { mylogrus.MyLog.Errorf("agora api:acquire resp toStruts err:%v, body:%v", err, string(body)) return "", 0, err } mylogrus.MyLog.Infof("agora api:acquire resp success sid:%v", resourceBody.ResourceId) return resourceBody.ResourceId, uid, nil } func StartRecording(token string, cname string) (string, string, uint32, error) { mylogrus.MyLog.Infof("agora start recording, token: %s, cname: %s", token, cname) resourceId, uid, err := acquireResourceId(cname) if err != nil { return "", "", 0, err } appId := config.GetAgoraAppId() url := urlBase + appId + "/cloud_recording/resourceid/" + resourceId + "/mode/individual/start" appsCollection := make(map[string]interface{}) appsCollection["combinationPolicy"] = "postpone_transcoding" // 打开延时转码 recordingConfig := map[string]interface{}{ "channelType": 0, "streamTypes": 2, "subscribeUidGroup": 0, "maxIdleTime": 5, } /* snapshotConfig := map[string]interface{}{ "captureInterval": 5, "fileType": []string{"jpg"}, }*/ storageConfig := map[string]interface{}{ "vendor": 2, "region": 6, "bucket": config.GetConfigOss().OSS_BUCKET, "accessKey": config.GetConfigOss().OSS_ACCESS_KEY_ID, "secretKey": config.GetConfigOss().OSS_ACCESS_KEY_SECRET, "fileNamePrefix": []string{"nextvideo", "agoraRecording"}, } clientRequest := map[string]interface{}{ "token": token, "appsCollection": appsCollection, "recordingConfig": recordingConfig, //"snapshotConfig": snapshotConfig, "storageConfig": storageConfig, } params := make(map[string]interface{}) params["cname"] = cname params["uid"] = strconv.FormatUint(uint64(uid), 10) params["clientRequest"] = clientRequest bytesData, err := json.Marshal(params) if err != nil { return "", "", 0, err } reader := bytes.NewReader(bytesData) mylogrus.MyLog.Infof("agora start recording, url:%s, param:%s", url, string(bytesData)) client := &http.Client{} req, err := http.NewRequest("POST", url, reader) if err != nil { mylogrus.MyLog.Errorf("agora api:start request err:%v", err) return "", "", 0, err // handle error } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora api:start do err:%v", err) return "", "", 0, err } defer resp.Body.Close() mylogrus.MyLog.Infof("req header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return "", "", 0, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Infof("agora api:start resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora api:start resp err:%v", err) return "", "", 0, err } var resourceBody StartResourceBody if err := json.Unmarshal(body, &resourceBody); err != nil { mylogrus.MyLog.Errorf("agora api:start resp toStruts err:%v, body:%v", err, string(body)) return "", "", 0, err } return resourceId, resourceBody.Sid, uid, nil } func StopRecording(token, resourceId, cname, sid string, uid uint32) (*StopResponseBody, error) { mylogrus.MyLog.Debugf("agora stop recording token: %s, resourceId: %s, cname: %s, sid: %s", token, resourceId, cname, sid) appId := config.GetAgoraAppId() url := urlBase + appId + "/cloud_recording/resourceid/" + resourceId + "/sid/" + sid + "/mode/individual/stop" clientRequest := map[string]interface{}{} params := make(map[string]interface{}) params["cname"] = cname params["uid"] = strconv.FormatUint(uint64(uid), 10) params["clientRequest"] = clientRequest bytesData, err := json.Marshal(params) if err != nil { return nil, err } reader := bytes.NewReader(bytesData) mylogrus.MyLog.Debugf("agora stop recording, url:%s, param:%s", url, string(bytesData)) client := &http.Client{} req, err := http.NewRequest("POST", url, reader) if err != nil { mylogrus.MyLog.Errorf("agora api:stop request err:%v", err) return nil, err // handle error } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora api:stop do err:%v", err) return nil, err } defer resp.Body.Close() mylogrus.MyLog.Debugf("req header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Debugf("agora api:stop resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora api:stop resp err:%v", err) return nil, err } var stopResponseBody StopResponseBody if err := json.Unmarshal(body, &stopResponseBody); err != nil { mylogrus.MyLog.Errorf("agora api:stop resp toStruts err:%v, body:%v", err, string(body)) return nil, err } return &stopResponseBody, nil } func Query(resourceId, sid string) (int, error) { appId := config.GetAgoraAppId() url := urlBase + appId + "/cloud_recording/resourceid/" + resourceId + "/sid/" + sid + "/mode/individual/query" client := &http.Client{} req, err := http.NewRequest("GET", url, nil) if err != nil { mylogrus.MyLog.Errorf("agora api:acquire request err:%v", err) return 0, err // handle error } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora api:acquire do err:%v", err) return 0, err } defer resp.Body.Close() mylogrus.MyLog.Infof("req header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return resp.StatusCode, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Infof("agora api:acquire resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora api:acquire resp err:%v", err) return resp.StatusCode, err } mylogrus.MyLog.Info(body) return 0, nil } type KickingResponseBody struct { Status string `json:"status"` Id uint64 `json:"id"` } //增加封禁封禁规则 func AddKickingGroupRule(channelId, uid, ip string) (*KickingResponseBody, error) { mylogrus.MyLog.Infoln("agora AddKickingGroupRule channelId: %s, %s, %s", channelId, uid, ip) appId := config.GetAgoraAppId() url := "https://api.agora.io/dev/v1/kicking-rule" params := make(map[string]interface{}) params["appid"] = appId params["cname"] = channelId params["uid"] = uid params["ip"] = ip if len(channelId) > 0 { params["time"] = 60 * 24 //封禁时长,不用担心,因为封禁之后,业务能控制不生产token } else { params["time"] = 60 } params["privileges"] = []string{"publish_audio"} bytesData, err := json.Marshal(params) if err != nil { return nil, err } reader := bytes.NewReader(bytesData) mylogrus.MyLog.Infof("agora AddKickingGroupRule, url:%v, param:%s", url, string(bytesData)) client := &http.Client{} req, err := http.NewRequest("POST", url, reader) if err != nil { mylogrus.MyLog.Errorf("agora AddKickingGroupRule api:stop request err:%v", err) return nil, err // handle error } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora AddKickingGroupRule api:stop do err:%v", err) return nil, err } defer resp.Body.Close() mylogrus.MyLog.Infof("req AddKickingGroupRule header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Debugf("agora AddKickingGroupRule api:stop resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora AddKickingGroupRule api:stop resp err:%v", err) return nil, err } var kickingResponseBody KickingResponseBody if err := json.Unmarshal(body, &kickingResponseBody); err != nil { mylogrus.MyLog.Errorf("agora AddKickingGroupRule api:stop resp toStruts err:%v, body:%v", err, string(body)) return nil, err } return &kickingResponseBody, nil } //删除封禁频道规则 func DelKickingRule(agoraRuleId uint64) (*KickingResponseBody, error) { mylogrus.MyLog.Infof("agora DelKickingRule agoraRuleId: %s", agoraRuleId) appId := config.GetAgoraAppId() url := "https://api.agora.io/dev/v1/kicking-rule" params := make(map[string]interface{}) params["appid"] = appId params["id"] = agoraRuleId bytesData, err := json.Marshal(params) if err != nil { return nil, err } reader := bytes.NewReader(bytesData) mylogrus.MyLog.Infof("agora DelKickingRule, url:%v, param:%s", url, string(bytesData)) client := &http.Client{} req, err := http.NewRequest("DELETE", url, reader) if err != nil { mylogrus.MyLog.Errorf("agora DelKickingRule api:stop request err:%v", err) return nil, err // handle error } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora DelKickingRule api:stop do err:%v", err) return nil, err } defer resp.Body.Close() mylogrus.MyLog.Info("req DelKickingRule header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Debugf("agora DelKickingRule api:stop resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora DelKickingRule api:stop resp err:%v", err) return nil, err } var kickingResponseBody KickingResponseBody if err := json.Unmarshal(body, &kickingResponseBody); err != nil { mylogrus.MyLog.Errorf("agora DelKickingRule api:stop resp toStruts err:%v, body:%v", err, string(body)) return nil, err } return &kickingResponseBody, nil } type ruleElem struct { Id int64 `json:"id"` Uid string `json:"uid"` StrUid bool `json:"str_uid"` Cname string `json:"cname"` Ip *string `json:"ip"` Ts time.Time `json:"ts"` Privileges []string `json:"privileges"` ClientIp string `json:"clientIp"` Reason *string `json:"reason"` CreateAt time.Time `json:"createAt"` UpdateAt time.Time `json:"updateAt"` } type GetKickingResponseBody struct { Status string `json:"status"` Rules []ruleElem `json:"rules"` } // 查询封禁规则 func GetKickingRule() (*GetKickingResponseBody, error) { mylogrus.MyLog.Infoln("agora GetKickingRule") appId := config.GetAgoraAppId() url := "https://api.agora.io/dev/v1/kicking-rule?appid=" + appId client := &http.Client{} req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { mylogrus.MyLog.Errorf("agora GetKickingRule api:stop request err:%v", err) return nil, err } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { mylogrus.MyLog.Errorf("agora GetKickingRule api:stop do err:%v", err) return nil, err } defer resp.Body.Close() mylogrus.MyLog.Infof("req GetKickingRule header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) mylogrus.MyLog.Debugf("agora GetKickingRule api:stop resp body:%v", string(body)) if err != nil { mylogrus.MyLog.Errorf("agora GetKickingRule api:stop resp err:%v", err) return nil, err } var getResponse GetKickingResponseBody if err := json.Unmarshal(body, &getResponse); err != nil { mylogrus.MyLog.Errorf("agora GetKickingRule api:stop resp toStruts err:%v, body:%v", err, string(body)) return nil, err } return &getResponse, nil } type GetUserStatusRsp struct { Success bool `json:"success"` Data struct { Join int64 `json:"join"` Uid int64 `json:"uid"` InChannel bool `json:"in_channel"` Platform int `json:"platform"` Role int `json:"role"` } `json:"data"` } // 查询用户状态 func GetUserStatus(uid int, chanName string) (*GetUserStatusRsp, error) { logger := mylogrus.MyLog.WithField("agora", "GetUserStatus") appId := config.GetAgoraAppId() url := "https://api.agora.io/dev/v1/channel/user/property/" + appId + "/" + strconv.Itoa(uid) + "/" + chanName client := &http.Client{} req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { logger.Errorf("NewRequest err:%v", err) return nil, err } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { logger.Errorf("Do err:%v", err) return nil, err } defer resp.Body.Close() logger.Infof("header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) logger.Infof("resp body:%v", string(body)) if err != nil { logger.Errorf("resp err:%v", err) return nil, err } var getResponse GetUserStatusRsp if err := json.Unmarshal(body, &getResponse); err != nil { logger.Errorf("unmarshal err:%v, body:%v", err, string(body)) return nil, err } logger.Infof("Rsp: %+v", getResponse) return &getResponse, nil } type GetUserListRsp struct { Success bool `json:"success"` Data struct { ChannelExist bool `json:"channel_exist"` Mode int `json:"mode"` Broadcasters []uint64 `json:"broadcasters"` Audience []uint64 `json:"audience"` AudienceTotal uint `json:"audience_total"` } `json:"data"` } // 查询用户列表 func GetUserList(chanName string) (*GetUserListRsp, error) { logger := mylogrus.MyLog.WithField("agora", "GetUserList") appId := config.GetAgoraAppId() url := "https://api.agora.io/dev/v1/channel/user/" + appId + "/" + chanName client := &http.Client{} req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { logger.Errorf("NewRequest err:%v", err) return nil, err } req.Header.Set("Content-Type", "application/json;charset=utf-8") req.Header.Set("Authorization", "Basic "+createCredential()) resp, err := client.Do(req) if err != nil { logger.Errorf("Do err:%v", err) return nil, err } defer resp.Body.Close() logger.Infof("header: %v, StatusCode = %d, %s", req.Header, resp.StatusCode, resp.Status) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("%w", resp.Status) } body, err := ioutil.ReadAll(resp.Body) logger.Infof("resp body:%v", string(body)) if err != nil { logger.Errorf("resp err:%v", err) return nil, err } var getResponse GetUserListRsp if err := json.Unmarshal(body, &getResponse); err != nil { logger.Errorf("unmarshal err:%v, body:%v", err, string(body)) return nil, err } logger.Infof("Rsp: %+v", getResponse) return &getResponse, nil }