diff --git a/Dockerfile b/Dockerfile index 8bbe97a..5e006d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,9 +13,7 @@ COPY . . RUN mkdir -p /opt/antholume # Compile -RUN go build -o /opt/antholume/server; \ - cp -a ./templates /opt/antholume/templates; \ - cp -a ./assets /opt/antholume/assets; +RUN go build -o /opt/antholume/server # Create Image FROM busybox:1.36 diff --git a/Dockerfile-BuildKit b/Dockerfile-BuildKit index da9c6fb..0351120 100644 --- a/Dockerfile-BuildKit +++ b/Dockerfile-BuildKit @@ -15,9 +15,7 @@ ARG TARGETARCH RUN --mount=target=. \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg \ - GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /opt/antholume/server; \ - cp -a ./templates /opt/antholume/templates; \ - cp -a ./assets /opt/antholume/assets; + GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /opt/antholume/server # Create Image FROM busybox:1.36 diff --git a/Makefile b/Makefile index 79473ac..3446322 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ build_local: build_tailwind go mod download - rm -r ./build + rm -r ./build || true mkdir -p ./build - cp -a ./templates ./build/templates - cp -a ./assets ./build/assets env GOOS=linux GOARCH=amd64 go build -o ./build/server_linux_amd64 env GOOS=linux GOARCH=arm64 go build -o ./build/server_linux_arm64 @@ -31,7 +29,6 @@ docker_build_release_latest: build_tailwind build_tailwind: tailwind build -o ./assets/style.css --minify - clean: rm -rf ./build diff --git a/api/api.go b/api/api.go index bba82b0..6e0be26 100644 --- a/api/api.go +++ b/api/api.go @@ -2,8 +2,10 @@ package api import ( "crypto/rand" + "embed" + "fmt" "html/template" - "io/ioutil" + "io/fs" "net/http" "path/filepath" "strings" @@ -23,18 +25,21 @@ type API struct { Config *config.Config DB *database.DBManager HTMLPolicy *bluemonday.Policy + Assets *embed.FS } -func NewApi(db *database.DBManager, c *config.Config) *API { +func NewApi(db *database.DBManager, c *config.Config, assets embed.FS) *API { api := &API{ HTMLPolicy: bluemonday.StrictPolicy(), Router: gin.Default(), Config: c, DB: db, + Assets: &assets, } // Assets & Web App Templates - api.Router.Static("/assets", "./assets") + assetsDir, _ := fs.Sub(assets, "assets") + api.Router.StaticFS("/assets", http.FS(assetsDir)) // Generate Secure Token var newToken []byte @@ -172,37 +177,40 @@ func (api *API) generateTemplates() *multitemplate.Renderer { } // Load Base - b, _ := ioutil.ReadFile("./templates/base.html") + b, _ := api.Assets.ReadFile("templates/base.html") baseTemplate := template.Must(template.New("base").Funcs(helperFuncs).Parse(string(b))) // Load SVGs - svgs, _ := filepath.Glob("./templates/svgs/*") - for _, path := range svgs { - basename := filepath.Base(path) + svgs, _ := api.Assets.ReadDir("templates/svgs") + for _, item := range svgs { + basename := item.Name() + path := fmt.Sprintf("templates/svgs/%s", basename) name := strings.TrimSuffix(basename, filepath.Ext(basename)) - b, _ := ioutil.ReadFile(path) + b, _ := api.Assets.ReadFile(path) baseTemplate = template.Must(baseTemplate.New("svg/" + name).Parse(string(b))) } // Load Components - components, _ := filepath.Glob("./templates/components/*") - for _, path := range components { - basename := filepath.Base(path) + components, _ := api.Assets.ReadDir("templates/components") + for _, item := range components { + basename := item.Name() + path := fmt.Sprintf("templates/components/%s", basename) name := strings.TrimSuffix(basename, filepath.Ext(basename)) - b, _ := ioutil.ReadFile(path) + b, _ := api.Assets.ReadFile(path) baseTemplate = template.Must(baseTemplate.New("component/" + name).Parse(string(b))) } // Load Pages - pages, _ := filepath.Glob("./templates/pages/*") - for _, path := range pages { - basename := filepath.Base(path) + pages, _ := api.Assets.ReadDir("templates/pages") + for _, item := range pages { + basename := item.Name() + path := fmt.Sprintf("templates/pages/%s", basename) name := strings.TrimSuffix(basename, filepath.Ext(basename)) // Clone Base Template - b, _ := ioutil.ReadFile(path) + b, _ := api.Assets.ReadFile(path) pageTemplate, _ := template.Must(baseTemplate.Clone()).New("page/" + name).Parse(string(b)) render.Add("page/"+name, pageTemplate) } diff --git a/api/app-routes.go b/api/app-routes.go index ec4f6c5..c6557b1 100644 --- a/api/app-routes.go +++ b/api/app-routes.go @@ -72,23 +72,23 @@ type requestDocumentAdd struct { func (api *API) webManifest(c *gin.Context) { c.Header("Content-Type", "application/manifest+json") - c.File("./assets/manifest.json") + c.FileFromFS("./assets/manifest.json", http.FS(api.Assets)) } func (api *API) serviceWorker(c *gin.Context) { - c.File("./assets/sw.js") + c.FileFromFS("./assets/sw.js", http.FS(api.Assets)) } func (api *API) faviconIcon(c *gin.Context) { - c.File("./assets/icons/favicon.ico") + c.FileFromFS("./assets/icons/favicon.ico", http.FS(api.Assets)) } func (api *API) localDocuments(c *gin.Context) { - c.File("./assets/local/index.html") + c.FileFromFS("./assets/local/index.html", http.FS(api.Assets)) } func (api *API) documentReader(c *gin.Context) { - c.File("./assets/reader/index.html") + c.FileFromFS("./assets/reader/index.html", http.FS(api.Assets)) } func (api *API) createAppResourcesRoute(routeName string, args ...map[string]any) func(*gin.Context) { @@ -284,7 +284,7 @@ func (api *API) getDocumentCover(c *gin.Context) { // Handle Identified Document if document.Coverfile != nil { if *document.Coverfile == "UNKNOWN" { - c.File("./assets/images/no-cover.jpg") + c.FileFromFS("./assets/images/no-cover.jpg", http.FS(api.Assets)) return } @@ -295,7 +295,7 @@ func (api *API) getDocumentCover(c *gin.Context) { _, err = os.Stat(safePath) if err != nil { log.Error("[getDocumentCover] File Should But Doesn't Exist:", err) - c.File("./assets/images/no-cover.jpg") + c.FileFromFS("./assets/images/no-cover.jpg", http.FS(api.Assets)) return } @@ -348,7 +348,7 @@ func (api *API) getDocumentCover(c *gin.Context) { // Return Unknown Cover if coverFile == "UNKNOWN" { - c.File("./assets/images/no-cover.jpg") + c.FileFromFS("./assets/images/no-cover.jpg", http.FS(api.Assets)) return } diff --git a/main.go b/main.go index 9f15017..5d293b2 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "embed" "os" "os/signal" "sync" @@ -11,6 +12,9 @@ import ( "reichard.io/bbank/server" ) +//go:embed templates/* assets/* +var assets embed.FS + type UTCFormatter struct { log.Formatter } @@ -51,7 +55,7 @@ func cmdServer(ctx *cli.Context) error { signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) // Start Server - server := server.NewServer() + server := server.NewServer(assets) server.StartServer(&wg, done) // Wait & Close diff --git a/server/server.go b/server/server.go index d8a49d7..754328f 100644 --- a/server/server.go +++ b/server/server.go @@ -2,6 +2,7 @@ package server import ( "context" + "embed" "net/http" "os" "path/filepath" @@ -22,10 +23,10 @@ type Server struct { httpServer *http.Server } -func NewServer() *Server { +func NewServer(assets embed.FS) *Server { c := config.Load() db := database.NewMgr(c) - api := api.NewApi(db, c) + api := api.NewApi(db, c, assets) // Create Paths docDir := filepath.Join(c.DataPath, "documents")