service.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. package service
  2. import (
  3. "fmt"
  4. "github.com/gin-contrib/static"
  5. "github.com/gin-gonic/gin"
  6. "github.com/yddeng/utils/task"
  7. "net/http"
  8. "reflect"
  9. "strings"
  10. "sync"
  11. "time"
  12. "github.com/swaggo/gin-swagger"
  13. ginSwaggerFiles "github.com/swaggo/files"
  14. "filecloud/docs"
  15. "filecloud/internal/handler"
  16. )
  17. var (
  18. app *gin.Engine
  19. taskQueue *task.TaskPool
  20. )
  21. func Launch() {
  22. taskQueue = task.NewTaskPool(1, 1024)
  23. // 初始化任务队列
  24. logger.Info("Task queue initialized")
  25. // 初始化 Swagger 信息
  26. docs.SwaggerInfo.Title = "FileCloud API"
  27. docs.SwaggerInfo.Description = "FileCloud API documentation"
  28. docs.SwaggerInfo.Version = "1.0"
  29. docs.SwaggerInfo.BasePath = "/api"
  30. docs.SwaggerInfo.Host = config.WebAddr
  31. app = gin.New()
  32. app.Use(gin.Logger(), gin.Recovery())
  33. // 跨域
  34. app.Use(func(ctx *gin.Context) {
  35. ctx.Header("Access-Control-Allow-Origin", "*")
  36. ctx.Header("Access-Control-Allow-Headers", "*")
  37. ctx.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH")
  38. ctx.Header("Access-Control-Allow-Credentials", "true")
  39. ctx.Header("Access-Control-Expose-Headers", "*")
  40. if ctx.Request.Method == "OPTIONS" {
  41. // 处理浏览器的options请求时,返回200状态即可
  42. ctx.JSON(http.StatusOK, "")
  43. ctx.Abort()
  44. return
  45. }
  46. ctx.Next()
  47. })
  48. // if config.StaticFS {
  49. // // 静态资源浏览
  50. // app.StaticFS("/static", gin.Dir(config.FilePath, true))
  51. // }
  52. // 前端
  53. if config.WebIndex != "" {
  54. app.Use(static.Serve("/static", static.LocalFile(config.WebIndex, false)))
  55. app.NoRoute(func(ctx *gin.Context) {
  56. ctx.File(config.WebIndex + "/index.html")
  57. })
  58. } else {
  59. // 使用内置的 public 目录
  60. app.Use(static.Serve("/static", static.LocalFile("public", false)))
  61. app.NoRoute(func(ctx *gin.Context) {
  62. ctx.File("public/index.html")
  63. })
  64. }
  65. // 注册 Swagger 路由
  66. app.GET("/swagger/*any", ginSwagger.WrapHandler(ginSwaggerFiles.Handler))
  67. initHandler(app)
  68. port := strings.Split(config.WebAddr, ":")[1]
  69. webAddr := fmt.Sprintf("0.0.0.0:%s", port)
  70. // logger.Infof("start web service on %s", config.WebAddr)
  71. if err := app.Run(webAddr); err != nil {
  72. logger.Error(err)
  73. }
  74. }
  75. func Stop() {
  76. }
  77. // 应答结构
  78. type Result struct {
  79. Success bool `json:"success"`
  80. Message string `json:"message"`
  81. Data interface{} `json:"data"`
  82. }
  83. type WaitConn struct {
  84. code int
  85. ctx *gin.Context
  86. route string
  87. result Result
  88. done chan struct{}
  89. doneOnce sync.Once
  90. }
  91. func newWaitConn(ctx *gin.Context, route string) *WaitConn {
  92. return &WaitConn{
  93. ctx: ctx,
  94. code: http.StatusOK,
  95. route: route,
  96. done: make(chan struct{}),
  97. }
  98. }
  99. func (this *WaitConn) Done(code ...int) {
  100. this.doneOnce.Do(func() {
  101. if this.result.Message == "" {
  102. this.result.Success = true
  103. }
  104. if len(code) > 0 {
  105. this.code = code[0]
  106. }
  107. close(this.done)
  108. })
  109. }
  110. func (this *WaitConn) GetRoute() string {
  111. return this.route
  112. }
  113. func (this *WaitConn) Context() *gin.Context {
  114. return this.ctx
  115. }
  116. func (this *WaitConn) SetResult(message string, data interface{}) {
  117. this.result.Message = message
  118. this.result.Data = data
  119. }
  120. func (this *WaitConn) Wait() {
  121. <-this.done
  122. }
  123. type webTask func()
  124. func (t webTask) Do() {
  125. t()
  126. }
  127. func transBegin(ctx *gin.Context, fn interface{}, args ...reflect.Value) {
  128. val := reflect.ValueOf(fn)
  129. if val.Kind() != reflect.Func {
  130. panic("value not func")
  131. }
  132. typ := val.Type()
  133. if typ.NumIn() != len(args)+1 {
  134. panic("func argument error")
  135. }
  136. route := getCurrentRoute(ctx)
  137. wait := newWaitConn(ctx, route)
  138. if err := taskQueue.SubmitTask(webTask(func() {
  139. ok := checkToken(ctx, route)
  140. if !ok {
  141. wait.SetResult("Token验证失败", nil)
  142. wait.Done(401)
  143. return
  144. }
  145. val.Call(append([]reflect.Value{reflect.ValueOf(wait)}, args...))
  146. })); err != nil {
  147. wait.SetResult("访问人数过多", nil)
  148. wait.Done()
  149. }
  150. wait.Wait()
  151. ctx.JSON(wait.code, wait.result)
  152. }
  153. func getCurrentRoute(ctx *gin.Context) string {
  154. return ctx.FullPath()
  155. }
  156. func getJsonBody(ctx *gin.Context, inType reflect.Type) (inValue reflect.Value, err error) {
  157. if inType.Kind() == reflect.Ptr {
  158. inValue = reflect.New(inType.Elem())
  159. } else {
  160. inValue = reflect.New(inType)
  161. }
  162. if err = ctx.ShouldBindJSON(inValue.Interface()); err != nil {
  163. return
  164. }
  165. if inType.Kind() != reflect.Ptr {
  166. inValue = inValue.Elem()
  167. }
  168. return
  169. }
  170. func WarpHandle(fn interface{}) gin.HandlerFunc {
  171. val := reflect.ValueOf(fn)
  172. if val.Kind() != reflect.Func {
  173. panic("value not func")
  174. }
  175. typ := val.Type()
  176. switch typ.NumIn() {
  177. case 1: // func(done *WaitConn)
  178. return func(ctx *gin.Context) {
  179. transBegin(ctx, fn)
  180. }
  181. case 2: // func(done *WaitConn, req struct)
  182. return func(ctx *gin.Context) {
  183. inValue, err := getJsonBody(ctx, typ.In(1))
  184. if err != nil {
  185. ctx.JSON(http.StatusBadRequest, gin.H{
  186. "message": "Json unmarshal failed!",
  187. "error": err.Error(),
  188. })
  189. return
  190. }
  191. transBegin(ctx, fn, inValue)
  192. }
  193. default:
  194. panic("func symbol error")
  195. }
  196. }
  197. var (
  198. // 需要验证token的路由
  199. routeNeedToken = map[string]struct{}{
  200. "/file/list": {},
  201. "/file/mkdir": {},
  202. "/file/remove": {},
  203. "/file/rename": {},
  204. "/file/mvcp": {},
  205. "/file/download": {},
  206. "/upload/check": {},
  207. "/upload/upload": {},
  208. "/shared/create": {},
  209. "/shared/list": {},
  210. "/shared/cancel": {},
  211. }
  212. )
  213. func checkToken(ctx *gin.Context, route string) bool {
  214. if _, ok := routeNeedToken[route]; !ok {
  215. return true
  216. }
  217. tkn := ctx.GetHeader("Access-Token")
  218. if tkn == "" {
  219. return false
  220. }
  221. if accessTokenExpire.IsZero() || time.Now().After(accessTokenExpire) {
  222. accessToken = ""
  223. accessTokenExpire = time.Time{}
  224. return false
  225. }
  226. return tkn == accessToken
  227. }
  228. func initHandler(app *gin.Engine) {
  229. authHandle := new(authHandler)
  230. authGroup := app.Group("/auth")
  231. authGroup.POST("/login", WarpHandle(authHandle.login))
  232. taskHandle := new(taskHandler)
  233. fileGroup := app.Group("/file")
  234. fileGroup.GET("/task", WarpHandle(taskHandle.taskInfo))
  235. // 注册文件相关 API
  236. apiGroup := app.Group("/api/files")
  237. apiGroup.POST("", handler.UploadFile)
  238. apiGroup.GET("", handler.ListFiles)
  239. }