Files
yawn/server/packages.go

109 lines
2.4 KiB
Go

package main
import (
"bytes"
"crypto/sha256"
"fmt"
"io/fs"
"mime"
"os"
"os/exec"
"path/filepath"
"time"
)
type memoryAsset struct {
contentType string
content []byte
etag string
modified time.Time
}
func buildPackages(root string) (map[string]memoryAsset, error) {
output, err := os.MkdirTemp("", "yawn-packages-*")
if err != nil {
return nil, err
}
defer os.RemoveAll(output)
if err := runBuild(root, "wasm-pack", "build", filepath.Join(root, "core"),
"--target", "web", "--out-dir", filepath.Join(output, "pkg"), "--release"); err != nil {
return nil, err
}
if err := runBuild(root, "node", filepath.Join(root, "server", "build.mjs"), root, output); err != nil {
return nil, err
}
return loadPackages(output)
}
func loadPackages(directory string) (map[string]memoryAsset, error) {
assets := make(map[string]memoryAsset)
for _, name := range []string{
"core.js",
"handles.js",
"worker.js",
"importer-worker.js",
"bvh-worker.js",
} {
asset, err := loadMemoryAsset(filepath.Join(directory, name))
if err != nil {
return nil, err
}
assets[name] = asset
}
err := filepath.WalkDir(filepath.Join(directory, "pkg"), func(path string, entry fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if entry.IsDir() {
return nil
}
relative, err := filepath.Rel(filepath.Join(directory, "pkg"), path)
if err != nil {
return err
}
asset, err := loadMemoryAsset(path)
if err != nil {
return err
}
assets[filepath.ToSlash(filepath.Join("pkg", relative))] = asset
return nil
})
if err != nil {
return nil, err
}
return assets, nil
}
func runBuild(directory, name string, arguments ...string) error {
command := exec.Command(name, arguments...)
command.Dir = directory
command.Env = os.Environ()
var output bytes.Buffer
command.Stdout = &output
command.Stderr = &output
if err := command.Run(); err != nil {
return fmt.Errorf("%s: %w\n%s", name, err, output.String())
}
return nil
}
func loadMemoryAsset(path string) (memoryAsset, error) {
content, err := os.ReadFile(path)
if err != nil {
return memoryAsset{}, err
}
digest := sha256.Sum256(content)
contentType := mime.TypeByExtension(filepath.Ext(path))
if contentType == "" {
contentType = "application/octet-stream"
}
return memoryAsset{
contentType: contentType,
content: content,
etag: fmt.Sprintf("\"%x\"", digest[:12]),
modified: time.Now().UTC(),
}, nil
}