235 lines
5.8 KiB
Go
235 lines
5.8 KiB
Go
package webapi
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto/tls"
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/golang-jwt/jwt/v4"
|
||
"io"
|
||
"net"
|
||
"net/http"
|
||
"net/url"
|
||
"strings"
|
||
"sync"
|
||
"sync/atomic"
|
||
"time"
|
||
|
||
"google.golang.org/protobuf/proto"
|
||
"mongo.games.com/goserver/core/logger"
|
||
)
|
||
|
||
const DEFAULT_TIMEOUT = time.Second * 30
|
||
|
||
var WebApiStats = new(sync.Map)
|
||
|
||
type ApiStats struct {
|
||
RunTimes int64 //执行次数
|
||
TotalRuningTime int64 //总执行时间
|
||
MaxRuningTime int64 //最长执行时间
|
||
TimeoutTimes int64 //执行超时次数
|
||
}
|
||
|
||
func DeviceOs(os string) string {
|
||
switch os {
|
||
case "ios":
|
||
return "2"
|
||
case "android":
|
||
return "1"
|
||
default:
|
||
return "0"
|
||
}
|
||
}
|
||
|
||
// API调用
|
||
// action 为需要调用的api, 例如 /api/Send/SendCode
|
||
// params 为需发送的参数
|
||
// protocol = https || http ||Post
|
||
func API_OP(url string, params url.Values) (map[string]interface{}, error) {
|
||
//res, err := http.PostForm("http://192.168.1.160:9090/api/Sms/SendCaptcha", params)
|
||
res, err := http.PostForm(Config.GameApiURL+url, params)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer res.Body.Close()
|
||
body, err := io.ReadAll(res.Body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
//println(url, " ret:", string(body[:]))
|
||
|
||
result := make(map[string]interface{})
|
||
json.Unmarshal(body, &result)
|
||
|
||
return result, nil
|
||
}
|
||
|
||
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// GET方式请求
|
||
func getRequest(appId, action string, params map[string]string, body proto.Message, protocol string, dura time.Duration) ([]byte, error) {
|
||
var client *http.Client
|
||
if strings.ToUpper(protocol) == "HTTPS" {
|
||
tr := &http.Transport{
|
||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||
}
|
||
client = &http.Client{Transport: tr}
|
||
} else {
|
||
client = &http.Client{}
|
||
}
|
||
data, err := proto.Marshal(body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
callUrl := MakeURL(appId, action, params, data)
|
||
logger.Logger.Tracef("getRequest url: %v params: %v request body: %v", callUrl, params, body)
|
||
req, err := http.NewRequest("GET", callUrl, nil)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var stats *ApiStats
|
||
if v, exist := WebApiStats.Load(action); exist {
|
||
stats = v.(*ApiStats)
|
||
} else {
|
||
stats = &ApiStats{}
|
||
WebApiStats.Store(action, stats)
|
||
}
|
||
|
||
var isTimeout bool
|
||
start := time.Now()
|
||
defer func() {
|
||
ps := int64(time.Now().Sub(start) / time.Millisecond)
|
||
if stats != nil {
|
||
if isTimeout {
|
||
atomic.AddInt64(&stats.TimeoutTimes, 1)
|
||
}
|
||
atomic.AddInt64(&stats.RunTimes, 1)
|
||
atomic.AddInt64(&stats.TotalRuningTime, ps)
|
||
if atomic.LoadInt64(&stats.MaxRuningTime) < ps {
|
||
atomic.StoreInt64(&stats.MaxRuningTime, ps)
|
||
}
|
||
}
|
||
}()
|
||
|
||
//设置超时
|
||
client.Timeout = dura
|
||
req.Close = true
|
||
resp, err := client.Do(req)
|
||
if err != nil {
|
||
if uerr, ok := err.(net.Error); ok {
|
||
isTimeout = uerr.Timeout()
|
||
}
|
||
return nil, err
|
||
}
|
||
defer resp.Body.Close()
|
||
if resp.StatusCode == 200 {
|
||
body, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return body, err
|
||
}
|
||
logger.Logger.Errorf("getRequest url:%v params:%v request body:%v code:%v", callUrl, params, body, resp.StatusCode)
|
||
return nil, fmt.Errorf("StatusCode:%d", resp.StatusCode)
|
||
}
|
||
|
||
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// POST方式请求
|
||
func postRequest(appId, action string, params map[string]string, body proto.Message, protocol string, dura time.Duration) ([]byte, error) {
|
||
var client *http.Client
|
||
if strings.ToUpper(protocol) == "HTTPS" {
|
||
tr := &http.Transport{
|
||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||
}
|
||
client = &http.Client{Transport: tr}
|
||
} else {
|
||
client = &http.Client{}
|
||
}
|
||
|
||
data, err := proto.Marshal(body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
callUrl := MakeURL(appId, action, params, data)
|
||
logger.Logger.Tracef("postRequest url: %v request body: %v", callUrl, body)
|
||
req, err := http.NewRequest("POST", callUrl, bytes.NewBuffer(data))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var stats *ApiStats
|
||
if v, exist := WebApiStats.Load(action); exist {
|
||
stats = v.(*ApiStats)
|
||
} else {
|
||
stats = &ApiStats{}
|
||
WebApiStats.Store(action, stats)
|
||
}
|
||
|
||
var isTimeout bool
|
||
start := time.Now()
|
||
defer func() {
|
||
ps := int64(time.Now().Sub(start) / time.Millisecond)
|
||
if stats != nil {
|
||
if isTimeout {
|
||
atomic.AddInt64(&stats.TimeoutTimes, 1)
|
||
}
|
||
atomic.AddInt64(&stats.RunTimes, 1)
|
||
atomic.AddInt64(&stats.TotalRuningTime, ps)
|
||
if atomic.LoadInt64(&stats.MaxRuningTime) < ps {
|
||
atomic.StoreInt64(&stats.MaxRuningTime, ps)
|
||
}
|
||
}
|
||
}()
|
||
|
||
//设置超时
|
||
client.Timeout = dura
|
||
req.Close = true
|
||
resp, err := client.Do(req)
|
||
if err != nil {
|
||
if uerr, ok := err.(net.Error); ok {
|
||
isTimeout = uerr.Timeout()
|
||
}
|
||
return nil, err
|
||
}
|
||
defer resp.Body.Close()
|
||
if resp.StatusCode == http.StatusOK {
|
||
body, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return body, err
|
||
}
|
||
logger.Logger.Errorf("postRequest url:%v request body: %v code: %v", callUrl, body, resp.StatusCode)
|
||
return nil, fmt.Errorf("StatusCode:%d", resp.StatusCode)
|
||
}
|
||
|
||
func Stats() map[string]ApiStats {
|
||
stats := make(map[string]ApiStats)
|
||
WebApiStats.Range(func(k, v interface{}) bool {
|
||
if s, ok := v.(*ApiStats); ok {
|
||
ss := *s //计数可能不精准
|
||
stats[k.(string)] = ss
|
||
}
|
||
return true
|
||
})
|
||
return stats
|
||
}
|
||
|
||
func ParseJwtWithClaims(key any, jwtStr string, options ...jwt.ParserOption) (jwt.Claims, error) {
|
||
mc := jwt.MapClaims{}
|
||
token, err := jwt.ParseWithClaims(jwtStr, mc, func(token *jwt.Token) (interface{}, error) {
|
||
return key, nil
|
||
}, options...)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 校验 Claims 对象是否有效,基于 exp(过期时间),nbf(不早于),iat(签发时间)等进行判断(如果有这些声明的话)。
|
||
if !token.Valid {
|
||
return nil, err
|
||
}
|
||
return token.Claims, nil
|
||
}
|