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,118 @@
package main
import (
"flag"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/services/slb"
)
// LTAI5tCB8SmJcwfO
// dX4kgF4VcblsbCVdKvtCGCmvNbLkZK
// ./AliyunCloudClient -t b -o update -key LTAI5tCB8SmJcwfO -sec dX4kgF4VcblsbCVdKvtCGCmvNbLkZK -reg cn-hangzhou -lb "[{"ServerId":"ServerId","Weight":"0"}]
func main() {
var target string
flag.StringVar(&target, "t", "b", "target: b=backendServer")
var operation string
flag.StringVar(&operation, "o", "update", "operation: add、update、remove")
var accessKeyId string
flag.StringVar(&accessKeyId, "key", "accessKeyId", "accessKeyId")
var accessSecret string
flag.StringVar(&accessSecret, "sec", "accessSecret", "accessSecret")
var regionId string
flag.StringVar(&regionId, "reg", "regionId", "regionId: cn-hangzhou")
var loadBalancerId string
flag.StringVar(&loadBalancerId, "lb", "loadBalancerId", "loadBalancerId")
var params string
flag.StringVar(&params, "params", "", `SetBackendServers: [{"ServerId":"ServerId","Weight":"0"}]
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
`)
flag.Parse()
flag.Usage()
fmt.Printf("target=%s,operation=%s,accessKeyId=%s,accessSecret=%s,regionId=%s,loadBalancerId=%s,params=%s", target, operation, accessKeyId, accessSecret, regionId, loadBalancerId, params)
if target == "b" {
switch operation {
case "update":
SetBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params)
break
case "add":
AddBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params)
break
case "remove":
RemoveBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params)
break
default:
fmt.Println("operation: " + operation + " not support")
}
} else {
fmt.Println("target: " + target + " not support")
}
}
func SetBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params string) {
// client, err := slb.NewClientWithAccessKey(regionId, accessKeyId, accessSecret)
// if nil != err {
// fmt.Println("get client error:")
// fmt.Println(err.Error())
// }
// request := slb.CreateSetBackendServersRequest()
// request.Scheme = "https"
// request.LoadBalancerId = loadBalancerId
// request.BackendServers = params
// if nil == client {
// fmt.Println("error: client is nil")
// return
// }
// response, err := client.SetBackendServers(request)
// if err != nil {
// fmt.Print(err.Error())
// }
// fmt.Printf("response is %#v\n", response)
}
func AddBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params string) {
client, err := slb.NewClientWithAccessKey(regionId, accessKeyId, accessSecret)
request := slb.CreateAddBackendServersRequest()
request.Scheme = "https"
request.LoadBalancerId = loadBalancerId
request.BackendServers = params
if nil == client {
fmt.Println("error: client is nil")
return
}
response, err := client.AddBackendServers(request)
if err != nil {
fmt.Print(err.Error())
}
fmt.Printf("response is %#v\n", response)
}
func RemoveBackendServers(regionId, accessKeyId, accessSecret, loadBalancerId, params string) {
client, err := slb.NewClientWithAccessKey(regionId, accessKeyId, accessSecret)
request := slb.CreateRemoveBackendServersRequest()
request.Scheme = "https"
request.LoadBalancerId = loadBalancerId
request.BackendServers = params
if nil == client {
fmt.Println("error: client is nil")
return
}
response, err := client.RemoveBackendServers(request)
if err != nil {
fmt.Print(err.Error())
}
fmt.Printf("response is %#v\n", response)
}

View File

@ -0,0 +1,70 @@
package main
import (
"encoding/json"
"fmt"
"strconv"
"github.com/tealeg/xlsx"
)
func main02() {
data := ReadSheet("./CmdTools/星钻VIP体系.xlsx", 0)
fmt.Println(json.Marshal(data))
for index, item := range data {
if index > 0 {
level, _ := strconv.Atoi(item[0])
exp, _ := strconv.Atoi(item[1])
fmt.Printf("insert into t_vip_config (id,vip_level,min_exp,vip_name,vip_icon,create_time) values (%d,%d,%d,'v%d','https://xz-static.10909.com/XingZuanCommon/Img/Vip/%d@2x.png',now());\n", level, level, exp, level, level)
}
}
}
func ReadSheet(file string, sheet int) [][]string {
var result [][]string
xlFile, err := xlsx.OpenFile(file)
if err != nil {
fmt.Println(err.Error())
return result
}
for index, row := range xlFile.Sheets[sheet].Rows {
if index > 60 {
break
}
var data []string
for index, cell := range row.Cells {
if index > 1 {
break
}
text := cell.String()
println(text)
data = append(data, text)
}
result = append(result, data)
}
return result
}
func ReadAll(file string) {
// 打开文件
xlFile, err := xlsx.OpenFile(file)
if err != nil {
fmt.Println(err.Error())
return
}
// 遍历sheet页读取
for _, sheet := range xlFile.Sheets {
fmt.Println("sheet name: ", sheet.Name)
//遍历行读取
for _, row := range sheet.Rows {
// 遍历每行的列读取
for _, cell := range row.Cells {
text := cell.String()
fmt.Printf("%20s", text)
}
fmt.Print("\n")
}
}
fmt.Println("\n\nimport success")
}

View File

@ -0,0 +1,94 @@
package main
import (
"flag"
"fmt"
clb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
)
// ./TencentCloudClient -t b -o add -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"Targets\":[{\"InstanceId\":\"ins-n2i7x483\",\"Weight\":20}]}"
// ./TencentCloudClient -t b -o remove -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"InstanceIds\":[\"ins-n2i7x483\"]}"
func main03() {
var target string
flag.StringVar(&target, "t", "b", "target: b=backendServer")
var operation string
flag.StringVar(&operation, "o", "add", "operation: add、remove")
var accessKeyId string
flag.StringVar(&accessKeyId, "key", "secretId", "accessKeyId")
var accessSecret string
flag.StringVar(&accessSecret, "sec", "secretKey", "accessSecret")
var regionId string
flag.StringVar(&regionId, "reg", "regionId", "regionId: cn-hangzhou")
var params string
flag.StringVar(&params, "params", "params", `
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
`)
flag.Parse()
flag.Usage()
fmt.Printf("target=%s,operation=%s,accessKeyId=%s,accessSecret=%s,regionId=%s,params=%s\n", target, operation, accessKeyId, accessSecret, regionId, params)
if target == "b" {
switch operation {
case "add":
ClassicBind(regionId, accessKeyId, accessSecret, params)
break
case "remove":
ClassicRemove(regionId, accessKeyId, accessSecret, params)
break
default:
fmt.Println("operation: " + operation + " not support")
}
} else {
fmt.Println("target: " + target + " not support")
}
}
func ClassicBind(regionId, accessKeyId, accessSecret, params string) {
credential := common.NewCredential(accessKeyId, accessSecret)
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "clb.tencentcloudapi.com"
client, _ := clb.NewClient(credential, regionId, cpf)
request := clb.NewRegisterTargetsWithClassicalLBRequest()
err := request.FromJsonString(params)
if err != nil {
panic(err)
}
response, err := client.RegisterTargetsWithClassicalLB(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Printf("An API error has returned: %s", err)
return
}
if err != nil {
panic(err)
}
fmt.Printf("%s", response.ToJsonString())
}
func ClassicRemove(regionId, accessKeyId, accessSecret, params string) {
credential := common.NewCredential(accessKeyId, accessSecret)
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "clb.tencentcloudapi.com"
client, _ := clb.NewClient(credential, regionId, cpf)
request := clb.NewDeregisterTargetsFromClassicalLBRequest()
err := request.FromJsonString(params)
if err != nil {
panic(err)
}
response, err := client.DeregisterTargetsFromClassicalLB(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
fmt.Printf("An API error has returned: %s", err)
return
}
if err != nil {
panic(err)
}
fmt.Printf("%s", response.ToJsonString())
}

View File

@ -0,0 +1,57 @@
# CMD 工具
## 阿里云SLB后端服务器client工具
### Usage
Example: SlbClient.exe -t lb -o update -reg cn-hangzhou -key LTAI5tCB8SmJcwfO -sec dX4kgF4VcblsbCVdKvtCGCmvNbLkZK -lb lb-bp1nz8xl5q8kiqfv0iumf -params "[{\"ServerId\":\"i-bp1hcv8qx0677hv9pr0s\",\"Weight\":\"100\"}]"
```
Usage of SlbClient.exe:
-key string
accessKeyId (default "accessKeyId")
-lb string
loadBalancerId (default "loadBalancerId")
-o string
operation: add、update、remove (default "update")
-params string
SetBackendServers: [{"ServerId":"ServerId","Weight":"0"}]
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
(default "params")
-reg string
regionId: cn-hangzhou (default "regionId")
-sec string
accessSecret (default "accessSecret")
-t string
target: lb (default "lb")
```
## 腾讯云CLB后端服务器client工具
### Usage
Example1 ./TencentCloudClient -t b -o add -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"Targets\":[{\"InstanceId\":\"ins-n2i7x483\",\"Weight\":20}]}"
Example2 ./TencentCloudClient -t b -o remove -key AKIDSoxxjI5tukPr9ECsQmwthKhroaCZlldI -sec b1FG2b3JMrESVLxjJdhYDgx12qPiplXB -reg ap-shanghai -params "{\"LoadBalancerId\":\"lb-jip7505r\",\"InstanceIds\":[\"ins-n2i7x483\"]}"
```
Usage of ./TencentCloudClient:
-key string
accessKeyId (default "secretId")
-o string
operation: add、remove (default "add")
-params string
AddBackendServers: [{"ServerId":"ServerId","Weight":"100","Type":"eni","ServerIp":"192.168.11.1"}]
RemoveBackendServers: [{"ServerId":"ServerId","Weight":"100"}]
(default "params")
-reg string
regionId: cn-hangzhou (default "regionId")
-sec string
accessSecret (default "secretKey")
-t string
target: b=backendServer (default "b")
```

146
pkg/common/ConstVar.go Normal file
View File

@ -0,0 +1,146 @@
package common
import (
"encoding/json"
"github.com/anxpp/beego/logs"
)
const (
//公用
//API版本号
// API_V_NUM = "1"
//API密钥
// API_SECRECT = "x63363eacf804b4394a120aea240fd9a"
//图片域名
PHOTO_URL_PREV = "https://photo-app.ddegame.cn/"
MEDIA_URL_PREV = "https://media-qiniu-app.ddegame.cn/"
//====== 三方key =======
//NETEASE_IM_APPKEY = "a0671ecde01ef03928ccfd460c62d203"
//NETEASE_IM_SECRET = "eb88916031ca"
//用户认证申请状态
USER_CERTIFY_STATUS_INIT = "1" //已提交
USER_CERTIFY_STATUS_SUCCESS = "2" //成功
USER_CERTIFY_STATUS_INIT_FAIL = "3" //初始化失败
USER_CERTIFY_STATUS_AUTH_FAIL = "4" //认证失败
USER_CERTIFY_STATUS_REFUSE = "5" //拒绝
// 模块和页面ID
//用户管理
MODULE_ID_USER_MANAGE = "1"
//基础数据
MODULE_ID_BASE_DATA = "4"
//财务管理
MODULE_ID_FIN_MANAGE = "7"
//数据报表
MODULE_ID_DATA_REPORT = "14"
//聊天室管理
MODULE_ID_ROOM_MANAGE = "20"
//付款管理
MODULE_ID_PAY_MANAGE = "100"
//抽奖管理
MODULE_ID_LUCK_MANAGE = "200"
//技能管理
MODULE_ID_SKILL_MANAGE = "300"
//技能订单管理
MODULE_ID_SKILL_ORDER_MANAGE = "400"
//技能订单列表
PAGE_ID_FIN_SKILL_ORDER_LIST = "401"
//用户列表
PAGE_ID_USER_LIST = "2"
//用户认证列表
PAGE_ID_USER_AUTH_LIST = "3"
//礼物列表
PAGE_ID_GIFT_LIST = "5"
//首页分类列表
PAGE_ID_HOME_TAB_LIST = "6"
//充值列表
PAGE_ID_FIN_RECHARGE_LIST = "8"
//提现列表
PAGE_ID_FIN_WITHDRAW_LIST = "9"
//兑换列表
PAGE_ID_FIN_EXCHANGE_LIST = "10"
//表情列表
PAGE_ID_FIN_EMOJI_ORDER_LIST = "11"
//守护订单列表
PAGE_ID_FIN_GUARD_ORDER_LIST = "12"
//打赏列表
PAGE_ID_FIN_PRESENT_GIFT_LIST = "13"
//日报表
PAGE_ID_DAY_REPORT = "15"
//厅日流水报表
PAGE_ID_DAY_ROOM_SALE_REPORT = "142"
//实时厅流水报表
PAGE_ID_TODAY_ROOM_SALE_RANK = "143"
//厅费用排行
PAGE_ID_TODAY_ROOM_MARKET_FEE_RANK = "144"
//聊天室列表
PAGE_ID_CHATROOM_LIST = "21"
//房主列表
PAGE_ID_CHATROOM_OWNER_LIST = "22"
//打赏列表
PAGE_ID_FIN_OPERATION_DIAMOND_LIST = "24"
//
PAGE_ID_FILTER_USER_NO = "25"
//付款单列表
PAGE_ID_PAY_ORDER_LIST = "101"
//客户列表
PAGE_ID_PAY_CUSTOMER_LIST = "102"
//砸蛋列表
PAGE_ID_HIT_EGG_LIST = "201"
//方案列表
PAGE_ID_SOLUTION_LIST_LIST = "202"
//权益列表
PAGE_ID_QUANYI_LIST_LIST = "203"
//用户砸蛋汇总
PAGE_ID_USER_HITEGG_SUMMARY = "204"
//技能申请列表
PAGE_ID_SKILL_APPLY_LIST_LIST = "301"
//技能列表
PAGE_ID_SKILL_LIST = "302"
//卖家列表
PAGE_ID_SELLER_LIST = "303"
//SKU列表
PAGE_ID_SKILL_SKU_LIST = "304"
//技能修改申请列表
PAGE_ID_SKILL_EDIT_LIST = "305"
//技能价格列表
PAGE_ID_SKILL_PRICE_LIST = "306"
//技能订单列表
PAGE_ID_SKILL_ORDER_LIST = "401"
// 代理订单类型 后台充值
AGENT_DIAMOND_ORDER_TYPE_ADMIN_RECHARGE = "1"
// 代理订单类型 上级转账
AGENT_DIAMOND_ORDER_TYPE_UPER_TRANSFER = "2"
// 文本反垃圾类型 - 昵称检测
RISK_TYPE_TEXT_NICKNAME = "nickname_detection"
RISK_TYPE_TEXT_COMMENT = "comment_detection" //评论检测
)
func LogJson(v interface{}) {
b, _ := json.Marshal(v)
logs.Info(string(b))
}
const photoDomainUrl = "https://ddphoto.youkeya.cn"

View File

@ -0,0 +1,96 @@
package HyTools
import (
"io/ioutil"
"net/http"
"strings"
)
// 调用POST请求
func HttpPost(url string, body string) (remoteResponse string, err error) {
bodyReader := strings.NewReader(body)
//application/x-www-form-urlencoded
//application/json
response, err1 := http.Post(url, "application/x-www-form-urlencoded", bodyReader)
if err1 != nil {
err = err1
return
}
defer response.Body.Close()
resBody, err2 := ioutil.ReadAll(response.Body)
if err2 != nil {
err = err2
return
}
remoteResponse = string(resBody)
return
}
// 复杂http请求
func HttpDo(httpMethod string, url string, headerMap map[string]string, rawBody string) (remoteResponse string, err error) {
client := &http.Client{}
req, err0 := http.NewRequest(httpMethod, url, strings.NewReader(rawBody))
if err0 != nil {
err = err0
return
}
if len(headerMap) > 0 {
for k, v := range headerMap {
req.Header.Set(k, v)
}
}
resp, err1 := client.Do(req)
if err1 != nil {
err = err1
return
}
defer resp.Body.Close()
body, err2 := ioutil.ReadAll(resp.Body)
if err2 != nil {
err = err2
return
}
remoteResponse = string(body)
return
}
func HttpPostJson(url string, body string) (remoteResponse string, err error) {
bodyReader := strings.NewReader(body)
//application/x-www-form-urlencoded
//application/json
response, err1 := http.Post(url, "application/json", bodyReader)
if err1 != nil {
err = err1
return
}
defer response.Body.Close()
resBody, err2 := ioutil.ReadAll(response.Body)
if err2 != nil {
err = err2
return
}
remoteResponse = string(resBody)
return
}

View File

@ -0,0 +1,40 @@
package HyTools
import (
"math/rand"
"time"
)
func RandInt64(min, max int64) int64 {
if min >= max || min == 0 || max == 0 {
return max
}
return rand.Int63n(max-min) + min
}
// 获取随机数字字符串
func GetRandNumber(l int) string {
str := "0123456789"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}
// 生成随机字符串
func GetRandomString(l int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyz"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}

View File

@ -0,0 +1,146 @@
package HyTools
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
)
// RSA加密
func RsaEncrypt(origData string, publicKey string) (string, error) {
block, _ := pem.Decode([]byte(publicKey)) //将密钥解析成公钥实例
if block == nil {
return "", errors.New("public key error")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) //解析pem.Decode返回的Block指针实例
if err != nil {
return "", err
}
pub := pubInterface.(*rsa.PublicKey)
partLen := pub.N.BitLen()/8 - 11
chunks := ByteSplit([]byte(origData), partLen)
buffer := bytes.NewBufferString("")
for _, chunk := range chunks {
bytes, err := rsa.EncryptPKCS1v15(rand.Reader, pub, chunk)
if err != nil {
return "", err
}
buffer.Write(bytes)
}
return base64.StdEncoding.EncodeToString(buffer.Bytes()), nil
}
// RSA解密
func RsaDecrypt(ciphertext string, privateKey string) (string, error) {
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return "", errors.New("private key error!")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
partLen := priv.N.BitLen() / 8
raw, err := base64.StdEncoding.DecodeString(ciphertext)
chunks := ByteSplit([]byte(raw), partLen)
buffer := bytes.NewBufferString("")
for _, chunk := range chunks {
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, priv, chunk)
if err != nil {
return "", err
}
buffer.Write(decrypted)
}
return buffer.String(), err
}
// RSA SHA1加签
func RsaSHA1Sign(data string, privateKey string) (string, error) {
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return "", errors.New("Sign private key decode error")
}
prk8, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", err
}
h := sha1.New()
h.Write([]byte(data))
hashed := h.Sum(nil)
sign, err := rsa.SignPKCS1v15(rand.Reader, prk8, crypto.SHA1, hashed)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(sign), err
}
// RSA SHA1验签
func RsaSHA1Verify(data string, sign string, publicKey string) error {
h := sha1.New()
h.Write([]byte(data))
hashed := h.Sum(nil)
decodedSign, err := base64.StdEncoding.DecodeString(sign)
if err != nil {
return err
}
block, _ := pem.Decode([]byte(publicKey))
if block == nil {
return errors.New("Sign public key decode error")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) //解析pem.Decode返回的Block指针实例
if err != nil {
return err
}
pub := pubInterface.(*rsa.PublicKey)
return rsa.VerifyPKCS1v15(pub, crypto.SHA1, hashed, decodedSign)
}

View File

@ -0,0 +1,30 @@
package HyTools
import (
"bytes"
"encoding/json"
"fmt"
)
type StringBuilder struct {
buf bytes.Buffer
}
func NewStringBuilder() *StringBuilder {
return &StringBuilder{buf: bytes.Buffer{}}
}
func (this *StringBuilder) Append(obj interface{}) *StringBuilder {
this.buf.WriteString(fmt.Sprintf("%v", obj))
return this
}
func (this *StringBuilder) ToString() string {
return this.buf.String()
}
// 字符串转int32
func JsonStr(v interface{}) string {
bys, _ := json.Marshal(v)
return string(bys)
}

View File

@ -0,0 +1,243 @@
package HyTools
import (
"bytes"
"crypto/md5"
"crypto/sha1"
"encoding/hex"
"fmt"
"math"
"strconv"
"strings"
"time"
)
// MD5加密
func StringToMD5(waitMD5string string) string {
h := md5.New()
h.Write([]byte(waitMD5string))
cipherStr := h.Sum(nil)
result := hex.EncodeToString(cipherStr)
return result
}
// SHA1加密
func StringToSHA1(waitMD5string string) string {
h := sha1.New()
h.Write([]byte(waitMD5string))
cipherStr := h.Sum(nil)
result := hex.EncodeToString(cipherStr)
return result
}
// 字符串转int64
func StringToInt64(waitString string) int64 {
stringInt64, err := strconv.ParseInt(waitString, 10, 64)
if err != nil {
return 0
}
return stringInt64
}
// 字符串转int32
func StringToInt(waitString string) int {
stringInt, err := strconv.Atoi(waitString)
if err != nil {
return 0
}
return stringInt
}
// 字符串转float64
func StringToFloat64(waitString string) float64 {
stringInt64, err := strconv.ParseFloat(waitString, 64)
if err != nil {
return 0
}
return stringInt64
}
// strconv.FormatFloat(float64, 'E', -1, 64)
// float64转字符串
func Float64ToString(waitFloat64 float64) string {
stringInt64 := strconv.FormatFloat(waitFloat64, 'f', -1, 64)
return stringInt64
}
// 截取字符串
func Substr(str string, start int, length int) string {
rs := []rune(str)
rl := len(rs)
end := 0
if start < 0 {
start = rl - 1 + start
}
end = start + length
if start > end {
start, end = end, start
}
if start < 0 {
start = 0
}
if start > rl {
start = rl
}
if end < 0 {
end = 0
}
if end > rl {
end = rl
}
return string(rs[start:end])
}
// map转html
func MapToXML(mapData map[string]string) string {
if len(mapData) == 0 {
return ""
}
sb := NewStringBuilder()
sb.Append("<xml>")
for key, val := range mapData {
sb.Append("<" + key + ">")
sb.Append(val)
sb.Append("</" + key + ">")
}
sb.Append("</xml>")
return sb.ToString()
}
// 获取当前年周
func GetCurrentYearWeek() string {
year, week := time.Now().ISOWeek()
return strconv.Itoa(year) + strconv.Itoa(week)
}
// 字符串转time类型
func StringToTime(dateString string) time.Time {
//获取本地location
toBeCharge := dateString //待转化为时间戳的字符串 注意 这里的小时和分钟还要秒必须写 因为是跟着模板走的 修改模板的话也可以不写
timeLayout := "2006-01-02 15:04:05" //转化所需模板
loc, _ := time.LoadLocation("Local") //重要:获取时区
theTime, _ := time.ParseInLocation(timeLayout, toBeCharge, loc) //使用模板在对应时区转化为time.time类型
//sr := theTime.Unix() //转化为时间戳 类型是int64
//时间戳转日期
//dataTimeStr := time.Unix(sr, 0).Format(timeLayout) //设置时间戳 使用模板格式化为日期字符串
return theTime
}
// 判断数组是否包含某个元素
func CheckStringIsInArray(arrayList []string, element string) bool {
if len(arrayList) == 0 {
return false
}
isInArray := false
for _, data := range arrayList {
if data == element {
isInArray = true
break
}
}
return isInArray
}
// slice to 字符串
func StringListToString(stringList []string, split string) string {
if len(split) == 0 {
split = ","
}
return strings.Replace(strings.Trim(fmt.Sprint(stringList), "[]"), " ", split, -1)
}
// map 转 url参数
func MapToUrlParams(mapData map[string]string) string {
mapLen := len(mapData)
if mapLen == 0 {
return ""
}
sb := NewStringBuilder()
i := 0
for k, v := range mapData {
sb.Append(k + "=" + v)
if i < mapLen-1 {
sb.Append("&")
}
i++
}
return sb.ToString()
}
// []byte 合并
func BytesCombine(pBytes ...[]byte) []byte {
return bytes.Join(pBytes, []byte(""))
}
// 获取当前UTC时间 秒数
func GetCurrentUtcTimeSecond() int64 {
return time.Now().UTC().Unix()
}
// byte数组分组
func ByteSplit(buf []byte, lim int) [][]byte {
var chunk []byte
chunks := make([][]byte, 0, len(buf)/lim+1)
for len(buf) >= lim {
chunk, buf = buf[:lim], buf[lim:]
chunks = append(chunks, chunk)
}
bufLen := len(buf)
if bufLen > 0 {
chunks = append(chunks, buf[:bufLen])
}
return chunks
}
func Float64ToIntRound(f float64) int {
return int(math.Round(f))
}

111
pkg/common/HyTools/Uuid.go Normal file
View File

@ -0,0 +1,111 @@
package HyTools
import (
crand "crypto/rand"
"encoding/hex"
"errors"
"fmt"
mrand "math/rand"
"regexp"
"strings"
"time"
"github.com/google/uuid"
)
// seeded indicates if math/rand has been seeded
var seeded bool = false
// uuidRegex matches the UUID string
var uuidRegex *regexp.Regexp = regexp.MustCompile(`^\{?([a-fA-F0-9]{8})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{4})-?([a-fA-F0-9]{12})\}?$`)
// UUID type.
type UUID [16]byte
// Hex returns a hex string representation of the UUID in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
func (this UUID) Hex() string {
x := [16]byte(this)
return fmt.Sprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
x[0], x[1], x[2], x[3], x[4],
x[5], x[6],
x[7], x[8],
x[9], x[10], x[11], x[12], x[13], x[14], x[15])
}
// Rand generates a new version 4 UUID.
func Rand() UUID {
var x [16]byte
randBytes(x[:])
x[6] = (x[6] & 0x0F) | 0x40
x[8] = (x[8] & 0x3F) | 0x80
return x
}
// FromStr returns a UUID based on a string.
// The string could be in the following format:
//
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
//
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
//
// If the string is not in one of these formats, it'll return an error.
func FromStr(s string) (id UUID, err error) {
if s == "" {
err = errors.New("Empty string")
return
}
parts := uuidRegex.FindStringSubmatch(s)
if parts == nil {
err = errors.New("Invalid string format")
return
}
var array [16]byte
slice, _ := hex.DecodeString(strings.Join(parts[1:], ""))
copy(array[:], slice)
id = array
return
}
// MustFromStr behaves similarly to FromStr except that it'll panic instead of
// returning an error.
func MustFromStr(s string) UUID {
id, err := FromStr(s)
if err != nil {
panic(err)
}
return id
}
// randBytes uses crypto random to get random numbers. If fails then it uses math random.
func randBytes(x []byte) {
length := len(x)
n, err := crand.Read(x)
if n != length || err != nil {
if !seeded {
mrand.Seed(time.Now().UnixNano())
}
for length > 0 {
length--
x[length] = byte(mrand.Int31n(256))
}
}
}
func GetUUID() string {
u7, _ := uuid.NewV7()
return strings.ReplaceAll(u7.String(), "-", "")
// var uuid UUID = Rand()
// return uuid.Hex()
}

1352
pkg/common/app_const.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
package document
type User struct {
Id string
Mobile string
RegionCode string
NickName string
Salt string
Password string
Status string
Avatar string
Gender string
Birthday string
WxUnionId string
QqOpenId string
MarketChannel string
CreateTime string
IsActive string
ActiveTime string
SignupSource string
SignupDevicePlatform string
SignupDeviceUdid string
IdNo string
IsAuth string
TrueName string
Sign string
ViewFlag string
VideoUrl string
School string
UserNo string
BankName string
BankUserName string
BankBranchName string
BankCardNo string
AuthFailReason string
AlipayAccount string
WellNoIcon string
}
//字符串: text keyword
//整数 : byte, short, integer, long
//浮点数: float, double
//布尔型: boolean
//日期: date
var UserIndex = map[string]interface{}{
"settings": map[string]interface{}{"number_of_shards": 5, "number_of_replicas": 1},
"mappings": map[string]interface{}{
"properties": map[string]interface{}{
"ActiveTime": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
"AlipayAccount": map[string]string{"type": "keyword"},
"AuthFailReason": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"Avatar": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"BankBranchName": map[string]string{"type": "keyword"},
"BankCardNo": map[string]string{"type": "keyword"},
"BankName": map[string]string{"type": "text"},
"BankUserName": map[string]string{"type": "text"},
"Birthday": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
"CreateTime": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
"Gender": map[string]string{"type": "keyword"},
"Id": map[string]string{"type": "keyword"},
"IdNo": map[string]string{"type": "keyword"},
"IsActive": map[string]string{"type": "keyword"},
"IsAuth": map[string]string{"type": "keyword"},
"MarketChannel": map[string]string{"type": "keyword"},
"Mobile": map[string]string{"type": "keyword"},
"NickName": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"QqOpenId": map[string]string{"type": "keyword"},
"RegionCode": map[string]string{"type": "keyword"},
"Salt": map[string]string{"type": "keyword"},
"School": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"Sign": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"SignupDevicePlatform": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"SignupDeviceUdid": map[string]string{"type": "keyword"},
"SignupSource": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"Status": map[string]string{"type": "keyword"},
"TrueName": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"UserNo": map[string]string{"type": "keyword"},
"VideoUrl": map[string]string{"type": "text", "analyzer": "ik_max_word"},
"ViewFlag": map[string]string{"type": "keyword"},
"WellNoIcon": map[string]string{"type": "keyword"},
"WxUnionId": map[string]string{"type": "keyword"},
},
},
}
var MessageIndex = map[string]interface{}{
"settings": map[string]interface{}{"number_of_shards": 5, "number_of_replicas": 1},
"mappings": map[string]interface{}{
"properties": map[string]interface{}{
"id": map[string]string{"type": "keyword"},
"curTime": map[string]string{"type": "date", "format": "yyyy-MM-dd HH:mm:ssZ||yyyy-MM-dd HH:mm:ss.SSSZ||yyyy-MM-ddZ||epoch_millis||epoch_second"},
},
},
}

261
pkg/common/es/es_client.go Normal file
View File

@ -0,0 +1,261 @@
package ess
import (
"servicebase/pkg/common/es/document"
"servicebase/pkg/common/messages"
"context"
"encoding/json"
"reflect"
"time"
"github.com/anxpp/beego/logs"
"github.com/olivere/elastic/v7"
"github.com/spf13/viper"
)
var client *elastic.Client
type EsClient struct {
}
func Init() {
index := messages.TagIndex(string(messages.EventTagUser))
client = _connect()
exists, e := client.IndexExists(index).Do(context.Background())
if e != nil {
logs.Error("IndexExists ", index, " error: ", e.Error())
return
}
if !exists {
logs.Info("es user not exist")
createIndex, e := client.CreateIndex(index).BodyJson(document.UserIndex).Do(context.Background())
if e != nil {
logs.Error("IndexCreate ", index, " error: ", e.Error())
return
}
if !createIndex.Acknowledged {
}
}
indexMessage := messages.TagIndex(string(messages.EventTagMessage))
existsMessage, e := client.IndexExists(indexMessage).Do(context.Background())
if e != nil {
logs.Error("IndexExists indexMessage", index, " error: ", e.Error())
return
}
if !existsMessage {
logs.Info("es indexMessage not exist")
createIndex, e := client.CreateIndex(indexMessage).BodyJson(document.MessageIndex).Do(context.Background())
if e != nil {
logs.Error("IndexCreate ", indexMessage, " error: ", e.Error())
return
}
if !createIndex.Acknowledged {
}
}
logs.Info("init elasticsearch finish")
}
func _connect() (c *elastic.Client) {
c, e := elastic.NewSimpleClient(
elastic.SetHealthcheck(true),
elastic.SetHealthcheckInterval(10*time.Second),
elastic.SetURL(viper.GetString("es.default.addr")),
// elastic.SetBasicAuth(beego.AppConfig.String("es_username"), beego.AppConfig.String("es_password")),
)
if e != nil {
logs.Error("NewClient_error: ", e.Error())
}
return c
}
// 创建记录
func (*EsClient) Create(index, id string, model interface{}) (body string, success bool, msg string) {
client := _connect()
_, e := client.Index().Index(index).Id(id).BodyJson(model).Do(context.Background())
if e != nil {
success = false
msg = e.Error()
b, _ := json.Marshal(model)
logs.Error("Document Create Error: ", e.Error(), " document: ", string(b), index, id)
return
}
success = true
return
}
// 判断存在
func (*EsClient) Exists(index, id string) (exists, success bool, msg string, e error) {
client := _connect()
exists, e = client.Exists().Index(index).Type("_doc").Id(id).Do(context.Background())
if e != nil {
success = false
msg = e.Error()
logs.Error("Id Exists Error: ", e.Error(), " id: ", id)
return
}
success = true
return
}
// 更新记录
func (*EsClient) Update(index, id string, model interface{}) (body string, success bool, msg string) {
client := _connect()
_, e := client.Update().Index(index).Id(id).Doc(model).Do(context.Background())
if e != nil {
success = false
msg = e.Error()
return
}
success = true
return
}
// 搜索
func (*EsClient) Search(index string, key string, fields ...string) (body []interface{}, success bool, msg string) {
client := _connect()
logs.Info("ES Search index =", index, " key =", key, " fields =", fields)
var list []*elastic.WildcardQuery
for _, field := range fields {
list = append(list, elastic.NewWildcardQuery(field, key))
}
s := client.Search().Index(index)
for _, query := range list {
s = s.Query(query)
}
res, e := s.From(0).Size(20).Pretty(true).Do(context.Background())
if e != nil {
success = false
msg = e.Error()
return
}
logs.Info(res.Status)
logs.Info(res.Hits.TotalHits)
var item document.User
for _, item := range res.Each(reflect.TypeOf(item)) {
if t, ok := item.(document.User); ok {
body = append(body, t)
}
}
//if res.Hits.TotalHits.Value > 0 {
// for _, hit := range res.Hits.Hits {
// var t document.User
// _ := json.Unmarshal(hit.Source, &t)
// body = append(body, t)
// }
//}
return
}
type ESFilter struct {
Queries []ESQuery
BoolMustInShouldQueries [][]ESQuery
Sort ESSort
}
type ESQuery struct {
Key string
Value string
Type string
}
type ESSort struct {
Field string
Ascending bool
}
// 搜索消息
func (*EsClient) SearchMulti(index string, filter ESFilter, page, size int) (result interface{}, success bool, msg string) {
client := _connect()
var list []elastic.Query
for _, item := range filter.Queries {
switch item.Type {
case "match":
list = append(list, elastic.NewMatchQuery(item.Key, item.Value))
case "multi_match":
list = append(list, elastic.NewMultiMatchQuery(item.Value).Type("best_fields").Lenient(true))
case "range_gte":
list = append(list, elastic.NewRangeQuery(item.Key).Gte(item.Value))
case "range_lte":
list = append(list, elastic.NewRangeQuery(item.Key).Lte(item.Value))
}
}
if len(filter.BoolMustInShouldQueries) > 0 {
BQ := elastic.NewBoolQuery()
var bqList []elastic.Query
for _, bq := range filter.BoolMustInShouldQueries {
var listBq []elastic.Query
boolQuery := elastic.NewBoolQuery()
for _, item := range bq {
switch item.Type {
case "match":
listBq = append(listBq, elastic.NewMatchQuery(item.Key, item.Value))
case "multi_match":
listBq = append(listBq, elastic.NewMultiMatchQuery(item.Value).Type("best_fields").Lenient(true))
case "range_gte":
listBq = append(listBq, elastic.NewRangeQuery(item.Key).Gte(item.Value))
case "range_lte":
listBq = append(listBq, elastic.NewRangeQuery(item.Key).Lte(item.Value))
}
}
boolQuery.Must(listBq...)
bqList = append(bqList, boolQuery)
}
BQ.Should(bqList...)
list = append(list, BQ)
}
query := elastic.NewBoolQuery().Filter(list...)
//logs.Info(len(list))
//a1, _ := query.Source()
//a2, _ := json.MarshalIndent(a1, "", " ")
//logs.Info(string(a2))
s := client.Search().Index(index).Query(query)
if len(filter.Sort.Field) > 0 {
s = s.Sort(filter.Sort.Field, filter.Sort.Ascending)
}
res, e := s.From(page * size).Size(size).Pretty(false).Do(context.Background())
if e != nil {
return
}
var body []interface{}
for _, item := range res.Hits.Hits {
b, _ := item.Source.MarshalJSON()
m := make(map[string]interface{})
_ = json.Unmarshal(b, &m)
body = append(body, m)
}
result = map[string]interface{}{
"Status": res.Status,
"Total": res.Hits.TotalHits,
"List": body,
}
return
}
// 搜索
func (*EsClient) QueryString(page, size int, index string, key string, fields ...string) (list []document.User, count int64, success bool, msg string) {
client := _connect()
logs.Info("ES QueryString index =", index, " key =", key, " fields =", fields)
query := elastic.NewQueryStringQuery(key)
for _, field := range fields {
query.Field(field)
}
query.AnalyzeWildcard(false)
s := client.Search().Index(index)
s = s.Query(query)
s = s.Sort("_score", false)
res, e := s.From(page * size).Size(size).Pretty(true).Do(context.Background())
if e != nil {
success = false
msg = e.Error()
return
}
count = res.TotalHits()
var user document.User
for _, item := range res.Each(reflect.TypeOf(user)) {
if t, ok := item.(document.User); ok {
list = append(list, t)
}
}
success = true
return
}

View File

@ -0,0 +1,81 @@
package ess
import (
"servicebase/pkg/common/messages"
"context"
"testing"
"time"
"github.com/anxpp/beego/logs"
"github.com/olivere/elastic/v7"
"github.com/spf13/viper"
)
func TestClient(t *testing.T) {
Init()
}
func TestClientCreateUser(t *testing.T) {
//for _, item := range models.LogUserRegisterAll() {
// cli := EsClient{}
// _, success, msg := cli.Create("test_user_register", item.Id, item)
// if !success {
// logs.Error(msg)
// }
//}
}
func TestClientSearch(t *testing.T) {
}
func _testConnect() (c *elastic.Client) {
c, e := elastic.NewSimpleClient(
elastic.SetHealthcheck(true),
elastic.SetHealthcheckInterval(10*time.Second),
// elastic.SetURL("http://47.97.157.234:9200"),
elastic.SetURL(viper.GetString("es.default.addr")),
// elastic.SetBasicAuth(beego.AppConfig.String("es_username"), beego.AppConfig.String("es_password")),
)
if e != nil {
logs.Error("NewClient_error: ", e.Error())
}
return c
}
func TestClientNew(t *testing.T) {
var client EsClient
client.Create("es_index_message", "003", map[string]interface{}{
"id": "003",
"curTime": 1440570500855,
"f1": 1234,
"f2": "22222",
"f3": "22222",
"f4": "22222",
"f5": "22222",
"f6": "2020-08-09 23:37:00",
})
}
func TestSearchMessage(t *testing.T) {
index := messages.TagIndex(string(messages.EventTagMessage))
client := _testConnect()
var list []elastic.Query
list = append(list, elastic.NewWildcardQuery("eventType", "1"))
list = append(list, elastic.NewMatchQuery("msgType", "TEXT"))
s := client.Search().Index(index)
for _, query := range list {
s = s.Query(query)
}
res, e := s.From(0).Size(20).Pretty(true).Do(context.Background())
if e != nil {
return
}
logs.Info(res.Status)
logs.Info(res.Hits.TotalHits)
logs.Info(len(res.Hits.Hits))
for i, item := range res.Hits.Hits {
b, _ := item.Source.MarshalJSON()
logs.Info(i, string(b))
}
time.Sleep(time.Second * 3)
}

View File

@ -0,0 +1,25 @@
package dto
type ChatRoomModelDTO struct {
Id string
OwnerUserId string
RoomNo string
RoomName string
MessageRoomId string
TabId string //分类ID
TemplateId string
CreateTime string
Status string
OpenTime string
RoomPwd string
MaxMemberCount string
IsHot string
RobotCount string
RoomTagIcon string
GuestCanUseEmoji string
SendMessageTimeGap string //发送消息间隔
UpSeatType string //1=排麦 2=自由麦
AudioQualityLevel string //音质等级 1=正常 2=高音质 3=超高音质
ViewSkewer string //是否显示福签 1=显示 0=不显示
IsViewHitegg string // 是否显示砸蛋
}

View File

@ -0,0 +1,5 @@
package dto
type RequestDTO struct {
Token string
}

View File

@ -0,0 +1,17 @@
package dto
type UserDTO struct {
UserId string
UserNo string
NickName string
Avatar string
Gender string
BirthDay string
VipLevel string
VipExp string
IsAuth string
Status string
TrueName string
Mobile string
AvatarDecoration string //头饰
}

View File

@ -0,0 +1,7 @@
package dto
type UserInviteSummaryDTO struct {
UserId string
InviteDiamond string
InviteUserCount string
}

View File

@ -0,0 +1,51 @@
package response
import "servicebase/pkg/common/http/dto"
type CommonResponse struct {
Code string
Result interface{}
Msg string
}
// 用户信息
type UserInfoResponse struct {
Code string
Result dto.UserDTO
Msg string
}
//获取用户邀请汇总数据返回
type UserInviteSummaryResponse struct {
Code string
Result dto.UserInviteSummaryDTO
Msg string
}
func Success(data interface{}) (res CommonResponse) {
res.Code = "6000"
res.Result = data
return
}
func Page(data interface{}, count int64) (res CommonResponse) {
res.Code = "6000"
res.Result = map[string]interface{}{
"list": data,
"count": count,
}
return
}
func Failed(msg string) (res CommonResponse) {
res.Code = "8020"
res.Msg = msg
return
}
func Gen(code, msg string, result interface{}) (res CommonResponse) {
res.Code = code
res.Msg = msg
res.Result = result
return
}

View File

@ -0,0 +1,12 @@
package messages
// 活跃消息
type Active struct {
MessageId string
UserId string //用户ID
DeviceId string //设备ID
ActiveTime string //活跃的平台
ActivePlatform string //活跃的平台
ActiveDeviceModel string //活跃的设备型号
ActiveIp string //活跃的IP
}

View File

@ -0,0 +1,26 @@
package messages
// 错误消息(补偿)
type Error struct {
MessageId string
Code string // 错误代码
Content string // 错误内容(json)
Tag ErrorTag // 消息标签auto=自动处理 manual=手动处理 auto_to_manual=自动转手动
}
type ErrorTag string
const (
Auto ErrorTag = "AUTO"
Manual ErrorTag = "MANUAL"
AutoToManual ErrorTag = "AUTO_TO_MANUAL"
)
type ErrorState string
const (
ErrorCreate ErrorState = "CREATED"
ErrorSuccess ErrorState = "SUCCESS"
ErrorFailed ErrorState = "FAILED"
ErrorReSuccess ErrorState = "RE_SUCCESS"
)

View File

@ -0,0 +1,49 @@
package messages
import (
"encoding/json"
"github.com/spf13/viper"
)
// 事件
type Event struct {
MessageId string
Tag EventTag // 消息标签EventTagUser=用户
Flag EventFlag // 消息标签EventFlagCreate=创建 EventFlagUpdate=更新
EventId string // 事件ID
EventContent interface{} // 事件内容
}
type EventTag string
const (
EventTagUser EventTag = "user"
EventTagRoomInto EventTag = "into_room"
EventTagMessage EventTag = "message"
)
func TagIndex(key string) string {
switch key {
case string(EventTagUser):
return viper.GetString("es.default.indexUser")
case string(EventTagMessage):
return viper.GetString("es.default.indexMessage")
default:
return ""
}
}
type EventFlag string
const (
EventFlagSave EventFlag = "save"
EventFlagCreate EventFlag = "create"
EventFlagUpdate EventFlag = "update"
EventFlagDelete EventFlag = "delete"
)
func (message *Event) ToJson() string {
b, _ := json.Marshal(message)
return string(b)
}

View File

@ -0,0 +1,12 @@
package messages
// 注册消息
type Register struct {
MessageId string
UserId string //用户ID
DeviceId string //设备ID
RegisterTime string //注册时间
ChannelCode string //渠道代码
Ip string //ip
Platform string //平台
}

View File

@ -0,0 +1,98 @@
package messages
// 交易消息
type Transaction struct {
MessageId string
FromUserId string //发起用户ID
FromCurrency TransactionCurrencyEnum //扣款类型
FromAmount string //扣款数量
FromPlatform string //扣款所在平台
ToUserId string //接收用户
ToCurrency TransactionCurrencyEnum //接收类型
ToAmount string //接收数量
TransactionRate string //交易抽成
TransactionState TransactionStateEnum //交易状态
TransactionType TransactionTypeEnum //充值、打赏、购买表情、购买守护、兑换、砸蛋、提现、订单等
TransactionId string //充值ID、打赏ID、购买表情ID、购买守护ID、兑换ID、砸蛋ID、提现ID、订单ID等
TransactionCreateTime string //交易创建时间
TransactionCompleteTime string //交易完成时间
TransactionSubjectId string //充值为产品ID、打赏为房间ID、购买表情为表情ID、购买守护为房间ID、兑换为配置ID、砸蛋为配置ID、提现为配置ID、订单为品类ID
TransactionCode TransactionCodeEnum //充值为充值渠道支付宝H5、支付宝App、微信、运营赠送等、打赏为打赏类型(单个、批量)、购买表情为空、购买守护为守护类型、兑换为空、砸蛋为中奖等级、提现为银行名称、订单为空
TransactionAmount string //交易金额(单位为扣款类型)
TransactionAmountCoupon string //交易优惠金额(单位为扣款类型)
TransactionAmountCouponId string //交易优惠凭证ID
TransactionAmountPay string //交易实际支付金额(单位为扣款类型)
GuildId string //俱乐部ID
}
// 交易更新消息
type TransactionUpdate struct {
MessageId string
TransactionState TransactionStateEnum //交易状态
TransactionId string //充值ID、打赏ID、购买表情ID、购买守护ID、兑换ID、砸蛋ID、提现ID、订单ID等
TransactionCompleteTime string //交易完成时间
}
type TransactionCodeEnum string
const (
RewardSimple TransactionCodeEnum = "SIMPLE" //单个打赏
RewardMulti TransactionCodeEnum = "MULTI" //批量打赏
RewardBagSimple TransactionCodeEnum = "BAG_SIMPLE" //背包礼物单个打赏
RewardBagMulti TransactionCodeEnum = "BAG_MULTI" //背包礼物批量打赏
GuardLevel01 TransactionCodeEnum = "1" //青铜守护
GuardLevel02 TransactionCodeEnum = "2" //白银守护
GuardLevel03 TransactionCodeEnum = "3" //黄金守护
Hunting1 TransactionCodeEnum = "1" //单砸
Hunting10 TransactionCodeEnum = "10" //十砸
Hunting100 TransactionCodeEnum = "100" //百砸
RechargeAppAlipay TransactionCodeEnum = "AppAlipay" //app支付宝
RechargeAppWeChat TransactionCodeEnum = "AppWeChat" //app微信
RechargeAppIap TransactionCodeEnum = "AppIap" //appIap
RechargeH5Alipay TransactionCodeEnum = "H5Alipay" //H5支付宝
RechargeH5WeChatClub TransactionCodeEnum = "H5WeChatClub" //H5微信公众号
RechargeOperation TransactionCodeEnum = "Operation" //Operation
)
type TransactionStateEnum string
const (
CREATED TransactionStateEnum = "CREATED" //已创建
SUCCESS TransactionStateEnum = "SUCCESS" //成功
FAILED TransactionStateEnum = "FAILED" //失败
)
type TransactionCurrencyEnum string
const (
DIAMOND TransactionCurrencyEnum = "DIAMOND" //钻石
CRYSTAL TransactionCurrencyEnum = "CRYSTAL" //晶石
MONEY TransactionCurrencyEnum = "MONEY" //钱
FRAGMENT TransactionCurrencyEnum = "FRAGMENT" //碎片
)
type TransactionTypeEnum string
const (
RECHARGE TransactionTypeEnum = "RECHARGE" //充值
RechargeNCoin TransactionTypeEnum = "RECHARGE_N_COIN" //充值N币
REWARD TransactionTypeEnum = "REWARD" //打赏
REWARDNCoin TransactionTypeEnum = "REWARD_N_COIN" //打赏
GUARD TransactionTypeEnum = "GUARD" //购买守护
EMOJI TransactionTypeEnum = "EMOJI" //购买表情
OperationDiamond TransactionTypeEnum = "OPERATION_DIAMOND" //手工加钻石
OperationCrystal TransactionTypeEnum = "OPERATION_CRYSTAL" //手工加晶石
OperationCrystalReduce TransactionTypeEnum = "OPERATION_CRYSTAL_REDUCE" //手工扣除晶石
EXCHANGE TransactionTypeEnum = "EXCHANGE" //兑换
HUNTING TransactionTypeEnum = "HUNTING" //星空寻宝
WithdrawNCoin TransactionTypeEnum = "WITHDRAW_N_COIN" //提现 N币
ORDER TransactionTypeEnum = "ORDER" //订单
ORDERNCoin TransactionTypeEnum = "ORDER_N_COIN" //订单
ORDER_H5 TransactionTypeEnum = "ORDER_H5" //订单
ORDER_H5_NCoin TransactionTypeEnum = "ORDER_H5_N_COIN" //订单
LUCK_GIFT TransactionTypeEnum = "LUCK_GIFT" //幸运礼物
LuckGiftNCoin TransactionTypeEnum = "LUCK_GIFT_N_COIN" //幸运礼物
)

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
}

View File

@ -0,0 +1,45 @@
package network
import (
"encoding/json"
)
const (
SuccessCode = "6000" // 成功
NeedLogin = "6018" // 登陆过期
ErrorCode = "6020" // 错误
)
type Response struct {
Code string
Result interface{}
Msg string
}
type EmptyResponse struct {
}
func Fail(msg string) Response {
response := Response{Code: ErrorCode, Msg: msg}
return response
}
func Invalid() string {
response := Response{Code: NeedLogin, Msg: "用户身份已过期"}
str, _ := json.Marshal(response)
return string(str)
}
func Success(data interface{}) Response {
response := Response{Code: SuccessCode, Result: data}
return response
}
func Page(data interface{}, count int64) Response {
response := Response{Code: SuccessCode, Result: map[string]interface{}{
"List": data,
"Count": count,
}}
return response
}

148
pkg/common/pinyin/pinyin.go Normal file
View File

@ -0,0 +1,148 @@
package pinyin
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"unicode/utf8"
)
type vowel int32
var (
ys = []vowel{'ā', 'ē', 'ī', 'ō', 'ū', 'ǖ', 'Ā', 'Ē', 'Ī', 'Ō', 'Ū', 'Ǖ'} // 单韵母 一声
es = []vowel{'á', 'é', 'í', 'ó', 'ú', 'ǘ', 'Á', 'É', 'Í', 'Ó', 'Ú', 'Ǘ'} // 单韵母 二声
ss = []vowel{'ǎ', 'ě', 'ǐ', 'ǒ', 'ǔ', 'ǚ', 'Ǎ', 'Ě', 'Ǐ', 'Ǒ', 'Ǔ', 'Ǚ'} // 单韵母 三声
fs = []vowel{'à', 'è', 'ì', 'ò', 'ù', 'ǜ', 'À', 'È', 'Ì', 'Ò', 'Ù', 'Ǜ'} // 单韵母 四声
ws = []vowel{'a', 'e', 'i', 'o', 'u', 'v', 'A', 'E', 'I', 'O', 'U', 'V'} // 单韵母 无声调
)
var (
pinyinTemp map[vowel]interface{}
toneTemp map[vowel]vowel
)
const (
Tone string = "带声调的拼音" // 带声调的拼音 例如Cào
InitialsInCapitals string = "首字母大写不带声调" // 首字母大写不带声调 例如Cao
None string = "" //如果匹配不到汉字,就靠大家维护下 【匹配失败手动添加代码到pinyin.txt】
)
func LoadingPYFile(filename string) {
f, err := os.Open(filename)
if err != nil {
fmt.Println(err)
}
if err != nil {
panic(err)
}
pinyinTemp = make(map[vowel]interface{}, 0)
toneTemp = make(map[vowel]vowel)
for i, t := range ys {
toneTemp[t] = ws[i]
}
for i, t := range es {
toneTemp[t] = ws[i]
}
for i, t := range ss {
toneTemp[t] = ws[i]
}
for i, t := range fs {
toneTemp[t] = ws[i]
}
defer func() {
_ = f.Close()
}()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
//单行分割取出拼音
str := strings.Split(scanner.Text(), "=>")
if len(str) < 2 {
continue
}
i, err := strconv.ParseInt(str[0], 16, 32)
if err != nil {
continue
}
pinyinTemp[vowel(i)] = str[1]
//fmt.Println(pinyinTemp[vowel(i)])
}
}
func PY(source string) (string, error) {
return PYSplit(source, "", "")
}
func PYSplit(source string, split string, types string) (string, error) {
hz := []vowel(source)
words := make([]string, 0)
for _, s := range hz {
word, err := _vowel(s, types)
if err != nil {
return None, err
}
if len(word) > 0 {
words = append(words, word)
}
}
return strings.Join(words, split), nil
}
func _vowel(source vowel, types string) (string, error) {
switch types {
case Tone:
return getTone(source), nil
case InitialsInCapitals:
return getInitialsInCapitals(source), nil
default:
return getDefault(source), nil
}
}
func getTone(source vowel) string {
if pinyinTemp[source] != nil {
return pinyinTemp[source].(string)
}
return string(source)
}
func getInitialsInCapitals(source vowel) string {
def := getDefault(source)
var result string
if def == "" {
return def
}
str := []vowel(def)
if str[0] > 32 {
str[0] = str[0] - 32
}
for _, v := range str {
result += string(v)
}
return result
}
func getDefault(source vowel) string {
tone := getTone(source)
var result string
if tone == "" {
return None
}
resultLen := make([]vowel, utf8.RuneCountInString(tone))
count := 0
for _, t := range tone {
changes, ok := toneTemp[vowel(t)]
if ok {
resultLen[count] = changes
} else {
resultLen[count] = vowel(t)
}
count++
}
for _, v := range resultLen {
result += string(v)
}
return result
}

41208
pkg/common/pinyin/pinyin.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
package pinyin
import "testing"
func TestTo_Py(t *testing.T) {
LoadingPYFile("./pinyin.txt")
s, _ := PY("3425另264325一4个44平444台")
println(s)
}

30
pkg/common/req/req.go Normal file
View File

@ -0,0 +1,30 @@
package req
const (
defaultPage = 1
defaultSize = 10
)
type Page struct {
Page int64 `json:"page" form:"page" uri:"page"`
Size int64 `json:"size" form:"size" uri:"size"`
}
func (p *Page) check() {
if p.Page < 1 {
p.Page = defaultPage
}
if p.Size <= 0 {
p.Size = defaultSize
}
}
func (p *Page) Offset() int {
p.check()
return int(p.Page*p.Size - p.Size)
}
func (p *Page) Limit() int {
p.check()
return int(p.Size)
}

View File

@ -0,0 +1,154 @@
package util
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
const (
PhotoDomainUrl = "https://photo-app.ddegame.cn/"
TimeLayout = "2006-01-02 15:04:05"
DateLayout = "2006-01-02"
DateLayoutShort = "20060102"
)
func FullPhotoUrl(path string) string {
if len(path) == 0 {
return ""
}
if strings.Index(path, "http") == 0 {
return path
}
return PhotoDomainUrl + path
}
func Md5ForList(s ...string) string {
sort.Strings(s)
h := md5.New()
h.Write([]byte(strings.Join(s, "")))
return hex.EncodeToString(h.Sum(nil))
}
func StringToInt(source string) int {
target, _ := strconv.Atoi(source)
return target
}
func StringToFloat(source string) float64 {
target, _ := strconv.ParseFloat(source, 64)
return target
}
func StringIntPlus(s1, s2 string) string {
return strconv.Itoa(StringToInt(s1) + StringToInt(s2))
}
func StringIntMultiply(s1, s2 string) string {
return strconv.Itoa(StringToInt(s1) * StringToInt(s2))
}
func StringIntSub(s1, s2 string) string {
return strconv.Itoa(StringToInt(s1) - StringToInt(s2))
}
func StringFloatSub(s1, s2 string) string {
return strconv.FormatFloat(StringToFloat(s1)-StringToFloat(s2), 'f', -1, 64)
}
func ListToSet(list []string) (set []string) {
m := make(map[string]bool, 0)
for i := range list {
m[list[i]] = true
}
for k := range m {
set = append(set, k)
}
return
}
func ToJson(source interface{}) []byte {
b, _ := json.Marshal(source)
return b
}
func ToJsonString(source interface{}) string {
return string(ToJson(source))
}
func NowTimeToString() string {
return time.Now().Format(TimeLayout)
}
func NowTimeIncreaseString(t time.Duration) string {
return time.Now().Add(t).Format(TimeLayout)
}
func NowDateToString() string {
return time.Now().Format(DateLayout)
}
func NowDateToStringShort() string {
return time.Now().Format(DateLayoutShort)
}
func DateToString(source time.Time) string {
return source.Format(TimeLayout)
}
func Md5(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
func ProcessTimeStr(s string) (string, error) {
// 定义两种时间格式
layout1 := "2006-01-02 15:04:05" // 无时区的格式
layout2 := "2006-01-02 15:04:05 -0700 MST" // 带时区的格式(包含偏移和时区名称)
// 尝试解析为无时区格式
_, err1 := time.Parse(layout1, s)
if err1 == nil {
return s, nil // 直接返回原字符串
}
// 尝试解析为带时区格式
t2, err2 := time.Parse(layout2, s)
if err2 == nil {
// 格式化为无时区格式
return t2.Format(layout1), nil
}
// 两种格式都不匹配
return "", fmt.Errorf("invalid time format: %s", s)
}
// 解析url里的参数为map
func ParseUrlParameter(fullUrl string) (result map[string]string) {
result = make(map[string]string)
// 解析URL
parsedURL, err := url.Parse(fullUrl)
if err != nil {
fmt.Printf("解析URL失败: %v\n", err)
return
}
// 解析查询参数
queryParams := parsedURL.Query()
// 输出所有参数
for key, values := range queryParams {
result[key] = values[0]
}
return
}

View File

@ -0,0 +1,17 @@
package util
import (
"servicebase/pkg/common"
"fmt"
"testing"
)
func Test_processTimeStr(t *testing.T) {
tmp, e := ProcessTimeStr("2025-05-29 09:08:38 +0800 CST")
fmt.Printf("%v %v\n", tmp, e)
}
func TestParseUrlParameter(t *testing.T) {
// assets/img/op_1754967614.png?c=#000000&s=160
ParseUrlParameter(common.FullPhotoUrl("assets/img/op_1754967614.png?c=%23000000&s=160"))
}