From 3517d64da805ff1d69a11c6fbb077e76f3ed04dd Mon Sep 17 00:00:00 2001 From: "franz.germann" Date: Thu, 27 Mar 2025 12:45:43 +0000 Subject: [PATCH] adapt-project-structure (#3) Reviewed-on: https://forgejo.edf-bootstrap.cx.fg1.ffm.osc.live/Franz.Germann/ascii-live/pulls/3 Co-authored-by: franz.germann Co-committed-by: franz.germann --- go.mod | 2 +- handlers/handlers.go | 102 +++++++++++++++++++++++++++++++++++++++++++ main.go | 101 ++---------------------------------------- 3 files changed, 107 insertions(+), 98 deletions(-) create mode 100644 handlers/handlers.go diff --git a/go.mod b/go.mod index 1751516..bc5ce83 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/hugomd/ascii-live +module forgejo.edf-bootstrap.cx.fg1.ffm.osc.live/Franz.Germann/ascii-live go 1.24.1 diff --git a/handlers/handlers.go b/handlers/handlers.go new file mode 100644 index 0000000..ea0364f --- /dev/null +++ b/handlers/handlers.go @@ -0,0 +1,102 @@ +package handlers + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "forgejo.edf-bootstrap.cx.fg1.ffm.osc.live/Franz.Germann/ascii-live/frames" + "github.com/golang/glog" + "github.com/gorilla/mux" +) + +var NotFoundMessage = map[string]string{ + "error": "Frames not found. Navigate to /ascii/list for list of frames. Navigate to https://github.com/hugomd/ascii-live to submit new frames.", +} + +var NotCurledMessage = map[string]string{ + "error": "You almost ruined a good surprise. Come on, curl it in terminal.", +} + +var availableFrames []string + +func init() { + for k := range frames.FrameMap { + availableFrames = append(availableFrames, k) + } +} + +func writeJson(w http.ResponseWriter, r *http.Request, res interface{}, status int) { + w.Header().Set("Content-Type", "application/json") + data, err := json.Marshal(res) + if err != nil { + return + } + w.WriteHeader(status) + fmt.Fprint(w, string(data)) +} + +func ListHandler(w http.ResponseWriter, r *http.Request) { + writeJson(w, r, map[string][]string{"frames": availableFrames}, http.StatusOK) +} + +func NotFoundHandler(w http.ResponseWriter, r *http.Request) { + writeJson(w, r, NotFoundMessage, http.StatusNotFound) +} + +func NotCurledHandler(w http.ResponseWriter, r *http.Request) { + writeJson(w, r, NotCurledMessage, http.StatusExpectationFailed) +} + +func Handler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + flusher := w.(http.Flusher) + + vars := mux.Vars(r) + frameSource := vars["frameSource"] + glog.Infof("Frame source %s", frameSource) + + frames, ok := frames.FrameMap[frameSource] + if !ok { + NotFoundHandler(w, r) + return + } + + userAgent := r.Header.Get("User-Agent") + if !strings.Contains(userAgent, "curl") { + NotCurledHandler(w, r) + return + } + + w.Header().Set("Transfer-Encoding", "chunked") + w.WriteHeader(http.StatusOK) + + i := 0 + for { + select { + // Handle client disconnects + case <-ctx.Done(): + glog.Infof("Client stopped listening") + return + default: + if i >= frames.GetLength() { + i = 0 + } + // Artificially wait between reponses. + time.Sleep(frames.GetSleep()) + + // Clear screen + clearScreen := "\033[2J\033[H" + newLine := "\n" + + // Write frames + fmt.Fprint(w, clearScreen+frames.GetFrame(i)+newLine) + i++ + + // Send some data. + flusher.Flush() + } + } +} diff --git a/main.go b/main.go index ff76b46..4d75192 100644 --- a/main.go +++ b/main.go @@ -1,108 +1,15 @@ package main import ( - "encoding/json" "flag" - "fmt" "net/http" - "strings" - "time" - "github.com/hugomd/ascii-live/frames" + "forgejo.edf-bootstrap.cx.fg1.ffm.osc.live/Franz.Germann/ascii-live/handlers" "github.com/golang/glog" "github.com/gorilla/mux" ) -var NotFoundMessage = map[string]string{ - "error": "Frames not found. Navigate to /ascii/list for list of frames. Navigate to https://github.com/hugomd/ascii-live to submit new frames.", -} - -var NotCurledMessage = map[string]string{ - "error": "You almost ruined a good surprise. Come on, curl it in terminal.", -} - -var availableFrames []string - -func init() { - for k := range frames.FrameMap { - availableFrames = append(availableFrames, k) - } -} - -func writeJson(w http.ResponseWriter, r *http.Request, res interface{}, status int) { - w.Header().Set("Content-Type", "application/json") - data, err := json.Marshal(res) - if err != nil { - return - } - w.WriteHeader(status) - fmt.Fprint(w, string(data)) -} - -func listHandler(w http.ResponseWriter, r *http.Request) { - writeJson(w, r, map[string][]string{"frames": availableFrames}, http.StatusOK) -} - -func notFoundHandler(w http.ResponseWriter, r *http.Request) { - writeJson(w, r, NotFoundMessage, http.StatusNotFound) -} - -func notCurledHandler(w http.ResponseWriter, r *http.Request) { - writeJson(w, r, NotCurledMessage, http.StatusExpectationFailed) -} - -func handler(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - flusher := w.(http.Flusher) - - vars := mux.Vars(r) - frameSource := vars["frameSource"] - glog.Infof("Frame source %s", frameSource) - - frames, ok := frames.FrameMap[frameSource] - if !ok { - notFoundHandler(w, r) - return - } - - userAgent := r.Header.Get("User-Agent") - if !strings.Contains(userAgent, "curl") { - notCurledHandler(w, r) - return - } - - w.Header().Set("Transfer-Encoding", "chunked") - w.WriteHeader(http.StatusOK) - - i := 0 - for { - select { - // Handle client disconnects - case <-ctx.Done(): - glog.Infof("Client stopped listening") - return - default: - if i >= frames.GetLength() { - i = 0 - } - // Artificially wait between reponses. - time.Sleep(frames.GetSleep()) - - // Clear screen - clearScreen := "\033[2J\033[H" - newLine := "\n" - - // Write frames - fmt.Fprint(w, clearScreen+frames.GetFrame(i)+newLine) - i++ - - // Send some data. - flusher.Flush() - } - } -} - // Server. func main() { flag.Parse() @@ -110,9 +17,9 @@ func main() { flag.Set("logtostderr", "true") r := mux.NewRouter() - r.HandleFunc("/ascii-live/list", listHandler).Methods("GET") - r.HandleFunc("/ascii-live/{frameSource}", handler).Methods("GET") - r.NotFoundHandler = http.HandlerFunc(notFoundHandler) + r.HandleFunc("/ascii-live/list", handlers.ListHandler).Methods("GET") + r.HandleFunc("/ascii-live/{frameSource}", handlers.Handler).Methods("GET") + r.NotFoundHandler = http.HandlerFunc(handlers.NotFoundHandler) srv := &http.Server{ Handler: r,