working as intended
This commit is contained in:
@@ -5,11 +5,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"io/fs"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"git.noctra.dev/noctra/servtex/globals"
|
"git.noctra.dev/noctra/servtex/globals"
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns the current time in the timezone specified in the config file
|
// Returns the current time in the timezone specified in the config file
|
||||||
@@ -111,15 +113,89 @@ func ConfigReader(configFileName string, configOptionStorage *globals.Config) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contents copied from https://github.com/fsnotify/fsnotify/blob/main/cmd/fsnotify/watch.go
|
||||||
|
func watchLoop(watcher *fsnotify.Watcher, callOnChange func() error) {
|
||||||
|
defer watcher.Close()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
// Errors
|
||||||
|
case err, ok := <-watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
LogLine(fmt.Sprintf("Watcher crashed on error, manual compile only: %s", err), 4)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
LogLine(fmt.Sprintf("Watcher Error: %s", err), 3)
|
||||||
|
|
||||||
|
// Events
|
||||||
|
case event, ok := <-watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
LogLine(fmt.Sprintf("Watcher crashed on event, manual compile only: %s", event), 4)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
LogLine(fmt.Sprintf("File change noticed: %s", event.Name), 2)
|
||||||
|
|
||||||
|
err := callOnChange()
|
||||||
|
if err != nil {
|
||||||
|
LogLine(fmt.Sprintf("Latex compilation failed: %s", err), 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = watcher.Add(event.Name); err != nil {
|
||||||
|
LogLine(fmt.Sprintf("File could not be re-added to watcher: %s", event.Name), 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func texFinder(path string) []string {
|
||||||
|
var texFiles []string
|
||||||
|
err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !d.IsDir() && filepath.Ext(path) == ".tex" {
|
||||||
|
texFiles = append(texFiles, path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
LogLine("Some paths could not be traversed while search for .tex files", 3)
|
||||||
|
}
|
||||||
|
return texFiles
|
||||||
|
}
|
||||||
|
|
||||||
// Watches a specified directory and calls a function on change
|
// Watches a specified directory and calls a function on change
|
||||||
//
|
//
|
||||||
// Optionally, a minimum time to wait for consecutive changes can be specified
|
// Optionally, a minimum time to wait for consecutive changes can be specified
|
||||||
func ChangeWatch(path string, callOnChange func()) {
|
func ChangeWatch(path string, callOnChange func() error) {
|
||||||
LogLine("File change noticed", 2)
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
LogLine("File system watcher could not be initialised, manual compile only", 4)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range texFinder(path) {
|
||||||
|
if err = watcher.Add(file); err != nil {
|
||||||
|
LogLine(fmt.Sprintf("File could not be added to watcher: %s", err), 4)
|
||||||
|
}
|
||||||
|
LogLine(fmt.Sprintf("File added to watcher: %s", file), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
go watchLoop(watcher, callOnChange)
|
||||||
|
|
||||||
|
LogLine("Watcher initialised", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func updateExecutionTimestamp(execution *globals.LatexExecution) {
|
||||||
|
execution.Timestamp = GetLocalTimePretty()
|
||||||
|
execution.TimestampRFC = GetLocalTimeRFC()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intended to be run as goroutine
|
// Intended to be run as goroutine
|
||||||
func LatexCompile(config globals.Config, execution *globals.LatexExecution) error {
|
func LatexCompile() error {
|
||||||
|
execution := &globals.LatexExec
|
||||||
|
config := globals.AppConfig
|
||||||
if execution.ExecutionLock.TryLock() {
|
if execution.ExecutionLock.TryLock() {
|
||||||
defer execution.ExecutionLock.Unlock()
|
defer execution.ExecutionLock.Unlock()
|
||||||
} else {
|
} else {
|
||||||
@@ -143,7 +219,8 @@ func LatexCompile(config globals.Config, execution *globals.LatexExecution) erro
|
|||||||
default:
|
default:
|
||||||
execution.ExecutionState = "Unknown Latex Engine"
|
execution.ExecutionState = "Unknown Latex Engine"
|
||||||
execution.Output = []byte{}
|
execution.Output = []byte{}
|
||||||
execution.Timestamp = GetLocalTimePretty()
|
updateExecutionTimestamp(execution)
|
||||||
|
|
||||||
LogLine("Unsupported LaTeX Engine", 4)
|
LogLine("Unsupported LaTeX Engine", 4)
|
||||||
return errors.New("Unsupported LaTeX Engine")
|
return errors.New("Unsupported LaTeX Engine")
|
||||||
}
|
}
|
||||||
@@ -156,8 +233,9 @@ func LatexCompile(config globals.Config, execution *globals.LatexExecution) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
execution.Output = stdout
|
execution.Output = stdout
|
||||||
execution.Timestamp = GetLocalTimePretty()
|
|
||||||
execution.ExecutionState = "Done"
|
execution.ExecutionState = "Done"
|
||||||
|
updateExecutionTimestamp(execution)
|
||||||
|
|
||||||
LogLine("LaTeX execution finished", 2)
|
LogLine("LaTeX execution finished", 2)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,16 +77,17 @@ func SSEventHandler(writer http.ResponseWriter, request *http.Request) {
|
|||||||
writer.Header().Set("Content-Type", "text/event-stream")
|
writer.Header().Set("Content-Type", "text/event-stream")
|
||||||
writer.Header().Set("Cache-Control", "no-cache")
|
writer.Header().Set("Cache-Control", "no-cache")
|
||||||
writer.Header().Set("Connection", "keep-alive")
|
writer.Header().Set("Connection", "keep-alive")
|
||||||
|
ssePing(&writer)
|
||||||
|
|
||||||
lastExecution := "startup"
|
lastExecution := "startup"
|
||||||
for range time.Tick(time.Second) {
|
for range time.Tick(time.Second) {
|
||||||
if lastExecution == globals.LatexExec.Timestamp {
|
if lastExecution == globals.LatexExec.TimestampRFC {
|
||||||
ssePing(&writer)
|
ssePing(&writer)
|
||||||
} else {
|
} else {
|
||||||
sseStatusSend(&writer)
|
sseStatusSend(&writer)
|
||||||
ssePDFSend(&writer)
|
ssePDFSend(&writer)
|
||||||
sseOutputSend(&writer)
|
sseOutputSend(&writer)
|
||||||
// comment out for testing purposes
|
lastExecution = globals.LatexExec.TimestampRFC
|
||||||
lastExecution = globals.LatexExec.Timestamp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,6 +115,6 @@ func MainHandler(writer http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PDFCompile(writer http.ResponseWriter, request *http.Request) {
|
func PDFCompile(writer http.ResponseWriter, request *http.Request) {
|
||||||
backend.LatexCompile(globals.AppConfig, &globals.LatexExec)
|
backend.LatexCompile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type LatexExecution struct {
|
|||||||
ExecutionLock sync.Mutex
|
ExecutionLock sync.Mutex
|
||||||
ExecutionState string
|
ExecutionState string
|
||||||
Timestamp string
|
Timestamp string
|
||||||
|
TimestampRFC string
|
||||||
Output []byte
|
Output []byte
|
||||||
}
|
}
|
||||||
var LatexExec LatexExecution
|
var LatexExec LatexExecution
|
||||||
|
|||||||
23
main.go
23
main.go
@@ -1,14 +1,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
"io/fs"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.noctra.dev/noctra/servtex/backend"
|
"git.noctra.dev/noctra/servtex/backend"
|
||||||
"git.noctra.dev/noctra/servtex/frontend"
|
"git.noctra.dev/noctra/servtex/frontend"
|
||||||
"git.noctra.dev/noctra/servtex/globals"
|
"git.noctra.dev/noctra/servtex/globals"
|
||||||
@@ -49,6 +51,15 @@ func main() {
|
|||||||
if globals.AppConfig.WebserverSecure {
|
if globals.AppConfig.WebserverSecure {
|
||||||
go serverSecure.ListenAndServeTLS(globals.AppConfig.CertificatePath, globals.AppConfig.CertificateKeyPath)
|
go serverSecure.ListenAndServeTLS(globals.AppConfig.CertificatePath, globals.AppConfig.CertificateKeyPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// file system change watch
|
||||||
|
absTexPath, err := filepath.Abs(globals.AppConfig.LatexSourceFilePath)
|
||||||
|
if err == nil {
|
||||||
|
backend.ChangeWatch(filepath.Dir(absTexPath), backend.LatexCompile)
|
||||||
|
} else {
|
||||||
|
backend.LogLine("Absolute TeX file path could not be gotten", 4)
|
||||||
|
}
|
||||||
|
|
||||||
backend.LogLine("Started", 2)
|
backend.LogLine("Started", 2)
|
||||||
fmt.Println("Press CTRL-C to Exit ServTeX")
|
fmt.Println("Press CTRL-C to Exit ServTeX")
|
||||||
|
|
||||||
@@ -61,7 +72,7 @@ func main() {
|
|||||||
fmt.Print("\r")
|
fmt.Print("\r")
|
||||||
|
|
||||||
// shutdown
|
// shutdown
|
||||||
context, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
context, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err = server.Shutdown(context); err != nil {
|
if err = server.Shutdown(context); err != nil {
|
||||||
backend.LogLine("Graceful Shutdown failed", 4)
|
backend.LogLine("Graceful Shutdown failed", 4)
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
\documentclass{article}
|
\documentclass{article}
|
||||||
\begin{document}
|
\begin{document}
|
||||||
(This is an Example Document)
|
(This is an Example Document)
|
||||||
|
Filewatcher Test Document
|
||||||
|
Filewatcher Test Document
|
||||||
|
Filewatcher Test Document
|
||||||
|
Filewatcher Test Document
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
Reference in New Issue
Block a user