From 0e54a6f9f5298623d5a13450c93a01f5d3e539d0 Mon Sep 17 00:00:00 2001 From: John Donaldson Date: Mon, 21 Oct 2019 15:36:20 +0100 Subject: [PATCH 01/22] Staging some intermediate dehydrator work --- src/handlers.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/handlers.go b/src/handlers.go index a699223..f68a244 100644 --- a/src/handlers.go +++ b/src/handlers.go @@ -1,13 +1,16 @@ package main import ( + "archive/zip" "bufio" + "bytes" "encoding/json" "fmt" "io" "log" "net/http" "os" + "path/filepath" "strconv" "strings" ) @@ -247,6 +250,71 @@ func (ctx *Instance) staticHandler(w http.ResponseWriter, req *http.Request) { http.ServeContent(w, req, path, d.ModTime(), f) } +func (ctx *Instance) dehydrateHandler(w http.ResponseWriter, req *http.Request) { + /* + teamId := req.FormValue("id") + if _, err := ctx.TeamName(teamId); err != nil { + http.Error(w, "Must provide team ID", http.StatusUnauthorized) + return + } + */ + + zipBaseDir := "moth" + + buf := new(bytes.Buffer) + + zipWriter := zip.NewWriter( buf ) + + writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, "puzzles.json"), ctx.jPuzzleList) + writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, "points.json"), ctx.jPointsLog) + + for category_name, category := range ctx.categories { + for _, file := range category.zf.File { + parts := strings.Split(file.Name, "/") + + if (parts[0] == "content") { + fmt.Printf("Inspecting %s/%s\n", category_name, file.Name) + local_buf := new(bytes.Buffer) + fh, _ := file.Open() + defer fh.Close() + local_buf.ReadFrom(fh) + writeZipContents(zipWriter, fmt.Sprintf("%s/%s/%s", zipBaseDir, category_name, file.Name), local_buf.Bytes()) + } + } + } + + filepath.Walk(ctx.ThemeDir, func (path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if ! info.IsDir() { + fmt.Printf("Walking %s\n", path) + local_buf := new(bytes.Buffer) + fh, _ := os.Open(path) + defer fh.Close() + local_buf.ReadFrom(fh) + writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, path), local_buf.Bytes()) + } + return nil + }) + + zipWriter.Close() + + w.Header().Set("Content-Type", "application/zip") + w.WriteHeader(http.StatusOK) + w.Write(buf.Bytes()) +} + +func writeZipContents(z *zip.Writer, path string, contents []byte) error { + f, err := z.Create(path) + if err != nil { + return err + } + f.Write(contents) + + return nil +} + type FurtiveResponseWriter struct { w http.ResponseWriter statusCode *int @@ -289,4 +357,5 @@ func (ctx *Instance) BindHandlers() { ctx.mux.HandleFunc(ctx.Base+"/content/", ctx.contentHandler) ctx.mux.HandleFunc(ctx.Base+"/puzzles.json", ctx.puzzlesHandler) ctx.mux.HandleFunc(ctx.Base+"/points.json", ctx.pointsHandler) + ctx.mux.HandleFunc(ctx.Base+"/dehydrate", ctx.dehydrateHandler) } From 95bcc860e0f49091ba73f14778dde4be8db7d7c5 Mon Sep 17 00:00:00 2001 From: John Donaldson Date: Fri, 25 Oct 2019 23:53:40 +0100 Subject: [PATCH 02/22] Working cache support --- src/handlers.go | 53 ++++++++++++++++++++++++++++--- theme/index.html | 4 ++- theme/manifest.json | 9 ++++++ theme/moth-pwa.js | 18 +++++++++++ theme/moth.js | 72 ++++++++++++++++++++++++++++++++++++++----- theme/puzzle.html | 1 + theme/scoreboard.html | 5 +-- theme/sw.js | 49 +++++++++++++++++++++++++++++ 8 files changed, 197 insertions(+), 14 deletions(-) create mode 100644 theme/manifest.json create mode 100644 theme/moth-pwa.js create mode 100644 theme/sw.js diff --git a/src/handlers.go b/src/handlers.go index f68a244..ee9d1dc 100644 --- a/src/handlers.go +++ b/src/handlers.go @@ -10,7 +10,9 @@ import ( "log" "net/http" "os" + "path" "path/filepath" + "regexp" "strconv" "strings" ) @@ -265,15 +267,16 @@ func (ctx *Instance) dehydrateHandler(w http.ResponseWriter, req *http.Request) zipWriter := zip.NewWriter( buf ) + // Package up important JSON endpoints writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, "puzzles.json"), ctx.jPuzzleList) writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, "points.json"), ctx.jPointsLog) + // Package up files for currently-unlocked puzzles in categories for category_name, category := range ctx.categories { for _, file := range category.zf.File { parts := strings.Split(file.Name, "/") if (parts[0] == "content") { - fmt.Printf("Inspecting %s/%s\n", category_name, file.Name) local_buf := new(bytes.Buffer) fh, _ := file.Open() defer fh.Close() @@ -283,17 +286,21 @@ func (ctx *Instance) dehydrateHandler(w http.ResponseWriter, req *http.Request) } } + // Pack up the theme files + theme_root_re := regexp.MustCompile(fmt.Sprintf("^%s", ctx.ThemeDir)) filepath.Walk(ctx.ThemeDir, func (path string, info os.FileInfo, err error) error { if err != nil { return err } - if ! info.IsDir() { - fmt.Printf("Walking %s\n", path) + + if ! info.IsDir() { // Only package up files local_buf := new(bytes.Buffer) fh, _ := os.Open(path) defer fh.Close() local_buf.ReadFrom(fh) - writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, path), local_buf.Bytes()) + localized_path := theme_root_re.ReplaceAllLiteralString( path, "") + fmt.Printf("Localized path is %s\n", localized_path) + writeZipContents(zipWriter, fmt.Sprintf("%s/%s", zipBaseDir, localized_path), local_buf.Bytes()) } return nil }) @@ -305,7 +312,44 @@ func (ctx *Instance) dehydrateHandler(w http.ResponseWriter, req *http.Request) w.Write(buf.Bytes()) } +func (ctx *Instance) manifestHandler(w http.ResponseWriter, req *http.Request) { + manifest := make([]string, 0) + manifest = append(manifest, "puzzles.json") + manifest = append(manifest, "points.json") + + // Pack up the theme files + theme_root_re := regexp.MustCompile(fmt.Sprintf("^%s/", ctx.ThemeDir)) + filepath.Walk(ctx.ThemeDir, func (path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if ! info.IsDir() { // Only package up files + localized_path := theme_root_re.ReplaceAllLiteralString( path, "") + manifest = append(manifest, localized_path) + } + return nil + }) + + // Package up files for currently-unlocked puzzles in categories + for category_name, category := range ctx.categories { + for _, file := range category.zf.File { + parts := strings.Split(file.Name, "/") + + if (parts[0] == "content") { + manifest = append(manifest, path.Join("content", category_name, path.Join(parts[1:]...))) + } + } + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + manifest_json, _ := json.Marshal(manifest) + w.Write(manifest_json) +} + func writeZipContents(z *zip.Writer, path string, contents []byte) error { + path = filepath.Clean(path) + fmt.Printf("Writing contents to %s\n", path) f, err := z.Create(path) if err != nil { return err @@ -357,5 +401,6 @@ func (ctx *Instance) BindHandlers() { ctx.mux.HandleFunc(ctx.Base+"/content/", ctx.contentHandler) ctx.mux.HandleFunc(ctx.Base+"/puzzles.json", ctx.puzzlesHandler) ctx.mux.HandleFunc(ctx.Base+"/points.json", ctx.pointsHandler) + ctx.mux.HandleFunc(ctx.Base+"/state_manifest.json", ctx.manifestHandler) ctx.mux.HandleFunc(ctx.Base+"/dehydrate", ctx.dehydrateHandler) } diff --git a/theme/index.html b/theme/index.html index 89bdf48..811878e 100644 --- a/theme/index.html +++ b/theme/index.html @@ -5,7 +5,9 @@ + +

MOTH

@@ -20,7 +22,7 @@
- +