|
|
package dapi
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"epur-pay/cache"
|
|
|
"epur-pay/model"
|
|
|
"epur-pay/pkg/config"
|
|
|
"epur-pay/pkg/logger"
|
|
|
"epur-pay/pkg/rds"
|
|
|
"epur-pay/pkg/utils"
|
|
|
"fmt"
|
|
|
"github.com/deatil/go-cryptobin/cryptobin/crypto"
|
|
|
"net/url"
|
|
|
"reflect"
|
|
|
"runtime"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
var LockPool sync.Map
|
|
|
|
|
|
func (a *ApiBase) apiHandler() error {
|
|
|
if a.paramNum == 1 {
|
|
|
a.funcValue.Call(valOf(a))
|
|
|
} else {
|
|
|
if err := a.getBody(); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
a.funcValue.Call(valOf(a, a.body))
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) limitRouterRuleHandler() error {
|
|
|
|
|
|
if cache.Global.LimitRouter.Api != nil {
|
|
|
key := cache.Global.LimitRouter.Api.Key(a.C)
|
|
|
if bucket, ok := cache.Global.LimitRouter.Api.GetBucket(key); ok {
|
|
|
count := bucket.TakeAvailable(1)
|
|
|
if count == 0 {
|
|
|
return a.ReturnPublicErrorResponse(a.Translate("rateLimit"))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) headerHandler() error {
|
|
|
|
|
|
//站点处理
|
|
|
a.siteHandler()
|
|
|
//币种处理
|
|
|
a.currencyHander()
|
|
|
//时区处理
|
|
|
a.localHandler()
|
|
|
//分页参数处理
|
|
|
a.pageHandler()
|
|
|
//语言处理
|
|
|
a.getLangByAppRequest()
|
|
|
//版本管理
|
|
|
if err := a.versionHander(); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) siteHandler() {
|
|
|
a.Site = a.C.GetHeader("site")
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) currencyHander() {
|
|
|
a.Currency = a.C.GetHeader("currency")
|
|
|
if len(a.Currency) <= 0 {
|
|
|
a.Currency = "USD"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) GetPage() int {
|
|
|
page1, _ := a.C.GetQuery("page")
|
|
|
page, _ := strconv.Atoi(page1)
|
|
|
if page <= 0 {
|
|
|
page = 1
|
|
|
}
|
|
|
return page
|
|
|
}
|
|
|
func (a *ApiBase) pageHandler() {
|
|
|
page1, _ := a.C.GetQuery("page")
|
|
|
size1, _ := a.C.GetQuery("size")
|
|
|
|
|
|
page, _ := strconv.Atoi(page1)
|
|
|
limit, _ := strconv.Atoi(size1)
|
|
|
|
|
|
if page <= 0 {
|
|
|
page = 1
|
|
|
}
|
|
|
if limit >= 100 {
|
|
|
limit = 100
|
|
|
} else if limit <= 0 {
|
|
|
limit = 20
|
|
|
}
|
|
|
|
|
|
a.Limit = limit
|
|
|
a.Offset = (page - 1) * limit
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) localHandler() {
|
|
|
var err error
|
|
|
a.Local, err = time.LoadLocation(a.C.GetHeader("Timezone")) //等同于"UTC"
|
|
|
if err != nil {
|
|
|
a.Local = nil
|
|
|
}
|
|
|
|
|
|
if len(a.C.GetHeader("Timezone")) == 0 {
|
|
|
a.Local = nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) getBody() error {
|
|
|
|
|
|
if a.C.Request.Method == "POST" ||
|
|
|
a.C.Request.Method == "PUT" ||
|
|
|
a.C.Request.Method == "PATCH" {
|
|
|
|
|
|
row, err := a.C.GetRawData()
|
|
|
if err != nil {
|
|
|
logger.ErrorLogger.Errorln(err.Error())
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
var data string
|
|
|
|
|
|
data = string(row)
|
|
|
|
|
|
if config.Cf.Common.RunMode == "debug" {
|
|
|
logger.AccessLogger.Infof("%s 请求数据 -> %s", a.C.FullPath(), data)
|
|
|
}
|
|
|
|
|
|
if a.Log != nil && a.Log.Event != "登陆" {
|
|
|
a.Log.Data = data
|
|
|
}
|
|
|
|
|
|
err = json.Unmarshal([]byte(data), &a.body)
|
|
|
if err != nil {
|
|
|
|
|
|
logger.AccessLogger.Errorf("===> BindJSON: %s", a.Translate("param_fail"))
|
|
|
|
|
|
return a.ReturnErrorResponse(InvalidParams, a.Translate("param_fail"))
|
|
|
}
|
|
|
if a.InParams.IsErrors {
|
|
|
var errMsg []string
|
|
|
ValidateField(a.body, func(typeOfCat reflect.Type, fieldName string) {
|
|
|
field, ok := typeOfCat.FieldByName(fieldName) //通过反射获取filed
|
|
|
if ok {
|
|
|
errMsg = append(errMsg, a.Translate(field.Tag.Get("label")))
|
|
|
}
|
|
|
})
|
|
|
if len(errMsg) > 0 {
|
|
|
return a.ReturnErrorResponse(InvalidParams, strings.Join(errMsg, ","))
|
|
|
}
|
|
|
} else {
|
|
|
var errMsg string
|
|
|
ValidateField(a.body, func(typeOfCat reflect.Type, fieldName string) {
|
|
|
field, ok := typeOfCat.FieldByName(fieldName) //通过反射获取filed
|
|
|
if ok {
|
|
|
errMsg = field.Tag.Get("label")
|
|
|
return
|
|
|
}
|
|
|
})
|
|
|
if len(errMsg) > 0 {
|
|
|
return a.ReturnErrorResponse(InvalidParams, a.Translate(errMsg))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func valOf(i ...interface{}) []reflect.Value {
|
|
|
var rt []reflect.Value
|
|
|
for _, i2 := range i {
|
|
|
rt = append(rt, reflect.ValueOf(i2))
|
|
|
}
|
|
|
return rt
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) ClientIp() string {
|
|
|
|
|
|
ip := a.C.Request.Header.Get("Cf-Connecting-Ip")
|
|
|
|
|
|
if len(ip) <= 0 {
|
|
|
ip = a.C.Request.Header.Get("X-Real-Ip")
|
|
|
}
|
|
|
|
|
|
if len(ip) <= 0 {
|
|
|
ip = a.C.ClientIP()
|
|
|
}
|
|
|
|
|
|
return ip
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) Translate(key string) string {
|
|
|
return cache.Global.Caches.Language.GetLang(a.Lang, key)
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) RefreshCache(key string) error {
|
|
|
return Cf.ApiRefreshCache(key)
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) authHandler() error {
|
|
|
if a.InParams.IsTicket || a.InParams.IsTicketSkip {
|
|
|
if err := a.getUser(a.C.Request.Header.Get("Token")); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) getUser(token string) error {
|
|
|
|
|
|
var uid int64
|
|
|
a.Token = token
|
|
|
|
|
|
if a.InParams.IsTicket && len(a.Token) <= 0 {
|
|
|
return a.ReturnErrorResponse(600, a.Translate("reset_login"))
|
|
|
} else if len(a.Token) > 0 {
|
|
|
//logger.AccessLogger.Infoln("---> getUser DecryptToken ", a.Token)
|
|
|
t, e := DecryptToken(a.Token)
|
|
|
if !e {
|
|
|
if a.InParams.IsTicket {
|
|
|
return a.ReturnErrorResponse(600, a.Translate("not_found"))
|
|
|
}
|
|
|
} else {
|
|
|
uid, _ = strconv.ParseInt(strings.Split(t, ",")[0], 10, 64)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if uid > 0 {
|
|
|
a.User = cache.Global.Caches.User.Get(uid)
|
|
|
|
|
|
if a.User == nil { //解决用户被删除后token无效的问题
|
|
|
if a.InParams.IsTicket {
|
|
|
return a.ReturnErrorResponse(600, a.Translate("reset_login"))
|
|
|
} else {
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if a.User.Detail.Token != a.Token {
|
|
|
if a.InParams.IsTicket {
|
|
|
return a.ReturnErrorResponse(600, a.Translate("reset_login"))
|
|
|
} else {
|
|
|
a.User = nil
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if a.User.Uid <= 0 {
|
|
|
if a.InParams.IsTicket {
|
|
|
return a.ReturnErrorResponse(600, a.Translate("not_found"))
|
|
|
} else {
|
|
|
a.User = nil
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果必须是超级权限操作,需要判断是否存在权限ID=1的数据 //!a.User.RoleIds.Of(1)
|
|
|
if a.InParams.IsSuperOnly && a.User.Uid != 1 {
|
|
|
logger.AccessLogger.Errorf("---> Uid: [%d] Super权限错误 %s", a.User.Uid, a.InParams.Permission)
|
|
|
return a.ReturnErrorResponse(602, a.Translate("AT004"))
|
|
|
}
|
|
|
|
|
|
// 这里验证用户是否拥有接口操作权限
|
|
|
if len(a.InParams.Permission) > 0 {
|
|
|
if !cache.Global.Caches.RolePermission.Check(a.User.RoleIds, a.InParams.Permission) {
|
|
|
logger.AccessLogger.Errorf("---> Uid: [%d] 尚无权限: [%s] %v", a.User.Uid, a.InParams.Permission, a.User.RoleIds)
|
|
|
return a.ReturnPublicErrorResponse(a.Translate("AT058"))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if a.User.Status != "0" {
|
|
|
if a.InParams.IsTicket || (a.InParams.IsTicketSkip && a.User != nil) {
|
|
|
if !a.InParams.IsNoCheckBlackList {
|
|
|
return a.ReturnErrorResponse(602, a.Translate("black_list"))
|
|
|
}
|
|
|
} else {
|
|
|
a.User = nil
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) lockTrade() error {
|
|
|
//logger.AccessLogger.Infof("params:%+v user:%+v", a.InParams.IsLockTradeForMerchant, a.User)
|
|
|
if a.InParams.IsForUpdate && a.User != nil {
|
|
|
if _, ok := LockPool.Load(fmt.Sprintf("%s%d", a.C.FullPath(), a.User.Uid)); ok {
|
|
|
return a.ReturnPublicErrorResponse(a.Translate("LLLP"))
|
|
|
} else {
|
|
|
LockPool.Store(fmt.Sprintf("%s%d", a.C.FullPath(), a.User.Uid), true)
|
|
|
}
|
|
|
}
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) freeTrade() {
|
|
|
if a.InParams.IsForUpdate && a.User != nil {
|
|
|
LockPool.Delete(fmt.Sprintf("%s%d", a.C.FullPath(), a.User.Uid))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) saveLog() {
|
|
|
|
|
|
defer func() {
|
|
|
err := recover()
|
|
|
if err != nil {
|
|
|
buf := make([]byte, 1<<16)
|
|
|
runtime.Stack(buf, true)
|
|
|
e := reflect.ValueOf(err)
|
|
|
logger.ErrorLogger.Errorln(e.String())
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
//logger.AccessLogger.Warnln(a.Error, a.InParams.IsSkipErrorSaveLog)
|
|
|
|
|
|
if a.Log != nil && a.Log.Uid > 0 &&
|
|
|
(a.Error == nil || a.InParams.IsSkipErrorSaveLog) {
|
|
|
// 如果是super操作也记录
|
|
|
if a.Log.Name == "super" && a.Log.UserType == "1" {
|
|
|
a.Log.IsSuper = "1"
|
|
|
a.Log.Ip = ""
|
|
|
}
|
|
|
a.Log.A1 = cache.GetIpAddress(a.Log.Ip)
|
|
|
|
|
|
if a.Error != nil {
|
|
|
a.Log.Event = fmt.Sprintf("%s(失败)", a.Log.Event)
|
|
|
}
|
|
|
|
|
|
if err := rds.DB.Create(a.Log).Error; err != nil {
|
|
|
logger.ErrorLogger.Errorln(err.Error())
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) getLangByAppRequest() {
|
|
|
|
|
|
lan := a.C.Request.Header.Get("Language")
|
|
|
|
|
|
languageCode := ""
|
|
|
countryCode := ""
|
|
|
if len(strings.Split(lan, "_")) > 1 {
|
|
|
languageCode = strings.Split(lan, "_")[0]
|
|
|
countryCode = strings.Split(lan, "_")[1]
|
|
|
}
|
|
|
|
|
|
row := ""
|
|
|
|
|
|
tmpLanguageCodes := make([]model.SysLanguage, 0)
|
|
|
for _, v := range cache.Global.Caches.Language.List {
|
|
|
if v.LanguageCode == languageCode {
|
|
|
tmpLanguageCodes = append(tmpLanguageCodes, v)
|
|
|
}
|
|
|
}
|
|
|
isFind := false
|
|
|
for _, v := range tmpLanguageCodes {
|
|
|
if v.CountryCode == countryCode {
|
|
|
isFind = true
|
|
|
row = fmt.Sprintf("%s_%s", v.LanguageCode, v.CountryCode)
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
if !isFind && len(tmpLanguageCodes) > 0 {
|
|
|
row = fmt.Sprintf("%s_%s", tmpLanguageCodes[0].LanguageCode, tmpLanguageCodes[0].CountryCode)
|
|
|
}
|
|
|
|
|
|
if len(row) <= 0 {
|
|
|
row = cache.Global.Caches.Language.DefaultLanguage
|
|
|
}
|
|
|
|
|
|
if len(row) <= 0 {
|
|
|
row = "en_US"
|
|
|
}
|
|
|
a.Lang = row
|
|
|
}
|
|
|
|
|
|
func (a *ApiBase) versionHander() error {
|
|
|
|
|
|
appVersion := a.C.Request.Header.Get("appversion")
|
|
|
{
|
|
|
|
|
|
var version *model.Version
|
|
|
|
|
|
if a.Site == "h5Pc" {
|
|
|
version = cache.Global.Caches.Version.Get("2")
|
|
|
} else if a.Site == "h5App" {
|
|
|
version = cache.Global.Caches.Version.Get("1")
|
|
|
} else if a.Site == "h5Admin" {
|
|
|
version = cache.Global.Caches.Version.Get("0")
|
|
|
}
|
|
|
|
|
|
if version != nil && version.Id > 0 {
|
|
|
if len(appVersion) > 0 {
|
|
|
|
|
|
requestVersion, err := strconv.ParseInt(appVersion, 10, 64)
|
|
|
if err != nil {
|
|
|
logger.AccessLogger.Errorln("requestVersion version error", appVersion)
|
|
|
return nil
|
|
|
}
|
|
|
currVersion, err := strconv.ParseInt(version.Version, 10, 64)
|
|
|
if err != nil {
|
|
|
logger.AccessLogger.Errorln("currVersion version error", version.Version)
|
|
|
return nil
|
|
|
}
|
|
|
if currVersion > requestVersion && version.Force == "0" {
|
|
|
return a.ReturnErrorResponse(920, a.Translate("versionUpdateing"))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// 加密
|
|
|
func EncryptToken(uid int64) string {
|
|
|
|
|
|
return url.QueryEscape(crypto.FromString(fmt.Sprintf("%d,%d", uid, utils.Time2StampSecond()+24*60*60)).
|
|
|
SetKey("dfertf12dfertf12").
|
|
|
SetIv("dfertf12dfertf12").
|
|
|
Aes().
|
|
|
CBC().
|
|
|
PKCS7Padding().
|
|
|
Encrypt().
|
|
|
ToBase64String())
|
|
|
}
|
|
|
|
|
|
func DecryptToken(token string) (string, bool) {
|
|
|
token, _ = url.QueryUnescape(token)
|
|
|
|
|
|
cyptde := crypto.
|
|
|
FromBase64String(token).
|
|
|
SetKey("dfertf12dfertf12").
|
|
|
SetIv("dfertf12dfertf12").
|
|
|
Aes().
|
|
|
CBC().
|
|
|
PKCS7Padding().
|
|
|
Decrypt().
|
|
|
ToString()
|
|
|
if len(cyptde) <= 0 {
|
|
|
return "", false
|
|
|
}
|
|
|
return cyptde, true
|
|
|
}
|