v2.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package v2
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
  7. "github.com/improbable-eng/grpc-web/go/grpcweb"
  8. "github.com/labstack/echo/v4"
  9. "github.com/pkg/errors"
  10. "go.uber.org/zap"
  11. "google.golang.org/grpc"
  12. "google.golang.org/grpc/credentials/insecure"
  13. "google.golang.org/grpc/reflection"
  14. "github.com/usememos/memos/internal/log"
  15. apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
  16. "github.com/usememos/memos/server/profile"
  17. "github.com/usememos/memos/store"
  18. )
  19. type APIV2Service struct {
  20. apiv2pb.UnimplementedWorkspaceServiceServer
  21. apiv2pb.UnimplementedAuthServiceServer
  22. apiv2pb.UnimplementedUserServiceServer
  23. apiv2pb.UnimplementedMemoServiceServer
  24. apiv2pb.UnimplementedResourceServiceServer
  25. apiv2pb.UnimplementedTagServiceServer
  26. apiv2pb.UnimplementedInboxServiceServer
  27. apiv2pb.UnimplementedActivityServiceServer
  28. apiv2pb.UnimplementedWebhookServiceServer
  29. apiv2pb.UnimplementedMarkdownServiceServer
  30. Secret string
  31. Profile *profile.Profile
  32. Store *store.Store
  33. grpcServer *grpc.Server
  34. grpcServerPort int
  35. }
  36. func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store, grpcServerPort int) *APIV2Service {
  37. grpc.EnableTracing = true
  38. authProvider := NewGRPCAuthInterceptor(store, secret)
  39. grpcServer := grpc.NewServer(
  40. grpc.ChainUnaryInterceptor(
  41. authProvider.AuthenticationInterceptor,
  42. ),
  43. )
  44. apiv2Service := &APIV2Service{
  45. Secret: secret,
  46. Profile: profile,
  47. Store: store,
  48. grpcServer: grpcServer,
  49. grpcServerPort: grpcServerPort,
  50. }
  51. apiv2pb.RegisterWorkspaceServiceServer(grpcServer, apiv2Service)
  52. apiv2pb.RegisterAuthServiceServer(grpcServer, apiv2Service)
  53. apiv2pb.RegisterUserServiceServer(grpcServer, apiv2Service)
  54. apiv2pb.RegisterMemoServiceServer(grpcServer, apiv2Service)
  55. apiv2pb.RegisterTagServiceServer(grpcServer, apiv2Service)
  56. apiv2pb.RegisterResourceServiceServer(grpcServer, apiv2Service)
  57. apiv2pb.RegisterInboxServiceServer(grpcServer, apiv2Service)
  58. apiv2pb.RegisterActivityServiceServer(grpcServer, apiv2Service)
  59. apiv2pb.RegisterWebhookServiceServer(grpcServer, apiv2Service)
  60. apiv2pb.RegisterMarkdownServiceServer(grpcServer, apiv2Service)
  61. reflection.Register(grpcServer)
  62. return apiv2Service
  63. }
  64. func (s *APIV2Service) GetGRPCServer() *grpc.Server {
  65. return s.grpcServer
  66. }
  67. // RegisterGateway registers the gRPC-Gateway with the given Echo instance.
  68. func (s *APIV2Service) RegisterGateway(ctx context.Context, e *echo.Echo) error {
  69. // Create a client connection to the gRPC Server we just started.
  70. // This is where the gRPC-Gateway proxies the requests.
  71. conn, err := grpc.DialContext(
  72. ctx,
  73. fmt.Sprintf(":%d", s.grpcServerPort),
  74. grpc.WithTransportCredentials(insecure.NewCredentials()),
  75. )
  76. if err != nil {
  77. return err
  78. }
  79. gwMux := runtime.NewServeMux()
  80. if err := apiv2pb.RegisterWorkspaceServiceHandler(context.Background(), gwMux, conn); err != nil {
  81. return err
  82. }
  83. if err := apiv2pb.RegisterAuthServiceHandler(context.Background(), gwMux, conn); err != nil {
  84. return err
  85. }
  86. if err := apiv2pb.RegisterUserServiceHandler(context.Background(), gwMux, conn); err != nil {
  87. return err
  88. }
  89. if err := apiv2pb.RegisterMemoServiceHandler(context.Background(), gwMux, conn); err != nil {
  90. return err
  91. }
  92. if err := apiv2pb.RegisterTagServiceHandler(context.Background(), gwMux, conn); err != nil {
  93. return err
  94. }
  95. if err := apiv2pb.RegisterResourceServiceHandler(context.Background(), gwMux, conn); err != nil {
  96. return err
  97. }
  98. if err := apiv2pb.RegisterInboxServiceHandler(context.Background(), gwMux, conn); err != nil {
  99. return err
  100. }
  101. if err := apiv2pb.RegisterActivityServiceHandler(context.Background(), gwMux, conn); err != nil {
  102. return err
  103. }
  104. if err := apiv2pb.RegisterWebhookServiceHandler(context.Background(), gwMux, conn); err != nil {
  105. return err
  106. }
  107. if err := apiv2pb.RegisterMarkdownServiceHandler(context.Background(), gwMux, conn); err != nil {
  108. return err
  109. }
  110. e.Any("/api/v2/*", echo.WrapHandler(gwMux))
  111. // GRPC web proxy.
  112. options := []grpcweb.Option{
  113. grpcweb.WithCorsForRegisteredEndpointsOnly(false),
  114. grpcweb.WithOriginFunc(func(origin string) bool {
  115. return true
  116. }),
  117. }
  118. wrappedGrpc := grpcweb.WrapServer(s.grpcServer, options...)
  119. e.Any("/memos.api.v2.*", echo.WrapHandler(wrappedGrpc))
  120. // Start gRPC server.
  121. listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Profile.Addr, s.grpcServerPort))
  122. if err != nil {
  123. return errors.Wrap(err, "failed to start gRPC server")
  124. }
  125. go func() {
  126. if err := s.grpcServer.Serve(listen); err != nil {
  127. log.Error("grpc server listen error", zap.Error(err))
  128. }
  129. }()
  130. return nil
  131. }