package frontend import ( "embed" "fmt" "net/http" "net/url" "os" "path/filepath" "strings" "time" "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 // Sends a Ping to keep the connection alive func ssePing(writer *http.ResponseWriter) { fmt.Fprintf((*writer), ": ping\n\n") (*writer).(http.Flusher).Flush() } // Sends new Event // // Reads globals.LatexExec func sseStatusSend(writer *http.ResponseWriter) { 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() backend.LogLine("Status Event has been sent", 1) } // Sends new Event // // Reads globals.LatexExec func ssePDFSend(writer *http.ResponseWriter) { 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() backend.LogLine("PDF Event has been sent", 1) } // Sends new Event // // Reads globals.LatexExec func sseOutputSend(writer *http.ResponseWriter) { 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() backend.LogLine("Output Event has been sent", 1) } // 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) { writer.Header().Set("Content-Type", "text/event-stream") writer.Header().Set("Cache-Control", "no-cache") writer.Header().Set("Connection", "keep-alive") lastExecution := "startup" 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 } } } // Serves the compiled PDF file func PDFHandler(writer http.ResponseWriter, request *http.Request) { pdfPath := filepath.Join(globals.AppConfig.LatexOutputPath, "servtex.pdf") pdf, err := os.Open(pdfPath) if err != nil { backend.LogLine("PDF file could not be found or read", 1) http.NotFound(writer, request) return } defer pdf.Close() writer.Header().Set("Content-Type", "application/pdf") http.ServeFile(writer, request, pdfPath) } // 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) } func PDFCompile(writer http.ResponseWriter, request *http.Request) { backend.LatexCompile(globals.AppConfig, &globals.LatexExec) }