package frontend import ( "fmt" "time" "embed" "strings" "net/http" "net/url" "git.noctra.dev/noctra/servtex/backend" "git.noctra.dev/noctra/servtex/globals" ) //go:embed jscss/bootstrap.min.css //go:embed jscss/custom-view.css //go:embed jscss/htmx.min.js //go:embed jscss/htmx-ext-sse.js //go:embed templates/main.html var WebFiles embed.FS // Adds necessary Headers for SSE func sseHeadersAdd(writer *http.ResponseWriter) { (*writer).Header().Set("Content-Type", "text/event-stream") (*writer).Header().Set("Cache-Control", "no-cache") (*writer).Header().Set("Connection", "keep-alive") } // Sends a Ping to keep the connection alive func ssePing(writer *http.ResponseWriter) { sseHeadersAdd(writer) fmt.Fprintf((*writer), ": ping\n\n") (*writer).(http.Flusher).Flush() } // Sends new Event // // Reads globals.LatexExec func sseStatusSend(writer *http.ResponseWriter) { sseHeadersAdd(writer) fmt.Fprintf((*writer), "event: status\n") fmt.Fprintf((*writer), "data: Execution Time: %s\n", globals.LatexExec.Timestamp) fmt.Fprintf((*writer), "data: Execution State: %s\n\n", globals.LatexExec.ExecutionState) (*writer).(http.Flusher).Flush() } // Sends new Event // // Reads globals.LatexExec func ssePDFSend(writer *http.ResponseWriter) { sseHeadersAdd(writer) fmt.Fprintf((*writer), "event: pdf\n") iframe := fmt.Sprintf( ``, url.QueryEscape(backend.GetLocalTimeRFC()), ) fmt.Fprintf((*writer), "data: %s\n\n", iframe) (*writer).(http.Flusher).Flush() } // Sends new Event // // Reads globals.LatexExec func sseOutputSend(writer *http.ResponseWriter) { sseHeadersAdd(writer) fmt.Fprintf((*writer), "event: output\n") lines := strings.SplitSeq(string(globals.LatexExec.Output), "\n") for line := range lines { fmt.Fprintf((*writer), "data: %s\n", line) } fmt.Fprintf((*writer), "\n") (*writer).(http.Flusher).Flush() } // Server Side Event Handler // // Sends a Ping instead of actual data when no new data available to save bandwidth func SSEventHandler(writer http.ResponseWriter, request *http.Request) { lastExecution := "" for range time.Tick(time.Second) { if lastExecution == globals.LatexExec.Timestamp { ssePing(&writer) } else { sseStatusSend(&writer) ssePDFSend(&writer) sseOutputSend(&writer) // comment out for testing purposes lastExecution = globals.LatexExec.Timestamp } } } func PDFHandler(writer http.ResponseWriter, request *http.Request) { http.NotFound(writer, request) } // Serves the main page of ServTeX func MainHandler(writer http.ResponseWriter, request *http.Request) { writer.Header().Set("Content-Type", "text/html") main, _ := WebFiles.ReadFile("templates/main.html") writer.Write(main) }