appmanager-api: render, install
diff --git a/core/installer/cmd/app_manager.go b/core/installer/cmd/app_manager.go
index 1fc6d64..249dcfb 100644
--- a/core/installer/cmd/app_manager.go
+++ b/core/installer/cmd/app_manager.go
@@ -1,9 +1,19 @@
package main
import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
"os"
"github.com/giolekva/pcloud/core/installer"
+
+ "github.com/labstack/echo/v4"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh"
)
@@ -11,30 +21,37 @@
var appManagerFlags struct {
sshKey string
repoAddr string
+ port int
}
func appManagerCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "appmanager",
- RunE: installCmdRun,
+ RunE: appManagerCmdRun,
}
cmd.Flags().StringVar(
- &installFlags.sshKey,
+ &appManagerFlags.sshKey,
"ssh-key",
"",
"",
)
cmd.Flags().StringVar(
- &installFlags.repoAddr,
+ &appManagerFlags.repoAddr,
"repo-addr",
"",
"",
)
+ cmd.Flags().IntVar(
+ &appManagerFlags.port,
+ "port",
+ 8080,
+ "",
+ )
return cmd
}
func appManagerCmdRun(cmd *cobra.Command, args []string) error {
- sshKey, err := os.ReadFile(installFlags.sshKey)
+ sshKey, err := os.ReadFile(appManagerFlags.sshKey)
if err != nil {
return err
}
@@ -42,14 +59,148 @@
if err != nil {
return err
}
- repo, err := cloneRepo(installFlags.repoAddr, signer)
+ repo, err := cloneRepo(appManagerFlags.repoAddr, signer)
if err != nil {
return err
}
- _, err = installer.NewAppManager(repo, signer)
+ m, err := installer.NewAppManager(repo, signer)
if err != nil {
return err
}
- // TODO(gio): start server
+ r := installer.NewInMemoryAppRepository(installer.CreateAllApps())
+ s := &server{
+ port: appManagerFlags.port,
+ m: m,
+ r: r,
+ }
+ s.start()
return nil
}
+
+type server struct {
+ port int
+ m *installer.AppManager
+ r installer.AppRepository
+}
+
+func (s *server) start() {
+ e := echo.New()
+ e.GET("/api/app-repo", s.handleAppRepo)
+ e.POST("/api/app/:slug/render", s.handleAppRender)
+ e.POST("/api/app/:slug/install", s.handleAppInstall)
+ e.GET("/api/app/:slug", s.handleApp)
+ webapp, err := url.Parse("http://localhost:5173")
+ if err != nil {
+ panic(err)
+ }
+ // var f ff
+ e.Any("/*", echo.WrapHandler(httputil.NewSingleHostReverseProxy(webapp)))
+ // e.Any("/*", echo.WrapHandler(&f))
+ fmt.Printf("Starting HTTP server on port: %d\n", s.port)
+ log.Fatal(e.Start(fmt.Sprintf(":%d", s.port)))
+}
+
+type app struct {
+ Name string `json:"name"`
+ Slug string `json:"slug"`
+ Schema string `json:"schema"`
+}
+
+func (s *server) handleAppRepo(c echo.Context) error {
+ all, err := s.r.GetAll()
+ if err != nil {
+ return err
+ }
+ resp := make([]app, len(all))
+ for i, a := range all {
+ resp[i] = app{a.Name, a.Name, a.Schema}
+ }
+ return c.JSON(http.StatusOK, resp)
+}
+
+func (s *server) handleApp(c echo.Context) error {
+ slug := c.Param("slug")
+ a, err := s.r.Find(slug)
+ if err != nil {
+ return err
+ }
+ return c.JSON(http.StatusOK, app{a.Name, a.Name, a.Schema})
+}
+
+type file struct {
+ Name string `json:"name"`
+ Contents string `json:"contents"`
+}
+
+type rendered struct {
+ Readme string `json:"readme"`
+ Files []file `json:"files"`
+}
+
+func (s *server) handleAppRender(c echo.Context) error {
+ slug := c.Param("slug")
+ contents, err := ioutil.ReadAll(c.Request().Body)
+ if err != nil {
+ return err
+ }
+ global, err := s.m.Config()
+ if err != nil {
+ return err
+ }
+ var values map[string]any
+ if err := json.Unmarshal(contents, &values); err != nil {
+ return err
+ }
+ all := map[string]any{
+ "Global": global.Values,
+ "Values": values,
+ }
+ a, err := s.r.Find(slug)
+ if err != nil {
+ return err
+ }
+ var readme bytes.Buffer
+ if err := a.Readme.Execute(&readme, all); err != nil {
+ return err
+ }
+ var resp rendered
+ resp.Readme = readme.String()
+ for _, tmpl := range a.Templates {
+ var f bytes.Buffer
+ if err := tmpl.Execute(&f, all); err != nil {
+ fmt.Printf("%+v\n", all)
+ fmt.Println(err.Error())
+ return err
+ } else {
+ resp.Files = append(resp.Files, file{tmpl.Name(), f.String()})
+ }
+ }
+ out, err := json.Marshal(resp)
+ if err != nil {
+ return err
+ }
+ if _, err := c.Response().Writer.Write(out); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (s *server) handleAppInstall(c echo.Context) error {
+ slug := c.Param("slug")
+ contents, err := ioutil.ReadAll(c.Request().Body)
+ if err != nil {
+ return err
+ }
+ var values map[string]any
+ if err := json.Unmarshal(contents, &values); err != nil {
+ return err
+ }
+ a, err := s.r.Find(slug)
+ if err != nil {
+ return err
+ }
+ if err := s.m.Install(*a, values); err != nil {
+ return err
+ }
+ return c.String(http.StatusOK, "Installed")
+}