server.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "time"
  7. "github.com/pkg/errors"
  8. "github.com/usememos/memos/api"
  9. apiV1 "github.com/usememos/memos/api/v1"
  10. "github.com/usememos/memos/plugin/telegram"
  11. "github.com/usememos/memos/server/profile"
  12. "github.com/usememos/memos/store"
  13. "github.com/labstack/echo/v4"
  14. "github.com/labstack/echo/v4/middleware"
  15. )
  16. type Server struct {
  17. e *echo.Echo
  18. ID string
  19. Secret string
  20. Profile *profile.Profile
  21. Store *store.Store
  22. telegramBot *telegram.Bot
  23. }
  24. func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
  25. e := echo.New()
  26. e.Debug = true
  27. e.HideBanner = true
  28. e.HidePort = true
  29. s := &Server{
  30. e: e,
  31. Store: store,
  32. Profile: profile,
  33. }
  34. telegramBotHandler := newTelegramHandler(store)
  35. s.telegramBot = telegram.NewBotWithHandler(telegramBotHandler)
  36. e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
  37. Format: `{"time":"${time_rfc3339}",` +
  38. `"method":"${method}","uri":"${uri}",` +
  39. `"status":${status},"error":"${error}"}` + "\n",
  40. }))
  41. e.Use(middleware.Gzip())
  42. e.Use(middleware.CORS())
  43. e.Use(middleware.SecureWithConfig(middleware.SecureConfig{
  44. Skipper: defaultGetRequestSkipper,
  45. XSSProtection: "1; mode=block",
  46. ContentTypeNosniff: "nosniff",
  47. XFrameOptions: "SAMEORIGIN",
  48. HSTSPreloadEnabled: false,
  49. }))
  50. e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
  51. ErrorMessage: "Request timeout",
  52. Timeout: 30 * time.Second,
  53. }))
  54. serverID, err := s.getSystemServerID(ctx)
  55. if err != nil {
  56. return nil, err
  57. }
  58. s.ID = serverID
  59. embedFrontend(e)
  60. secret := "usememos"
  61. if profile.Mode == "prod" {
  62. secret, err = s.getSystemSecretSessionName(ctx)
  63. if err != nil {
  64. return nil, err
  65. }
  66. }
  67. s.Secret = secret
  68. rootGroup := e.Group("")
  69. s.registerRSSRoutes(rootGroup)
  70. publicGroup := e.Group("/o")
  71. publicGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
  72. return JWTMiddleware(s, next, s.Secret)
  73. })
  74. registerGetterPublicRoutes(publicGroup)
  75. s.registerResourcePublicRoutes(publicGroup)
  76. apiGroup := e.Group("/api")
  77. apiGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
  78. return JWTMiddleware(s, next, s.Secret)
  79. })
  80. s.registerSystemRoutes(apiGroup)
  81. s.registerUserRoutes(apiGroup)
  82. s.registerMemoRoutes(apiGroup)
  83. s.registerMemoResourceRoutes(apiGroup)
  84. s.registerShortcutRoutes(apiGroup)
  85. s.registerResourceRoutes(apiGroup)
  86. s.registerTagRoutes(apiGroup)
  87. s.registerStorageRoutes(apiGroup)
  88. s.registerOpenAIRoutes(apiGroup)
  89. s.registerMemoRelationRoutes(apiGroup)
  90. apiV1Service := apiV1.NewAPIV1Service(s.Secret, profile, store)
  91. apiV1Service.Register(rootGroup)
  92. return s, nil
  93. }
  94. func (s *Server) Start(ctx context.Context) error {
  95. if err := s.createServerStartActivity(ctx); err != nil {
  96. return errors.Wrap(err, "failed to create activity")
  97. }
  98. go s.telegramBot.Start(ctx)
  99. return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port))
  100. }
  101. func (s *Server) Shutdown(ctx context.Context) {
  102. ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
  103. defer cancel()
  104. // Shutdown echo server
  105. if err := s.e.Shutdown(ctx); err != nil {
  106. fmt.Printf("failed to shutdown server, error: %v\n", err)
  107. }
  108. // Close database connection
  109. if err := s.Store.GetDB().Close(); err != nil {
  110. fmt.Printf("failed to close database, error: %v\n", err)
  111. }
  112. fmt.Printf("memos stopped properly\n")
  113. }
  114. func (s *Server) GetEcho() *echo.Echo {
  115. return s.e
  116. }
  117. func (s *Server) createServerStartActivity(ctx context.Context) error {
  118. payload := api.ActivityServerStartPayload{
  119. ServerID: s.ID,
  120. Profile: s.Profile,
  121. }
  122. payloadBytes, err := json.Marshal(payload)
  123. if err != nil {
  124. return errors.Wrap(err, "failed to marshal activity payload")
  125. }
  126. activity, err := s.Store.CreateActivity(ctx, &api.ActivityCreate{
  127. CreatorID: api.UnknownID,
  128. Type: api.ActivityServerStart,
  129. Level: api.ActivityInfo,
  130. Payload: string(payloadBytes),
  131. })
  132. if err != nil || activity == nil {
  133. return errors.Wrap(err, "failed to create activity")
  134. }
  135. return err
  136. }