webserver up and running for http/https, logger timestamp format change
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
10
config.json
10
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"
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
{{ define "body" }}
|
||||
<body>
|
||||
<div class="container-fluid h-100 d-flex flex-column">
|
||||
<div class="row output flex-grow-1">
|
||||
<div class="col-3 left-sidebar" hx-sse="connect:/sse on:status" hx-swap="innerHTML">
|
||||
Status <br>
|
||||
Last Compilation <br>
|
||||
Such Info <br>
|
||||
Much wow
|
||||
</div>
|
||||
<div class="col-9 p-0">
|
||||
<iframe class="pdf-frame" src="servetex.pdf?ts=0" hx-sse="connect:/sse on:pdf" hx-swap="outerHTML"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div class="command-out" hx-sse="connect:/sse on:output" hx-swap="innerHTML">
|
||||
compile start
|
||||
compile file-x
|
||||
compile file-y
|
||||
example output
|
||||
warning but who cares
|
||||
finished compilation
|
||||
output file created
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
{{ end }}
|
||||
@@ -1,14 +0,0 @@
|
||||
{{ define "head" }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>ServTeX</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/jscss/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/jscss/custom-view.css">
|
||||
<script src="/jscss/htmx.min.js"></script>
|
||||
</head>
|
||||
|
||||
{{ end }}
|
||||
|
||||
@@ -1 +1,41 @@
|
||||
{{ template "header" . }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>ServTeX</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/jscss/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/jscss/custom-view.css">
|
||||
<script src="/jscss/htmx.min.js"></script>
|
||||
<script src="/jscss/htmx-ext-sse.js"></script>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<div class="container-fluid h-100 d-flex flex-column">
|
||||
<div class="row output flex-grow-1">
|
||||
<div class="col-3 left-sidebar" hx-sse="connect:/sse on:status" hx-swap="innerHTML">
|
||||
Status <br>
|
||||
Last Compilation <br>
|
||||
Such Info <br>
|
||||
Much wow
|
||||
</div>
|
||||
<div class="col-9 p-0">
|
||||
<iframe class="pdf-frame" src="/pdf?ts=0" hx-sse="connect:/sse on:pdf" hx-swap="outerHTML"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div class="command-out" hx-sse="connect:/sse on:output" hx-swap="innerHTML">
|
||||
compile start<br>
|
||||
compile file-x<br>
|
||||
compile file-y<br>
|
||||
example output<br>
|
||||
warning but who cares<br>
|
||||
finished compilation<br>
|
||||
output file created<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<iframe class="pdf-frame" src="servetex.pdf?ts={{ .timestamp }}" hx-sse="connect:/sse/pdf" hx-swap="outerHTML"></iframe>
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
54
main.go
54
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")
|
||||
}
|
||||
|
||||
|
||||
19
testing.crt
Normal file
19
testing.crt
Normal file
@@ -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-----
|
||||
28
testing.key
Normal file
28
testing.key
Normal file
@@ -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-----
|
||||
Reference in New Issue
Block a user