This commit is contained in:
2025-07-07 20:11:59 +08:00
parent ab0fdbc447
commit 06e3aa2eb3
2009 changed files with 193082 additions and 0 deletions

292
internal/cmd/cmd.go Normal file
View File

@ -0,0 +1,292 @@
package cmd
import (
"context"
"fmt"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"unsafe"
_ "unsafe"
"github.com/tiger1103/gfast/v3/api/v1/common/coryCommon"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/net/goai"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gres"
"github.com/gogf/gf/v2/os/gsession"
"github.com/gogf/gf/v2/os/gspath"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"github.com/tiger1103/gfast/v3/api/saft_hat"
"github.com/tiger1103/gfast/v3/api/video_hat"
"github.com/tiger1103/gfast/v3/internal/consts"
"github.com/tiger1103/gfast/v3/internal/router"
"github.com/tiger1103/gfast/v3/library/libValidate"
"github.com/tiger1103/gfast/v3/library/upload"
"github.com/tiger1103/gfast/v3/task"
)
var Main = gcmd.Command{
Name: "main",
Usage: "main",
Brief: "start http server",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
g.Log().SetFlags(glog.F_ASYNC | glog.F_TIME_DATE | glog.F_TIME_TIME | glog.F_FILE_LONG)
g.Log().Info(ctx, "GFast version:", consts.Version)
s := g.Server()
getwd, err := os.Getwd()
getwd = strings.ReplaceAll(getwd, "\\", "/")
//s.Group("/file", func(group *ghttp.RouterGroup) {
// group.Middleware(commonService.Middleware().MiddlewareCORS)
//})
s.AddStaticPath("/resource", getwd+"/resource") // 指向当前资源
s.AddStaticPath(coryCommon.GlobalFile, getwd+"/resource/public") // 指向pc
s.AddStaticPath("/wxfile", getwd+"/resource/public") // 指向小程序
s.Group("/", func(group *ghttp.RouterGroup) {
router.R.BindController(ctx, group)
})
//// zm/api/wxApplet/wxApplet/
//s.BindHookHandler("/zm/api/wxApplet/wxApplet/*", ghttp.HookBeforeServe, bandWxApp)
s.BindHookHandler("/file/*", ghttp.HookBeforeServe, reStaticFile)
// 重新配置swaggerUI静态页面--start--,若要使用原版gf字段swaggerUI请删除或注释此段
s.BindHookHandler(g.Cfg().MustGet(ctx, "server.swaggerPath").String()+"/*", ghttp.HookBeforeServe, func(r *ghttp.Request) {
content := gstr.ReplaceByMap(consts.SwaggerUITemplate, map[string]string{
`{SwaggerUIDocUrl}`: g.Cfg().MustGet(ctx, "server.openapiPath").String(),
`{SwaggerUIDocNamePlaceHolder}`: gstr.TrimRight(fmt.Sprintf(`//%s`, r.Host)),
})
r.Response.Write(content)
r.ExitAll()
})
// 重新配置swaggerUI静态页面--end--
enhanceOpenAPIDoc(s)
// 注册相关组件
register()
key := g.Cfg().MustGet(gctx.New(), "wx.key")
crt := g.Cfg().MustGet(gctx.New(), "wx.crt")
if len(key.String()) > 0 && len(crt.String()) > 0 {
s.EnableHTTPS(crt.String(), key.String())
}
s.Run()
return nil
},
}
type staticFile struct {
File *gres.File // Resource file object.
Path string // File path.
IsDir bool // Is directory.
}
type middleware struct {
served bool // Is the request served, which is used for checking response status 404.
request *Request // The request object pointer.
handlerIndex int // Index number for executing sequence purpose for handler items.
handlerMDIndex int // Index number for executing sequence purpose for bound middleware of handler item.
}
type Request struct {
*http.Request
Server *ghttp.Server // Server.
Cookie *ghttp.Cookie // Cookie.
Session *gsession.Session // Session.
Response *ghttp.Response // Corresponding Response of this request.
Router *ghttp.Router // Matched Router for this request. Note that it's not available in HOOK handler.
EnterTime int64 // Request starting time in milliseconds.
LeaveTime int64 // Request to end time in milliseconds.
Middleware *middleware // Middleware manager.
StaticFile *staticFile // Static file object for static file serving.
// =================================================================================================================
// Private attributes for internal usage purpose.
// =================================================================================================================
handlers []*ghttp.HandlerItemParsed // All matched handlers containing handler, hook and middleware for this request.
serveHandler *ghttp.HandlerItemParsed // Real handler serving for this request, not hook or middleware.
handlerResponse interface{} // Handler response object for Request/Response handler.
hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
parsedQuery bool // A bool marking whether the GET parameters parsed.
parsedBody bool // A bool marking whether the request body parsed.
parsedForm bool // A bool marking whether request Form parsed for HTTP method PUT, POST, PATCH.
paramsMap map[string]interface{} // Custom parameters map.
routerMap map[string]string // Router parameters map, which might be nil if there are no router parameters.
queryMap map[string]interface{} // Query parameters map, which is nil if there's no query string.
formMap map[string]interface{} // Form parameters map, which is nil if there's no form of data from the client.
bodyMap map[string]interface{} // Body parameters map, which might be nil if their nobody content.
error error // Current executing error of the request.
exitAll bool // A bool marking whether current request is exited.
parsedHost string // The parsed host name for current host used by GetHost function.
clientIp string // The parsed client ip for current host used by GetClientIp function.
bodyContent []byte // Request body content.
isFileRequest bool // A bool marking whether current request is file serving.
viewObject *gview.View // Custom template view engine object for this response.
viewParams gview.Params // Custom template view variables for this response.
originUrlPath string // Original URL path that passed from client.
}
type staticPathItem struct {
Prefix string
Path string
}
//// bandWxApp 禁止访问小程序
//func bandWxApp(r *ghttp.Request) {
// // 如果不为 /zm/api/wxApplet/wxApplet/sysUserProjectRelevancy/list
// if r.URL.Path != "/zm/api/wxApplet/wxApplet/sysUserProjectRelevancy/list" {
// r.Response.WriteJsonExit(g.Map{"code": 403, "msg": "禁止访问"})
// }
//}
// staticFile 重赋值中间件
func reStaticFile(r *ghttp.Request) {
isURLEncoded := func(s string) bool {
// 如果 s 为空,直接返回 false
if s == "" {
return false
}
_, err := url.QueryUnescape(s)
return err == nil
}
if !isURLEncoded(r.URL.RawPath) {
return
}
// 解码 URL
r.URL.Path, _ = url.QueryUnescape(r.URL.RawPath)
fileRequestField := reflect.ValueOf(r).Elem().FieldByName("isFileRequest")
reflect.NewAt(fileRequestField.Type(), unsafe.Pointer(fileRequestField.UnsafeAddr())).Elem().Set(reflect.ValueOf(true))
configField := reflect.ValueOf(r.Server)
staticPathList := []staticPathItem{}
staticPaths := configField.Elem().FieldByName("config").FieldByName("StaticPaths")
for i := range make([]struct{}, staticPaths.Len()) {
prefix := staticPaths.Index(i).FieldByName("Prefix").String()
path := staticPaths.Index(i).FieldByName("Path").String()
staticPathList = append(staticPathList, staticPathItem{
Prefix: prefix,
Path: path,
})
}
indexFileList := []string{}
IndexFiles := configField.Elem().FieldByName("config").FieldByName("IndexFiles")
for i := range make([]struct{}, IndexFiles.Len()) {
indexFileList = append(indexFileList, IndexFiles.Index(i).String())
}
SearchPathsList := []string{}
SearchPaths := configField.Elem().FieldByName("config").FieldByName("SearchPaths")
for i := range make([]struct{}, SearchPaths.Len()) {
SearchPathsList = append(SearchPathsList, SearchPaths.Index(i).String())
}
(*Request)(unsafe.Pointer(r)).StaticFile = searchStaticFile(r.URL.Path, staticPathList, SearchPathsList, indexFileList)
}
func searchStaticFile(uri string, StaticPaths []staticPathItem, SearchPaths, indexFileList []string) *staticFile {
var (
file *gres.File
path string
dir bool
)
// Firstly search the StaticPaths mapping.
if len(StaticPaths) > 0 {
for _, item := range StaticPaths {
if len(uri) >= len(item.Prefix) && strings.EqualFold(item.Prefix, uri[0:len(item.Prefix)]) {
// To avoid case like: /static/style -> /static/style.css
if len(uri) > len(item.Prefix) && uri[len(item.Prefix)] != '/' {
continue
}
file = gres.GetWithIndex(item.Path+uri[len(item.Prefix):], indexFileList)
if file != nil {
return &staticFile{
File: file,
IsDir: file.FileInfo().IsDir(),
}
}
path, dir = gspath.Search(item.Path, uri[len(item.Prefix):], indexFileList...)
if path != "" {
return &staticFile{
Path: path,
IsDir: dir,
}
}
}
}
}
// Secondly search the root and searching paths.
if len(SearchPaths) > 0 {
for _, p := range SearchPaths {
file = gres.GetWithIndex(p+uri, indexFileList)
if file != nil {
return &staticFile{
File: file,
IsDir: file.FileInfo().IsDir(),
}
}
if path, dir = gspath.Search(p, uri, indexFileList...); path != "" {
return &staticFile{
Path: path,
IsDir: dir,
}
}
}
}
// Lastly search the resource manager.
if len(StaticPaths) == 0 && len(SearchPaths) == 0 {
if file = gres.GetWithIndex(uri, indexFileList); file != nil {
return &staticFile{
File: file,
IsDir: file.FileInfo().IsDir(),
}
}
}
return nil
}
// 相关组件注册
func register() {
// 注册上传组件
upload.Register()
// 注册自定义验证规则
libValidate.Register()
// 执行计划任务
task.Run()
go video_hat.WsConnection() // 连接视频安全帽平台
// go saft_hat.StartWs() // 开启安全帽 WS 推送端口8222
go saft_hat.HeartCheck() // 开启安全帽设备数据的心跳检测
}
func enhanceOpenAPIDoc(s *ghttp.Server) {
openapi := s.GetOpenApi()
openapi.Config.CommonResponse = ghttp.DefaultHandlerResponse{}
openapi.Config.CommonResponseDataField = `Data`
// API description.
openapi.Info = goai.Info{
Title: consts.OpenAPITitle,
Description: consts.OpenAPIDescription,
Contact: &goai.Contact{
Name: consts.OpenAPIContactName,
URL: consts.OpenAPIContactUrl,
},
}
}