From aa76d9c7210b7dc611cc7c292aca1b3e7c60bfb7 Mon Sep 17 00:00:00 2001 From: Maximilian Wagner Date: Thu, 25 Dec 2025 23:31:48 +0100 Subject: [PATCH] webserver up and running for http/https, logger timestamp format change --- .gitignore | 6 +++- backend/backend.go | 26 ++++++++++------ config.json | 10 +++--- frontend/templates/body.html | 27 ----------------- frontend/templates/head.html | 14 --------- frontend/templates/main.html | 42 ++++++++++++++++++++++++- frontend/templates/sse-pdf.html | 1 - frontend/webserver.go | 22 +++++++++++++- globals/memory.go | 3 ++ main.go | 54 ++++++++++++++++++++++++++++++--- testing.crt | 19 ++++++++++++ testing.key | 28 +++++++++++++++++ 12 files changed, 190 insertions(+), 62 deletions(-) delete mode 100644 frontend/templates/body.html delete mode 100644 frontend/templates/head.html delete mode 100644 frontend/templates/sse-pdf.html create mode 100644 testing.crt create mode 100644 testing.key diff --git a/.gitignore b/.gitignore index fa07660..3b1931e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ *.dll *.so *.dylib -servtex # Test binary, built with `go test -c` *.test @@ -14,3 +13,8 @@ servtex # Output of the go coverage tool, specifically when used with LiteIDE *.out +# Custom Additions +servtex +servtex.log +output + diff --git a/backend/backend.go b/backend/backend.go index 9ba9ae4..7b4ad1e 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -1,13 +1,15 @@ package backend import ( + "encoding/json" + "errors" + "fmt" "os" "os/exec" "path/filepath" - "encoding/json" - "errors" - "git.noctra.dev/noctra/servtex/globals" "time" + + "git.noctra.dev/noctra/servtex/globals" ) // Returns the current time in the timezone specified in the config file @@ -21,13 +23,19 @@ func GetLocalTimeRFC() string { return GetLocalTime().Format(time.RFC3339) } +func GetLocalTimeLog() string { + return GetLocalTime().Format("2006/01/02 15:04:05") +} + // Returns the current localtime in custom pretty print format func GetLocalTimePretty() string { return GetLocalTime().Format("02.01.2006 15:04") } +// Writes to log and prints to screen func LogLine(message string) { - logline := "\n" + GetLocalTimeRFC() + " - " + message + logline := GetLocalTimeLog() + " ServTeX: " + message + "\n" + fmt.Print(logline) globals.LogFile.WriteString(logline) } @@ -37,8 +45,7 @@ func LogLine(message string) { func configReaderParse(filePath string, configOptionStorage *globals.Config) error { jsonData, err := os.ReadFile(filePath) if err == nil { - err = json.Unmarshal(jsonData, &configOptionStorage) - if err != nil { + if err = json.Unmarshal(jsonData, &configOptionStorage); err != nil { return errors.New("Config file could not be read") } } else { @@ -89,10 +96,13 @@ func ChangeWatch(path string, callOnChange func()) { // Intended to be run as goroutine func LatexCompile(config globals.Config, execution *globals.LatexExecution) error { - if !execution.ExecutionLock.TryLock() { + if execution.ExecutionLock.TryLock() { + defer execution.ExecutionLock.Unlock() + } else { LogLine("LaTeX execution already underway") return errors.New("Execution already in progress") } + LogLine("LaTeX execution started") execution.ExecutionState = "Started" @@ -109,7 +119,6 @@ func LatexCompile(config globals.Config, execution *globals.LatexExecution) erro execution.ExecutionState = "Unknown Latex Engine" execution.Output = []byte{} execution.Timestamp = GetLocalTimePretty() - execution.ExecutionLock.Unlock() return errors.New("Unknown Latex Engine") } @@ -123,7 +132,6 @@ func LatexCompile(config globals.Config, execution *globals.LatexExecution) erro execution.Output = stdout execution.Timestamp = GetLocalTimePretty() execution.ExecutionState = "Done" - execution.ExecutionLock.Unlock() return nil } diff --git a/config.json b/config.json index 7e4e2b0..3f2632c 100644 --- a/config.json +++ b/config.json @@ -6,9 +6,11 @@ "latexSourceFilePath": "", "latexOutputPath": "./output", - "webserverDomain": "localhost:9876", - "webserverSecure": false, - "certificatePath": "", - "certificateKeyPath": "", + "webserverDomain": "localhost", + "webserverPort": "8080", + "webserverSecure": true, + "webserverPortSecure": "8443", + "certificatePath": "./testing.crt", + "certificateKeyPath": "./testing.key", "timezone": "Europe/Berlin" } diff --git a/frontend/templates/body.html b/frontend/templates/body.html deleted file mode 100644 index 5d12c8e..0000000 --- a/frontend/templates/body.html +++ /dev/null @@ -1,27 +0,0 @@ -{{ define "body" }} - -
-
- -
- -
-
-
- compile start - compile file-x - compile file-y - example output - warning but who cares - finished compilation - output file created -
-
- - -{{ end }} diff --git a/frontend/templates/head.html b/frontend/templates/head.html deleted file mode 100644 index 0e5358e..0000000 --- a/frontend/templates/head.html +++ /dev/null @@ -1,14 +0,0 @@ -{{ define "head" }} - - - - ServTeX - - - - - - - -{{ end }} - diff --git a/frontend/templates/main.html b/frontend/templates/main.html index af7c923..c2ce990 100644 --- a/frontend/templates/main.html +++ b/frontend/templates/main.html @@ -1 +1,41 @@ -{{ template "header" . }} + + + + ServTeX + + + + + + + + + + +
+
+ +
+ +
+
+
+ compile start
+ compile file-x
+ compile file-y
+ example output
+ warning but who cares
+ finished compilation
+ output file created
+
+
+ + + + + diff --git a/frontend/templates/sse-pdf.html b/frontend/templates/sse-pdf.html deleted file mode 100644 index 17cd0b5..0000000 --- a/frontend/templates/sse-pdf.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/webserver.go b/frontend/webserver.go index 8ae4941..03ce086 100644 --- a/frontend/webserver.go +++ b/frontend/webserver.go @@ -3,6 +3,7 @@ package frontend import ( "fmt" "time" + "embed" "strings" "net/http" "net/url" @@ -10,6 +11,13 @@ import ( "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") @@ -74,7 +82,7 @@ func sseOutputSend(writer *http.ResponseWriter) { // Server Side Event Handler // // Sends a Ping instead of actual data when no new data available to save bandwidth -func SSEEventSender(writer http.ResponseWriter, request *http.Request) { +func SSEventHandler(writer http.ResponseWriter, request *http.Request) { lastExecution := "" for range time.Tick(time.Second) { if lastExecution == globals.LatexExec.Timestamp { @@ -89,3 +97,15 @@ func SSEEventSender(writer http.ResponseWriter, request *http.Request) { } } + +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) +} + diff --git a/globals/memory.go b/globals/memory.go index 181d437..f01fedc 100644 --- a/globals/memory.go +++ b/globals/memory.go @@ -17,7 +17,9 @@ type Config struct { // webserver WebserverDomain string `json:"webserverDomain"` + WebserverPort string `json:"webserverPort"` WebserverSecure bool `json:"webserverSecure"` + WebserverPortSecure string `json:"webserverPortSecure"` CertificatePath string `json:"certificatePath"` CertificateKeyPath string `json:"certificateKeyPath"` Timezone string `json:"timezone"` @@ -35,3 +37,4 @@ var LatexExec LatexExecution var LogFile *os.File + diff --git a/main.go b/main.go index 4064909..9175d21 100644 --- a/main.go +++ b/main.go @@ -2,20 +2,66 @@ package main import ( "os" - "git.noctra.dev/noctra/servtex/globals" + "os/signal" + "syscall" + "io/fs" + "context" + "fmt" + "time" + "net/http" "git.noctra.dev/noctra/servtex/backend" - //"net/http" + "git.noctra.dev/noctra/servtex/frontend" + "git.noctra.dev/noctra/servtex/globals" ) - // Exit Codes: // 0 - ok // 1 - config file could not be read +// 2 - log file could not be accessed func main() { + // application init err := backend.ConfigReader("config.json", &globals.AppConfig) if err != nil { os.Exit(1) } - globals.LogFile, err = os.Open(globals.AppConfig.LogFilePath) + globals.LogFile, err = os.OpenFile(globals.AppConfig.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { os.Exit(2) } + + globals.LatexExec.Timestamp = "mytimestamp" + + // webserver init + server := &http.Server{Addr: globals.AppConfig.WebserverDomain + ":" + globals.AppConfig.WebserverPort} + serverSecure := &http.Server{Addr: globals.AppConfig.WebserverDomain + ":" + globals.AppConfig.WebserverPortSecure} + + http.HandleFunc("/", frontend.MainHandler) + http.HandleFunc("/sse", frontend.SSEventHandler) + http.HandleFunc("/pdf", frontend.PDFHandler) + jscss, _ := fs.Sub(frontend.WebFiles, "jscss") + http.Handle("/jscss/", http.StripPrefix("/jscss/", http.FileServer(http.FS(jscss)))) + + go server.ListenAndServe() + if globals.AppConfig.WebserverSecure { + go serverSecure.ListenAndServeTLS(globals.AppConfig.CertificatePath, globals.AppConfig.CertificateKeyPath) + } + backend.LogLine("Started") + + // shutdown logic + fmt.Println("Press CTRL-C to Exit ServTeX") + + stop := make(chan os.Signal, 1) + signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) + + <-stop + + context, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + fmt.Print("\r") + if err = server.Shutdown(context); err != nil { + backend.LogLine("Graceful Shutdown failed") + } + if err = serverSecure.Shutdown(context); err != nil { + backend.LogLine("Graceful Shutdown failed") + } + backend.LogLine("Stopped") } diff --git a/testing.crt b/testing.crt new file mode 100644 index 0000000..ece7049 --- /dev/null +++ b/testing.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUfDzMzEHwX7jXT3lKp9+o3MreMNUwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTIyNTIxNTgzMFoXDTI2MTIy +NTIxNTgzMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAyORa1+z/hdvaFX9IRRiadw51xmuVNWenMslb+hu2+PWz +yAwYLNm03JAomFV/Qxm3RCUiZ9kPPw+CWjert40BX908k7rb5IeV4pHAsJkvR65T +ZFCnCpR+e7nOIhy7zDmlilcATq77/AWhyfodR0lUuSTMSO8dYwZRs2rTAkItAo3j +RnMDom742lBjTn7b4F/FZOstbPXX9j1povIyYQ5k92HqRwVeTG+h7w3njnoMOYeW +YOWUUB1LyPHdzPJ50ooqvsNdBcYkkAR8C/R5czUaF/KUXHYM0zoz+QPk+KqTRGeJ +XNVB99viI6QlNVniY0YtJBWl/TEzSQVbt1lEMf3JmwIDAQABo1MwUTAdBgNVHQ4E +FgQUscO27AhUsPrR0NaYDuWgHvgFMrIwHwYDVR0jBBgwFoAUscO27AhUsPrR0NaY +DuWgHvgFMrIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANDUA +YrkofOVQ4Y33YGYTpPSf8CKIOMgJuKFihre7fcBevwRqBkhu+QBty3hvfzJSzUEx +bT9twiO94F8gke1KAWjZQpd05aAtoa3OHf3JPTvRlPqNMpP+g+gCAj2Fm3NT8yBW +nQyIRFg1DVydc61HxvR49DqiigzV+GgjcSS/WAtEDu6l/WhmvGCTHwYxY6w3LT+R +3E/JEp/Mp9o55IFR9tz5wL3R5w4R5JwQZOKdbzQPkYjoxXjI3ldfXC9U/h86t5Md +QmdWYyIfQxsqGoA0LAsUll/zwv1ywudeK1lxNtywXIKIur90a3D81MiTkzbhytVE +DKD9klpayWzekOXrlA== +-----END CERTIFICATE----- diff --git a/testing.key b/testing.key new file mode 100644 index 0000000..bf389fa --- /dev/null +++ b/testing.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDI5FrX7P+F29oV +f0hFGJp3DnXGa5U1Z6cyyVv6G7b49bPIDBgs2bTckCiYVX9DGbdEJSJn2Q8/D4Ja +N6u3jQFf3TyTutvkh5XikcCwmS9HrlNkUKcKlH57uc4iHLvMOaWKVwBOrvv8BaHJ ++h1HSVS5JMxI7x1jBlGzatMCQi0CjeNGcwOibvjaUGNOftvgX8Vk6y1s9df2PWmi +8jJhDmT3YepHBV5Mb6HvDeeOegw5h5Zg5ZRQHUvI8d3M8nnSiiq+w10FxiSQBHwL +9HlzNRoX8pRcdgzTOjP5A+T4qpNEZ4lc1UH32+IjpCU1WeJjRi0kFaX9MTNJBVu3 +WUQx/cmbAgMBAAECggEAY3JboBlT0rVnS44DPiU0TeyME+ns5o+FvsfcLr8qgCrN +USHfk9A/zpHUbrigM5zW0raZRhQ3Dm4EhtmZOVdlj0mrM6xkL0iJQ6wIWcOzGoZr +BLVCQ6QHywLLTqqvsqT01DtGTS0lU3iMQzp75O6hsLdNI2uvPfaCWlFu3Gba9jBb +ZdT+qd9cca3FQSL0fut3msLNr2STtKLgVTEB7IHz2lEbsioBTcd7IlrsXQKTsR9N +UOyTbOzDybt5kWmDYvtuQ7cfMfEuv4fWCBtFib1JljswJI2TaE1Gwpb7u8Hcq2w9 +FCAPtxltYnNRO4Xhru+zkxnG2kVNf/3Z6jzsnfIFHQKBgQDqOl4cwiev8oLwyXbR +UVL7dfXjTGv6PphRAvXHwkOAH8xzndQT6ro7g3ftODDnndN/+/orblB3K4iBMQeU +GVkmKQb1J2sXhRyf5e60WX3ZrhmW7+n7Fmx+znF98NZNSF6QhoYQmfy2ffXlwped +FFyZIkD+MrpNn0hpDa+yS/uA9QKBgQDbkLtxZMo1NKBhC8hKLRO4gzNzTt4n3cbm +psT8bo56fJYjWcr6RGlUJXF+Hol+2cn7MUtYJDpfwT72L6+BF0uv6R6s8eL2R5gE +/gBkIhvx0fMrP5hR+GPd5Gd7PLudbNL5hVH1uOBOkbscy/XhIon32iD+AZzTkybP +DOxO5uZGTwKBgGxkRlkYoDUUDPRQxuNmtvgXRorBOta7UNFshUDD7WjFTl/SkeoF +ndkcpcrpTfhhWRbJDKQ8kJAVXT4r6k3mzRKTudyJOU3RE8YLKcPcBhlOMBlhPO4t +Glg0QOD/Kqzo6JoJJtFX8VKiR8DjpDXUzmUvLNR1tTFmnKPA6aWg8+phAoGADDww +dc0sB3L7TO0fKCMC6lFFWLOYZZhSMSAx8e8nOWQf6bBjQzb0t5+uh1ykRNFWFA1X +KX47UoKuQ4G8wfDOYusWroR8JUUwD3coBmxwKjWM22gb0NWKmx7TNWbY/ZjG2Oi4 +/Hxk43vzdVNYTEdkcM9S71SfrJqSmw8ZS/xJ8LkCgYEA3DaHLR4KNitppL4Tx+5j +dpIKUlCVCtxp4cOtpyuDSg8ssfHB3ZsX7j3+KFX0hF4imORAfUlUkzayuAAw6spF +luPjDo+9g8mmVi3FArkbmef67L98A8C947EpoaqAeZWmFpG2w5tOB0vZcn/gFzOp +hA4tRHe4o26/PRBUb4GFlq8= +-----END PRIVATE KEY-----