package web import ( "database/sql" "fmt" "log" "sync" "time" "dyproxy/providers/db" "github.com/fsnotify/fsnotify" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/middleware/logger" "github.com/gofiber/fiber/v3/middleware/recover" "github.com/rogeecn/fabfile" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" ) var users map[string]string = map[string]string{ "rogeecn": "xixi@0202", } type Config struct { Version string Path string Static string } var config *Config func load(f string) error { viper.SetConfigFile(f) viper.SetConfigType("yaml") if err := viper.ReadInConfig(); err != nil { return err } if err := viper.Unmarshal(&config); err != nil { return err } viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { if e.Op != fsnotify.Write { return } if err := viper.Unmarshal(&config); err != nil { log.Println(err) } log.Printf("config changed: %+v", config) }) return nil } func ServeE(cmd *cobra.Command, args []string) error { logrus.SetLevel(logrus.WarnLevel) conf, err := cmd.Flags().GetString("config") if err != nil { return err } if err := load(conf); err != nil { return err } db, err := db.Connect(fabfile.MustFind("data.db")) if err != nil { return err } defer db.Close() return New( WithDB(db), WithLogger(), WithRecover(), WithRoutes(), WithPendingCleaner(), ).Serve(9090) } type Option func(*WebServer) func WithDB(db *sql.DB) Option { return func(p *WebServer) { p.db = db } } func WithLogger() Option { return func(s *WebServer) { s.engine.Use(logger.New()) } } // WithRecover func WithRecover() Option { return func(s *WebServer) { s.engine.Use(recover.New()) } } type WebServer struct { db *sql.DB engine *fiber.App local *time.Location pendingItems map[int32]time.Time listLock sync.RWMutex } func New(opts ...Option) *WebServer { cstSh, _ := time.LoadLocation("Asia/Shanghai") s := &WebServer{ engine: fiber.New(), local: cstSh, } for _, opt := range opts { opt(s) } return s } // run func (p *WebServer) Serve(port uint) error { log.Printf("server start serve at: :%d", port) return p.engine.Listen(fmt.Sprintf(":%d", port)) } func WithPendingCleaner() Option { return func(s *WebServer) { if s.pendingItems == nil { s.pendingItems = make(map[int32]time.Time) } go func() { for range time.NewTicker(time.Minute * 1).C { s.listLock.Lock() for k, v := range s.pendingItems { if time.Since(v) > time.Minute*2 { delete(s.pendingItems, k) } } s.listLock.Unlock() } }() } }