123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- package service
- import (
- "fmt"
- "github.com/gin-contrib/static"
- "github.com/gin-gonic/gin"
- "github.com/yddeng/utils/task"
- "net/http"
- "reflect"
- "strings"
- "sync"
- "time"
- )
- var (
- app *gin.Engine
- taskQueue *task.TaskPool
- )
- func Launch() {
- taskQueue = task.NewTaskPool(1, 1024)
- app = gin.New()
- app.Use(gin.Logger(), gin.Recovery())
- // 跨域
- app.Use(func(ctx *gin.Context) {
- ctx.Header("Access-Control-Allow-Origin", "*")
- ctx.Header("Access-Control-Allow-Headers", "*")
- ctx.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH")
- ctx.Header("Access-Control-Allow-Credentials", "true")
- ctx.Header("Access-Control-Expose-Headers", "*")
- if ctx.Request.Method == "OPTIONS" {
- // 处理浏览器的options请求时,返回200状态即可
- ctx.JSON(http.StatusOK, "")
- ctx.Abort()
- return
- }
- ctx.Next()
- })
- // if config.StaticFS {
- // // 静态资源浏览
- // app.StaticFS("/static", gin.Dir(config.FilePath, true))
- // }
- // 前端
- if config.WebIndex != "" {
- app.Use(static.Serve("/", static.LocalFile(config.WebIndex, false)))
- app.NoRoute(func(ctx *gin.Context) {
- ctx.File(config.WebIndex + "/index.html")
- })
- }
- initHandler(app)
- port := strings.Split(config.WebAddr, ":")[1]
- webAddr := fmt.Sprintf("0.0.0.0:%s", port)
- logger.Infof("start web service on %s", config.WebAddr)
- if err := app.Run(webAddr); err != nil {
- logger.Error(err)
- }
- }
- func Stop() {
- }
- // 应答结构
- type Result struct {
- Success bool `json:"success"`
- Message string `json:"message"`
- Data interface{} `json:"data"`
- }
- type WaitConn struct {
- code int
- ctx *gin.Context
- route string
- result Result
- done chan struct{}
- doneOnce sync.Once
- }
- func newWaitConn(ctx *gin.Context, route string) *WaitConn {
- return &WaitConn{
- ctx: ctx,
- code: http.StatusOK,
- route: route,
- done: make(chan struct{}),
- }
- }
- func (this *WaitConn) Done(code ...int) {
- this.doneOnce.Do(func() {
- if this.result.Message == "" {
- this.result.Success = true
- }
- if len(code) > 0 {
- this.code = code[0]
- }
- close(this.done)
- })
- }
- func (this *WaitConn) GetRoute() string {
- return this.route
- }
- func (this *WaitConn) Context() *gin.Context {
- return this.ctx
- }
- func (this *WaitConn) SetResult(message string, data interface{}) {
- this.result.Message = message
- this.result.Data = data
- }
- func (this *WaitConn) Wait() {
- <-this.done
- }
- type webTask func()
- func (t webTask) Do() {
- t()
- }
- func transBegin(ctx *gin.Context, fn interface{}, args ...reflect.Value) {
- val := reflect.ValueOf(fn)
- if val.Kind() != reflect.Func {
- panic("value not func")
- }
- typ := val.Type()
- if typ.NumIn() != len(args)+1 {
- panic("func argument error")
- }
- route := getCurrentRoute(ctx)
- wait := newWaitConn(ctx, route)
- if err := taskQueue.SubmitTask(webTask(func() {
- ok := checkToken(ctx, route)
- if !ok {
- wait.SetResult("Token验证失败", nil)
- wait.Done(401)
- return
- }
- val.Call(append([]reflect.Value{reflect.ValueOf(wait)}, args...))
- })); err != nil {
- wait.SetResult("访问人数过多", nil)
- wait.Done()
- }
- wait.Wait()
- ctx.JSON(wait.code, wait.result)
- }
- func getCurrentRoute(ctx *gin.Context) string {
- return ctx.FullPath()
- }
- func getJsonBody(ctx *gin.Context, inType reflect.Type) (inValue reflect.Value, err error) {
- if inType.Kind() == reflect.Ptr {
- inValue = reflect.New(inType.Elem())
- } else {
- inValue = reflect.New(inType)
- }
- if err = ctx.ShouldBindJSON(inValue.Interface()); err != nil {
- return
- }
- if inType.Kind() != reflect.Ptr {
- inValue = inValue.Elem()
- }
- return
- }
- func WarpHandle(fn interface{}) gin.HandlerFunc {
- val := reflect.ValueOf(fn)
- if val.Kind() != reflect.Func {
- panic("value not func")
- }
- typ := val.Type()
- switch typ.NumIn() {
- case 1: // func(done *WaitConn)
- return func(ctx *gin.Context) {
- transBegin(ctx, fn)
- }
- case 2: // func(done *WaitConn, req struct)
- return func(ctx *gin.Context) {
- inValue, err := getJsonBody(ctx, typ.In(1))
- if err != nil {
- ctx.JSON(http.StatusBadRequest, gin.H{
- "message": "Json unmarshal failed!",
- "error": err.Error(),
- })
- return
- }
- transBegin(ctx, fn, inValue)
- }
- default:
- panic("func symbol error")
- }
- }
- var (
- // 需要验证token的路由
- routeNeedToken = map[string]struct{}{
- "/file/list": {},
- "/file/mkdir": {},
- "/file/remove": {},
- "/file/rename": {},
- "/file/mvcp": {},
- "/file/download": {},
- "/upload/check": {},
- "/upload/upload": {},
- "/shared/create": {},
- "/shared/list": {},
- "/shared/cancel": {},
- }
- )
- func checkToken(ctx *gin.Context, route string) bool {
- if _, ok := routeNeedToken[route]; !ok {
- return true
- }
- tkn := ctx.GetHeader("Access-Token")
- if tkn == "" {
- return false
- }
- if accessTokenExpire.IsZero() || time.Now().After(accessTokenExpire) {
- accessToken = ""
- accessTokenExpire = time.Time{}
- return false
- }
- return tkn == accessToken
- }
- func initHandler(app *gin.Engine) {
- authHandle := new(authHandler)
- authGroup := app.Group("/auth")
- authGroup.POST("/login", WarpHandle(authHandle.login))
- taskHandle := new(taskHandler)
- fileGroup := app.Group("/file")
- fileGroup.GET("/task", WarpHandle(taskHandle.taskInfo))
- }
|