server.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package server
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "time"
  9. "github.com/google/uuid"
  10. "github.com/labstack/echo/v4"
  11. "github.com/labstack/echo/v4/middleware"
  12. "github.com/pkg/errors"
  13. echoSwagger "github.com/swaggo/echo-swagger"
  14. apiv1 "github.com/usememos/memos/api/v1"
  15. apiv2 "github.com/usememos/memos/api/v2"
  16. "github.com/usememos/memos/common/log"
  17. "github.com/usememos/memos/common/util"
  18. "github.com/usememos/memos/plugin/telegram"
  19. "github.com/usememos/memos/server/profile"
  20. "github.com/usememos/memos/server/service"
  21. "github.com/usememos/memos/store"
  22. "go.uber.org/zap"
  23. )
  24. type Server struct {
  25. e *echo.Echo
  26. ID string
  27. Secret string
  28. Profile *profile.Profile
  29. Store *store.Store
  30. // API services.
  31. apiV2Service *apiv2.APIV2Service
  32. // Asynchronous runners.
  33. backupRunner *service.BackupRunner
  34. telegramBot *telegram.Bot
  35. }
  36. func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
  37. e := echo.New()
  38. e.Debug = true
  39. e.HideBanner = true
  40. e.HidePort = true
  41. telegramBot := telegram.NewBotWithHandler(newTelegramHandler(store))
  42. s := &Server{
  43. e: e,
  44. Store: store,
  45. Profile: profile,
  46. // Asynchronous runners.
  47. backupRunner: service.NewBackupRunner(store),
  48. telegramBot: telegramBot,
  49. }
  50. e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
  51. Format: `{"time":"${time_rfc3339}",` +
  52. `"method":"${method}","uri":"${uri}",` +
  53. `"status":${status},"error":"${error}"}` + "\n",
  54. }))
  55. e.Use(middleware.Gzip())
  56. e.Use(middleware.CORS())
  57. e.Use(middleware.SecureWithConfig(middleware.SecureConfig{
  58. Skipper: defaultGetRequestSkipper,
  59. XSSProtection: "1; mode=block",
  60. ContentTypeNosniff: "nosniff",
  61. XFrameOptions: "SAMEORIGIN",
  62. HSTSPreloadEnabled: false,
  63. }))
  64. e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
  65. ErrorMessage: "Request timeout",
  66. Timeout: 30 * time.Second,
  67. }))
  68. serverID, err := s.getSystemServerID(ctx)
  69. if err != nil {
  70. return nil, fmt.Errorf("failed to retrieve system server ID: %w", err)
  71. }
  72. s.ID = serverID
  73. // Serve frontend.
  74. embedFrontend(e)
  75. // Serve swagger in dev/demo mode.
  76. if profile.Mode == "dev" || profile.Mode == "demo" {
  77. e.GET("/api/*", echoSwagger.WrapHandler)
  78. }
  79. secret := "usememos"
  80. if profile.Mode == "prod" {
  81. secret, err = s.getSystemSecretSessionName(ctx)
  82. if err != nil {
  83. return nil, fmt.Errorf("failed to retrieve system secret session name: %w", err)
  84. }
  85. }
  86. s.Secret = secret
  87. rootGroup := e.Group("")
  88. apiV1Service := apiv1.NewAPIV1Service(s.Secret, profile, store, telegramBot)
  89. apiV1Service.Register(rootGroup)
  90. s.apiV2Service = apiv2.NewAPIV2Service(s.Secret, profile, store, s.Profile.Port+1)
  91. // Register gRPC gateway as api v2.
  92. if err := s.apiV2Service.RegisterGateway(ctx, e); err != nil {
  93. return nil, fmt.Errorf("failed to register gRPC gateway: %w", err)
  94. }
  95. return s, nil
  96. }
  97. func (s *Server) Start(ctx context.Context) error {
  98. if err := s.createServerStartActivity(ctx); err != nil {
  99. return errors.Wrap(err, "failed to create activity")
  100. }
  101. go s.telegramBot.Start(ctx)
  102. go s.backupRunner.Run(ctx)
  103. // Start gRPC server.
  104. listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Profile.Addr, s.Profile.Port+1))
  105. if err != nil {
  106. return err
  107. }
  108. go func() {
  109. if err := s.apiV2Service.GetGRPCServer().Serve(listen); err != nil {
  110. log.Error("grpc server listen error", zap.Error(err))
  111. }
  112. }()
  113. return s.e.Start(fmt.Sprintf("%s:%d", s.Profile.Addr, s.Profile.Port))
  114. }
  115. func (s *Server) Shutdown(ctx context.Context) {
  116. ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
  117. defer cancel()
  118. // Shutdown echo server
  119. if err := s.e.Shutdown(ctx); err != nil {
  120. fmt.Printf("failed to shutdown server, error: %v\n", err)
  121. }
  122. // Close database connection
  123. if err := s.Store.GetDB().Close(); err != nil {
  124. fmt.Printf("failed to close database, error: %v\n", err)
  125. }
  126. fmt.Printf("memos stopped properly\n")
  127. }
  128. func (s *Server) GetEcho() *echo.Echo {
  129. return s.e
  130. }
  131. func (s *Server) getSystemServerID(ctx context.Context) (string, error) {
  132. serverIDSetting, err := s.Store.GetSystemSetting(ctx, &store.FindSystemSetting{
  133. Name: apiv1.SystemSettingServerIDName.String(),
  134. })
  135. if err != nil {
  136. return "", err
  137. }
  138. if serverIDSetting == nil || serverIDSetting.Value == "" {
  139. serverIDSetting, err = s.Store.UpsertSystemSetting(ctx, &store.SystemSetting{
  140. Name: apiv1.SystemSettingServerIDName.String(),
  141. Value: uuid.NewString(),
  142. })
  143. if err != nil {
  144. return "", err
  145. }
  146. }
  147. return serverIDSetting.Value, nil
  148. }
  149. func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
  150. secretSessionNameValue, err := s.Store.GetSystemSetting(ctx, &store.FindSystemSetting{
  151. Name: apiv1.SystemSettingSecretSessionName.String(),
  152. })
  153. if err != nil {
  154. return "", err
  155. }
  156. if secretSessionNameValue == nil || secretSessionNameValue.Value == "" {
  157. secretSessionNameValue, err = s.Store.UpsertSystemSetting(ctx, &store.SystemSetting{
  158. Name: apiv1.SystemSettingSecretSessionName.String(),
  159. Value: uuid.NewString(),
  160. })
  161. if err != nil {
  162. return "", err
  163. }
  164. }
  165. return secretSessionNameValue.Value, nil
  166. }
  167. func (s *Server) createServerStartActivity(ctx context.Context) error {
  168. payload := apiv1.ActivityServerStartPayload{
  169. ServerID: s.ID,
  170. Profile: s.Profile,
  171. }
  172. payloadBytes, err := json.Marshal(payload)
  173. if err != nil {
  174. return errors.Wrap(err, "failed to marshal activity payload")
  175. }
  176. activity, err := s.Store.CreateActivity(ctx, &store.Activity{
  177. CreatorID: apiv1.UnknownID,
  178. Type: apiv1.ActivityServerStart.String(),
  179. Level: apiv1.ActivityInfo.String(),
  180. Payload: string(payloadBytes),
  181. })
  182. if err != nil || activity == nil {
  183. return errors.Wrap(err, "failed to create activity")
  184. }
  185. return err
  186. }
  187. func defaultGetRequestSkipper(c echo.Context) bool {
  188. return c.Request().Method == http.MethodGet
  189. }
  190. func defaultAPIRequestSkipper(c echo.Context) bool {
  191. path := c.Request().URL.Path
  192. return util.HasPrefixes(path, "/api", "/api/v1", "api/v2")
  193. }