server.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. metric "github.com/usememos/memos/plugin/metrics"
  10. "github.com/usememos/memos/server/profile"
  11. "github.com/usememos/memos/store"
  12. "github.com/usememos/memos/store/db"
  13. "github.com/gorilla/sessions"
  14. "github.com/labstack/echo-contrib/session"
  15. "github.com/labstack/echo/v4"
  16. "github.com/labstack/echo/v4/middleware"
  17. )
  18. type Server struct {
  19. e *echo.Echo
  20. ID string
  21. Profile *profile.Profile
  22. Store *store.Store
  23. Collector *MetricCollector
  24. }
  25. func NewServer(ctx context.Context, profile *profile.Profile) (*Server, error) {
  26. e := echo.New()
  27. e.Debug = true
  28. e.HideBanner = true
  29. e.HidePort = true
  30. s := &Server{
  31. e: e,
  32. Profile: profile,
  33. }
  34. db := db.NewDB(profile)
  35. if err := db.Open(ctx); err != nil {
  36. return nil, errors.Wrap(err, "cannot open db")
  37. }
  38. storeInstance := store.New(db.DBInstance, profile)
  39. s.Store = storeInstance
  40. e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
  41. Format: `{"time":"${time_rfc3339}",` +
  42. `"method":"${method}","uri":"${uri}",` +
  43. `"status":${status},"error":"${error}"}` + "\n",
  44. }))
  45. e.Use(middleware.Gzip())
  46. e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
  47. Skipper: s.DefaultAuthSkipper,
  48. TokenLookup: "cookie:_csrf",
  49. }))
  50. e.Use(middleware.CORS())
  51. e.Use(middleware.SecureWithConfig(middleware.SecureConfig{
  52. Skipper: DefaultGetRequestSkipper,
  53. XSSProtection: "1; mode=block",
  54. ContentTypeNosniff: "nosniff",
  55. XFrameOptions: "SAMEORIGIN",
  56. HSTSPreloadEnabled: false,
  57. }))
  58. e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
  59. ErrorMessage: "Request timeout",
  60. Timeout: 30 * time.Second,
  61. }))
  62. serverID, err := s.getSystemServerID(ctx)
  63. if err != nil {
  64. return nil, err
  65. }
  66. s.ID = serverID
  67. secretSessionName := "usememos"
  68. if profile.Mode == "prod" {
  69. secretSessionName, err = s.getSystemSecretSessionName(ctx)
  70. if err != nil {
  71. return nil, err
  72. }
  73. }
  74. e.Use(session.Middleware(sessions.NewCookieStore([]byte(secretSessionName))))
  75. embedFrontend(e)
  76. // Register MetricCollector to server.
  77. s.registerMetricCollector()
  78. rootGroup := e.Group("")
  79. s.registerRSSRoutes(rootGroup)
  80. webhookGroup := e.Group("/h")
  81. s.registerResourcePublicRoutes(webhookGroup)
  82. publicGroup := e.Group("/o")
  83. s.registerResourcePublicRoutes(publicGroup)
  84. registerGetterPublicRoutes(publicGroup)
  85. apiGroup := e.Group("/api")
  86. apiGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
  87. return aclMiddleware(s, next)
  88. })
  89. s.registerSystemRoutes(apiGroup)
  90. s.registerAuthRoutes(apiGroup)
  91. s.registerUserRoutes(apiGroup)
  92. s.registerMemoRoutes(apiGroup)
  93. s.registerShortcutRoutes(apiGroup)
  94. s.registerResourceRoutes(apiGroup)
  95. s.registerTagRoutes(apiGroup)
  96. return s, nil
  97. }
  98. func (s *Server) Run(ctx context.Context) error {
  99. if err := s.createServerStartActivity(ctx); err != nil {
  100. return errors.Wrap(err, "failed to create activity")
  101. }
  102. s.Collector.Identify(ctx)
  103. return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port))
  104. }
  105. func (s *Server) createServerStartActivity(ctx context.Context) error {
  106. payload := api.ActivityServerStartPayload{
  107. ServerID: s.ID,
  108. Profile: s.Profile,
  109. }
  110. payloadStr, err := json.Marshal(payload)
  111. if err != nil {
  112. return errors.Wrap(err, "failed to marshal activity payload")
  113. }
  114. activity, err := s.Store.CreateActivity(ctx, &api.ActivityCreate{
  115. CreatorID: api.UnknownID,
  116. Type: api.ActivityServerStart,
  117. Level: api.ActivityInfo,
  118. Payload: string(payloadStr),
  119. })
  120. if err != nil || activity == nil {
  121. return errors.Wrap(err, "failed to create activity")
  122. }
  123. s.Collector.Collect(ctx, &metric.Metric{
  124. Name: string(activity.Type),
  125. })
  126. return err
  127. }