✨ 添加基础类
This commit is contained in:
parent
e36c37b39b
commit
bdc4a13e83
108
internal/conv/conv.go
Normal file
108
internal/conv/conv.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Email:1711788888@qq.com
|
||||||
|
* @Date: 2021/8/31 11:16 下午
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package conv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stringInterface interface {
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorInterface interface {
|
||||||
|
Error() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func String(any interface{}) string {
|
||||||
|
switch v := any.(type) {
|
||||||
|
case nil:
|
||||||
|
return ""
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case int:
|
||||||
|
return strconv.Itoa(v)
|
||||||
|
case int8:
|
||||||
|
return strconv.Itoa(int(v))
|
||||||
|
case int16:
|
||||||
|
return strconv.Itoa(int(v))
|
||||||
|
case int32:
|
||||||
|
return strconv.Itoa(int(v))
|
||||||
|
case int64:
|
||||||
|
return strconv.FormatInt(v, 10)
|
||||||
|
case uint:
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
case uint8:
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
case uint16:
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
case uint64:
|
||||||
|
return strconv.FormatUint(v, 10)
|
||||||
|
case float32:
|
||||||
|
return strconv.FormatFloat(float64(v), 'f', -1, 32)
|
||||||
|
case float64:
|
||||||
|
return strconv.FormatFloat(v, 'f', -1, 64)
|
||||||
|
case bool:
|
||||||
|
return strconv.FormatBool(v)
|
||||||
|
case []byte:
|
||||||
|
return string(v)
|
||||||
|
case time.Time:
|
||||||
|
return v.String()
|
||||||
|
case *time.Time:
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return v.String()
|
||||||
|
default:
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if i, ok := v.(stringInterface); ok {
|
||||||
|
return i.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if i, ok := v.(errorInterface); ok {
|
||||||
|
return i.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
rv = reflect.ValueOf(v)
|
||||||
|
kind = rv.Kind()
|
||||||
|
)
|
||||||
|
|
||||||
|
switch kind {
|
||||||
|
case reflect.Chan,
|
||||||
|
reflect.Map,
|
||||||
|
reflect.Slice,
|
||||||
|
reflect.Func,
|
||||||
|
reflect.Ptr,
|
||||||
|
reflect.Interface,
|
||||||
|
reflect.UnsafePointer:
|
||||||
|
if rv.IsNil() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
return rv.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind == reflect.Ptr {
|
||||||
|
return String(rv.Elem().Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, e := json.Marshal(v); e != nil {
|
||||||
|
return fmt.Sprint(v)
|
||||||
|
} else {
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
146
internal/core/client.go
Normal file
146
internal/core/client.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Email:1711788888@qq.com
|
||||||
|
* @Date: 2021/8/27 11:31 上午
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ady-tis/internal/enum"
|
||||||
|
"ady-tis/internal/sign"
|
||||||
|
"ady-tis/internal/types"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.echol.cn/loser/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultBaseUrl = "https://console.tim.qq.com"
|
||||||
|
defaultVersion = "v4"
|
||||||
|
defaultContentType = "json"
|
||||||
|
defaultExpiration = 3600
|
||||||
|
)
|
||||||
|
|
||||||
|
var invalidResponse = NewError(enum.InvalidResponseCode, "invalid response")
|
||||||
|
|
||||||
|
type Client interface {
|
||||||
|
// Get GET请求
|
||||||
|
Get(serviceName string, command string, data interface{}, resp interface{}) error
|
||||||
|
// Post POST请求
|
||||||
|
Post(serviceName string, command string, data interface{}, resp interface{}) error
|
||||||
|
// Put PUT请求
|
||||||
|
Put(serviceName string, command string, data interface{}, resp interface{}) error
|
||||||
|
// Patch PATCH请求
|
||||||
|
Patch(serviceName string, command string, data interface{}, resp interface{}) error
|
||||||
|
// Delete DELETE请求
|
||||||
|
Delete(serviceName string, command string, data interface{}, resp interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
client *http.Client
|
||||||
|
opt *Options
|
||||||
|
userSig string
|
||||||
|
userSigExpireAt int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
AppId int // 应用SDKAppID,可在即时通信 IM 控制台 的应用卡片中获取。
|
||||||
|
AppSecret string // 密钥信息,可在即时通信 IM 控制台 的应用详情页面中获取,具体操作请参见 获取密钥
|
||||||
|
UserId string // 用户ID
|
||||||
|
Expiration int // UserSig过期时间
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(opt *Options) Client {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
c := new(client)
|
||||||
|
c.opt = opt
|
||||||
|
c.client = http.NewClient()
|
||||||
|
c.client.SetContentType(http.ContentTypeJson)
|
||||||
|
c.client.SetBaseUrl(defaultBaseUrl)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get GET请求
|
||||||
|
func (c *client) Get(serviceName string, command string, data interface{}, resp interface{}) error {
|
||||||
|
return c.request(http.MethodGet, serviceName, command, data, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post POST请求
|
||||||
|
func (c *client) Post(serviceName string, command string, data interface{}, resp interface{}) error {
|
||||||
|
return c.request(http.MethodPost, serviceName, command, data, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put PUT请求
|
||||||
|
func (c *client) Put(serviceName string, command string, data interface{}, resp interface{}) error {
|
||||||
|
return c.request(http.MethodPut, serviceName, command, data, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch PATCH请求
|
||||||
|
func (c *client) Patch(serviceName string, command string, data interface{}, resp interface{}) error {
|
||||||
|
return c.request(http.MethodPatch, serviceName, command, data, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete DELETE请求
|
||||||
|
func (c *client) Delete(serviceName string, command string, data interface{}, resp interface{}) error {
|
||||||
|
return c.request(http.MethodDelete, serviceName, command, data, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// request Request请求
|
||||||
|
func (c *client) request(method, serviceName, command string, data, resp interface{}) error {
|
||||||
|
res, err := c.client.Request(method, c.buildUrl(serviceName, command), data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = res.Scan(resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r, ok := resp.(types.ActionBaseRespInterface); ok {
|
||||||
|
if r.GetActionStatus() == enum.FailActionStatus {
|
||||||
|
return NewError(r.GetErrorCode(), r.GetErrorInfo())
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.GetErrorCode() != enum.SuccessCode {
|
||||||
|
return NewError(r.GetErrorCode(), r.GetErrorInfo())
|
||||||
|
}
|
||||||
|
} else if r, ok := resp.(types.BaseRespInterface); ok {
|
||||||
|
if r.GetErrorCode() != enum.SuccessCode {
|
||||||
|
return NewError(r.GetErrorCode(), r.GetErrorInfo())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return invalidResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildUrl 构建一个请求URL
|
||||||
|
func (c *client) buildUrl(serviceName string, command string) string {
|
||||||
|
format := "/%s/%s/%s?sdkappid=%d&identifier=%s&usersig=%s&random=%d&contenttype=%s"
|
||||||
|
random := rand.Int31()
|
||||||
|
userSig := c.getUserSig()
|
||||||
|
//fmt.Println(fmt.Sprintf(format, defaultVersion, serviceName, command, c.opt.AppId, c.opt.UserId, userSig, random, defaultContentType))
|
||||||
|
return fmt.Sprintf(format, defaultVersion, serviceName, command, c.opt.AppId, c.opt.UserId, userSig, random, defaultContentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getUserSig 获取签名
|
||||||
|
func (c *client) getUserSig() string {
|
||||||
|
now, expiration := time.Now(), c.opt.Expiration
|
||||||
|
|
||||||
|
if expiration <= 0 {
|
||||||
|
expiration = defaultExpiration
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.userSig == "" || c.userSigExpireAt <= now.Unix() {
|
||||||
|
c.userSig, _ = sign.GenUserSig(c.opt.AppId, c.opt.AppSecret, c.opt.UserId, expiration)
|
||||||
|
c.userSigExpireAt = now.Add(time.Duration(expiration) * time.Second).Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.userSig
|
||||||
|
}
|
38
internal/core/error.go
Normal file
38
internal/core/error.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Email:1711788888@qq.com
|
||||||
|
* @Date: 2021/8/27 1:12 下午
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
type Error interface {
|
||||||
|
error
|
||||||
|
Code() int
|
||||||
|
Message() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type respError struct {
|
||||||
|
code int
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewError(code int, message string) Error {
|
||||||
|
return &respError{
|
||||||
|
code: code,
|
||||||
|
message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *respError) Error() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *respError) Code() int {
|
||||||
|
return e.code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *respError) Message() string {
|
||||||
|
return e.message
|
||||||
|
}
|
16
internal/enum/code.go
Normal file
16
internal/enum/code.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @Author: wanglin
|
||||||
|
* @Author: wanglin@vspn.com
|
||||||
|
* @Date: 2021/11/3 10:45
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package enum
|
||||||
|
|
||||||
|
const (
|
||||||
|
SuccessActionStatus = "OK" // 成功状态
|
||||||
|
FailActionStatus = "FAIL" // 失败状态
|
||||||
|
SuccessCode = 0 // 成功
|
||||||
|
InvalidParamsCode = -1 // 无效参数(自定义)
|
||||||
|
InvalidResponseCode = -2 // 无效响应(自定义)
|
||||||
|
)
|
50
internal/enum/enum.go
Normal file
50
internal/enum/enum.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Email:1711788888@qq.com
|
||||||
|
* @Date: 2021/8/28 1:14 上午
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package enum
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 消息类型
|
||||||
|
MsgText = "TIMTextElem" // 消息元素
|
||||||
|
MsgLocation = "TIMLocationElem" // 地理位置消息元素
|
||||||
|
MsgFace = "TIMFaceElem" // 表情消息元素
|
||||||
|
MsgCustom = "TIMCustomElem" // 自定义消息元素
|
||||||
|
MsgSound = "TIMSoundElem" // 语音消息元素
|
||||||
|
MsgImage = "TIMImageElem" // 图像消息元素
|
||||||
|
MsgFile = "TIMFileElem" // 文件消息元素
|
||||||
|
MsgVideo = "TIMVideoFileElem" // 视频消息元素
|
||||||
|
|
||||||
|
// 图片格式
|
||||||
|
ImageFormatJPG = 1 // JPG格式
|
||||||
|
ImageFormatGIF = 2 // GIF格式
|
||||||
|
ImageFormatPNG = 3 // PNG格式
|
||||||
|
ImageFormatBMP = 4 // BMP格式
|
||||||
|
ImageFormatOTHER = 255 // 其他格式
|
||||||
|
|
||||||
|
// 图片类型
|
||||||
|
ImageTypeOriginal = 1 // 原图
|
||||||
|
ImageTypePic = 2 // 大图
|
||||||
|
ImageTypeThumb = 3 // 缩略图
|
||||||
|
|
||||||
|
// 标准资料字段
|
||||||
|
StandardAttrNickname = "Tag_Profile_IM_Nick" // 昵称
|
||||||
|
StandardAttrGender = "Tag_Profile_IM_Gender" // 性别
|
||||||
|
StandardAttrBirthday = "Tag_Profile_IM_BirthDay" // 生日
|
||||||
|
StandardAttrLocation = "Tag_Profile_IM_Location" // 所在地
|
||||||
|
StandardAttrSignature = "Tag_Profile_IM_SelfSignature" // 个性签名
|
||||||
|
StandardAttrAllowType = "Tag_Profile_IM_AllowType" // 加好友验证方式
|
||||||
|
StandardAttrLanguage = "Tag_Profile_IM_Language" // 语言
|
||||||
|
StandardAttrAvatar = "Tag_Profile_IM_Image" // 头像URL
|
||||||
|
StandardAttrMsgSettings = "Tag_Profile_IM_MsgSettings" // 消息设置
|
||||||
|
StandardAttrAdminForbidType = "Tag_Profile_IM_AdminForbidType" // 管理员禁止加好友标识
|
||||||
|
StandardAttrLevel = "Tag_Profile_IM_Level" // 等级
|
||||||
|
StandardAttrRole = "Tag_Profile_IM_Role" // 角色
|
||||||
|
|
||||||
|
// 自定义属性前缀
|
||||||
|
CustomAttrPrefix = "Tag_Profile_Custom" // 自定义属性前缀
|
||||||
|
|
||||||
|
)
|
63
internal/random/random.go
Normal file
63
internal/random/random.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Author:1711788888@qq.com
|
||||||
|
* @Date: 2021/5/12 10:35
|
||||||
|
* @Desc: 随机数类库
|
||||||
|
*/
|
||||||
|
|
||||||
|
package random
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlphaStr = iota // 字母字
|
||||||
|
AlphaLowerStr // 小写字母
|
||||||
|
AlphaUpperStr // 大写字母
|
||||||
|
NumericStr // 数字
|
||||||
|
NoZeroNumericStr // 无0数字
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenStr 生成指定长度的字符串
|
||||||
|
func GenStr(mode, length int) string {
|
||||||
|
var (
|
||||||
|
pos int
|
||||||
|
lastStr string
|
||||||
|
seedStr string
|
||||||
|
)
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
switch mode {
|
||||||
|
case AlphaStr:
|
||||||
|
seedStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
case AlphaLowerStr:
|
||||||
|
seedStr = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
case AlphaUpperStr:
|
||||||
|
seedStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
case NumericStr:
|
||||||
|
seedStr = "0123456789"
|
||||||
|
case NoZeroNumericStr:
|
||||||
|
seedStr = "123456789"
|
||||||
|
}
|
||||||
|
|
||||||
|
seedLen := len(seedStr)
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
pos = rand.Intn(seedLen)
|
||||||
|
lastStr += seedStr[pos : pos+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenNumeric 生成指定范围的数字
|
||||||
|
func GenNumeric(min int, max int) int {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
if min < max {
|
||||||
|
return rand.Intn(max-min) + min
|
||||||
|
} else {
|
||||||
|
return rand.Intn(min-max) + max
|
||||||
|
}
|
||||||
|
}
|
28
internal/sign/base64.go
Normal file
28
internal/sign/base64.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Author:1711788888@qq.com
|
||||||
|
* @Date: 2021/5/27 19:15
|
||||||
|
* @Desc: BASE64
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sign
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func base64urlEncode(data []byte) string {
|
||||||
|
str := base64.StdEncoding.EncodeToString(data)
|
||||||
|
str = strings.Replace(str, "+", "*", -1)
|
||||||
|
str = strings.Replace(str, "/", "-", -1)
|
||||||
|
str = strings.Replace(str, "=", "_", -1)
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
func base64urlDecode(str string) ([]byte, error) {
|
||||||
|
str = strings.Replace(str, "_", "=", -1)
|
||||||
|
str = strings.Replace(str, "-", "/", -1)
|
||||||
|
str = strings.Replace(str, "*", "+", -1)
|
||||||
|
return base64.StdEncoding.DecodeString(str)
|
||||||
|
}
|
421
internal/sign/sign.go
Normal file
421
internal/sign/sign.go
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Author:1711788888@qq.com
|
||||||
|
* @Date: 2021/5/27 19:11
|
||||||
|
* @Desc: Transmission signature.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sign
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/zlib"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*【功能说明】用于签发 TRTC 和 IM 服务中必须要使用的 UserSig 鉴权票据
|
||||||
|
*
|
||||||
|
*【参数说明】
|
||||||
|
* sdkappid - 应用id
|
||||||
|
* key - 计算 usersig 用的加密密钥,控制台可获取
|
||||||
|
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||||||
|
* expire - UserSig 票据的过期时间,单位是秒,比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了。
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: Used to issue UserSig that is required by the TRTC and IM services.
|
||||||
|
*
|
||||||
|
* Parameter description:
|
||||||
|
* sdkappid - Application ID
|
||||||
|
* userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
|
||||||
|
* key - The encryption key used to calculate usersig can be obtained from the console.
|
||||||
|
* expire - UserSig expiration time, in seconds. For example, 86400 indicates that the generated UserSig will expire one day after being generated.
|
||||||
|
*/
|
||||||
|
func GenUserSig(sdkappid int, key string, userid string, expire int) (string, error) {
|
||||||
|
return genSig(sdkappid, key, userid, expire, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenUserSigWithBuf(sdkappid int, key string, userid string, expire int, buf []byte) (string, error) {
|
||||||
|
return genSig(sdkappid, key, userid, expire, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*【功能说明】
|
||||||
|
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。
|
||||||
|
* PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力:
|
||||||
|
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。
|
||||||
|
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。
|
||||||
|
* 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。
|
||||||
|
*
|
||||||
|
*【参数说明】
|
||||||
|
* sdkappid - 应用id。
|
||||||
|
* key - 计算 usersig 用的加密密钥,控制台可获取。
|
||||||
|
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||||||
|
* expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。
|
||||||
|
* roomid - 房间号,用于指定该 userid 可以进入的房间号
|
||||||
|
* privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关:
|
||||||
|
* - 第 1 位:0000 0001 = 1,创建房间的权限
|
||||||
|
* - 第 2 位:0000 0010 = 2,加入房间的权限
|
||||||
|
* - 第 3 位:0000 0100 = 4,发送语音的权限
|
||||||
|
* - 第 4 位:0000 1000 = 8,接收语音的权限
|
||||||
|
* - 第 5 位:0001 0000 = 16,发送视频的权限
|
||||||
|
* - 第 6 位:0010 0000 = 32,接收视频的权限
|
||||||
|
* - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限
|
||||||
|
* - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限
|
||||||
|
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。
|
||||||
|
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function:
|
||||||
|
* Used to issue PrivateMapKey that is optional for room entry.
|
||||||
|
* PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities.
|
||||||
|
* - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room.
|
||||||
|
* - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room.
|
||||||
|
* To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info.
|
||||||
|
*
|
||||||
|
* Parameter description:
|
||||||
|
* sdkappid - Application ID
|
||||||
|
* userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
|
||||||
|
* key - The encryption key used to calculate usersig can be obtained from the console.
|
||||||
|
* roomid - ID of the room to which the specified UserID can enter.
|
||||||
|
* expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated.
|
||||||
|
* privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features:
|
||||||
|
* - Bit 1: 0000 0001 = 1, permission for room creation
|
||||||
|
* - Bit 2: 0000 0010 = 2, permission for room entry
|
||||||
|
* - Bit 3: 0000 0100 = 4, permission for audio sending
|
||||||
|
* - Bit 4: 0000 1000 = 8, permission for audio receiving
|
||||||
|
* - Bit 5: 0001 0000 = 16, permission for video sending
|
||||||
|
* - Bit 6: 0010 0000 = 32, permission for video receiving
|
||||||
|
* - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing)
|
||||||
|
* - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing)
|
||||||
|
* - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid.
|
||||||
|
* - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
func GenPrivateMapKey(sdkappid int, key string, userid string, expire int, roomid uint32, privilegeMap uint32) (string, error) {
|
||||||
|
var userbuf []byte = genUserBuf(userid, sdkappid, roomid, expire, privilegeMap, 0, "")
|
||||||
|
return genSig(sdkappid, key, userid, expire, userbuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*【功能说明】
|
||||||
|
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。
|
||||||
|
* PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力:
|
||||||
|
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。
|
||||||
|
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。
|
||||||
|
* 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。
|
||||||
|
*
|
||||||
|
*【参数说明】
|
||||||
|
* sdkappid - 应用id。
|
||||||
|
* key - 计算 usersig 用的加密密钥,控制台可获取。
|
||||||
|
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||||||
|
* expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。
|
||||||
|
* roomStr - 字符串房间号,用于指定该 userid 可以进入的房间号
|
||||||
|
* privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关:
|
||||||
|
* - 第 1 位:0000 0001 = 1,创建房间的权限
|
||||||
|
* - 第 2 位:0000 0010 = 2,加入房间的权限
|
||||||
|
* - 第 3 位:0000 0100 = 4,发送语音的权限
|
||||||
|
* - 第 4 位:0000 1000 = 8,接收语音的权限
|
||||||
|
* - 第 5 位:0001 0000 = 16,发送视频的权限
|
||||||
|
* - 第 6 位:0010 0000 = 32,接收视频的权限
|
||||||
|
* - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限
|
||||||
|
* - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限
|
||||||
|
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。
|
||||||
|
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function:
|
||||||
|
* Used to issue PrivateMapKey that is optional for room entry.
|
||||||
|
* PrivateMapKey must be used together with UserSig but with more powerful permission control capabilities.
|
||||||
|
* - UserSig can only control whether a UserID has permission to use the TRTC service. As long as the UserSig is correct, the user with the corresponding UserID can enter or leave any room.
|
||||||
|
* - PrivateMapKey specifies more stringent permissions for a UserID, including whether the UserID can be used to enter a specific room and perform audio/video upstreaming in the room.
|
||||||
|
* To enable stringent PrivateMapKey permission bit verification, you need to enable permission key in TRTC console > Application Management > Application Info.
|
||||||
|
*
|
||||||
|
* Parameter description:
|
||||||
|
* sdkappid - Application ID
|
||||||
|
* userid - User ID. The value can be up to 32 bytes in length and contain letters (a-z and A-Z), digits (0-9), underscores (_), and hyphens (-).
|
||||||
|
* key - The encryption key used to calculate usersig can be obtained from the console.
|
||||||
|
* roomstr - ID of the room to which the specified UserID can enter.
|
||||||
|
* expire - PrivateMapKey expiration time, in seconds. For example, 86400 indicates that the generated PrivateMapKey will expire one day after being generated.
|
||||||
|
* privilegeMap - Permission bits. Eight bits in the same byte are used as the permission switches of eight specific features:
|
||||||
|
* - Bit 1: 0000 0001 = 1, permission for room creation
|
||||||
|
* - Bit 2: 0000 0010 = 2, permission for room entry
|
||||||
|
* - Bit 3: 0000 0100 = 4, permission for audio sending
|
||||||
|
* - Bit 4: 0000 1000 = 8, permission for audio receiving
|
||||||
|
* - Bit 5: 0001 0000 = 16, permission for video sending
|
||||||
|
* - Bit 6: 0010 0000 = 32, permission for video receiving
|
||||||
|
* - Bit 7: 0100 0000 = 64, permission for substream video sending (screen sharing)
|
||||||
|
* - Bit 8: 1000 0000 = 200, permission for substream video receiving (screen sharing)
|
||||||
|
* - privilegeMap == 1111 1111 == 255: Indicates that the UserID has all feature permissions of the room specified by roomid.
|
||||||
|
* - privilegeMap == 0010 1010 == 42: Indicates that the UserID has only the permissions to enter the room and receive audio/video data.
|
||||||
|
*/
|
||||||
|
func GenPrivateMapKeyWithStringRoomID(sdkappid int, key string, userid string, expire int, roomStr string, privilegeMap uint32) (string, error) {
|
||||||
|
var userbuf []byte = genUserBuf(userid, sdkappid, 0, expire, privilegeMap, 0, roomStr)
|
||||||
|
return genSig(sdkappid, key, userid, expire, userbuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func genUserBuf(account string, dwSdkappid int, dwAuthID uint32,
|
||||||
|
dwExpTime int, dwPrivilegeMap uint32, dwAccountType uint32, roomStr string) []byte {
|
||||||
|
|
||||||
|
offset := 0
|
||||||
|
length := 1 + 2 + len(account) + 20 + len(roomStr)
|
||||||
|
if len(roomStr) > 0 {
|
||||||
|
length = length + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
userBuf := make([]byte, length)
|
||||||
|
|
||||||
|
//ver
|
||||||
|
if len(roomStr) > 0 {
|
||||||
|
userBuf[offset] = 1
|
||||||
|
} else {
|
||||||
|
userBuf[offset] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((len(account) & 0xFF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(len(account) & 0x00FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
for ; offset < len(account)+3; offset++ {
|
||||||
|
userBuf[offset] = account[offset-3]
|
||||||
|
}
|
||||||
|
|
||||||
|
//dwSdkAppid
|
||||||
|
userBuf[offset] = (byte)((dwSdkappid & 0xFF000000) >> 24)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwSdkappid & 0x00FF0000) >> 16)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwSdkappid & 0x0000FF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(dwSdkappid & 0x000000FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
//dwAuthId
|
||||||
|
userBuf[offset] = (byte)((dwAuthID & 0xFF000000) >> 24)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwAuthID & 0x00FF0000) >> 16)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwAuthID & 0x0000FF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(dwAuthID & 0x000000FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
//dwExpTime now+300;
|
||||||
|
currTime := time.Now().Unix()
|
||||||
|
var expire = currTime + int64(dwExpTime)
|
||||||
|
userBuf[offset] = (byte)((expire & 0xFF000000) >> 24)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((expire & 0x00FF0000) >> 16)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((expire & 0x0000FF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(expire & 0x000000FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
//dwPrivilegeMap
|
||||||
|
userBuf[offset] = (byte)((dwPrivilegeMap & 0xFF000000) >> 24)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwPrivilegeMap & 0x00FF0000) >> 16)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwPrivilegeMap & 0x0000FF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(dwPrivilegeMap & 0x000000FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
//dwAccountType
|
||||||
|
userBuf[offset] = (byte)((dwAccountType & 0xFF000000) >> 24)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwAccountType & 0x00FF0000) >> 16)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)((dwAccountType & 0x0000FF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(dwAccountType & 0x000000FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
if len(roomStr) > 0 {
|
||||||
|
userBuf[offset] = (byte)((len(roomStr) & 0xFF00) >> 8)
|
||||||
|
offset++
|
||||||
|
userBuf[offset] = (byte)(len(roomStr) & 0x00FF)
|
||||||
|
offset++
|
||||||
|
|
||||||
|
for ; offset < length; offset++ {
|
||||||
|
userBuf[offset] = roomStr[offset-(length-len(roomStr))]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userBuf
|
||||||
|
}
|
||||||
|
|
||||||
|
func hmacsha256(sdkappid int, key string, identifier string, currTime int64, expire int, base64UserBuf *string) string {
|
||||||
|
var contentToBeSigned string
|
||||||
|
contentToBeSigned = "TLS.identifier:" + identifier + "\n"
|
||||||
|
contentToBeSigned += "TLS.sdkappid:" + strconv.Itoa(sdkappid) + "\n"
|
||||||
|
contentToBeSigned += "TLS.time:" + strconv.FormatInt(currTime, 10) + "\n"
|
||||||
|
contentToBeSigned += "TLS.expire:" + strconv.Itoa(expire) + "\n"
|
||||||
|
if nil != base64UserBuf {
|
||||||
|
contentToBeSigned += "TLS.userbuf:" + *base64UserBuf + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
h := hmac.New(sha256.New, []byte(key))
|
||||||
|
h.Write([]byte(contentToBeSigned))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func genSig(sdkappid int, key string, identifier string, expire int, userbuf []byte) (string, error) {
|
||||||
|
currTime := time.Now().Unix()
|
||||||
|
sigDoc := make(map[string]interface{})
|
||||||
|
sigDoc["TLS.ver"] = "2.0"
|
||||||
|
sigDoc["TLS.identifier"] = identifier
|
||||||
|
sigDoc["TLS.sdkappid"] = sdkappid
|
||||||
|
sigDoc["TLS.expire"] = expire
|
||||||
|
sigDoc["TLS.time"] = currTime
|
||||||
|
var base64UserBuf string
|
||||||
|
if nil != userbuf {
|
||||||
|
base64UserBuf = base64.StdEncoding.EncodeToString(userbuf)
|
||||||
|
sigDoc["TLS.userbuf"] = base64UserBuf
|
||||||
|
sigDoc["TLS.sig"] = hmacsha256(sdkappid, key, identifier, currTime, expire, &base64UserBuf)
|
||||||
|
} else {
|
||||||
|
sigDoc["TLS.sig"] = hmacsha256(sdkappid, key, identifier, currTime, expire, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(sigDoc)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
w := zlib.NewWriter(&b)
|
||||||
|
if _, err = w.Write(data); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err = w.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return base64urlEncode(b.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserSig 检验UserSig在now时间点时是否有效
|
||||||
|
// VerifyUserSig Check if UserSig is valid at now time
|
||||||
|
func VerifyUserSig(sdkappid uint64, key string, userid string, usersig string, now time.Time) error {
|
||||||
|
sig, err := newUserSig(usersig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return sig.verify(sdkappid, key, userid, now, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserSigWithBuf 检验带UserBuf的UserSig在now时间点是否有效
|
||||||
|
// VerifyUserSigWithBuf Check if UserSig with UserBuf is valid at now
|
||||||
|
func VerifyUserSigWithBuf(sdkappid uint64, key string, userid string, usersig string, now time.Time, userbuf []byte) error {
|
||||||
|
sig, err := newUserSig(usersig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return sig.verify(sdkappid, key, userid, now, userbuf)
|
||||||
|
}
|
||||||
|
|
||||||
|
type userSig struct {
|
||||||
|
Version string `json:"TLS.ver,omitempty"`
|
||||||
|
Identifier string `json:"TLS.identifier,omitempty"`
|
||||||
|
SdkAppID uint64 `json:"TLS.sdkappid,omitempty"`
|
||||||
|
Expire int64 `json:"TLS.expire,omitempty"`
|
||||||
|
Time int64 `json:"TLS.time,omitempty"`
|
||||||
|
UserBuf []byte `json:"TLS.userbuf,omitempty"`
|
||||||
|
Sig string `json:"TLS.sig,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUserSig(usersig string) (userSig, error) {
|
||||||
|
b, err := base64urlDecode(usersig)
|
||||||
|
if err != nil {
|
||||||
|
return userSig{}, err
|
||||||
|
}
|
||||||
|
r, err := zlib.NewReader(bytes.NewReader(b))
|
||||||
|
if err != nil {
|
||||||
|
return userSig{}, err
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return userSig{}, err
|
||||||
|
}
|
||||||
|
if err = r.Close(); err != nil {
|
||||||
|
return userSig{}, err
|
||||||
|
}
|
||||||
|
var sig userSig
|
||||||
|
if err = json.Unmarshal(data, &sig); err != nil {
|
||||||
|
return userSig{}, nil
|
||||||
|
}
|
||||||
|
return sig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userSig) verify(sdkappid uint64, key string, userid string, now time.Time, userbuf []byte) error {
|
||||||
|
if sdkappid != u.SdkAppID {
|
||||||
|
return ErrSdkAppIDNotMatch
|
||||||
|
}
|
||||||
|
if userid != u.Identifier {
|
||||||
|
return ErrIdentifierNotMatch
|
||||||
|
}
|
||||||
|
if now.Unix() > u.Time+u.Expire {
|
||||||
|
return ErrExpired
|
||||||
|
}
|
||||||
|
if userbuf != nil {
|
||||||
|
if u.UserBuf == nil {
|
||||||
|
return ErrUserBufTypeNotMatch
|
||||||
|
}
|
||||||
|
if !bytes.Equal(userbuf, u.UserBuf) {
|
||||||
|
return ErrUserBufNotMatch
|
||||||
|
}
|
||||||
|
} else if u.UserBuf != nil {
|
||||||
|
return ErrUserBufTypeNotMatch
|
||||||
|
}
|
||||||
|
if u.sign(key) != u.Sig {
|
||||||
|
return ErrSigNotMatch
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userSig) sign(key string) string {
|
||||||
|
var sb bytes.Buffer
|
||||||
|
sb.WriteString("TLS.identifier:")
|
||||||
|
sb.WriteString(u.Identifier)
|
||||||
|
sb.WriteString("\n")
|
||||||
|
sb.WriteString("TLS.sdkappid:")
|
||||||
|
sb.WriteString(strconv.FormatUint(u.SdkAppID, 10))
|
||||||
|
sb.WriteString("\n")
|
||||||
|
sb.WriteString("TLS.time:")
|
||||||
|
sb.WriteString(strconv.FormatInt(u.Time, 10))
|
||||||
|
sb.WriteString("\n")
|
||||||
|
sb.WriteString("TLS.expire:")
|
||||||
|
sb.WriteString(strconv.FormatInt(u.Expire, 10))
|
||||||
|
sb.WriteString("\n")
|
||||||
|
if u.UserBuf != nil {
|
||||||
|
sb.WriteString("TLS.userbuf:")
|
||||||
|
sb.WriteString(base64.StdEncoding.EncodeToString(u.UserBuf))
|
||||||
|
sb.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
h := hmac.New(sha256.New, []byte(key))
|
||||||
|
h.Write(sb.Bytes())
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误类型
|
||||||
|
var (
|
||||||
|
ErrSdkAppIDNotMatch = errors.New("sdk appid not match")
|
||||||
|
ErrIdentifierNotMatch = errors.New("identifier not match")
|
||||||
|
ErrExpired = errors.New("expired")
|
||||||
|
ErrUserBufTypeNotMatch = errors.New("userbuf type not match")
|
||||||
|
ErrUserBufNotMatch = errors.New("userbuf not match")
|
||||||
|
ErrSigNotMatch = errors.New("sig not match")
|
||||||
|
)
|
30
internal/types/interface.go
Normal file
30
internal/types/interface.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Email:1711788888@qq.com
|
||||||
|
* @Date: 2021/8/27 12:54 下午
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
type BaseRespInterface interface {
|
||||||
|
GetErrorCode() int
|
||||||
|
GetErrorInfo() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *BaseResp) GetErrorCode() int {
|
||||||
|
return r.ErrorCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *BaseResp) GetErrorInfo() string {
|
||||||
|
return r.ErrorInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActionBaseRespInterface interface {
|
||||||
|
BaseRespInterface
|
||||||
|
GetActionStatus() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ActionBaseResp) GetActionStatus() string {
|
||||||
|
return r.ActionStatus
|
||||||
|
}
|
171
internal/types/types.go
Normal file
171
internal/types/types.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* @Author: Echo
|
||||||
|
* @Author:1711788888@qq.com
|
||||||
|
* @Date: 2021/5/28 19:24
|
||||||
|
* @Desc: TODO
|
||||||
|
*/
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
type (
|
||||||
|
BaseResp struct {
|
||||||
|
ErrorCode int `json:"ErrorCode"`
|
||||||
|
ErrorInfo string `json:"ErrorInfo"`
|
||||||
|
ErrorDisplay string `json:"ErrorDisplay,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionBaseResp struct {
|
||||||
|
BaseResp
|
||||||
|
ActionStatus string `json:"ActionStatus"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AndroidInfo Android离线推送消息
|
||||||
|
AndroidInfo struct {
|
||||||
|
Sound string `json:"Sound,omitempty"` // (选填)Android 离线推送声音文件路径。
|
||||||
|
HuaWeiChannelID string `json:"HuaWeiChannelID,omitempty"` // (选填)华为手机 EMUI 10.0 及以上的通知渠道字段。该字段不为空时,会覆盖控制台配置的 ChannelID 值;该字段为空时,不会覆盖控制台配置的 ChannelID 值。
|
||||||
|
XiaoMiChannelID string `json:"XiaoMiChannelID,omitempty"` // (选填)小米手机 MIUI 10 及以上的通知类别(Channel)适配字段。该字段不为空时,会覆盖控制台配置的 ChannelID 值;该字段为空时,不会覆盖控制台配置的 ChannelID 值。
|
||||||
|
OPPOChannelID string `json:"OPPOChannelID,omitempty"` // (选填)OPPO 手机 Android 8.0 及以上的 NotificationChannel 通知适配字段。该字段不为空时,会覆盖控制台配置的 ChannelID 值;该字段为空时,不会覆盖控制台配置的 ChannelID 值。
|
||||||
|
GoogleChannelID string `json:"GoogleChannelID,omitempty"` // (选填)Google 手机 Android 8.0 及以上的通知渠道字段。Google 推送新接口(上传证书文件)支持 channel id,旧接口(填写服务器密钥)不支持。
|
||||||
|
VIVOClassification int `json:"VIVOClassification,omitempty"` // (选填)VIVO 手机推送消息分类,“0”代表运营消息,“1”代表系统消息,不填默认为1。
|
||||||
|
HuaWeiImportance string `json:"HuaWeiImportance,omitempty"` // (选填)华为推送通知消息分类,取值为 LOW、NORMAL,不填默认为 NORMAL。
|
||||||
|
ExtAsHuaweiIntentParam int `json:"ExtAsHuaweiIntentParam,omitempty"` // (选填)在控制台配置华为推送为“打开应用内指定页面”的前提下,传“1”表示将透传内容 Ext 作为 Intent 的参数,“0”表示将透传内容 Ext 作为 Action 参数。不填默认为0。两种传参区别可参见 华为推送文档。
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApnsInfo IOS离线推送消息
|
||||||
|
ApnsInfo struct {
|
||||||
|
BadgeMode int `json:"BadgeMode,omitempty"` // (选填)这个字段缺省或者为0表示需要计数,为1表示本条消息不需要计数,即右上角图标数字不增加。
|
||||||
|
Title string `json:"Title,omitempty"` // (选填)该字段用于标识 APNs 推送的标题,若填写则会覆盖最上层 Title。
|
||||||
|
SubTitle string `json:"SubTitle,omitempty"` // (选填)该字段用于标识 APNs 推送的子标题。
|
||||||
|
Image string `json:"Image,omitempty"` // (选填)该字段用于标识 APNs 携带的图片地址,当客户端拿到该字段时,可以通过下载图片资源的方式将图片展示在弹窗上。
|
||||||
|
MutableContent int `json:"MutableContent,omitempty"` // (选填)为1表示开启 iOS 10 的推送扩展,默认为0。
|
||||||
|
}
|
||||||
|
|
||||||
|
// OfflinePushInfo 离线推送消息
|
||||||
|
OfflinePushInfo struct {
|
||||||
|
PushFlag int `json:"PushFlag,omitempty"` // (选填)推送标识。0表示推送,1表示不离线推送。
|
||||||
|
Title string `json:"Title,omitempty"` // (选填)离线推送标题。该字段为 iOS 和 Android 共用。
|
||||||
|
Desc string `json:"Desc,omitempty"` // (选填)离线推送内容。该字段会覆盖上面各种消息元素 TIMMsgElement 的离线推送展示文本。若发送的消息只有一个 TIMCustomElem 自定义消息元素,该 Desc 字段会覆盖 TIMCustomElem 中的 Desc 字段。如果两个 Desc 字段都不填,将收不到该自定义消息的离线推送。
|
||||||
|
Ext string `json:"Ext,omitempty"` // (选填)离线推送透传内容。由于国内各 Android 手机厂商的推送平台要求各不一样,请保证此字段为 JSON 格式,否则可能会导致收不到某些厂商的离线推送。
|
||||||
|
AndroidInfo *AndroidInfo `json:"AndroidInfo,omitempty"` // (选填)Android 离线推送消息
|
||||||
|
ApnsInfo *ApnsInfo `json:"ApnsInfo,omitempty"` // (选填)IOS离线推送消息
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgBody 消息内容
|
||||||
|
MsgBody struct {
|
||||||
|
MsgType string `json:"MsgType"`
|
||||||
|
MsgContent interface{} `json:"MsgContent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagPair 标签对
|
||||||
|
TagPair struct {
|
||||||
|
Tag string `json:"Tag"` // 标签
|
||||||
|
Value interface{} `json:"Value"` // 标签值
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgTextContent 文本消息内容
|
||||||
|
MsgTextContent struct {
|
||||||
|
Text string `json:"Text"` // (必填)消息内容。当接收方为 iOS 或 Android 后台在线时,作为离线推送的文本展示。
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgLocationContent 地理位置消息元素
|
||||||
|
MsgLocationContent struct {
|
||||||
|
Desc string `json:"Desc"` // (必填)地理位置描述信息
|
||||||
|
Latitude float64 `json:"Latitude"` // (必填)纬度
|
||||||
|
Longitude float64 `json:"Longitude"` // (必填)经度
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgFaceContent 表情消息元素
|
||||||
|
MsgFaceContent struct {
|
||||||
|
Index int `json:"Index"` // (必填)表情索引,用户自定义
|
||||||
|
Data string `json:"Data"` // (选填)额外数据
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgCustomContent 自定义消息元素
|
||||||
|
MsgCustomContent struct {
|
||||||
|
Desc string `json:"Desc"` // (选填)自定义消息描述信息。当接收方为 iOS 或 Android 后台在线时,做离线推送文本展示。 若发送自定义消息的同时设置了 OfflinePushInfo.Desc 字段,此字段会被覆盖,请优先填 OfflinePushInfo.Desc 字段。
|
||||||
|
Data string `json:"Data"` // (必填)自定义消息数据。 不作为 APNs 的 payload 字段下发,故从 payload 中无法获取 Data 字段
|
||||||
|
Ext string `json:"Ext"` // (选填)扩展字段。当接收方为 iOS 系统且应用处在后台时,此字段作为 APNs 请求包 Payloads 中的 Ext 键值下发,Ext 的协议格式由业务方确定,APNs 只做透传。
|
||||||
|
Sound string `json:"Sound"` // (选填)自定义 APNs 推送铃音。
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"` // (必填)语音时长,单位:秒。
|
||||||
|
DownloadFlag int `json:"Download_Flag"` // (必填)语音下载方式标记。目前 Download_Flag 取值只能为2,表示可通过Url字段值的 URL 地址直接下载语音。
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgImageContent 图像消息元素
|
||||||
|
MsgImageContent struct {
|
||||||
|
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 地址直接下载相应文件
|
||||||
|
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"` // (必填)缩略图高度
|
||||||
|
ThumbFormat string `json:"ThumbFormat"` // (必填)缩略图格式,例如 JPG、BMP 等
|
||||||
|
ThumbDownloadFlag int `json:"ThumbDownloadFlag"` // (必填)视频缩略图下载方式标记。目前 ThumbDownloadFlag 取值只能为2,表示可通过ThumbUrl字段值的 URL 地址直接下载视频缩略图。
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageInfo 图片下载信息
|
||||||
|
ImageInfo struct {
|
||||||
|
Type int `json:"Type"` // (必填)图片类型: 1-原图,2-大图,3-缩略图。
|
||||||
|
Size int `json:"Size"` // (必填)图片数据大小,单位:字节。
|
||||||
|
Width int `json:"Width"` // (必填)图片宽度。
|
||||||
|
Height int `json:"Height"` // (必填)图片高度。
|
||||||
|
Url string `json:"URL"` // (必填)图片下载地址。
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenderType 性别类型
|
||||||
|
GenderType string
|
||||||
|
|
||||||
|
// AllowType 加好友验证方式
|
||||||
|
AllowType string
|
||||||
|
|
||||||
|
// AdminForbidType 管理员禁止加好友标识类型
|
||||||
|
AdminForbidType string
|
||||||
|
|
||||||
|
// SyncOtherMachine 同步至其他设备
|
||||||
|
SyncOtherMachine int
|
||||||
|
|
||||||
|
// PushFlag 推送标识
|
||||||
|
PushFlag int
|
||||||
|
|
||||||
|
// HuaWeiImportance 华为推送通知消息分类
|
||||||
|
HuaWeiImportance string
|
||||||
|
|
||||||
|
// HuaweiIntentParam 华为推送为“打开应用内指定页面”的前提下透传参数行为
|
||||||
|
HuaweiIntentParam int
|
||||||
|
|
||||||
|
// VivoClassification VIVO手机推送消息分类
|
||||||
|
VivoClassification int
|
||||||
|
|
||||||
|
// BadgeMode IOS徽章计数模式
|
||||||
|
BadgeMode int
|
||||||
|
|
||||||
|
// MutableContent IOS10的推送扩展开关
|
||||||
|
MutableContent int
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user