423 lines
8.8 KiB
Go
423 lines
8.8 KiB
Go
package util
|
||
|
||
import (
|
||
"backend/msg"
|
||
"bytes"
|
||
"crypto/aes"
|
||
"crypto/cipher"
|
||
crand "crypto/rand"
|
||
"encoding/base64"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"math/rand"
|
||
"os"
|
||
"reflect"
|
||
"slices"
|
||
"strconv"
|
||
"strings"
|
||
"text/template"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"golang.org/x/net/websocket"
|
||
"google.golang.org/protobuf/proto"
|
||
)
|
||
|
||
var MergeData = make(map[string]interface{})
|
||
var MergeEmitData = make(map[string]interface{})
|
||
|
||
func init() {
|
||
data, err := os.ReadFile("conf/MergeData.json")
|
||
if err != nil {
|
||
log.Printf("failed to read conf/MergeData.json: %v", err)
|
||
} else {
|
||
var m map[string]interface{}
|
||
if err := json.Unmarshal(data, &m); err != nil {
|
||
log.Printf("failed to unmarshal MergeData.json: %v", err)
|
||
} else {
|
||
MergeData = m
|
||
}
|
||
}
|
||
|
||
data, err = os.ReadFile("conf/MergeDataEmit.json")
|
||
if err != nil {
|
||
log.Printf("failed to read conf/MergeEmitData.json: %v", err)
|
||
} else {
|
||
var m map[string]interface{}
|
||
if err := json.Unmarshal(data, &m); err != nil {
|
||
log.Printf("failed to unmarshal MergeEmitData.json: %v", err)
|
||
} else {
|
||
MergeEmitData = m
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取结构体名称
|
||
func GetStructName(v interface{}) string {
|
||
t := reflect.TypeOf(v)
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
if t.Kind() == reflect.Struct {
|
||
return t.Name()
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func PackMsg(m proto.Message) []byte {
|
||
buf, _ := proto.Marshal(m)
|
||
Func := GetStructName(m)
|
||
req := &msg.AdminReq{
|
||
Func: Func,
|
||
Info: buf,
|
||
}
|
||
buf, _ = proto.Marshal(req)
|
||
return append([]byte{0, 2}, buf...)
|
||
}
|
||
|
||
func UnpackMsg(buf []byte, n int) ([]byte, error) {
|
||
res := &msg.AdminRes{}
|
||
err := proto.Unmarshal(buf[2:n], res)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return res.Info, nil
|
||
}
|
||
|
||
func ParseUid(uid int) (int, int) {
|
||
AppId := uid / 100000000
|
||
ServerId := uid % 100000000 / 100000
|
||
return AppId, ServerId
|
||
}
|
||
|
||
func Int(a interface{}) int {
|
||
if a == nil {
|
||
return 0
|
||
}
|
||
switch v := a.(type) {
|
||
case int:
|
||
return v
|
||
case int32:
|
||
return int(v)
|
||
case int64:
|
||
return int(v)
|
||
case float64:
|
||
return int(v)
|
||
case string:
|
||
r, err := strconv.Atoi(v)
|
||
if err != nil {
|
||
return 0
|
||
}
|
||
return r
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func InArray(Id int, s []int) bool {
|
||
for _, v := range s {
|
||
if v == Id {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func Now() int64 {
|
||
return time.Now().Unix()
|
||
}
|
||
|
||
func Year() int {
|
||
return time.Now().Year()
|
||
}
|
||
|
||
func SendAdminMsg(ws *websocket.Conn, req proto.Message) (map[string]interface{}, error) {
|
||
reqBuf := PackMsg(req)
|
||
_, err := ws.Write(reqBuf)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to write to websocket: %v", err)
|
||
}
|
||
|
||
readbuf := make([]byte, 4096)
|
||
n, err := ws.Read(readbuf)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to read from websocket: %v", err)
|
||
}
|
||
resBuf, _ := UnpackMsg(readbuf, n)
|
||
r := make(map[string]interface{})
|
||
json.Unmarshal(resBuf, &r)
|
||
return r, nil
|
||
}
|
||
|
||
func FloatDecimals(f float64, n int) float64 {
|
||
format := fmt.Sprintf("%%.%df", n)
|
||
r, _ := strconv.ParseFloat(fmt.Sprintf(format, f), 64)
|
||
return r
|
||
}
|
||
|
||
// 将两个参数转换成浮点数,如果无法转换则为0,实现两个浮点数的除法,除数为0的话,返回0
|
||
func FloatDiv(a, b interface{}, Decimal int) float64 {
|
||
af := toFloat64(a)
|
||
bf := toFloat64(b)
|
||
if bf == 0 {
|
||
return 0
|
||
}
|
||
result := af / bf
|
||
format := fmt.Sprintf("%%.%df", Decimal)
|
||
r, _ := strconv.ParseFloat(fmt.Sprintf(format, result), 64)
|
||
return r
|
||
}
|
||
|
||
func Decimal(f float64, n int) float64 {
|
||
format := fmt.Sprintf("%%.%df", n)
|
||
r, _ := strconv.ParseFloat(fmt.Sprintf(format, f), 64)
|
||
return r
|
||
}
|
||
|
||
// 辅助函数:将interface{}转换为float64
|
||
func toFloat64(v interface{}) float64 {
|
||
switch val := v.(type) {
|
||
case int:
|
||
return float64(val)
|
||
case int32:
|
||
return float64(val)
|
||
case int64:
|
||
return float64(val)
|
||
case float32:
|
||
return float64(val)
|
||
case float64:
|
||
return val
|
||
case string:
|
||
r, err := strconv.ParseFloat(val, 64)
|
||
if err != nil {
|
||
return 0
|
||
}
|
||
return r
|
||
default:
|
||
return 0
|
||
}
|
||
}
|
||
|
||
const (
|
||
SECRET_KEY = ")VQbB(vpy=U(wcp)"
|
||
)
|
||
|
||
// 加密字符串
|
||
func Encrypt(plainText string) (string, error) {
|
||
block, err := aes.NewCipher([]byte(SECRET_KEY))
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
cipherText := make([]byte, aes.BlockSize+len(plainText))
|
||
iv := cipherText[:aes.BlockSize]
|
||
if _, err := io.ReadFull(crand.Reader, iv); err != nil {
|
||
return "", err
|
||
}
|
||
|
||
stream := cipher.NewCFBEncrypter(block, iv)
|
||
stream.XORKeyStream(cipherText[aes.BlockSize:], []byte(plainText))
|
||
|
||
return base64.URLEncoding.EncodeToString(cipherText), nil
|
||
}
|
||
|
||
// 解密字符串
|
||
func Decrypt(cipherText string) (string, error) {
|
||
cipherTextBytes, err := base64.URLEncoding.DecodeString(cipherText)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
block, err := aes.NewCipher([]byte(SECRET_KEY))
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
if len(cipherTextBytes) < aes.BlockSize {
|
||
return "", fmt.Errorf("cipherText too short")
|
||
}
|
||
|
||
iv := cipherTextBytes[:aes.BlockSize]
|
||
cipherTextBytes = cipherTextBytes[aes.BlockSize:]
|
||
|
||
stream := cipher.NewCFBDecrypter(block, iv)
|
||
stream.XORKeyStream(cipherTextBytes, cipherTextBytes)
|
||
|
||
return string(cipherTextBytes), nil
|
||
}
|
||
|
||
func ParseTmpl(file string, data interface{}) string {
|
||
t, err := template.ParseFiles(file)
|
||
if err != nil {
|
||
log.Fatalf("failed to parse template file: %v", err)
|
||
}
|
||
var buf bytes.Buffer
|
||
err = t.Execute(&buf, data)
|
||
if err != nil {
|
||
log.Fatalf("failed to execute template: %v", err)
|
||
}
|
||
s := buf.String()
|
||
return s
|
||
}
|
||
|
||
// 将字符串转换成一行的字符串格式,并再进行一次转义输出
|
||
func ToTmplStr(input string) string {
|
||
// 转义换行符
|
||
escapedStr := strings.ReplaceAll(input, "\r", "")
|
||
escapedStr = strings.ReplaceAll(escapedStr, "\n", "\\n")
|
||
escapedStr = strings.ReplaceAll(escapedStr, "\"", "\\\"")
|
||
// 转义输出
|
||
// return template.HTMLEscapeString(escapedStr)
|
||
return escapedStr
|
||
}
|
||
|
||
func Ternary(condition bool, trueVal, falseVal interface{}) interface{} {
|
||
if condition {
|
||
return trueVal
|
||
}
|
||
return falseVal
|
||
}
|
||
|
||
func TimestampToDate(timestamp int64, Tz string) string {
|
||
loc, err := time.LoadLocation(Tz)
|
||
if err != nil {
|
||
log.Printf("failed to load location %s: %v", Tz, err)
|
||
loc = time.UTC // 默认使用UTC
|
||
}
|
||
t := time.Unix(timestamp, 0).In(loc)
|
||
return t.Format("2006-01-02")
|
||
}
|
||
func TimestampToDateTime(timestamp int64, Tz string) string {
|
||
loc, err := time.LoadLocation(Tz)
|
||
if err != nil {
|
||
log.Printf("failed to load location %s: %v", Tz, err)
|
||
loc = time.UTC // 默认使用UTC
|
||
}
|
||
t := time.Unix(timestamp, 0).In(loc)
|
||
return t.Format("2006-01-02 15:04:05")
|
||
}
|
||
|
||
func GenerateToken() string {
|
||
// 生成一个安全的随机token,适合网页登录
|
||
b := make([]byte, 32)
|
||
if _, err := crand.Read(b); err != nil {
|
||
return ""
|
||
}
|
||
return base64.URLEncoding.EncodeToString(b)
|
||
}
|
||
|
||
func GeneratedCode(Phone string) (string, error) {
|
||
Code := Rand6DigitNumber()
|
||
err := SmsCode(Phone, Code)
|
||
if err != nil {
|
||
return "", fmt.Errorf("failed to send SMS code: %v", err)
|
||
}
|
||
return Code, err
|
||
}
|
||
|
||
func Rand6DigitNumber() string {
|
||
n := rand.Intn(1000000)
|
||
return fmt.Sprintf("%06d", n)
|
||
}
|
||
|
||
func GetToken(c *gin.Context) string {
|
||
// 从请求头中获取Token
|
||
token := c.GetHeader("Authorization")
|
||
if len(token) > 7 && token[:7] == "Bearer " {
|
||
token = token[7:] // 去掉"Bearer "前缀
|
||
}
|
||
return token
|
||
}
|
||
|
||
func GetRole(code int) string {
|
||
switch code {
|
||
case 0:
|
||
return "super"
|
||
case 1:
|
||
return "admin"
|
||
case 2:
|
||
return "user"
|
||
case 99:
|
||
return "wb_transfer"
|
||
default:
|
||
return "guest"
|
||
}
|
||
}
|
||
|
||
func ToJson(v interface{}) string {
|
||
data, err := json.Marshal(v)
|
||
if err != nil {
|
||
log.Printf("failed to marshal to JSON: %v", err)
|
||
return ""
|
||
}
|
||
return string(data)
|
||
}
|
||
|
||
func AddAdminLog(c *gin.Context, action string, params interface{}) {
|
||
admin := c.GetString("admin")
|
||
ip := c.ClientIP()
|
||
db := MPool.GetGameDB()
|
||
_, err := db.Exec("INSERT INTO admin_log (admin, action, params, ip, createTime) VALUES (?, ?, ?, ?, ?)",
|
||
admin, action, ToJson(params), ip, Now())
|
||
if err != nil {
|
||
fmt.Printf("failed to insert admin log: %v", err)
|
||
return
|
||
}
|
||
}
|
||
|
||
func ParseParam(s string) map[string]interface{} {
|
||
result := make(map[string]interface{})
|
||
if strings.TrimSpace(s) == "" {
|
||
return result
|
||
}
|
||
if err := json.Unmarshal([]byte(s), &result); err != nil {
|
||
return map[string]interface{}{}
|
||
}
|
||
return result
|
||
}
|
||
|
||
func CheckContainChess(ChessList []string, Emit []string) bool {
|
||
if len(Emit) == 0 {
|
||
return true
|
||
}
|
||
for _, c := range ChessList {
|
||
d, ok := MergeData[c]
|
||
if !ok {
|
||
continue
|
||
}
|
||
if d == nil {
|
||
continue
|
||
}
|
||
m, ok := d.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
Color := m["Color"].(string)
|
||
Serise := getSeriseByColor(Color)
|
||
if InArrayStr(Serise, Emit) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func InArrayStr(s string, arr []string) bool {
|
||
return slices.Contains(arr, s)
|
||
}
|
||
|
||
func getSeriseByColor(Color string) string {
|
||
for k, v := range MergeEmitData {
|
||
d := v.(map[string]interface{})
|
||
colors, ok := d["Order_Type"].(string)
|
||
if !ok {
|
||
continue
|
||
}
|
||
colorList := strings.Split(colors, ",")
|
||
if InArrayStr(Color, colorList) {
|
||
return k
|
||
}
|
||
}
|
||
return Color
|
||
}
|