2026-05-08 07:27:06 +08:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"apigo.cc/go/log"
|
|
|
|
|
"errors"
|
|
|
|
|
"reflect"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
|
|
|
|
)
|
|
|
|
|
|
2026-05-08 22:41:01 +08:00
|
|
|
// Map 通用 Map 类型
|
|
|
|
|
type Map = map[string]any
|
|
|
|
|
|
|
|
|
|
// Arr 通用切片类型
|
|
|
|
|
type Arr = []any
|
|
|
|
|
|
2026-05-08 07:27:06 +08:00
|
|
|
// WebServiceOptions 服务注册选项
|
|
|
|
|
type WebServiceOptions struct {
|
|
|
|
|
Priority int
|
|
|
|
|
NoDoc bool
|
|
|
|
|
NoBody bool
|
|
|
|
|
NoLog200 bool
|
|
|
|
|
Host string
|
|
|
|
|
Ext Map
|
|
|
|
|
// Limiters []*Limiter // TODO: Integrate Limiter
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// webServiceType 内部存储的服务元数据
|
|
|
|
|
type webServiceType struct {
|
|
|
|
|
authLevel int
|
|
|
|
|
method string
|
|
|
|
|
path string
|
|
|
|
|
pathMatcher *regexp.Regexp
|
|
|
|
|
pathArgs []string
|
|
|
|
|
parmsNum int
|
|
|
|
|
inType reflect.Type
|
|
|
|
|
inIndex int
|
|
|
|
|
headersType reflect.Type
|
|
|
|
|
headersIndex int
|
|
|
|
|
requestIndex int
|
|
|
|
|
httpRequestIndex int
|
|
|
|
|
responseIndex int
|
|
|
|
|
responseWriterIndex int
|
|
|
|
|
loggerIndex int
|
|
|
|
|
callerIndex int
|
|
|
|
|
funcType reflect.Type
|
|
|
|
|
funcValue reflect.Value
|
|
|
|
|
options WebServiceOptions
|
|
|
|
|
data Map
|
|
|
|
|
memo string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
serverId string
|
|
|
|
|
serverAddr string
|
|
|
|
|
serverProto = "http"
|
|
|
|
|
serverProtoName = "http"
|
|
|
|
|
running = false
|
|
|
|
|
|
|
|
|
|
webServices = make(map[string]*webServiceType)
|
|
|
|
|
regexWebServices = make([]*webServiceType, 0)
|
|
|
|
|
webServicesLock = sync.RWMutex{}
|
|
|
|
|
webServicesList = make([]*webServiceType, 0)
|
|
|
|
|
|
|
|
|
|
websocketServices = make(map[string]*websocketServiceType)
|
|
|
|
|
websocketServicesLock = sync.RWMutex{}
|
2026-05-08 22:41:01 +08:00
|
|
|
websocketServicesList = make([]*webServiceType, 0)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
|
|
|
|
// 过滤器与拦截器
|
|
|
|
|
inFilters = make([]func(*map[string]any, *Request, *Response, *log.Logger) any, 0)
|
|
|
|
|
outFilters = make([]func(map[string]any, *Request, *Response, any, *log.Logger) (any, bool), 0)
|
|
|
|
|
errorHandle func(any, *Request, *Response) any
|
|
|
|
|
webAuthChecker func(int, *log.Logger, *string, map[string]any, *Request, *Response, *WebServiceOptions) (pass bool, object any)
|
|
|
|
|
webAuthCheckers = make(map[int]func(int, *log.Logger, *string, map[string]any, *Request, *Response, *WebServiceOptions) (pass bool, object any))
|
|
|
|
|
|
|
|
|
|
// 注入点
|
|
|
|
|
injectObjects = make(map[reflect.Type]any)
|
|
|
|
|
injectFunctions = make(map[reflect.Type]func() any)
|
|
|
|
|
|
|
|
|
|
usedDeviceIdKey string
|
|
|
|
|
usedClientAppKey string
|
|
|
|
|
usedSessionIdKey string
|
|
|
|
|
sessionIdMaker func() string
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// SetClientKeys 设置客户端标识相关的 Key 映射
|
|
|
|
|
func SetClientKeys(deviceIdKey, clientAppKey, sessionIdKey string) {
|
|
|
|
|
usedDeviceIdKey = deviceIdKey
|
|
|
|
|
usedClientAppKey = clientAppKey
|
|
|
|
|
usedSessionIdKey = sessionIdKey
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetSessionIdMaker 设置自定义会话 ID 生成器
|
|
|
|
|
func SetSessionIdMaker(maker func() string) {
|
|
|
|
|
sessionIdMaker = maker
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetAuthChecker 设置全局鉴权器
|
|
|
|
|
func SetAuthChecker(authChecker func(authLevel int, logger *log.Logger, url *string, in map[string]any, request *Request, response *Response, options *WebServiceOptions) (pass bool, object any)) {
|
|
|
|
|
webAuthChecker = authChecker
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddAuthChecker 为指定级别添加鉴权器
|
|
|
|
|
func AddAuthChecker(authLevels []int, authChecker func(authLevel int, logger *log.Logger, url *string, in map[string]any, request *Request, response *Response, options *WebServiceOptions) (pass bool, object any)) {
|
|
|
|
|
for _, al := range authLevels {
|
|
|
|
|
webAuthCheckers[al] = authChecker
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetInFilter 设置前置过滤器
|
|
|
|
|
func SetInFilter(filter func(in *map[string]any, request *Request, response *Response, logger *log.Logger) (out any)) {
|
|
|
|
|
inFilters = append(inFilters, filter)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetOutFilter 设置后置过滤器
|
|
|
|
|
func SetOutFilter(filter func(in map[string]any, request *Request, response *Response, out any, logger *log.Logger) (newOut any, isOver bool)) {
|
|
|
|
|
outFilters = append(outFilters, filter)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Register 注册服务(通用方法)
|
|
|
|
|
func Register(authLevel int, path string, serviceFunc any, memo string) {
|
|
|
|
|
Restful(authLevel, "", path, serviceFunc, memo)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restful 注册指定方法的服务
|
|
|
|
|
func Restful(authLevel int, method, path string, serviceFunc any, memo string) {
|
|
|
|
|
RestfulWithOptions(authLevel, method, path, serviceFunc, memo, WebServiceOptions{})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RestfulWithOptions 注册带选项的服务
|
|
|
|
|
func RestfulWithOptions(authLevel int, method, path string, serviceFunc any, memo string, options WebServiceOptions) {
|
|
|
|
|
s, err := makeCachedService(serviceFunc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// TODO: Log error properly when logger is ready
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.authLevel = authLevel
|
|
|
|
|
s.options = options
|
|
|
|
|
s.method = method
|
|
|
|
|
s.path = path
|
|
|
|
|
s.memo = memo
|
|
|
|
|
|
|
|
|
|
// 解析路径参数 {name}
|
|
|
|
|
finder, err := regexp.Compile("{(.*?)}")
|
|
|
|
|
if err == nil {
|
|
|
|
|
keyName := regexp.QuoteMeta(path)
|
|
|
|
|
finds := finder.FindAllStringSubmatch(path, 20)
|
|
|
|
|
for _, found := range finds {
|
|
|
|
|
keyName = strings.Replace(keyName, regexp.QuoteMeta(found[0]), "(.*?)", 1)
|
|
|
|
|
s.pathArgs = append(s.pathArgs, found[1])
|
|
|
|
|
}
|
|
|
|
|
if len(s.pathArgs) > 0 {
|
|
|
|
|
s.pathMatcher, _ = regexp.Compile("^" + keyName + "$")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
webServicesLock.Lock()
|
|
|
|
|
defer webServicesLock.Unlock()
|
|
|
|
|
|
|
|
|
|
// 简单路径匹配
|
|
|
|
|
if s.pathMatcher == nil {
|
|
|
|
|
webServices[method+path] = s // TODO: Include Host in key
|
|
|
|
|
} else {
|
|
|
|
|
regexWebServices = append(regexWebServices, s)
|
|
|
|
|
}
|
|
|
|
|
webServicesList = append(webServicesList, s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func makeCachedService(matchedService any) (*webServiceType, error) {
|
|
|
|
|
funcType := reflect.TypeOf(matchedService)
|
|
|
|
|
if funcType.Kind() != reflect.Func {
|
|
|
|
|
return nil, errors.New("handler must be a function")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
targetService := &webServiceType{
|
|
|
|
|
parmsNum: funcType.NumIn(),
|
|
|
|
|
inIndex: -1,
|
|
|
|
|
headersIndex: -1,
|
|
|
|
|
requestIndex: -1,
|
|
|
|
|
httpRequestIndex: -1,
|
|
|
|
|
responseIndex: -1,
|
|
|
|
|
responseWriterIndex: -1,
|
|
|
|
|
loggerIndex: -1,
|
|
|
|
|
callerIndex: -1,
|
|
|
|
|
funcType: funcType,
|
|
|
|
|
funcValue: reflect.ValueOf(matchedService),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < targetService.parmsNum; i++ {
|
|
|
|
|
t := funcType.In(i)
|
|
|
|
|
tStr := t.String()
|
|
|
|
|
switch tStr {
|
|
|
|
|
case "*service.Request":
|
|
|
|
|
targetService.requestIndex = i
|
|
|
|
|
case "*http.Request":
|
|
|
|
|
targetService.httpRequestIndex = i
|
|
|
|
|
case "*service.Response":
|
|
|
|
|
targetService.responseIndex = i
|
|
|
|
|
case "http.ResponseWriter":
|
|
|
|
|
targetService.responseWriterIndex = i
|
|
|
|
|
case "*log.Logger":
|
|
|
|
|
targetService.loggerIndex = i
|
|
|
|
|
default:
|
|
|
|
|
if t.Kind() == reflect.Struct || (t.Kind() == reflect.Map && t.Elem().Kind() == reflect.Interface) {
|
|
|
|
|
if targetService.inType == nil {
|
|
|
|
|
targetService.inIndex = i
|
|
|
|
|
targetService.inType = t
|
|
|
|
|
} else if targetService.headersType == nil {
|
|
|
|
|
targetService.headersIndex = i
|
|
|
|
|
targetService.headersType = t
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return targetService, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetInject 获取注入对象
|
|
|
|
|
func GetInject(dataType reflect.Type) any {
|
|
|
|
|
if obj, exists := injectObjects[dataType]; exists {
|
|
|
|
|
return obj
|
|
|
|
|
}
|
|
|
|
|
if factory, exists := injectFunctions[dataType]; exists {
|
|
|
|
|
return factory()
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|