Compare commits

...

3 Commits

Author SHA1 Message Date
xuthus5 e2f6f1ad3a
refactor: new json lib 2024-04-25 23:18:43 +08:00
xuthus5 0469c4d45a
feat: replace json lib to sonic 2024-04-20 02:00:06 +08:00
Young Xu 14f42cfded
reflect: renew ErrMsg 2024-04-07 20:39:41 +08:00
7 changed files with 231 additions and 328 deletions

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.21.5
// protoc v5.26.1
// source: core.proto
package coco
@ -25,11 +25,12 @@ type ErrMsg struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ErrCode int32 `protobuf:"varint,1,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"` // 错误码
ErrMsg string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"` // 错误信息
Hint string `protobuf:"bytes,3,opt,name=hint,proto3" json:"hint,omitempty"` // 日志ID
ErrCode int32 `protobuf:"varint,1,opt,name=err_code,json=errCode,proto3" json:"err_code,omitempty"` // 错误码
ErrMsg string `protobuf:"bytes,2,opt,name=err_msg,json=errMsg,proto3" json:"err_msg,omitempty"` // 错误信息
Hint string `protobuf:"bytes,3,opt,name=hint,proto3" json:"hint,omitempty"` // 请求标记
RequestId string `protobuf:"bytes,4,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` // 请求id
// @json: -
Autonomy bool `protobuf:"varint,4,opt,name=autonomy,proto3" json:"autonomy,omitempty"` //
Autonomy bool `protobuf:"varint,5,opt,name=autonomy,proto3" json:"autonomy,omitempty"` // 框架自动化
}
func (x *ErrMsg) Reset() {
@ -85,6 +86,13 @@ func (x *ErrMsg) GetHint() string {
return ""
}
func (x *ErrMsg) GetRequestId() string {
if x != nil {
return x.RequestId
}
return ""
}
func (x *ErrMsg) GetAutonomy() bool {
if x != nil {
return x.Autonomy
@ -96,14 +104,16 @@ var File_core_proto protoreflect.FileDescriptor
var file_core_proto_rawDesc = []byte{
0x0a, 0x0a, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x63, 0x6f,
0x72, 0x65, 0x22, 0x6c, 0x0a, 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x19, 0x0a, 0x08,
0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07,
0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f, 0x6d,
0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73, 0x67,
0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x68, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x3b, 0x63, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x63, 0x6f, 0x22, 0x8b, 0x01, 0x0a, 0x06, 0x45, 0x72, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x19, 0x0a,
0x08, 0x65, 0x72, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x07, 0x65, 0x72, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x72, 0x72, 0x5f,
0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x4d, 0x73,
0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x68, 0x69, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x79,
0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x3b, 0x63, 0x6f, 0x63, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
@ -121,7 +131,7 @@ func file_core_proto_rawDescGZIP() []byte {
var file_core_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_core_proto_goTypes = []interface{}{
(*ErrMsg)(nil), // 0: core.ErrMsg
(*ErrMsg)(nil), // 0: coco.ErrMsg
}
var file_core_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type

View File

@ -4,10 +4,12 @@ package coco;
option go_package = "./;coco";
message ErrMsg {
int32 err_code = 1; //
string err_msg = 2; //
string hint = 3; // ID
int32 err_code = 1; //
string err_msg = 2; //
string hint = 3; //
string request_id = 4; // id
// @json: -
bool autonomy = 4; //
bool autonomy = 5; //
}

View File

@ -1,47 +1,74 @@
package coco
import "fmt"
import (
"errors"
"fmt"
)
const UnknownError = "unknown"
const (
// ErrNil 正常
ErrNil = 0
// ErrSystemError 系统错误
ErrSystemError = -1
// ErrProcessPanic 服务PANIC
ErrProcessPanic = -10
)
// ErrorNil 正常
ErrorNil = 0
// ErrorInternalServer 系统错误
ErrorInternalServer = 500
// ErrorNotImplemented 方法没有实现
ErrorNotImplemented = 501
// ErrorBadGateway 网关错误
ErrorBadGateway = 502
// ErrorServiceUnavailable 服务不可用
ErrorServiceUnavailable = 503
// ErrorGatewayTimeout 网关超时
ErrorGatewayTimeout = 504
// ErrorBadRequest 请求参数无效
ErrorBadRequest = 400
// ErrorUnauthorized 未授权访问
ErrorUnauthorized = 401
// ErrorPaymentRequired 缺少参数
ErrorPaymentRequired = 402
// ErrorForbidden 禁止访问
ErrorForbidden = 403
// ErrorNotFound 找不到记录
ErrorNotFound = 404
// ErrorMethodNotAllowed 请求不被允许
ErrorMethodNotAllowed = 405
// ErrorNotAcceptable 不被接受的请求
ErrorNotAcceptable = 406
// ErrorProxyAuthenticationRequired 代理需要授权
ErrorProxyAuthenticationRequired = 407
// ErrorRequestTimeout 请求超时
ErrorRequestTimeout = 408
// ErrorConflict 资源冲突
ErrorConflict = 409
const (
// ErrInvalidArg 请求参数无效
ErrInvalidArg = 1001
// ErrRecordNotFound 找不到记录
ErrRecordNotFound = 1002
// ErrConnectTimeout 连接超时
ErrConnectTimeout = 1003
// ErrFreqLimit 频率限制 [业务级]
ErrFreqLimit = 1004
// ErrRequestBroken 请求熔断
ErrRequestBroken = 1005
// ErrRequestRateLimit 请求限流 [服务级]
ErrRequestRateLimit = 1006
// ErrParamEmpty 请求参数为空
ErrParamEmpty = 1007
// ErrorFreqLimit 路由频率限制 [业务级]
ErrorFreqLimit = 1004
// ErrorRequestBroken 请求熔断
ErrorRequestBroken = 1005
// ErrorRequestRateLimit 请求流控 [服务级]
ErrorRequestRateLimit = 1006
// ErrorParamEmpty 请求参数为空
ErrorParamEmpty = 1007
)
var (
errCodeMap = map[int32]string{
ErrNil: "ok",
ErrSystemError: "system error",
ErrProcessPanic: "process panic",
ErrInvalidArg: "invalid arg",
ErrRecordNotFound: "record not found",
ErrConnectTimeout: "connect timeout",
ErrFreqLimit: "request freq limit",
ErrRequestBroken: "request is broken",
ErrRequestRateLimit: "request rate is limited",
ErrParamEmpty: "request param is empty",
ErrorNil: "ok",
ErrorInternalServer: "internal server error",
ErrorNotImplemented: "method not implemented",
ErrorBadGateway: "bad gateway",
ErrorServiceUnavailable: "service unavailable",
ErrorGatewayTimeout: "gateway timeout",
ErrorBadRequest: "bad request",
ErrorUnauthorized: "unauthorized",
ErrorPaymentRequired: "payment required",
ErrorForbidden: "forbidden",
ErrorNotFound: "not found",
ErrorMethodNotAllowed: "method not allowed",
ErrorNotAcceptable: "not acceptable",
ErrorProxyAuthenticationRequired: "proxy authentication is required",
ErrorRequestTimeout: "request timeout",
ErrorConflict: "conflict",
}
)
@ -49,48 +76,42 @@ func (m *ErrMsg) Error() string {
return fmt.Sprintf("err_code: %d, err_msg: %s", m.ErrCode, m.ErrMsg)
}
func RegisterError(m map[int32]string) {
func RegisterErrorCode(m map[int32]string) {
for k, v := range m {
errCodeMap[k] = v
}
}
// GetErrMsg 基于错误码返回错误信息
func GetErrMsg(errCode int32) string {
if errCode == 0 {
return "success"
}
// GetErrMsgMsg 基于错误码返回错误信息
func GetErrMsgMsg(errCode int32) string {
msg, ok := errCodeMap[errCode]
if ok {
return msg
}
if errCode < 0 {
return "system error"
}
return UnknownError
}
// CreateError 基于错误码返回错误信息
func CreateError(errCode int32) *ErrMsg {
return &ErrMsg{ErrCode: errCode, ErrMsg: errCodeMap[errCode]}
// GetErrMsg 基于错误码返回错误信息
func GetErrMsg(errCode int32) *ErrMsg {
return &ErrMsg{ErrCode: errCode, ErrMsg: GetErrMsgMsg(errCode)}
}
// GetErrCode 获取错误码 默认1 业务错误
func GetErrCode(err error) int {
// GetErrMsgCode 获取错误码 默认1 业务错误
func GetErrMsgCode(err error) int {
if err == nil {
return 0
}
if p, ok := err.(*ErrMsg); ok {
var p *ErrMsg
if errors.As(err, &p) {
return int(p.ErrCode)
}
return 1
}
// CreateErrorWithMsg 自定义创建错误 如果错误码已提前注册 errMsg将失效
// CreateErrorWithMsg 自定义创建错误
func CreateErrorWithMsg(errCode int32, errMsg string) *ErrMsg {
return &ErrMsg{ErrCode: errCode, ErrMsg: errMsg, Autonomy: true}
}

36
go.mod
View File

@ -3,36 +3,36 @@ module gitter.top/coco/coco
go 1.20
require (
github.com/bytedance/sonic v1.11.5
github.com/gin-gonic/gin v1.9.1
github.com/go-playground/validator/v10 v10.15.5
github.com/gorilla/schema v1.2.0
github.com/json-iterator/go v1.1.12
github.com/pkg/errors v0.9.1
github.com/go-playground/validator/v10 v10.19.0
github.com/gorilla/schema v1.3.0
github.com/sirupsen/logrus v1.9.3
google.golang.org/protobuf v1.31.0
google.golang.org/protobuf v1.33.0
)
require (
github.com/bytedance/sonic v1.10.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.3 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.5.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -2,6 +2,7 @@ package coco
import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
@ -10,11 +11,10 @@ import (
"runtime/debug"
"strings"
json "github.com/bytedance/sonic"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/gorilla/schema"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@ -33,39 +33,56 @@ type Result struct {
// 只能通过NewRegister()进行实例化 否则会panic
type Register struct {
// GET参数解析器
queryDecoder *schema.Decoder
engine *gin.Engine
addr string
queryDecoder *schema.Decoder
engine *gin.Engine
addr string
defaultContentType string
paramsValidate bool
}
type RegisterOptions func(register *Register)
// WithGinMode set gin router mode
// WithGinMode 设置运行模式
func WithGinMode(mode string) RegisterOptions {
return func(register *Register) {
gin.SetMode(mode)
}
}
// WithRecovery returns a middleware that recovers from any panics and writes a 500 if there was one.
// WithRecovery 自动处理panic异常
func WithRecovery() RegisterOptions {
return func(register *Register) {
register.engine.Use(gin.Recovery())
}
}
// WithCors 设置跨域
func WithCors() RegisterOptions {
return func(register *Register) {
register.engine.Use(CorsFilter())
}
}
// WithListenAddress 设置监听地址
func WithListenAddress(addr string) RegisterOptions {
return func(register *Register) {
register.addr = addr
}
}
// WithDisableRequestParamsValidate 是否默认关闭请求参数校验
func WithDisableRequestParamsValidate() RegisterOptions {
return func(register *Register) {
register.paramsValidate = true
}
}
func WithDefaultContentType(ct string) RegisterOptions {
return func(register *Register) {
register.defaultContentType = ct
}
}
// NewRegister 实例化注册器
func NewRegister() *Register {
var register = &Register{queryDecoder: schema.NewDecoder()}
@ -226,7 +243,7 @@ func (r *Register) getCallFunc(rFunc, rGroup reflect.Value) (gin.HandlerFunc, er
// 第二返回参数是否是error
if returnType := typ.Out(1); returnType != reflect.TypeOf((*error)(nil)).Elem() {
return nil, errors.Errorf("method : %v , returns[1] %v not error",
return nil, fmt.Errorf("method : %v , returns[1] %v not error",
runtime.FuncForPC(rFunc.Pointer()).Name(), returnType.String())
}
@ -252,7 +269,7 @@ func (r *Register) getCallFunc(rFunc, rGroup reflect.Value) (gin.HandlerFunc, er
err := r.bindAndValidate(c, req.Interface())
if err != nil {
c.JSON(http.StatusOK, Result{
ErrCode: ErrInvalidArg,
ErrCode: ErrorBadRequest,
ErrMsg: err.Error(),
})
return
@ -260,66 +277,21 @@ func (r *Register) getCallFunc(rFunc, rGroup reflect.Value) (gin.HandlerFunc, er
var returnValues = rFunc.Call([]reflect.Value{rGroup, reflect.ValueOf(&Context{Context: c}), req})
// 设置缺省 Content-Type
if c.Writer.Header().Get("Content-Type") == "" {
c.Writer.Header().Set("Content-Type", "application/json")
}
// 重定向的情况
if c.Writer.Status() == http.StatusFound || c.Writer.Status() == http.StatusMovedPermanently {
if r.isStatusFoundOrMoved(c) {
return
}
// 传输文件直接下载的情况
if !strings.Contains(c.Writer.Header().Get("Content-Type"), "application/json") {
if !r.isApplicationJson(c) {
return
}
if returnValues != nil {
resp := returnValues[0].Interface()
rerr := returnValues[1].Interface()
// 设置缺省 Content-Type
r.setDefaultContentType(c)
if rerr == nil {
c.Writer.WriteHeader(http.StatusOK)
respData, _ := jsoniter.Marshal(Result{
ErrCode: ErrNil,
ErrMsg: "ok",
Data: resp,
})
_, _ = c.Writer.Write(respData)
return
}
var err error
var errCode int
var errMsg string
var isAutonomy bool
if reflect.TypeOf(rerr).String() == "*core.ErrMsg" {
e := rerr.(*ErrMsg)
if e.Autonomy {
err = e
errCode = int(e.ErrCode)
errMsg = e.ErrMsg
isAutonomy = true
}
}
if !isAutonomy {
err = rerr.(error)
errCode = GetErrCode(err)
errMsg = GetErrMsg(int32(errCode))
}
c.Writer.WriteHeader(http.StatusOK)
respData, _ := jsoniter.Marshal(Result{
ErrCode: errCode,
ErrMsg: errMsg,
Data: resp,
})
_, _ = c.Writer.Write(respData)
return
}
// 处理返回值
r.processReturnValue(c, returnValues)
}, nil
}
@ -332,6 +304,9 @@ func (r *Register) mergeRequestParam(a, b map[string]interface{}) map[string]int
// bindAndValidate 绑定并校验参数
func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
if !r.paramsValidate {
return nil
}
// 非 application/json 直接透传
if c.GetHeader("Content-Type") != "application/json" {
// 如果只有query有数据则获取query中的参数
@ -345,7 +320,7 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
return nil
}
bodyBytes, _ := io.ReadAll(c.Request.Body)
c.Request.Body.Close()
_ = c.Request.Body.Close()
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
// 如果只有query有数据则获取query中的参数
@ -358,7 +333,7 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
}
// 如果只有body中有数据获取body中的参数
if len(c.Request.URL.Query()) == 0 && len(bodyBytes) != 0 {
err := jsoniter.Unmarshal(bodyBytes, req)
err := json.Unmarshal(bodyBytes, req)
if err != nil {
logrus.Errorf("unmarshal body failed: %+v", err)
return err
@ -373,18 +348,18 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
return err
}
var bodyMap = make(map[string]interface{})
err = jsoniter.Unmarshal(bodyBytes, bodyMap)
err = json.Unmarshal(bodyBytes, bodyMap)
if err != nil {
logrus.Errorf("unmarshal body failed: %+v", err)
return err
}
mergeMap := r.mergeRequestParam(queryMap, bodyMap)
body, err := jsoniter.Marshal(mergeMap)
body, err := json.Marshal(mergeMap)
if err != nil {
logrus.Errorf("merge query and body failed: %v", err)
return err
}
if err := jsoniter.Unmarshal(body, req); err != nil {
if err := json.Unmarshal(body, req); err != nil {
logrus.Errorf("unmarshal query and body failed: %v", err)
return err
}
@ -404,7 +379,8 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
err := validate.Struct(req)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
var invalidValidationError *validator.InvalidValidationError
if errors.As(err, &invalidValidationError) {
logrus.Errorf("validate failed: %+v", err)
return err
}
@ -418,6 +394,56 @@ func (r *Register) bindAndValidate(c *gin.Context, req interface{}) error {
return nil
}
// processReturnValue 处理返回值
func (r *Register) processReturnValue(c *gin.Context, returnValues []reflect.Value) {
if len(returnValues) != 2 {
return
}
resp := returnValues[0].Interface()
rerr := returnValues[1].Interface()
if rerr == nil {
c.Writer.WriteHeader(http.StatusOK)
respData, _ := json.Marshal(Result{
ErrCode: ErrorNil,
ErrMsg: GetErrMsgMsg(ErrorNil),
Data: resp,
})
_, _ = c.Writer.Write(respData)
return
}
var err error
var errCode int
var errMsg string
var isAutonomy bool
if reflect.TypeOf(rerr).String() == "*core.ErrMsg" {
e := rerr.(*ErrMsg)
if e.Autonomy {
err = e
errCode = int(e.ErrCode)
errMsg = e.ErrMsg
isAutonomy = true
}
}
if !isAutonomy {
err = rerr.(error)
errCode = GetErrMsgCode(err)
errMsg = GetErrMsgMsg(int32(errCode))
}
c.Writer.WriteHeader(http.StatusOK)
respData, _ := json.Marshal(Result{
ErrCode: errCode,
ErrMsg: errMsg,
Data: resp,
})
_, _ = c.Writer.Write(respData)
return
}
// CorsFilter 跨域过滤器
func CorsFilter() gin.HandlerFunc {
return func(c *gin.Context) {
@ -444,3 +470,20 @@ func ResponseHtmlHeader() gin.HandlerFunc {
c.Writer.Header().Set("Content-Type", "text/html")
}
}
func (r *Register) setDefaultContentType(c *gin.Context) {
if r.defaultContentType == "" {
r.defaultContentType = "application/json"
}
if c.Writer.Header().Get("Content-Type") == "" {
c.Writer.Header().Set("Content-Type", r.defaultContentType)
}
}
func (r *Register) isApplicationJson(c *gin.Context) bool {
return c.Writer.Header().Get("Content-Type") == "application/json"
}
func (r *Register) isStatusFoundOrMoved(c *gin.Context) bool {
return c.Writer.Status() == http.StatusFound || c.Writer.Status() == http.StatusMovedPermanently
}

View File

@ -27,8 +27,9 @@ func TestRegister_getCallFunc(t *testing.T) {
func TestNewRegister(t *testing.T) {
var register = NewRegister()
register.DefaultRouter(WithListenAddress(""), WithGinMode(gin.ReleaseMode), WithCors(), WithRecovery())
register.PreRun(nil)
register.DefaultRouter(WithListenAddress("localhost:8080"), WithGinMode(gin.ReleaseMode), WithCors(), WithRecovery())
// register.PreRun(nil)
// protoc core/file_module.proto --coco_out=core --go_out=core
//reg.RegisterStruct(AutoGenXXXRouterMap, &XXX{})
register.Run()

View File

@ -1,174 +0,0 @@
package utils
import (
"fmt"
log "github.com/sirupsen/logrus"
"reflect"
"strings"
)
func ReflectGet(obj interface{}, path string, failHint *string) (res interface{}, success bool) {
setFailHint := func(hint string) {
if failHint != nil {
*failHint = hint
}
}
for obj != nil && path != "" {
v := reflect.ValueOf(obj)
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
setFailHint("not struct type")
break
}
var fieldName string
pos := strings.IndexByte(path, '.')
if pos < 0 {
fieldName = path
path = ""
} else {
fieldName = path[:pos]
path = path[pos+1:]
}
f := v.FieldByName(fieldName)
if !f.IsValid() {
setFailHint(fmt.Sprintf("%s not found", fieldName))
break
}
if path == "" {
res = f.Interface()
success = true
break
}
obj = f.Interface()
}
return
}
func ReflectGetInt(obj interface{}, path string, failHint *string) (res int, success bool) {
setFailHint := func(hint string) {
if failHint != nil {
*failHint = hint
}
}
var i interface{}
i, success = ReflectGet(obj, path, failHint)
if !success {
return
}
switch v := i.(type) {
case int:
res = v
success = true
case int32:
res = int(v)
success = true
default:
setFailHint(fmt.Sprintf("type not match: %s", reflect.TypeOf(i).String()))
}
return
}
func ReflectGetStr(obj interface{}, path string, failHint *string) (res string, success bool) {
setFailHint := func(hint string) {
if failHint != nil {
*failHint = hint
}
}
var i interface{}
i, success = ReflectGet(obj, path, failHint)
if !success {
return
}
switch v := i.(type) {
case string:
res = v
success = true
case []byte:
res = string(v)
success = true
default:
setFailHint(fmt.Sprintf("type not match: %s", reflect.TypeOf(i).String()))
}
return
}
func Interface2Int(i interface{}) int {
vo := reflect.ValueOf(i)
vk := vo.Kind()
switch vk {
case reflect.Uint, reflect.Uint32, reflect.Uint64, reflect.Uint8, reflect.Uint16:
return int(vo.Uint())
}
return int(vo.Int())
}
func Interface2String(i interface{}) string {
vo := reflect.ValueOf(i)
if vo.Kind() != reflect.String {
log.Infof("expected string type, but got %v", vo.Type())
panic("expected string type")
}
return vo.String()
}
func EnsureIsSliceOrArray(obj interface{}) (res reflect.Value) {
vo := reflect.ValueOf(obj)
for vo.Kind() == reflect.Ptr || vo.Kind() == reflect.Interface {
vo = vo.Elem()
}
k := vo.Kind()
if k != reflect.Slice && k != reflect.Array {
panic(fmt.Sprintf("obj required slice or array type, but got %v", vo.Type()))
}
res = vo
return
}
func EnsureIsMapType(m reflect.Value, keyType, valType reflect.Type) {
if m.Kind() != reflect.Map {
panic(fmt.Sprintf("required map type, but got %v", m.Type()))
}
t := m.Type()
if t.Key() != keyType {
panic(fmt.Sprintf("map key type not equal, %v != %v", t.Key(), keyType))
}
if t.Elem() != valType {
panic(fmt.Sprintf("map val type not equal, %v != %v", t.Elem(), valType))
}
}
func ClearSlice(ptr interface{}) {
vo := reflect.ValueOf(ptr)
if vo.Kind() != reflect.Ptr {
panic("required ptr to slice type")
}
for vo.Kind() == reflect.Ptr {
vo = vo.Elem()
}
if vo.Kind() != reflect.Slice {
panic("required ptr to slice type")
}
vo.Set(reflect.MakeSlice(vo.Type(), 0, 0))
}
func GetSliceLen(i interface{}) int {
vo := reflect.ValueOf(i)
for vo.Kind() == reflect.Ptr {
vo = vo.Elem()
}
if vo.Kind() != reflect.Slice && vo.Kind() != reflect.Array {
panic("required slice or array type")
}
return vo.Len()
}