polish HTML debug view
This commit is contained in:
@@ -8,8 +8,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/stapelberg/qrbill"
|
"github.com/stapelberg/qrbill"
|
||||||
@@ -61,26 +59,39 @@ func qrchFromRequest(r *http.Request) *qrbill.QRCH {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fieldNameRe = regexp.MustCompile(`<br>( )*([^:]+):`)
|
func logic() error {
|
||||||
var stringLiteralRe = regexp.MustCompile(`"([^"]*)"`)
|
var listen = flag.String("listen", "localhost:9933", "[host]:port to listen on")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
http.HandleFunc("/qr", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
prefix := "[" + r.RemoteAddr + "]"
|
||||||
|
format := r.FormValue("format")
|
||||||
|
log.Printf("%s handling request for %s, format=%s", prefix, r.URL.Path, format)
|
||||||
|
defer log.Printf("%s request completed (%s)", prefix, r.URL.Path)
|
||||||
|
|
||||||
|
if format == "" {
|
||||||
|
msg := fmt.Sprintf("no ?format= parameter specified. Try %s",
|
||||||
|
"http://"+*listen+"/qr?format=html")
|
||||||
|
log.Printf("%s %s", prefix, msg)
|
||||||
|
http.Error(w, msg, http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func qrHandler(format string) http.Handler {
|
|
||||||
if format != "png" &&
|
if format != "png" &&
|
||||||
format != "svg" &&
|
format != "svg" &&
|
||||||
format != "txt" &&
|
format != "txt" &&
|
||||||
format != "html" {
|
format != "html" {
|
||||||
log.Fatalf("BUG: format must be either png, svg, txt or html")
|
msg := fmt.Sprintf("format (%q) must be one of png, svg, txt or html", format)
|
||||||
|
log.Printf("%s %s", prefix, msg)
|
||||||
|
http.Error(w, msg, http.StatusBadRequest)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
prefix := "[" + r.RemoteAddr + "]"
|
|
||||||
log.Printf("%s handling request for %s", prefix, r.URL.Path)
|
|
||||||
defer log.Printf("%s done: %s", prefix, r.URL.Path)
|
|
||||||
|
|
||||||
qrch := qrchFromRequest(r)
|
qrch := qrchFromRequest(r)
|
||||||
|
|
||||||
bill, err := qrch.Encode()
|
bill, err := qrch.Encode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Printf("%s %s", prefix, err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -90,14 +101,14 @@ func qrHandler(format string) http.Handler {
|
|||||||
case "png":
|
case "png":
|
||||||
code, err := bill.EncodeToImage()
|
code, err := bill.EncodeToImage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Printf("%s %s", prefix, err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := png.Encode(&buf, code); err != nil {
|
if err := png.Encode(&buf, code); err != nil {
|
||||||
log.Print(err)
|
log.Printf("%s %s", prefix, err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -108,7 +119,7 @@ func qrHandler(format string) http.Handler {
|
|||||||
var err error
|
var err error
|
||||||
b, err = bill.EncodeToSVG()
|
b, err = bill.EncodeToSVG()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Printf("%s %s", prefix, err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -120,58 +131,30 @@ func qrHandler(format string) http.Handler {
|
|||||||
spew.Fdump(w, qrch.Fill())
|
spew.Fdump(w, qrch.Fill())
|
||||||
|
|
||||||
case "html":
|
case "html":
|
||||||
w.Header().Add("Content-Type", "text/html; charset=utf-8")
|
debugHTML(w, r, prefix, qrch)
|
||||||
fmt.Fprintf(w, `<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>QR Bill HTML Debug Page</title>
|
|
||||||
<style type="text/css">
|
|
||||||
.fieldname { font-weight: bold; }
|
|
||||||
.stringliteral { color: blue; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body style="font-family: monospace">
|
|
||||||
`)
|
|
||||||
sp := spew.Sdump(qrch.Fill())
|
|
||||||
sp = strings.ReplaceAll(sp, "\n", "<br>")
|
|
||||||
sp = strings.ReplaceAll(sp, " ", " ")
|
|
||||||
sp = stringLiteralRe.ReplaceAllStringFunc(sp, func(stringLiteral string) string {
|
|
||||||
return `<span class="stringliteral">` + stringLiteral + "</span>"
|
|
||||||
})
|
|
||||||
sp = fieldNameRe.ReplaceAllStringFunc(sp, func(fieldName string) string {
|
|
||||||
return `<span class="fieldname">` + fieldName + "</span>"
|
|
||||||
})
|
|
||||||
fmt.Fprintf(w, "%s", sp)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add cache control headers
|
// TODO: add cache control headers
|
||||||
if _, err := io.Copy(w, bytes.NewReader(b)); err != nil {
|
if _, err := io.Copy(w, bytes.NewReader(b)); err != nil {
|
||||||
log.Print(err)
|
log.Printf("%s %s", prefix, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
func logic() error {
|
|
||||||
var listen = flag.String("listen", "localhost:9933", "[host]:port to listen on")
|
|
||||||
flag.Parse()
|
|
||||||
http.Handle("/qr.png", qrHandler("png"))
|
|
||||||
http.Handle("/qr.svg", qrHandler("svg"))
|
|
||||||
http.Handle("/qr.txt", qrHandler("txt"))
|
|
||||||
http.Handle("/qr.html", qrHandler("html"))
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.Path != "/" {
|
if r.URL.Path != "/" {
|
||||||
http.Error(w, "not found", http.StatusNotFound)
|
http.Error(w, "not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Add("Content-Type", "text/html; charset=utf-8")
|
w.Header().Add("Content-Type", "text/html; charset=utf-8")
|
||||||
// TODO: add explanation for how to construt a URL
|
// TODO: add explanation for how to construct a URL
|
||||||
// e.g. for usage in filemaker web view
|
// e.g. for usage in filemaker web view
|
||||||
fmt.Fprintf(w, "<ul>")
|
fmt.Fprintf(w, "<ul>")
|
||||||
fmt.Fprintf(w, `<li>PNG referenz: <a href="/qr.png">qr.png</a>`+"\n")
|
fmt.Fprintf(w, `<li>PNG referenz: <a href="/qr.png">qr.png</a>`+"\n")
|
||||||
fmt.Fprintf(w, `<li>SVG scalable: <a href="/qr.svg">qr.svg</a>`+"\n")
|
fmt.Fprintf(w, `<li>SVG scalable: <a href="/qr.svg">qr.svg</a>`+"\n")
|
||||||
fmt.Fprintf(w, `<li>debug: <a href="/qr.txt">qr.txt</a>`+"\n")
|
fmt.Fprintf(w, `<li>debug: <a href="/qr.html">qr.html</a>, or <a href="/qr.txt">qr.txt</a>`+"\n")
|
||||||
})
|
})
|
||||||
log.Printf("listening on http://%s", *listen)
|
log.Printf("QR Bill generation URL: http://%s/qr?format=html", *listen)
|
||||||
return http.ListenAndServe(*listen, nil)
|
return http.ListenAndServe(*listen, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
195
cmd/qrbill-api/debughtml.go
Normal file
195
cmd/qrbill-api/debughtml.go
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/stapelberg/qrbill"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fieldNameRe = regexp.MustCompile(`<br>( )*([^:]+):`)
|
||||||
|
stringLiteralRe = regexp.MustCompile(`"([^"]*)"`)
|
||||||
|
parenRe = regexp.MustCompile(`\(([^)]+)\) `)
|
||||||
|
)
|
||||||
|
|
||||||
|
var tmpl = template.Must(template.New("").Parse(`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>QR Bill HTML Debug Page</title>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
.fieldname { font-weight: bold; }
|
||||||
|
.stringliteral { color: blue; }
|
||||||
|
#spews { display: flex; }
|
||||||
|
#spews div { border: 1px solid black; margin: 1em; padding: 1em; }
|
||||||
|
.qrch { font-family: monospace; }
|
||||||
|
th { text-align: left; }
|
||||||
|
#params tr td:nth-child(2) { color: blue; }
|
||||||
|
#params tr td:nth-child(1)::before { content: "&"; }
|
||||||
|
#params tr td:nth-child(1)::after { content: "="; }
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="spews">
|
||||||
|
<div class="qrch">
|
||||||
|
<h1>URL parameters</h1>
|
||||||
|
<table id="params">
|
||||||
|
<tr>
|
||||||
|
<th>Parameter</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>criban</td>
|
||||||
|
<td>{{ .Criban }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>crname</td>
|
||||||
|
<td>{{ .Crname }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>craddr1</td>
|
||||||
|
<td>{{ .Craddr1 }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>craddr2</td>
|
||||||
|
<td>{{ .Craddr2 }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>crpost</td>
|
||||||
|
<td>{{ .Crpost }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>crcity</td>
|
||||||
|
<td>{{ .Crcity }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>crcountry</td>
|
||||||
|
<td>{{ .Crcountry }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>udname</td>
|
||||||
|
<td>{{ .Udname }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>udaddr1</td>
|
||||||
|
<td>{{ .Udaddr1 }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>udaddr2</td>
|
||||||
|
<td>{{ .Udaddr2 }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>udpost</td>
|
||||||
|
<td>{{ .Udpost }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>udcity</td>
|
||||||
|
<td>{{ .Udcity }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>udcountry</td>
|
||||||
|
<td>{{ .Udcountry }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>message</td>
|
||||||
|
<td>{{ .Message }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
`))
|
||||||
|
|
||||||
|
func debugHTML(w http.ResponseWriter, r *http.Request, prefix string, qrch *qrbill.QRCH) {
|
||||||
|
w.Header().Add("Content-Type", "text/html; charset=utf-8")
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := tmpl.Execute(&buf, struct {
|
||||||
|
Criban string
|
||||||
|
|
||||||
|
Crname string
|
||||||
|
Craddr1 string
|
||||||
|
Craddr2 string
|
||||||
|
Crpost string
|
||||||
|
Crcity string
|
||||||
|
Crcountry string
|
||||||
|
|
||||||
|
Udname string
|
||||||
|
Udaddr1 string
|
||||||
|
Udaddr2 string
|
||||||
|
Udpost string
|
||||||
|
Udcity string
|
||||||
|
Udcountry string
|
||||||
|
|
||||||
|
Message string
|
||||||
|
}{
|
||||||
|
Criban: r.FormValue("criban"),
|
||||||
|
|
||||||
|
Crname: r.FormValue("crname"),
|
||||||
|
Craddr1: r.FormValue("craddr1"),
|
||||||
|
Craddr2: r.FormValue("craddr2"),
|
||||||
|
Crpost: r.FormValue("crpost"),
|
||||||
|
Crcity: r.FormValue("crcity"),
|
||||||
|
Crcountry: r.FormValue("crcountry"),
|
||||||
|
|
||||||
|
Udname: r.FormValue("udname"),
|
||||||
|
Udaddr1: r.FormValue("udaddr1"),
|
||||||
|
Udaddr2: r.FormValue("udaddr2"),
|
||||||
|
Udpost: r.FormValue("udpost"),
|
||||||
|
Udcity: r.FormValue("udcity"),
|
||||||
|
Udcountry: r.FormValue("udcountry"),
|
||||||
|
|
||||||
|
Message: r.FormValue("message"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%s %s", prefix, err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s", buf.String())
|
||||||
|
|
||||||
|
spew := func(vars ...interface{}) string {
|
||||||
|
sp := spew.Sdump(vars...)
|
||||||
|
sp = strings.ReplaceAll(sp, "\n", "<br>")
|
||||||
|
sp = strings.ReplaceAll(sp, " ", " ")
|
||||||
|
sp = parenRe.ReplaceAllString(sp, "")
|
||||||
|
sp = stringLiteralRe.ReplaceAllStringFunc(sp, func(stringLiteral string) string {
|
||||||
|
return `<span class="stringliteral">` + stringLiteral + "</span>"
|
||||||
|
})
|
||||||
|
sp = fieldNameRe.ReplaceAllStringFunc(sp, func(fieldName string) string {
|
||||||
|
return `<span class="fieldname">` + fieldName + "</span>"
|
||||||
|
})
|
||||||
|
return sp
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, `<div class="qrch"><h1>input</h1>%s</div>`, spew(qrch))
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `<div class="qrch"><h1>validated</h1>%s</div>`, spew(qrch.Fill()))
|
||||||
|
|
||||||
|
r.URL.Path = "/qr"
|
||||||
|
v := r.URL.Query()
|
||||||
|
v.Set("format", "png")
|
||||||
|
r.URL.RawQuery = v.Encode()
|
||||||
|
fmt.Fprintf(w, `<div class="qrch"><h1>QR Bill</h1><img src="%s" width="200" height="200"></div>`, r.URL.String())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user