minor changes
This commit is contained in:
@@ -261,7 +261,6 @@ func LatexCompile() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LogLine("LaTeX execution started", 2)
|
LogLine("LaTeX execution started", 2)
|
||||||
execution.ExecutionState = "Started"
|
|
||||||
|
|
||||||
var latexCommand *exec.Cmd
|
var latexCommand *exec.Cmd
|
||||||
switch config.LatexEngine {
|
switch config.LatexEngine {
|
||||||
@@ -282,19 +281,17 @@ func LatexCompile() error {
|
|||||||
return errors.New("Unsupported LaTeX Engine")
|
return errors.New("Unsupported LaTeX Engine")
|
||||||
}
|
}
|
||||||
|
|
||||||
execution.ExecutionState = "Running"
|
|
||||||
stdout, err := latexCommand.Output()
|
stdout, err := latexCommand.Output()
|
||||||
if err != nil {
|
|
||||||
execution.ExecutionState = "Failed"
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
execution.Output = stdout
|
execution.Output = stdout
|
||||||
execution.ExecutionState = "Done"
|
if err == nil {
|
||||||
|
execution.ExecutionState = globals.LatexExecutionStateSuccess
|
||||||
|
} else {
|
||||||
|
execution.ExecutionState = globals.LatexExecutionStateFailure
|
||||||
|
}
|
||||||
updateExecutionTimestamp(execution)
|
updateExecutionTimestamp(execution)
|
||||||
|
|
||||||
LogLine("LaTeX execution finished", 2)
|
LogLine("LaTeX execution finished", 2)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the proxy is trusted. Returns trusted status and the proxy.
|
// Checks whether the proxy is trusted. Returns trusted status and the proxy.
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
.output {
|
.output {
|
||||||
height: 80vh;
|
height: 75vh;
|
||||||
}
|
}
|
||||||
.left-sidebar {
|
.left-sidebar {
|
||||||
padding: 15px;
|
padding: 10px;
|
||||||
|
width: 15vw;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
resize: both;
|
||||||
}
|
}
|
||||||
.pdf-frame {
|
.pdf-frame {
|
||||||
width: 100%;
|
width: 85vw;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
.command-out {
|
.command-out {
|
||||||
height: 20vh;
|
height: 25vh;
|
||||||
padding: 20px;
|
padding: 5px;
|
||||||
background-color: #eaeaea;
|
background-color: #eaeaea;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,29 +10,30 @@
|
|||||||
<script src="/jscss/htmx-ext-sse.js"></script>
|
<script src="/jscss/htmx-ext-sse.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid h-100 d-flex flex-column" hx-ext="sse" sse-connect="/sse">
|
<div class="container-fluid h-100 d-flex flex-column" hx-ext="sse" sse-connect="/sse">
|
||||||
<div class="row output flex-grow-1">
|
<div class="row output flex-grow-1">
|
||||||
|
|
||||||
<div class="col-3 left-sidebar d-flex flex-column justify-content-between">
|
<div class="col-3 left-sidebar d-flex flex-column justify-content-between">
|
||||||
<div>
|
<div>
|
||||||
<h4>ServTeX Status</h4> <br>
|
<h4>ServTeX</h4> <br>
|
||||||
<div sse-swap="status">
|
<div sse-swap="status">
|
||||||
Compilation has not run yet.
|
Compilation information unavailable.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<button class="btn btn-primary mt-2" hx-post="/compile" hx-trigger="click" hx-swap="none">Recompile</button>
|
<button class="btn btn-primary mt-2" hx-post="/compile" hx-trigger="click" hx-swap="none">Recompile</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-9 p-0" sse-swap="pdf">
|
<div class="col-9 p-0" sse-swap="pdf">
|
||||||
<iframe class="pdf-frame" src="/pdf?ts=0"></iframe>
|
<iframe class="pdf-frame" src="/pdf?ts=0"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="command-out" sse-swap="output">
|
|
||||||
</div>
|
<div class="command-out" sse-swap="output"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ func ssePing(writer *http.ResponseWriter) {
|
|||||||
// Reads globals.LatexExec
|
// Reads globals.LatexExec
|
||||||
func sseStatusSend(writer *http.ResponseWriter) {
|
func sseStatusSend(writer *http.ResponseWriter) {
|
||||||
fmt.Fprintf((*writer), "event: status\n")
|
fmt.Fprintf((*writer), "event: status\n")
|
||||||
fmt.Fprintf((*writer), "data: Execution Time: %s<br>\n", globals.LatexExec.Timestamp)
|
fmt.Fprintf((*writer), "data: Execution Time:<br>%s<br><br>\n", globals.LatexExec.Timestamp)
|
||||||
fmt.Fprintf((*writer), "data: Execution State: %s<br>\n\n", globals.LatexExec.ExecutionState)
|
fmt.Fprintf((*writer), "data: Execution State:<br>%s<br>\n\n", globals.LatexExec.ExecutionState)
|
||||||
|
|
||||||
(*writer).(http.Flusher).Flush()
|
(*writer).(http.Flusher).Flush()
|
||||||
backend.LogLine("Status Event has been sent", 1)
|
backend.LogLine("Status Event has been sent", 1)
|
||||||
@@ -85,22 +85,22 @@ func SSEventHandler(writer http.ResponseWriter, request *http.Request) {
|
|||||||
ssePing(&writer)
|
ssePing(&writer)
|
||||||
|
|
||||||
|
|
||||||
lastExecution := ""
|
lastExecution := &globals.LatexExecution{}
|
||||||
for range time.Tick(time.Second) {
|
for range time.Tick(time.Second) {
|
||||||
select {
|
select {
|
||||||
case <-request.Context().Done():
|
case <-request.Context().Done():
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
if lastExecution == globals.LatexExec.TimestampRFC {
|
if lastExecution.Equal(&globals.LatexExec) {
|
||||||
ssePing(&writer)
|
ssePing(&writer)
|
||||||
} else {
|
} else {
|
||||||
sseStatusSend(&writer)
|
sseStatusSend(&writer)
|
||||||
sseOutputSend(&writer)
|
sseOutputSend(&writer)
|
||||||
// let client keep current pdf, if compile failed
|
// let client keep current pdf, if compile failed
|
||||||
if globals.LatexExec.ExecutionState != "Failed" {
|
if globals.LatexExec.ExecutionState != globals.LatexExecutionStateFailure {
|
||||||
ssePDFSend(&writer)
|
ssePDFSend(&writer)
|
||||||
}
|
}
|
||||||
lastExecution = globals.LatexExec.TimestampRFC
|
lastExecution = globals.LatexExec.Copy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,35 @@ type LatexExecution struct {
|
|||||||
Output []byte
|
Output []byte
|
||||||
}
|
}
|
||||||
var LatexExec LatexExecution
|
var LatexExec LatexExecution
|
||||||
|
var LatexExecutionStateSuccess = "Success"
|
||||||
|
var LatexExecutionStateFailure = "Failure"
|
||||||
|
|
||||||
|
// Creates a copy of a LatexExecution (without the Mutex)
|
||||||
|
func (execution *LatexExecution) Copy() (exeCopy *LatexExecution) {
|
||||||
|
if execution == nil { return nil }
|
||||||
|
|
||||||
|
exeCopy = &LatexExecution{
|
||||||
|
ExecutionState: execution.ExecutionState,
|
||||||
|
Timestamp: execution.Timestamp,
|
||||||
|
TimestampRFC: execution.TimestampRFC,
|
||||||
|
}
|
||||||
|
|
||||||
|
if execution.Output != nil {
|
||||||
|
exeCopy.Output = make([]byte, len(execution.Output))
|
||||||
|
copy(exeCopy.Output, execution.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exeCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether the two executions are equal
|
||||||
|
func (left *LatexExecution) Equal(right *LatexExecution) (isEqual bool) {
|
||||||
|
if left.ExecutionState != right.ExecutionState { return false }
|
||||||
|
if left.Timestamp != right.Timestamp { return false }
|
||||||
|
if left.TimestampRFC != right.TimestampRFC { return false }
|
||||||
|
if string(left.Output) != string(right.Output) { return false }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type ClientInfo struct {
|
type ClientInfo struct {
|
||||||
ClientIP string
|
ClientIP string
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -77,7 +77,7 @@ func main() {
|
|||||||
|
|
||||||
// shutdown
|
// shutdown
|
||||||
// known issue: sse blocks shutdown if a client is still connected
|
// known issue: sse blocks shutdown if a client is still connected
|
||||||
context, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
context, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
server.Shutdown(context)
|
server.Shutdown(context)
|
||||||
serverSecure.Shutdown(context)
|
serverSecure.Shutdown(context)
|
||||||
|
|||||||
@@ -1,6 +1,95 @@
|
|||||||
\documentclass{article}
|
% This Example is AI-generated
|
||||||
|
|
||||||
|
\documentclass[12pt]{article}
|
||||||
|
\usepackage[a4paper,margin=1in]{geometry}
|
||||||
|
|
||||||
|
\title{Untitled Collection}
|
||||||
|
\author{ChatGPT}
|
||||||
|
\date{27.12.2025}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
(This is an Example Document)
|
\maketitle
|
||||||
Filewatcher Test Document
|
|
||||||
Filewatcher Test Document
|
\section*{Poem I}
|
||||||
|
|
||||||
|
The clock forgets the hour it keeps,\\
|
||||||
|
Ticks dissolving into air.\\
|
||||||
|
A window leans against the light,\\
|
||||||
|
Certain someone once stood there.
|
||||||
|
|
||||||
|
Words arrive without a mouth,\\
|
||||||
|
Footsteps hum inside the floor.\\
|
||||||
|
Meaning is a temporary guest,\\
|
||||||
|
Memory, a bolted door.
|
||||||
|
|
||||||
|
\bigskip
|
||||||
|
|
||||||
|
The sea repeats a single thought,\\
|
||||||
|
Correcting it with foam.\\
|
||||||
|
Every wave believes itself\\
|
||||||
|
The last to find a home.
|
||||||
|
|
||||||
|
\section*{Poem II}
|
||||||
|
|
||||||
|
Static gathers in the room,\\
|
||||||
|
Ideas flicker, then persist.\\
|
||||||
|
A sentence tries to finish itself\\
|
||||||
|
And fails deliberately mid-
|
||||||
|
|
||||||
|
Silence executes a perfect turn,\\
|
||||||
|
No witnesses remain.\\
|
||||||
|
The poem folds its syntax up\\
|
||||||
|
And waits to be explained.
|
||||||
|
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
\section*{Poem III}
|
||||||
|
|
||||||
|
Morning compiles the streets again,\\
|
||||||
|
Linking shadows, heat, and dust.\\
|
||||||
|
The sun asserts a theorem\\
|
||||||
|
No one bothers to distrust.
|
||||||
|
|
||||||
|
Coffee cools. The day begins.\\
|
||||||
|
Assumptions pass as facts.\\
|
||||||
|
Every plan degrades to noise\\
|
||||||
|
Once time begins to act.
|
||||||
|
|
||||||
|
\section*{Poem IV}
|
||||||
|
|
||||||
|
At night the city dereferences\\
|
||||||
|
Its towers into black.\\
|
||||||
|
Stars leak through abstraction gaps\\
|
||||||
|
The daylight failed to patch.
|
||||||
|
|
||||||
|
Sleep runs a background process,\\
|
||||||
|
Dreams spike the CPU.\\
|
||||||
|
By dawn the system boots once more,\\
|
||||||
|
Convinced the past was true.
|
||||||
|
|
||||||
|
\section*{Poem V}
|
||||||
|
|
||||||
|
The map insists the road is straight,\\
|
||||||
|
Though every mile disagrees.\\
|
||||||
|
Coordinates drift quietly\\
|
||||||
|
Between intent and certainty.
|
||||||
|
|
||||||
|
A compass spins, then settles down,\\
|
||||||
|
Pretending it was sure.\\
|
||||||
|
Direction is a post-hoc claim\\
|
||||||
|
We annotate as we move.
|
||||||
|
|
||||||
|
\section*{Poem VI}
|
||||||
|
|
||||||
|
The archive hums with idle truth,\\
|
||||||
|
Compressed but never gone.\\
|
||||||
|
Each file recalls a version where\\
|
||||||
|
The ending carried on.
|
||||||
|
|
||||||
|
We label loss as cleanup work,\\
|
||||||
|
Deletion dressed as care.\\
|
||||||
|
Nothing vanishes outright—\\
|
||||||
|
It only changes where.
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user