service.go 5.1 KB

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