diff --git a/src/handlers.go b/src/handlers.go index b58197c..3a513b4 100644 --- a/src/handlers.go +++ b/src/handlers.go @@ -1,9 +1,7 @@ package main import ( - "archive/zip" "bufio" - "bytes" "encoding/json" "fmt" "io" @@ -252,71 +250,23 @@ 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 ) - - // 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") { - 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()) - } - } - } - - // 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 - local_buf := new(bytes.Buffer) - fh, _ := os.Open(path) - defer fh.Close() - local_buf.ReadFrom(fh) - 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 - }) - - zipWriter.Close() - - w.Header().Set("Content-Type", "application/zip") - w.WriteHeader(http.StatusOK) - w.Write(buf.Bytes()) -} - func (ctx *Instance) manifestHandler(w http.ResponseWriter, req *http.Request) { if (! ctx.Runtime.export_manifest) { http.Error(w, "Endpoint disabled", http.StatusForbidden) return } + + teamId := req.FormValue("id") + if _, err := ctx.TeamName(teamId); err != nil { + http.Error(w, "Must provide a valid team ID", http.StatusUnauthorized) + return + } + + if (req.Method == http.MethodHead) { + w.WriteHeader(http.StatusOK) + return + } + manifest := make([]string, 0) manifest = append(manifest, "puzzles.json") manifest = append(manifest, "points.json") @@ -351,18 +301,6 @@ func (ctx *Instance) manifestHandler(w http.ResponseWriter, req *http.Request) { 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 - } - f.Write(contents) - - return nil -} - type FurtiveResponseWriter struct { w http.ResponseWriter statusCode *int @@ -405,6 +343,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+"/state_manifest.json", ctx.manifestHandler) - ctx.mux.HandleFunc(ctx.Base+"/dehydrate", ctx.dehydrateHandler) + ctx.mux.HandleFunc(ctx.Base+"/current_manifest.json", ctx.manifestHandler) } diff --git a/src/maintenance.go b/src/maintenance.go index a4cec4f..6144906 100644 --- a/src/maintenance.go +++ b/src/maintenance.go @@ -292,9 +292,11 @@ func (ctx *Instance) isEnabled() bool { func (ctx *Instance) UpdateConfig() { // Handle export manifest if _, err := os.Stat(ctx.StatePath("export_manifest")); err == nil { - log.Print("Enabling manifest export") - ctx.Runtime.export_manifest = true - } else { + if (! ctx.Runtime.export_manifest) { + log.Print("Enabling manifest export") + ctx.Runtime.export_manifest = true + } + } else if (ctx.Runtime.export_manifest) { log.Print("Disabling manifest export") ctx.Runtime.export_manifest = false } diff --git a/theme/moth.js b/theme/moth.js index f7d7c67..ff17ae2 100644 --- a/theme/moth.js +++ b/theme/moth.js @@ -105,7 +105,10 @@ function showPuzzles(teamId) { document.getElementById("puzzles").appendChild(spinner) heartbeat(teamId) setInterval(e => { heartbeat(teamId) }, 40000) + drawCacheButton(teamId) +} +function drawCacheButton(teamId) { let cacher = document.createElement("li"); let cache_button = document.createElement("a"); cache_button.innerText = "Cache"; @@ -118,6 +121,23 @@ function showPuzzles(teamId) { }); cacher.appendChild(cache_button); document.getElementsByTagName("nav")[0].getElementsByTagName("ul")[0].appendChild(cacher); + + function updateCacheButton() { + let headers = new Headers(); + headers.append("pragma", "no-cache"); + headers.append("cache-control", "no-cache"); + fetch("current_manifest.json?id=" + teamId, {method: "HEAD", headers: headers}) + .then( resp => { + if (resp.ok) { + cacher.style.disply = "initial"; + } else { + cacher.style.display = "none"; + } + }); + } + + setInterval ( updateCacheButton , 30000); + updateCacheButton(); } async function fetchAll(teamId) { @@ -126,7 +146,7 @@ async function fetchAll(teamId) { headers.append("cache-control", "no-cache"); requests = []; - requests.push( fetch("state_manifest.json?id=" + teamId, {headers: headers}) + requests.push( fetch("current_manifest.json?id=" + teamId, {headers: headers}) .then( resp => { if (resp.ok) { resp.json()