package main import ( "bytes" "context" "fmt" "io" "io/ioutil" "log" "net/http" "os" "os/user" "path/filepath" "varia.zone/snackbar/components" "github.com/a-h/templ" "github.com/codeclysm/extract/v3" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) // App is the application state. type App struct { ctx context.Context } // NewApp creates a new application state. func NewApp() *App { return &App{} } func (a *App) startup(ctx context.Context) { a.ctx = ctx } func ensureDataDir(homeDir string) error { paths := []string{ filepath.Join(homeDir, ".local"), filepath.Join(homeDir, ".local", "snackbar"), filepath.Join(homeDir, ".local", "snackbar", "hugo"), filepath.Join(homeDir, ".local", "snackbar", "sites"), } for _, fpath := range paths { if _, err := os.Stat(fpath); err != nil && os.IsNotExist(err) { if err := os.Mkdir(fpath, 0764); err != nil { return err } } } return nil } func ensureHugoBin(homeDir string) error { hugoVersion := "0.124.1" dataDir := filepath.Join(homeDir, ".local", "snackbar") hugoDir := filepath.Join(dataDir, "hugo") hugoBinPath := filepath.Join(hugoDir, "hugo") hugoTarPath := filepath.Join(hugoDir, fmt.Sprintf("hugo-%s.tar.gz", hugoVersion)) url := fmt.Sprintf("https://github.com/gohugoio/hugo/releases/download/v%s/hugo_extended_%s_linux-amd64.tar.gz", hugoVersion, hugoVersion) if _, err := os.Stat(hugoBinPath); err != nil && os.IsNotExist(err) { if err := httpGetFile(hugoTarPath, url); err != nil { return err } } fpath, err := ioutil.ReadFile(hugoTarPath) if err != nil { return err } if err := extract.Gz(context.TODO(), bytes.NewBuffer(fpath), hugoDir, nil); err != nil { return err } return nil } func httpGetFile(filepath, url string) error { out, err := os.Create(filepath) if err != nil { return err } defer out.Close() resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return err } _, err = io.Copy(out, resp.Body) if err != nil { return err } return nil } func initialise(w http.ResponseWriter, r *http.Request) { usr, err := user.Current() if err != nil { w.Write([]byte(fmt.Sprintf("unable to determine user: %s", err))) } if err := ensureDataDir(usr.HomeDir); err != nil { w.Write([]byte(fmt.Sprintf("unable to create data directory: %s", err))) } if err := ensureHugoBin(usr.HomeDir); err != nil { w.Write([]byte(fmt.Sprintf("unable to download hugo binary: %s", err))) } // TODO: is there a Hugo site already? templ.Handler(components.NewSiteInput()).ServeHTTP(w, r) } func hugoNewSite(w http.ResponseWriter, r *http.Request) { log.Printf("NEW SITE BEING CREATED: %s", r.FormValue("site-name")) } // NewRouter creates a new web router. func NewRouter() *chi.Mux { router := chi.NewRouter() router.Use(middleware.Logger) router.Use(middleware.Recoverer) router.Get("/init", initialise) router.Post("/hugo/new", hugoNewSite) return router }