server.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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/store"
  21. "go.uber.org/zap"
  22. )
  23. type Server struct {
  24. e *echo.Echo
  25. ID string
  26. Secret string
  27. Profile *profile.Profile
  28. Store *store.Store
  29. // API services.
  30. apiV2Service *apiv2.APIV2Service
  31. // Asynchronous runners.
  32. backupRunner *BackupRunner
  33. telegramBot *telegram.Bot
  34. }
  35. // @title memos API
  36. // @version 1.0
  37. // @description A privacy-first, lightweight note-taking service.
  38. //
  39. // @contact.name API Support
  40. // @contact.url https://github.com/orgs/usememos/discussions
  41. //
  42. // @license.name MIT License
  43. // @license.url https://github.com/usememos/memos/blob/main/LICENSE
  44. //
  45. // @BasePath /
  46. //
  47. // @externalDocs.url https://usememos.com/
  48. // @externalDocs.description Find out more about Memos
  49. //
  50. // @securitydefinitions.apikey ApiKeyAuth
  51. // @in query
  52. // @name openId
  53. // @description Insert your Open ID API Key here.
  54. func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
  55. e := echo.New()
  56. e.Debug = true
  57. e.HideBanner = true
  58. e.HidePort = true
  59. s := &Server{
  60. e: e,
  61. Store: store,
  62. Profile: profile,
  63. // Asynchronous runners.
  64. backupRunner: NewBackupRunner(store),
  65. telegramBot: telegram.NewBotWithHandler(newTelegramHandler(store)),
  66. }
  67. e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
  68. Format: `{"time":"${time_rfc3339}",` +
  69. `"method":"${method}","uri":"${uri}",` +
  70. `"status":${status},"error":"${error}"}` + "\n",
  71. }))
  72. e.Use(middleware.Gzip())
  73. e.Use(middleware.CORS())
  74. e.Use(middleware.SecureWithConfig(middleware.SecureConfig{
  75. Skipper: defaultGetRequestSkipper,
  76. XSSProtection: "1; mode=block",
  77. ContentTypeNosniff: "nosniff",
  78. XFrameOptions: "SAMEORIGIN",
  79. HSTSPreloadEnabled: false,
  80. }))
  81. e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
  82. ErrorMessage: "Request timeout",
  83. Timeout: 30 * time.Second,
  84. }))
  85. serverID, err := s.getSystemServerID(ctx)
  86. if err != nil {
  87. return nil, fmt.Errorf("failed to retrieve system server ID: %w", err)
  88. }
  89. s.ID = serverID
  90. embedFrontend(e)
  91. // This will serve Swagger UI at /api/index.html and Swagger 2.0 spec at /api/doc.json
  92. e.GET("/api/*", echoSwagger.WrapHandler)
  93. secret := "usememos"
  94. if profile.Mode == "prod" {
  95. secret, err = s.getSystemSecretSessionName(ctx)
  96. if err != nil {
  97. return nil, fmt.Errorf("failed to retrieve system secret session name: %w", err)
  98. }
  99. }
  100. s.Secret = secret
  101. rootGroup := e.Group("")
  102. apiV1Service := apiv1.NewAPIV1Service(s.Secret, profile, store)
  103. apiV1Service.Register(rootGroup)
  104. s.apiV2Service = apiv2.NewAPIV2Service(s.Secret, profile, store, s.Profile.Port+1)
  105. // Register gRPC gateway as api v2.
  106. if err := s.apiV2Service.RegisterGateway(ctx, e); err != nil {
  107. return nil, fmt.Errorf("failed to register gRPC gateway: %w", err)
  108. }
  109. return s, nil
  110. }
  111. func (s *Server) Start(ctx context.Context) error {
  112. if err := s.createServerStartActivity(ctx); err != nil {
  113. return errors.Wrap(err, "failed to create activity")
  114. }
  115. go s.telegramBot.Start(ctx)
  116. go s.backupRunner.Run(ctx)
  117. // Start gRPC server.
  118. listen, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Profile.Port+1))
  119. if err != nil {
  120. return err
  121. }
  122. go func() {
  123. if err := s.apiV2Service.GetGRPCServer().Serve(listen); err != nil {
  124. log.Error("grpc server listen error", zap.Error(err))
  125. }
  126. }()
  127. // programmatically set API version same as the server version
  128. apiv1.SwaggerInfo.Version = s.Profile.Version
  129. return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port))
  130. }
  131. func (s *Server) Shutdown(ctx context.Context) {
  132. ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
  133. defer cancel()
  134. // Shutdown echo server
  135. if err := s.e.Shutdown(ctx); err != nil {
  136. fmt.Printf("failed to shutdown server, error: %v\n", err)
  137. }
  138. // Close database connection
  139. if err := s.Store.GetDB().Close(); err != nil {
  140. fmt.Printf("failed to close database, error: %v\n", err)
  141. }
  142. fmt.Printf("memos stopped properly\n")
  143. }
  144. func (s *Server) GetEcho() *echo.Echo {
  145. return s.e
  146. }
  147. func (s *Server) getSystemServerID(ctx context.Context) (string, error) {
  148. serverIDSetting, err := s.Store.GetSystemSetting(ctx, &store.FindSystemSetting{
  149. Name: apiv1.SystemSettingServerIDName.String(),
  150. })
  151. if err != nil {
  152. return "", err
  153. }
  154. if serverIDSetting == nil || serverIDSetting.Value == "" {
  155. serverIDSetting, err = s.Store.UpsertSystemSetting(ctx, &store.SystemSetting{
  156. Name: apiv1.SystemSettingServerIDName.String(),
  157. Value: uuid.NewString(),
  158. })
  159. if err != nil {
  160. return "", err
  161. }
  162. }
  163. return serverIDSetting.Value, nil
  164. }
  165. func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
  166. secretSessionNameValue, err := s.Store.GetSystemSetting(ctx, &store.FindSystemSetting{
  167. Name: apiv1.SystemSettingSecretSessionName.String(),
  168. })
  169. if err != nil {
  170. return "", err
  171. }
  172. if secretSessionNameValue == nil || secretSessionNameValue.Value == "" {
  173. secretSessionNameValue, err = s.Store.UpsertSystemSetting(ctx, &store.SystemSetting{
  174. Name: apiv1.SystemSettingSecretSessionName.String(),
  175. Value: uuid.NewString(),
  176. })
  177. if err != nil {
  178. return "", err
  179. }
  180. }
  181. return secretSessionNameValue.Value, nil
  182. }
  183. func (s *Server) createServerStartActivity(ctx context.Context) error {
  184. payload := apiv1.ActivityServerStartPayload{
  185. ServerID: s.ID,
  186. Profile: s.Profile,
  187. }
  188. payloadBytes, err := json.Marshal(payload)
  189. if err != nil {
  190. return errors.Wrap(err, "failed to marshal activity payload")
  191. }
  192. activity, err := s.Store.CreateActivity(ctx, &store.Activity{
  193. CreatorID: apiv1.UnknownID,
  194. Type: apiv1.ActivityServerStart.String(),
  195. Level: apiv1.ActivityInfo.String(),
  196. Payload: string(payloadBytes),
  197. })
  198. if err != nil || activity == nil {
  199. return errors.Wrap(err, "failed to create activity")
  200. }
  201. return err
  202. }
  203. func defaultGetRequestSkipper(c echo.Context) bool {
  204. return c.Request().Method == http.MethodGet
  205. }
  206. func defaultAPIRequestSkipper(c echo.Context) bool {
  207. path := c.Request().URL.Path
  208. return util.HasPrefixes(path, "/api", "/api/v1", "api/v2")
  209. }