service.go 5.2 KB

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