diff --git a/client/api/rpchandler.go b/client/api/rpchandler.go new file mode 100644 index 00000000..707afd24 --- /dev/null +++ b/client/api/rpchandler.go @@ -0,0 +1,94 @@ +package api + +import ( + "context" + "github.com/anytypeio/go-anytype-infrastructure-experiments/client/api/apiproto" +) + +type rpcHandler struct { + controller Controller +} + +func (r *rpcHandler) CreateSpace(ctx context.Context, request *apiproto.CreateSpaceRequest) (resp *apiproto.CreateSpaceResponse, err error) { + id, err := r.controller.CreateSpace() + if err != nil { + return + } + resp = &apiproto.CreateSpaceResponse{Id: id} + return +} + +func (r *rpcHandler) DeriveSpace(ctx context.Context, request *apiproto.DeriveSpaceRequest) (resp *apiproto.DeriveSpaceResponse, err error) { + id, err := r.controller.DeriveSpace() + if err != nil { + return + } + resp = &apiproto.DeriveSpaceResponse{Id: id} + return +} + +func (r *rpcHandler) CreateDocument(ctx context.Context, request *apiproto.CreateDocumentRequest) (resp *apiproto.CreateDocumentResponse, err error) { + id, err := r.controller.CreateDocument(request.SpaceId) + if err != nil { + return + } + resp = &apiproto.CreateDocumentResponse{Id: id} + return +} + +func (r *rpcHandler) DeleteDocument(ctx context.Context, request *apiproto.DeleteDocumentRequest) (resp *apiproto.DeleteDocumentResponse, err error) { + err = r.controller.DeleteDocument(request.SpaceId, request.DocumentId) + if err != nil { + return + } + resp = &apiproto.DeleteDocumentResponse{} + return +} + +func (r *rpcHandler) AddText(ctx context.Context, request *apiproto.AddTextRequest) (resp *apiproto.AddTextResponse, err error) { + err = r.controller.AddText(request.SpaceId, request.DocumentId, request.Text) + if err != nil { + return + } + // TODO: update controller to add head + resp = &apiproto.AddTextResponse{ + DocumentId: request.DocumentId, + } + return +} + +func (r *rpcHandler) DumpTree(ctx context.Context, request *apiproto.DumpTreeRequest) (resp *apiproto.DumpTreeResponse, err error) { + dump, err := r.controller.DumpDocumentTree(request.SpaceId, request.DocumentId) + if err != nil { + return + } + resp = &apiproto.DumpTreeResponse{ + Dump: dump, + } + return +} + +func (r *rpcHandler) AllTrees(ctx context.Context, request *apiproto.AllTreesRequest) (resp *apiproto.AllTreesResponse, err error) { + ids, err := r.controller.AllDocumentIds(request.SpaceId) + if err != nil { + return + } + // TODO: add getting heads to controller + var trees []*apiproto.Tree + for _, id := range ids { + trees = append(trees, &apiproto.Tree{ + Id: id, + }) + } + resp = &apiproto.AllTreesResponse{Trees: trees} + return +} + +func (r *rpcHandler) AllSpaces(ctx context.Context, request *apiproto.AllSpacesRequest) (resp *apiproto.AllSpacesResponse, err error) { + ids, err := r.controller.AllSpaceIds() + if err != nil { + return + } + resp = &apiproto.AllSpacesResponse{SpaceIds: ids} + return +} diff --git a/client/api/service.go b/client/api/service.go index 7155ea38..b7c14d33 100644 --- a/client/api/service.go +++ b/client/api/service.go @@ -2,7 +2,7 @@ package api import ( "context" - "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/client/api/apiproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace" "github.com/anytypeio/go-anytype-infrastructure-experiments/client/document" clientstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage" @@ -11,10 +11,10 @@ import ( "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" - "go.uber.org/zap" - "io" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure" "net/http" - "strings" + "storj.io/drpc" ) const CName = "api.service" @@ -22,17 +22,19 @@ const CName = "api.service" var log = logger.NewNamed("api") func New() Service { - return &service{} + return &service{BaseDrpcServer: server.NewBaseDrpcServer()} } type Service interface { app.ComponentRunnable + drpc.Mux } type service struct { controller Controller srv *http.Server cfg *config.Config + *server.BaseDrpcServer } func (s *service) Init(a *app.App) (err error) { @@ -42,6 +44,7 @@ func (s *service) Init(a *app.App) (err error) { a.MustComponent(document.CName).(document.Service), a.MustComponent(account.CName).(account.Service)) s.cfg = a.MustComponent(config.CName).(*config.Config) + s.BaseDrpcServer.Init(a.MustComponent(secure.CName).(secure.Service)) return nil } @@ -50,145 +53,15 @@ func (s *service) Name() (name string) { } func (s *service) Run(ctx context.Context) (err error) { - defer func() { - if err == nil { - log.With(zap.String("port", s.cfg.APIServer.Port)).Info("api server started running") - } - }() - - s.srv = &http.Server{ - Addr: fmt.Sprintf(":%s", s.cfg.APIServer.Port), - } - mux := http.NewServeMux() - mux.HandleFunc("/deriveSpace", s.deriveSpace) - mux.HandleFunc("/createSpace", s.createSpace) - mux.HandleFunc("/loadSpace", s.loadSpace) - mux.HandleFunc("/allSpaceIds", s.allSpaceIds) - mux.HandleFunc("/createDocument", s.createDocument) - mux.HandleFunc("/deleteDocument", s.deleteDocument) - mux.HandleFunc("/allDocumentIds", s.allDocumentIds) - mux.HandleFunc("/addText", s.addText) - mux.HandleFunc("/dumpDocumentTree", s.dumpDocumentTree) - s.srv.Handler = mux - - go s.runServer() - return nil -} - -func (s *service) runServer() { - err := s.srv.ListenAndServe() + err = s.BaseDrpcServer.Run(ctx, s.cfg.APIServer.ListenAddrs, func(handler drpc.Handler) drpc.Handler { + return handler + }) if err != nil { - log.With(zap.Error(err)).Error("could not run api server") + return } + return apiproto.DRPCRegisterClientApi(s, &rpcHandler{s.controller}) } func (s *service) Close(ctx context.Context) (err error) { - return s.srv.Shutdown(ctx) -} - -func (s *service) deriveSpace(w http.ResponseWriter, req *http.Request) { - id, err := s.controller.DeriveSpace() - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, id) -} - -func (s *service) loadSpace(w http.ResponseWriter, req *http.Request) { - query := req.URL.Query() - spaceId := query.Get("spaceId") - err := s.controller.LoadSpace(query.Get("spaceId")) - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, spaceId) -} - -func (s *service) createSpace(w http.ResponseWriter, req *http.Request) { - id, err := s.controller.CreateSpace() - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, id) -} - -func (s *service) allSpaceIds(w http.ResponseWriter, req *http.Request) { - ids, err := s.controller.AllSpaceIds() - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, strings.Join(ids, "\n")) -} - -func (s *service) createDocument(w http.ResponseWriter, req *http.Request) { - query := req.URL.Query() - spaceId := query.Get("spaceId") - id, err := s.controller.CreateDocument(spaceId) - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, id) -} - -func (s *service) deleteDocument(w http.ResponseWriter, req *http.Request) { - query := req.URL.Query() - spaceId := query.Get("spaceId") - documentId := query.Get("documentId") - err := s.controller.DeleteDocument(spaceId, documentId) - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, documentId) -} - -func (s *service) allDocumentIds(w http.ResponseWriter, req *http.Request) { - query := req.URL.Query() - spaceId := query.Get("spaceId") - ids, err := s.controller.AllDocumentIds(spaceId) - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, strings.Join(ids, "\n")) -} - -func (s *service) addText(w http.ResponseWriter, req *http.Request) { - query := req.URL.Query() - spaceId := query.Get("spaceId") - documentId := query.Get("documentId") - text := query.Get("text") - err := s.controller.AddText(spaceId, documentId, text) - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, "Text added") -} - -func (s *service) dumpDocumentTree(w http.ResponseWriter, req *http.Request) { - query := req.URL.Query() - spaceId := query.Get("spaceId") - documentId := query.Get("documentId") - dump, err := s.controller.DumpDocumentTree(spaceId, documentId) - if err != nil { - sendText(w, http.StatusInternalServerError, err.Error()) - return - } - sendText(w, http.StatusOK, dump) -} - -func sendText(r http.ResponseWriter, code int, body string) { - r.Header().Set("Content-Type", "text/plain") - r.WriteHeader(code) - - _, err := io.WriteString(r, fmt.Sprintf("%s\n", body)) - if err != nil { - log.Error("writing response failed", zap.Error(err)) - } + return s.BaseDrpcServer.Close(ctx) } diff --git a/common/config/config.go b/common/config/config.go index 06168a4d..59afb523 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -26,7 +26,7 @@ type Config struct { Anytype Anytype `yaml:"anytype"` GrpcServer GrpcServer `yaml:"grpcServer"` Account Account `yaml:"account"` - APIServer APIServer `yaml:"apiServer"` + APIServer GrpcServer `yaml:"apiServer"` Nodes []Node `yaml:"nodes"` Space Space `yaml:"space"` Storage Storage `yaml:"storage"` diff --git a/etc/config.yml b/etc/config.yml index 86912342..f610e299 100644 --- a/etc/config.yml +++ b/etc/config.yml @@ -10,7 +10,9 @@ account: signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= apiServer: - port: "8080" + listenAddrs: + - 127.0.0.1:4430 + tls: false nodes: - peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu address: 127.0.0.1:4430