server.go 6.3 KB

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