package main import ( "log" "strings" "io/fs" "fmt" "path/filepath" "os" "os/signal" "syscall" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/template/html/v2" _ "github.com/mattn/go-sqlite3" recov "github.com/gofiber/fiber/v2/middleware/recover" "zedshaw.games/webapp/api" "zedshaw.games/webapp/data" ) func Fail(err error, format string, v ...any) error { err_format := fmt.Sprintf("ERROR: %v; %s", err, format) log.Printf(err_format, v...) return err } func RenderPages(pages_path string, target string) { engine := html.New(pages_path, ".html") engine.Load() err := filepath.WalkDir(pages_path, func(path string, d fs.DirEntry, err error) error { if !d.IsDir() { if err != nil { return Fail(err, "path: %s", path); } dir := filepath.Dir(path) err = os.MkdirAll(dir, 0750) if err != nil { return Fail(err, "making dir %s", dir); } split_path := strings.Split(path, string(os.PathSeparator))[1:] source_name := strings.Join(split_path, "/") // Render wants / even on windows ext := filepath.Ext(source_name) template_name, found := strings.CutSuffix(source_name, ext) if found && ext == ".html" { prefixed_path := append([]string{target}, split_path...) target_path := filepath.Join(prefixed_path...) // compare time stamps and skip if not newer out, err := os.OpenFile(target_path, os.O_RDWR|os.O_CREATE, 0644) if err != nil { return Fail(err, "writing file %s", target_path) } err = engine.Render(out, template_name, fiber.Map{"Title": "Hello"}) if err != nil { return Fail(err, "failed to render %s", path) } log.Printf("RENDER: %s -> %s", template_name, target_path) out.Close() } } return nil }) if err != nil { log.Fatalf("can't walk content") } } func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) engine := html.New("./views", ".html") app := fiber.New(fiber.Config{ Views: engine, ViewsLayout: "layouts/main", CaseSensitive: true, StrictRouting: true, }) RenderPages("./pages", "./public") app.Use(logger.New()) app.Use(recov.New()) api.Setup(app) data.Setup("sqlite3", "db.sqlite3") // this sets up graceful shutdown go func() { if err := app.Listen(":5001"); err != nil { log.Panic(err) } }() c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) _ = <-c log.Println("Shutdown now...") _ = app.Shutdown() api.Shutdown() data.Shutdown() log.Println("Done.") }