1 Star 0 Fork 41

甘欣亮 / lessgo

forked from andeyalee / lessgo 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
apihandler.go 5.57 KB
一键复制 编辑 原始数据 按行查看 历史
package lessgo
import (
"reflect"
"runtime"
"sort"
"strings"
"sync"
"github.com/henrylee2cn/lessgo/utils"
)
type (
ApiHandler struct {
Desc string // (可选)本操作的描述
Method string // (必填)请求方法,"*"表示除"WS"外全部方法,多方法写法:"GET|POST"或"GET POST",冲突时优先级WS>GET>*
Params []Param // (必填)参数说明列表(应该只声明当前中间件用到的参数),path参数类型的先后顺序与url中保持一致
HTTP200 []Result // (可选)HTTP Status Code 为200时的响应结果
Handler func(*Context) error // (必填)操作
id string // 操作的唯一标识符
methods []string // 真实的请求方法列表
suffix string // 路由节点的url参数后缀
inited bool // 标记是否已经初始化过
lock sync.Mutex
}
Param struct {
Name string // (必填)参数名
In string // (必填)参数出现位置
Required bool // (必填)是否必填
Model interface{} // (必填)参数值,API文档中依此推断参数值类型,同时作为默认值,当为nil时表示file文件上传
Desc string // (可选)参数描述
}
Result struct {
Code int `json:"code"` // (必填)返回结果码
Info interface{} `json:"info,omitempty"` // (可选)返回结果格式参考或描述
// Header interface{} // (可选)返回结果头部信息
}
)
/*
* 关于参数的说明
* 一、数据结构主要用于固定格式的服务器响应结构,适用于多个接口可能返回相同的数据结构,编辑保存后相关所有的引用都会变更。
* 支持的数据类型说明如下:
* 1、string:字符串类型
* 2、array:数组类型,子项只能是支持的数据类型中的一种,不能添加多个
* 3、object:对象类型,只支持一级属性,不支持嵌套,嵌套可以通过在属性中引入ref类型的对象或自定义数据格式
* 4、int:短整型
* 5、long:长整型
* 6、float:浮点型
* 7、double:浮点型
* 8、decimal:精确到比较高的浮点型
* 9、ref:引用类型,即引用定义好的数据结构
* 10、file:文件(Param.Model==nil)
*
* 二、参数位置
* body:http请求body
* cookie:本地cookie
* formData:表单参数
* header:http请求header
* path:http请求url,如getInfo/{userId}
* query:http请求拼接,如getInfo?userId={userId}
* 三、参数类型
* 自定义:目前仅支持自定义json格式,仅当"参数位置"为“body"有效
*/
var (
apiHandlerMap = map[string]*ApiHandler{}
apiHandlerLock sync.RWMutex
)
func NilApiHandler(desc string) *ApiHandler {
a := &ApiHandler{
Desc: desc,
}
a.initId()
a.inited = true
if getApiHandler(a.id) != nil {
return apiHandlerMap[a.id]
}
apiHandlerLock.Lock()
defer apiHandlerLock.Unlock()
apiHandlerMap[a.id] = a
return a
}
// 注册操作
func (a ApiHandler) Reg() *ApiHandler {
return a.init()
}
// 初始化并保存在全局唯一的操作列表中
func (a *ApiHandler) init() *ApiHandler {
a.lock.Lock()
defer a.lock.Unlock()
if a.inited {
return getApiHandler(a.id)
}
a.initMethod()
a.initParamsAndSuffix()
a.initId()
a.inited = true
if h := getApiHandler(a.id); h != nil {
return h
}
setApiHandler(a)
return a
}
// 虚拟操作的id
func (a *ApiHandler) Id() string {
return a.id
}
// // 操作的url前缀
// func (a *ApiHandler) Suffix() string {
// return a.suffix
// }
// 真实的请求方法列表(自动转换: "WS"->"GET", "*"->methods)
func (a *ApiHandler) Methods() []string {
return a.methods
}
func getApiHandler(id string) *ApiHandler {
apiHandlerLock.RLock()
defer apiHandlerLock.RUnlock()
return apiHandlerMap[id]
}
func setApiHandler(vh *ApiHandler) {
apiHandlerLock.Lock()
defer apiHandlerLock.Unlock()
apiHandlerMap[vh.id] = vh
for i, vh2 := range lessgo.apiHandlers {
if vh.Id() < vh2.Id() {
list := make([]*ApiHandler, len(lessgo.apiHandlers)+1)
copy(list, lessgo.apiHandlers[:i])
list[i] = vh
copy(list[i+1:], lessgo.apiHandlers[i:])
lessgo.apiHandlers = list
return
}
}
lessgo.apiHandlers = append(lessgo.apiHandlers, vh)
}
func (a *ApiHandler) initParamsAndSuffix() {
a.suffix = ""
for i, count := 0, len(a.Params); i < count; i++ {
switch a.Params[i].In {
case "path":
a.Params[i].Required = true //path参数不可缺省
a.suffix += "/:" + a.Params[i].Name //path参数作为url后缀
}
}
}
func (a *ApiHandler) initMethod() {
defer func() {
sort.Strings(a.methods) //方法排序,保证一致性
a.Method = strings.Join(a.methods, "|") //格式化,保证一致性
}()
a.methods = []string{}
a.Method = strings.ToUpper(a.Method)
// 检查websocket方法,若存在则不允许GET方法存在
if strings.Contains(a.Method, WS) {
a.Method = strings.Replace(a.Method, GET, "", -1)
a.methods = append(a.methods, WS)
}
// 遍历标准方法
for _, method := range methods {
if strings.Contains(a.Method, method) {
a.methods = append(a.methods, method)
}
}
// 当只含有 * 时表示除WS外任意方法
if len(a.methods) == 0 {
if strings.Contains(a.Method, ANY) {
a.methods = methods[:]
} else {
Log.Fatal("ApiHandler \"%v\"'s method can't be %v. ", a.Desc, a.Method)
}
}
}
func (a *ApiHandler) initId() {
add := "[" + a.suffix + "]" + "[" + a.Desc + "]" + "[" + a.Method + "]"
v := reflect.ValueOf(a.Handler)
t := v.Type()
if t.Kind() == reflect.Func {
a.id = runtime.FuncForPC(v.Pointer()).Name() + add
} else {
a.id = t.String() + add
}
a.id = utils.MakeHash(a.id)
}
Go
1
https://gitee.com/ganxinliang/lessgo.git
git@gitee.com:ganxinliang/lessgo.git
ganxinliang
lessgo
lessgo
master

搜索帮助