diff --git a/backend/backend.go b/backend/backend.go index 1613a57..a55a83d 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -2,26 +2,45 @@ package backend import ( "os" + "os/exec" "path/filepath" "encoding/json" "errors" - "fmt" "git.noctra.dev/noctra/servtex/globals" + "time" ) +func getLocalTime() time.Time { + timezone, _ := time.LoadLocation(globals.AppConfig.Timezone) + return time.Now().In(timezone) +} + +func getLocalTimePretty() string { + return getLocalTime().Format("02.01.2006 15:04") +} + +func LogLine(message string) { + logline := "\n" + getLocalTime().Format(time.RFC3339) + " - " + message + globals.LogFile.WriteString(logline) +} + // Helper for configReader() that does the actual reading +// Also validates the populated fields func configReaderParse(filePath string, configOptionStorage *globals.Config) error { jsonData, err := os.ReadFile(filePath) if err == nil { err = json.Unmarshal(jsonData, &configOptionStorage) if err != nil { - // log error unmarshal failure return errors.New("Config file could not be read") } } else { return errors.New("Config file does not exist") } + return configValidator(*configOptionStorage) +} + +func configValidator(config globals.Config) error { return nil } @@ -48,34 +67,52 @@ func ConfigReader(configFileName string, configOptionStorage *globals.Config) er err = configReaderParse(path, configOptionStorage) if err == nil { return nil } - // log error no config file found - return errors.New("Configuration file not found or json parsing error") + return err } // Watches a specified directory and calls a function on change // Optionally, a minimum time to wait for consecutive changes can be specified func ChangeWatch(path string, callOnChange func()) { + LogLine("File change noticed") } // Intended to be run as goroutine -func LatexCompile(config *globals.Config) error { - if !config.ExecutionLock.TryLock() { +func LatexCompile(config globals.Config, execution *globals.LatexExecution) error { + if !execution.ExecutionLock.TryLock() { + LogLine("LaTeX execution already underway") return errors.New("Execution already in progress") } + LogLine("LaTeX execution started") + execution.ExecutionState = "Started" - var latexCommand string + var latexCommand *exec.Cmd switch config.LatexEngine { case "lualatex": - latexCommand = fmt.Sprintf( - "lualatex -output-directory=%s -jobname=servtex %s", - config.LatexOutputPath, - config.LatexSourceFilePath, - ) - + latexCommand = exec.Command( + "lualatex", + "-output-directory=" + config.LatexOutputPath, + "-jobname=servtex", + config.LatexSourceFilePath, + ) + default: + execution.ExecutionState = "Unknown Latex Engine" + execution.Output = []byte{} + execution.Timestamp = getLocalTimePretty() + execution.ExecutionLock.Unlock() + return errors.New("Unknown Latex Engine") } - - fmt.Sprintf(latexCommand) // placeholder for compilation - config.ExecutionLock.Unlock() + + execution.ExecutionState = "Running" + stdout, err := latexCommand.Output() + if err != nil { + execution.ExecutionState = "Failed" + return err + } + + execution.Output = stdout + execution.Timestamp = getLocalTimePretty() + execution.ExecutionState = "Done" + execution.ExecutionLock.Unlock() return nil } diff --git a/config.json b/config.json index 4bbda70..7e4e2b0 100644 --- a/config.json +++ b/config.json @@ -9,5 +9,6 @@ "webserverDomain": "localhost:9876", "webserverSecure": false, "certificatePath": "", - "certificateKeyPath": "" + "certificateKeyPath": "", + "timezone": "Europe/Berlin" } diff --git a/frontend/templates/body.html b/frontend/templates/body.html index 3868fe9..8544776 100644 --- a/frontend/templates/body.html +++ b/frontend/templates/body.html @@ -12,7 +12,7 @@ -
+
compile start compile file-x compile file-y diff --git a/frontend/webserver.go b/frontend/webserver.go index 94ca71b..a48aaa8 100644 --- a/frontend/webserver.go +++ b/frontend/webserver.go @@ -1,2 +1,32 @@ package frontend +import ( + "net/http" + "fmt" + "git.noctra.dev/noctra/servtex/globals" +) + +// Publishes Meta Information relating to last execution +// Does not use contained Mutex, ignore warning +func SSEStatus(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") + + 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() +} + +func SSEOutput(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") + + 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() +} + diff --git a/globals/config.go b/globals/memory.go similarity index 70% rename from globals/config.go rename to globals/memory.go index 744a0b7..181d437 100644 --- a/globals/config.go +++ b/globals/memory.go @@ -1,6 +1,9 @@ package globals -import "sync" +import ( + "os" + "sync" +) type Config struct { // general @@ -17,9 +20,18 @@ type Config struct { WebserverSecure bool `json:"webserverSecure"` CertificatePath string `json:"certificatePath"` CertificateKeyPath string `json:"certificateKeyPath"` - - // to prevent competing compiles, not actual configuration - ExecutionLock sync.Mutex + Timezone string `json:"timezone"` } var AppConfig Config + +type LatexExecution struct { + ExecutionLock sync.Mutex + ExecutionState string + Timestamp string + Output []byte +} +var LatexExec LatexExecution + +var LogFile *os.File + diff --git a/go.mod b/go.mod index 6ff8378..8f12b97 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module git.noctra.dev/noctra/servtex go 1.25.5 + +require github.com/tmaxmax/go-sse v0.11.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bbc5a77 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/tmaxmax/go-sse v0.11.0 h1:nogmJM6rJUoOLoAwEKeQe5XlVpt9l7N82SS1jI7lWFg= +github.com/tmaxmax/go-sse v0.11.0/go.mod h1:u/2kZQR1tyngo1lKaNCj1mJmhXGZWS1Zs5yiSOD+Eg8= diff --git a/main.go b/main.go index 2519395..4064909 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,6 @@ package main import ( "os" - //"log/slog" "git.noctra.dev/noctra/servtex/globals" "git.noctra.dev/noctra/servtex/backend" //"net/http" @@ -14,8 +13,9 @@ import ( // 1 - config file could not be read func main() { err := backend.ConfigReader("config.json", &globals.AppConfig) - if err != nil { - os.Exit(1) - } + if err != nil { os.Exit(1) } + + globals.LogFile, err = os.Open(globals.AppConfig.LogFilePath) + if err != nil { os.Exit(2) } }