diff --git a/client/api/controller.go b/client/api/controller.go index 281bceb8..090e43a9 100644 --- a/client/api/controller.go +++ b/client/api/controller.go @@ -17,7 +17,7 @@ type Controller interface { // CreateSpace creates new space with random data CreateSpace() (id string, err error) // AllSpaceIds returns ids of all spaces - AllSpaceIds(spaceId string) (ids []string, err error) + AllSpaceIds() (ids []string, err error) // LoadSpace asks node to load a particular space LoadSpace(id string) (err error) @@ -42,6 +42,18 @@ type controller struct { account account.Service } +func newController(spaceService clientspace.Service, + storageService storage.ClientStorage, + docService document.Service, + account account.Service) Controller { + return &controller{ + spaceService: spaceService, + storageService: storageService, + docService: docService, + account: account, + } +} + func (c *controller) DeriveSpace() (id string, err error) { sp, err := c.spaceService.DeriveSpace(context.Background(), commonspace.SpaceDerivePayload{ SigningKey: c.account.Account().SignKey, @@ -72,7 +84,7 @@ func (c *controller) CreateSpace() (id string, err error) { return } -func (c *controller) AllSpaceIds(spaceId string) (ids []string, err error) { +func (c *controller) AllSpaceIds() (ids []string, err error) { return c.storageService.AllSpaceIds() } diff --git a/client/api/service.go b/client/api/service.go new file mode 100644 index 00000000..0ce5dcc0 --- /dev/null +++ b/client/api/service.go @@ -0,0 +1,169 @@ +package api + +import ( + "context" + "fmt" + "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" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account" + "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" + "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" + "net/http" + "strings" +) + +const CName = "api.service" + +var log = logger.NewNamed("api") + +func New() Service { + return &service{} +} + +type Service interface { + app.ComponentRunnable +} + +type service struct { + controller Controller + srv *http.Server + cfg *config.Config +} + +func (s *service) Init(a *app.App) (err error) { + s.controller = newController( + a.MustComponent(clientspace.CName).(clientspace.Service), + a.MustComponent(storage.CName).(clientstorage.ClientStorage), + a.MustComponent(document.CName).(document.Service), + a.MustComponent(account.CName).(account.Service)) + s.cfg = a.MustComponent(config.CName).(*config.Config) + return nil +} + +func (s *service) Name() (name string) { + return CName +} + +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("/allSpaceIds", s.allSpaceIds) + mux.HandleFunc("/createDocument", s.createDocument) + 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() + if err != nil { + log.With(zap.Error(err)).Error("could not run api server") + } +} + +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) 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) 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)) + } +}