diff --git a/internal/mirc/auto/api/v1/site.go b/internal/mirc/auto/api/v1/web_core.go similarity index 93% rename from internal/mirc/auto/api/v1/site.go rename to internal/mirc/auto/api/v1/web_core.go index 22e9e826..5887e010 100644 --- a/internal/mirc/auto/api/v1/site.go +++ b/internal/mirc/auto/api/v1/web_core.go @@ -6,14 +6,26 @@ import ( "net/http" "github.com/alimy/mir/v3" - "github.com/gin-gonic/gin" + gin "github.com/gin-gonic/gin" ) +type LoginReq struct { + AgentInfo AgentInfo `json:"agent_info"` + Name string `json:"name"` + Passwd string `json:"passwd"` +} + type AgentInfo struct { Platform string `json:"platform"` UserAgent string `json:"user_agent"` } +type LoginResp struct { + UserInfo + ServerInfo ServerInfo `json:"server_info"` + JwtToken string `json:"jwt_token"` +} + type ServerInfo struct { ApiVer string `json:"api_ver"` } @@ -22,26 +34,14 @@ type UserInfo struct { Name string `json:"name"` } -type LoginReq struct { - AgentInfo AgentInfo `json:"agent_info"` - Name string `json:"name"` - Passwd string `json:"passwd"` -} - -type LoginResp struct { - UserInfo - ServerInfo ServerInfo `json:"server_info"` - JwtToken string `json:"jwt_token"` -} - type WebCore interface { // Chain provide handlers chain for gin Chain() gin.HandlersChain - Index(c *gin.Context) mir.Error - Articles(c *gin.Context) mir.Error - Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) Logout(c *gin.Context) mir.Error + Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) + Articles(c *gin.Context) mir.Error + Index(c *gin.Context) mir.Error mustEmbedUnimplementedWebCoreServant() } @@ -53,10 +53,10 @@ type WebCoreBinding interface { } type WebCoreRender interface { - RenderIndex(c *gin.Context, err mir.Error) - RenderArticles(c *gin.Context, err mir.Error) - RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) RenderLogout(c *gin.Context, err mir.Error) + RenderLogin(c *gin.Context, data *LoginResp, err mir.Error) + RenderArticles(c *gin.Context, err mir.Error) + RenderIndex(c *gin.Context, err mir.Error) mustEmbedUnimplementedWebCoreRender() } @@ -69,12 +69,10 @@ func RegisterWebCoreServant(e *gin.Engine, s WebCore, b WebCoreBinding, r WebCor router.Use(middlewares...) // register routes info to router - router.Handle("GET", "/index/", func(c *gin.Context) { - r.RenderIndex(c, s.Index(c)) - }) - router.Handle("GET", "/articles/:category/", func(c *gin.Context) { - r.RenderArticles(c, s.Articles(c)) + router.Handle("POST", "/user/logout/", func(c *gin.Context) { + r.RenderLogout(c, s.Logout(c)) }) + router.Handle("POST", "/user/login/", func(c *gin.Context) { req, err := b.BindLogin(c) if err != nil { @@ -83,33 +81,30 @@ func RegisterWebCoreServant(e *gin.Engine, s WebCore, b WebCoreBinding, r WebCor resp, err := s.Login(c, req) r.RenderLogin(c, resp, err) }) - router.Handle("POST", "/user/logout/", func(c *gin.Context) { - r.RenderLogout(c, s.Logout(c)) - }) -} -// UnimplementedWebCoreServant can be embedded to have forward compatible implementations. -type UnimplementedWebCoreServant struct{} + { + h := func(c *gin.Context) { + r.RenderArticles(c, s.Articles(c)) + } + router.Handle("HEAD", "/articles/:category/", h) + router.Handle("GET", "/articles/:category/", h) + } + + router.Handle("GET", "/index/", func(c *gin.Context) { + r.RenderIndex(c, s.Index(c)) + }) -// UnimplementedWebCoreBinding can be embedded to have forward compatible implementations. -type UnimplementedWebCoreBinding struct { - BindAny func(*gin.Context, any) mir.Error } -// UnimplementedWebCoreRender can be embedded to have forward compatible implementations. -type UnimplementedWebCoreRender struct { - RenderAny func(*gin.Context, any, mir.Error) +// UnimplementedWebCoreServant can be embedded to have forward compatible implementations. +type UnimplementedWebCoreServant struct { } func (UnimplementedWebCoreServant) Chain() gin.HandlersChain { return nil } -func (UnimplementedWebCoreServant) Index(c *gin.Context) mir.Error { - return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) -} - -func (UnimplementedWebCoreServant) Articles(c *gin.Context) mir.Error { +func (UnimplementedWebCoreServant) Logout(c *gin.Context) mir.Error { return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } @@ -117,25 +112,22 @@ func (UnimplementedWebCoreServant) Login(c *gin.Context, req *LoginReq) (*LoginR return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } -func (UnimplementedWebCoreServant) Logout(c *gin.Context) mir.Error { +func (UnimplementedWebCoreServant) Articles(c *gin.Context) mir.Error { return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } -func (UnimplementedWebCoreServant) mustEmbedUnimplementedWebCoreServant() {} - -func (b *UnimplementedWebCoreBinding) BindLogin(c *gin.Context) (*LoginReq, mir.Error) { - obj := new(LoginReq) - err := b.BindAny(c, obj) - return obj, err +func (UnimplementedWebCoreServant) Index(c *gin.Context) mir.Error { + return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) } -func (b *UnimplementedWebCoreBinding) mustEmbedUnimplementedWebCoreBinding() {} +func (UnimplementedWebCoreServant) mustEmbedUnimplementedWebCoreServant() {} -func (r *UnimplementedWebCoreRender) RenderIndex(c *gin.Context, err mir.Error) { - r.RenderAny(c, nil, err) +// UnimplementedWebCoreRender can be embedded to have forward compatible implementations. +type UnimplementedWebCoreRender struct { + RenderAny func(*gin.Context, any, mir.Error) } -func (r *UnimplementedWebCoreRender) RenderArticles(c *gin.Context, err mir.Error) { +func (r *UnimplementedWebCoreRender) RenderLogout(c *gin.Context, err mir.Error) { r.RenderAny(c, nil, err) } @@ -143,8 +135,25 @@ func (r *UnimplementedWebCoreRender) RenderLogin(c *gin.Context, data *LoginResp r.RenderAny(c, data, err) } -func (r *UnimplementedWebCoreRender) RenderLogout(c *gin.Context, err mir.Error) { +func (r *UnimplementedWebCoreRender) RenderArticles(c *gin.Context, err mir.Error) { + r.RenderAny(c, nil, err) +} + +func (r *UnimplementedWebCoreRender) RenderIndex(c *gin.Context, err mir.Error) { r.RenderAny(c, nil, err) } func (r *UnimplementedWebCoreRender) mustEmbedUnimplementedWebCoreRender() {} + +// UnimplementedWebCoreBinding can be embedded to have forward compatible implementations. +type UnimplementedWebCoreBinding struct { + BindAny func(*gin.Context, any) mir.Error +} + +func (b *UnimplementedWebCoreBinding) BindLogin(c *gin.Context) (*LoginReq, mir.Error) { + obj := new(LoginReq) + err := b.BindAny(c, obj) + return obj, err +} + +func (b *UnimplementedWebCoreBinding) mustEmbedUnimplementedWebCoreBinding() {} diff --git a/internal/mirc/main.go b/internal/mirc/main.go index 46de42d1..bf45791f 100644 --- a/internal/mirc/main.go +++ b/internal/mirc/main.go @@ -17,7 +17,7 @@ import ( func main() { log.Println("generate code start") opts := Options{ - RunMode(InSerialMode), + RunMode(InSerialDebugMode), GeneratorName(GeneratorGin), SinkPath("auto"), } diff --git a/internal/mirc/routes/v1/web_core.go b/internal/mirc/routes/v1/web_core.go index 565fb04a..83193986 100644 --- a/internal/mirc/routes/v1/web_core.go +++ b/internal/mirc/routes/v1/web_core.go @@ -38,7 +38,7 @@ type WebCore struct { Chain Chain `mir:"-"` Group Group `mir:"v1"` Index func(Get) `mir:"/index/"` - Articles func(Get) `mir:"/articles/:category/"` + Articles func(Get, Head) `mir:"/articles/:category/"` Login func(Post, LoginReq) LoginResp `mir:"/user/login/"` Logout func(Post) `mir:"/user/logout/"` } diff --git a/internal/servants/servants.go b/internal/servants/servants.go index 4f1f0bcd..9ae3d0a7 100644 --- a/internal/servants/servants.go +++ b/internal/servants/servants.go @@ -15,16 +15,12 @@ import ( // RegisterWebServants register all the servants to gin.Engine func RegisterWebServants(e *gin.Engine) { - // 按需注册 docs、静态资源 - { - docs.RegisterDocs(e) - statick.RegisterStatick(e) - } + docs.RegisterDocs(e) + statick.RegisterStatick(e) + + cfg.Be("LocalOSS", func() { + localoss.RouteLocalOSS(e) + }) web.RouteWeb(e) - { - cfg.Be("LocalOSS", func() { - localoss.RouteLocalOSS(e) - }) - } } diff --git a/internal/service/http_server.go b/internal/service/http_server.go new file mode 100644 index 00000000..4a8fdf3b --- /dev/null +++ b/internal/service/http_server.go @@ -0,0 +1,83 @@ +// Copyright 2022 ROC. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package service + +import ( + "context" + "net/http" + "sync" + + "github.com/gin-gonic/gin" +) + +var ( + httpServers = make(map[string]*httpServer) +) + +const ( + httpServerInitilized uint8 = iota + 1 + httpServerStarted + httpServerStoped +) + +// httpServer wraper for gin.engine and http.Server +type httpServer struct { + sync.RWMutex + + e *gin.Engine + server *http.Server + serverStatus uint8 +} + +func (s *httpServer) status() uint8 { + s.RLock() + defer s.RUnlock() + + return s.serverStatus +} + +func (s *httpServer) start() error { + s.Lock() + if s.serverStatus == httpServerStarted || s.serverStatus == httpServerStoped { + return nil + } + oldStatus := s.serverStatus + s.serverStatus = httpServerStarted + s.Unlock() + + if err := s.server.ListenAndServe(); err != nil { + s.Lock() + s.serverStatus = oldStatus + s.Unlock() + + return err + } + return nil +} + +func (s *httpServer) stop() error { + s.Lock() + defer s.Unlock() + + if s.serverStatus == httpServerStoped || s.serverStatus == httpServerInitilized { + return nil + } + if err := s.server.Shutdown(context.Background()); err != nil { + return err + } + s.serverStatus = httpServerStoped + return nil +} + +func httpServerFrom(addr string, newServer func() *httpServer) *httpServer { + s, exist := httpServers[addr] + if exist { + return s + } + s = newServer() + s.serverStatus = httpServerInitilized + httpServers[addr] = s + return s +} diff --git a/internal/service/http_service.go b/internal/service/http_service.go new file mode 100644 index 00000000..11ec1b98 --- /dev/null +++ b/internal/service/http_service.go @@ -0,0 +1,49 @@ +// Copyright 2022 ROC. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package service + +import ( + "github.com/gin-gonic/gin" +) + +type httpService interface { + Service + + registerRoute(e *gin.Engine) +} + +type baseHttpService struct { + baseService + + server *httpServer +} + +func (s *baseHttpService) Init() error { + if s.server.status() != httpServerStarted { + s.registerRoute(s.server.e) + } + return nil +} + +func (s *baseHttpService) Start() error { + if err := s.server.start(); err != nil { + return err + } + return nil +} + +func (s *baseHttpService) Stop() error { + return s.server.stop() +} + +func (s *baseHttpService) registerRoute(e *gin.Engine) { + // default empty +} + +func newBaseHttpService(s *httpServer) httpService { + return &baseHttpService{ + server: s, + } +} diff --git a/internal/service/service.go b/internal/service/service.go index 84c9ec7a..31efbae0 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -4,14 +4,36 @@ package service +import ( + "log" + + "github.com/rocboss/paopao-ce/pkg/types" +) + type Service interface { Name() string - Start() - Stop() + Init() error + Start() error + Stop() error } -type baseService struct{} +type baseService types.Empty + +func (baseService) Name() string { + return "" +} func (baseService) String() string { return "" } + +func InitService() (ss []Service) { + ss = append(ss, newWebService()) + + for _, s := range ss { + if err := s.Init(); err != nil { + log.Fatalf("initial %s service error: %s", s.Name(), err) + } + } + return +} diff --git a/internal/service/web.go b/internal/service/web.go index a64a6f73..6ded25d3 100644 --- a/internal/service/web.go +++ b/internal/service/web.go @@ -5,9 +5,7 @@ package service import ( - "context" "fmt" - "log" "net/http" "github.com/fatih/color" @@ -18,23 +16,15 @@ import ( ) type webService struct { - baseService - - server *http.Server + httpService } func (s *webService) Name() string { return "WebService" } -func (s *webService) Start() { - if err := s.server.ListenAndServe(); err != nil { - log.Fatalf("run app failed: %s", err) - } -} - -func (s *webService) Stop() { - s.server.Shutdown(context.Background()) +func (s *webService) registerRoute(e *gin.Engine) { + servants.RegisterWebServants(e) } func (s *webService) String() string { @@ -72,16 +62,22 @@ func newWebEngine() *gin.Engine { return e } -func NewWebService() Service { - e := newWebEngine() - servants.RegisterWebServants(e) +func newWebService() Service { + addr := conf.ServerSetting.HttpIp + ":" + conf.ServerSetting.HttpPort + server := httpServerFrom(addr, func() *httpServer { + engine := newWebEngine() + return &httpServer{ + e: engine, + server: &http.Server{ + Addr: addr, + Handler: engine, + ReadTimeout: conf.ServerSetting.ReadTimeout, + WriteTimeout: conf.ServerSetting.WriteTimeout, + MaxHeaderBytes: 1 << 20, + }, + } + }) return &webService{ - server: &http.Server{ - Addr: conf.ServerSetting.HttpIp + ":" + conf.ServerSetting.HttpPort, - Handler: e, - ReadTimeout: conf.ServerSetting.ReadTimeout, - WriteTimeout: conf.ServerSetting.WriteTimeout, - MaxHeaderBytes: 1 << 20, - }, + httpService: newBaseHttpService(server), } }