1
0
Fork 0
mirror of https://github.com/Luzifer/tex-api.git synced 2024-11-08 08:10:09 +00:00

Allow to request log instead of PDF on error

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2023-09-06 19:54:02 +02:00
parent 3364efc57b
commit 9c91061cf1
Signed by: luzifer
GPG key ID: D91C3E91E4CAD6F5
4 changed files with 31 additions and 10 deletions

View file

@ -48,7 +48,7 @@ main.log
main.pdf main.pdf
# Using the default-env and exchanging a TeX file for a PDF # Using the default-env and exchanging a TeX file for a PDF
# curl -sSL -H 'Accept: application/pdf' --data-binary @main.tex -o main.pdf localhost:3000/job # curl -L -H 'Accept: application/pdf' --data-binary @main.tex -OJ localhost:3000/job
``` ```
What happened here is we packed all assets required for generating the letter into the ZIP archive, pushed it to the API, waited for it to build a TAR and extracted the resulting files from it. What happened here is we packed all assets required for generating the letter into the ZIP archive, pushed it to the API, waited for it to build a TAR and extracted the resulting files from it.
@ -69,3 +69,5 @@ GET /job/{uuid}/download Download the resulting archive (You may specify an
Accept header to select whether to receive a ZIP, a Accept header to select whether to receive a ZIP, a
TAR archive or just the raw PDF.) TAR archive or just the raw PDF.)
``` ```
All routes accept the `log-on-error` parameter: If set a PDF download (`Accept` header set to `application/pdf`) will return the log instead of the PDF if no PDF is found.

View file

@ -5,6 +5,7 @@ import (
"archive/zip" "archive/zip"
"bytes" "bytes"
"io" "io"
"io/fs"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -109,7 +110,7 @@ func buildAssetsZIP(uid uuid.UUID) (io.Reader, error) {
return buf, errors.Wrap(w.Close(), "closing zip file") return buf, errors.Wrap(w.Close(), "closing zip file")
} }
func getAssetsPDF(uid uuid.UUID) (io.Reader, error) { func getAssetsFile(uid uuid.UUID, ext string) (io.Reader, error) {
var ( var (
buf = new(bytes.Buffer) buf = new(bytes.Buffer)
found bool found bool
@ -121,7 +122,7 @@ func getAssetsPDF(uid uuid.UUID) (io.Reader, error) {
return err return err
} }
if path.Ext(info.Name()) != ".pdf" { if path.Ext(info.Name()) != ext {
return nil return nil
} }
@ -131,7 +132,7 @@ func getAssetsPDF(uid uuid.UUID) (io.Reader, error) {
} }
defer func() { defer func() {
if err := osFile.Close(); err != nil { if err := osFile.Close(); err != nil {
logrus.WithError(err).Error("closing output pdf file (leaked fd)") logrus.WithError(err).Error("closing output file (leaked fd)")
} }
}() }()
@ -145,7 +146,7 @@ func getAssetsPDF(uid uuid.UUID) (io.Reader, error) {
if !found { if !found {
// We found no file // We found no file
return nil, errors.New("no pdf found") return nil, fs.ErrNotExist
} }
return buf, errors.Wrap(err, "walking source dir") return buf, errors.Wrap(err, "walking source dir")

View file

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"io" "io"
"io/fs"
"net/http" "net/http"
"os" "os"
"time" "time"
@ -109,8 +110,14 @@ func downloadAssets(res http.ResponseWriter, r *http.Request) {
case "application/pdf": case "application/pdf":
contentType = "application/pdf" contentType = "application/pdf"
content, err = getAssetsPDF(uid)
filename = uid.String() + ".pdf" filename = uid.String() + ".pdf"
content, err = getAssetsFile(uid, ".pdf")
if errors.Is(err, fs.ErrNotExist) && r.URL.Query().Has("log-on-error") {
contentType = "application/octet-stream"
filename = uid.String() + ".log"
content, err = getAssetsFile(uid, ".log")
}
default: default:
content, err = buildAssetsZIP(uid) content, err = buildAssetsZIP(uid)

View file

@ -6,7 +6,6 @@ import (
"io" "io"
"math" "math"
"net/http" "net/http"
"net/url"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@ -133,6 +132,7 @@ func startNewJob(res http.ResponseWriter, r *http.Request) {
go jobProcessor(jobUUID) go jobProcessor(jobUUID)
u := urlMust(router.Get("waitForJob").URL("uid", jobUUID.String())) u := urlMust(router.Get("waitForJob").URL("uid", jobUUID.String()))
u.RawQuery = r.URL.Query().Encode()
http.Redirect(res, r, u.String(), http.StatusFound) http.Redirect(res, r, u.String(), http.StatusFound)
} }
@ -163,19 +163,30 @@ func waitForJob(res http.ResponseWriter, r *http.Request) {
fallthrough fallthrough
case statusStarted: case statusStarted:
u := urlMust(router.Get("waitForJob").URL("uid", uid.String()))
u.RawQuery = url.Values{"loop": []string{strconv.Itoa(loop)}}.Encode()
<-time.After(time.Duration(math.Pow(sleepBase, float64(loop))) * time.Second) <-time.After(time.Duration(math.Pow(sleepBase, float64(loop))) * time.Second)
params := r.URL.Query()
params.Set("loop", strconv.Itoa(loop))
u := urlMust(router.Get("waitForJob").URL("uid", uid.String()))
u.RawQuery = params.Encode()
http.Redirect(res, r, u.String(), http.StatusFound) http.Redirect(res, r, u.String(), http.StatusFound)
return return
case statusError: case statusError:
if r.URL.Query().Has("log-on-error") {
u := urlMust(router.Get("downloadAssets").URL("uid", uid.String()))
u.RawQuery = r.URL.Query().Encode()
http.Redirect(res, r, u.String(), http.StatusFound)
return
}
http.Error(res, "Processing ran into an error.", http.StatusInternalServerError) http.Error(res, "Processing ran into an error.", http.StatusInternalServerError)
case statusFinished: case statusFinished:
u := urlMust(router.Get("downloadAssets").URL("uid", uid.String())) u := urlMust(router.Get("downloadAssets").URL("uid", uid.String()))
u.RawQuery = r.URL.Query().Encode()
http.Redirect(res, r, u.String(), http.StatusFound) http.Redirect(res, r, u.String(), http.StatusFound)
} }
} }