github.com/database64128/shadowsocks-go@v1.7.0/api/api.go (about) 1 package api 2 3 import ( 4 "context" 5 "errors" 6 7 v1 "github.com/database64128/shadowsocks-go/api/v1" 8 "github.com/database64128/shadowsocks-go/jsonhelper" 9 "github.com/gofiber/contrib/fiberzap" 10 "github.com/gofiber/fiber/v2" 11 "github.com/gofiber/fiber/v2/middleware/etag" 12 "go.uber.org/zap" 13 ) 14 15 // Config stores the configuration for the RESTful API. 16 type Config struct { 17 Enabled bool `json:"enabled"` 18 19 // Reverse proxy 20 EnableTrustedProxyCheck bool `json:"enableTrustedProxyCheck"` 21 TrustedProxies []string `json:"trustedProxies"` 22 ProxyHeader string `json:"proxyHeader"` 23 24 // Listen 25 Listen string `json:"listen"` 26 CertFile string `json:"certFile"` 27 KeyFile string `json:"keyFile"` 28 ClientCertFile string `json:"clientCertFile"` 29 30 // Misc 31 SecretPath string `json:"secretPath"` 32 FiberConfigPath string `json:"fiberConfigPath"` 33 } 34 35 // Server returns a new API server from the config. 36 func (c *Config) Server(logger *zap.Logger) (*Server, *v1.ServerManager, error) { 37 if !c.Enabled { 38 return nil, nil, nil 39 } 40 41 fc := fiber.Config{ 42 ProxyHeader: c.ProxyHeader, 43 DisableStartupMessage: true, 44 Network: "tcp", 45 EnableTrustedProxyCheck: c.EnableTrustedProxyCheck, 46 TrustedProxies: c.TrustedProxies, 47 } 48 49 if c.FiberConfigPath != "" { 50 if err := jsonhelper.LoadAndDecodeDisallowUnknownFields(c.FiberConfigPath, &fc); err != nil { 51 return nil, nil, err 52 } 53 } 54 55 app := fiber.New(fc) 56 57 app.Use(etag.New()) 58 59 app.Use(fiberzap.New(fiberzap.Config{ 60 Logger: logger, 61 Fields: []string{"latency", "status", "method", "url", "ip"}, 62 })) 63 64 var router fiber.Router = app 65 if c.SecretPath != "" { 66 router = app.Group(c.SecretPath) 67 } 68 69 sm := v1.Routes(router) 70 71 return &Server{ 72 logger: logger, 73 app: app, 74 listen: c.Listen, 75 certFile: c.CertFile, 76 keyFile: c.KeyFile, 77 clientCertFile: c.ClientCertFile, 78 }, sm, nil 79 } 80 81 // Server is the RESTful API server. 82 type Server struct { 83 logger *zap.Logger 84 app *fiber.App 85 listen string 86 certFile string 87 keyFile string 88 clientCertFile string 89 } 90 91 // String implements the service.Service String method. 92 func (s *Server) String() string { 93 return "API server" 94 } 95 96 // Start starts the API server. 97 func (s *Server) Start() error { 98 go func() { 99 var err error 100 switch { 101 case s.clientCertFile != "": 102 err = s.app.ListenMutualTLS(s.listen, s.certFile, s.keyFile, s.clientCertFile) 103 case s.certFile != "": 104 err = s.app.ListenTLS(s.listen, s.certFile, s.keyFile) 105 default: 106 err = s.app.Listen(s.listen) 107 } 108 if err != nil { 109 s.logger.Fatal("Failed to start API server", zap.Error(err)) 110 } 111 }() 112 return nil 113 } 114 115 // Stop stops the API server. 116 func (s *Server) Stop() error { 117 if err := s.app.ShutdownWithTimeout(0); err != nil { 118 if errors.Is(err, context.DeadlineExceeded) { 119 return nil 120 } 121 return err 122 } 123 return nil 124 }