Skip to content

Commit

Permalink
Cache previews
Browse files Browse the repository at this point in the history
  • Loading branch information
pipe01 committed Oct 7, 2024
1 parent 6adb6b1 commit b099b72
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 10 deletions.
52 changes: 52 additions & 0 deletions tools/web-previewer/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
)

const previewCacheDir = "/tmp/preview-cache"

func init() {
if err := os.MkdirAll(previewCacheDir, 0755); err != nil {
panic(err)
}
}

func getCachedPath(job PreviewJob, commitSHA string) string {
scriptSum := md5.Sum([]byte(job.Script))

key := fmt.Sprintf("%s-%s-%t", commitSHA, hex.EncodeToString(scriptSum[:]), job.ShowInfo)

return filepath.Join(previewCacheDir, key)
}

func GetCachedPreview(job PreviewJob, commitSHA string) (io.ReadCloser, bool) {
path := getCachedPath(job, commitSHA)

if f, err := os.Open(path); err == nil {
return f, true
}

return nil, false
}

func CachePreview(job PreviewJob, commitSHA string, preview io.Reader) error {
path := getCachedPath(job, commitSHA)

f, err := os.Create(path)
if err != nil {
return fmt.Errorf("create cache file: %w", err)
}
defer f.Close()

if _, err := io.Copy(f, preview); err != nil {
return fmt.Errorf("write cache file: %w", err)
}

return nil
}
54 changes: 44 additions & 10 deletions tools/web-previewer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ var (
previewerPath string
)

type PreviewJob struct {
FirmwareSpec string
Script string
ShowInfo bool
}

func main() {
flag.StringVar(&previewerPath, "previewer", "", "Path to the previewer executable")
flag.DurationVar(&previewTimeout, "preview-timeout", 20*time.Second, "Timeout for the previewer")
Expand Down Expand Up @@ -72,10 +78,20 @@ func main() {
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "no-store")

if err := previewHandler(r.Context(), w, fwSpecifiers[0], script, showInfo); err != nil {
log.Err(err).Msg("failed to generate preview")
w.WriteHeader(http.StatusOK)

if f, ok := w.(http.Flusher); ok {
f.Flush()
}

job := PreviewJob{
FirmwareSpec: fwSpecifiers[0],
Script: script,
ShowInfo: showInfo,
}

w.WriteHeader(http.StatusInternalServerError)
if err := previewHandler(r.Context(), w, job); err != nil {
log.Err(err).Msg("failed to generate preview")

var fwErr FirmwareLoadError

Expand All @@ -94,28 +110,38 @@ func main() {
}
}

func previewHandler(ctx context.Context, rw io.Writer, fwSpecifier string, script string, showInfo bool) error {
func previewHandler(ctx context.Context, rw io.Writer, job PreviewJob) error {
previewLock.Lock()
defer previewLock.Unlock()

fwctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()

fwFile, err := loadFirmware(fwctx, fwSpecifier)
fwFile, err := loadFirmware(fwctx, job.FirmwareSpec)
if err != nil {
return fmt.Errorf("load firmware: %w", err)
}
cancel()
defer os.Remove(fwFile.FirmwareFile.Name())

if pr, ok := GetCachedPreview(job, fwFile.CommitSHA); ok {
defer pr.Close()

if _, err := io.Copy(rw, pr); err != nil {
return fmt.Errorf("write cached preview: %w", err)
}

return nil
}

prctx, cancel := context.WithTimeout(ctx, previewTimeout)
defer cancel()

var scrshotData bytes.Buffer

cmd := exec.CommandContext(prctx, previewerPath, "-screenshot", "/dev/stdout", fwFile.FirmwareFile.Name(), "/dev/stdin")
cmd.Stdout = &scrshotData
cmd.Stdin = strings.NewReader(script)
cmd.Stdin = strings.NewReader(job.Script)
cmd.Stderr = os.Stderr

start := time.Now()
Expand All @@ -126,16 +152,24 @@ func previewHandler(ctx context.Context, rw io.Writer, fwSpecifier string, scrip

previewerRunTime := time.Since(start)

log.Info().Str("fw", fwSpecifier).Str("commit", fwFile.CommitSHA).Dur("time", previewerRunTime).Msg("preview done")
log.Info().Str("fw", job.FirmwareSpec).Str("commit", fwFile.CommitSHA).Dur("time", previewerRunTime).Msg("preview done")

pr, pw := io.Pipe()
defer pw.Close()
defer pr.Close()

out := io.MultiWriter(rw, pw)

go CachePreview(job, fwFile.CommitSHA, pr)

if showInfo {
if job.ShowInfo {
info := fmt.Sprintf("%s %dms %s", fwFile.CommitSHA[:7], previewerRunTime.Milliseconds(), time.Now().UTC().Format(time.DateTime))

if err := drawInfoImage(&scrshotData, rw, info); err != nil {
if err := drawInfoImage(&scrshotData, out, info); err != nil {
return fmt.Errorf("draw info image: %w", err)
}
} else {
if _, err := scrshotData.WriteTo(rw); err != nil {
if _, err := scrshotData.WriteTo(out); err != nil {
return fmt.Errorf("write screenshot: %w", err)
}
}
Expand Down

0 comments on commit b099b72

Please sign in to comment.