diff --git a/cmd/qrbill-example/example.go b/cmd/qrbill-api/api.go
similarity index 66%
rename from cmd/qrbill-example/example.go
rename to cmd/qrbill-api/api.go
index 06d4042..e475202 100644
--- a/cmd/qrbill-example/example.go
+++ b/cmd/qrbill-api/api.go
@@ -8,8 +8,6 @@ import (
"io"
"log"
"net/http"
- "regexp"
- "strings"
"github.com/davecgh/go-spew/spew"
"github.com/stapelberg/qrbill"
@@ -61,26 +59,39 @@ func qrchFromRequest(r *http.Request) *qrbill.QRCH {
}
}
-var fieldNameRe = regexp.MustCompile(`
( )*([^:]+):`)
-var stringLiteralRe = regexp.MustCompile(`"([^"]*)"`)
+func logic() error {
+ var listen = flag.String("listen", "localhost:9933", "[host]:port to listen on")
+ flag.Parse()
-func qrHandler(format string) http.Handler {
- if format != "png" &&
- format != "svg" &&
- format != "txt" &&
- format != "html" {
- log.Fatalf("BUG: format must be either png, svg, txt or html")
- }
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ http.HandleFunc("/qr", 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)
+ 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
+ }
+
+ if format != "png" &&
+ format != "svg" &&
+ format != "txt" &&
+ format != "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
+ }
qrch := qrchFromRequest(r)
bill, err := qrch.Encode()
if err != nil {
- log.Print(err)
+ log.Printf("%s %s", prefix, err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -90,14 +101,14 @@ func qrHandler(format string) http.Handler {
case "png":
code, err := bill.EncodeToImage()
if err != nil {
- log.Print(err)
+ log.Printf("%s %s", prefix, err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var buf bytes.Buffer
if err := png.Encode(&buf, code); err != nil {
- log.Print(err)
+ log.Printf("%s %s", prefix, err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -108,7 +119,7 @@ func qrHandler(format string) http.Handler {
var err error
b, err = bill.EncodeToSVG()
if err != nil {
- log.Print(err)
+ log.Printf("%s %s", prefix, err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -120,58 +131,30 @@ func qrHandler(format string) http.Handler {
spew.Fdump(w, qrch.Fill())
case "html":
- w.Header().Add("Content-Type", "text/html; charset=utf-8")
- fmt.Fprintf(w, `
-
- QR Bill HTML Debug Page
-
-
-
-`)
- sp := spew.Sdump(qrch.Fill())
- sp = strings.ReplaceAll(sp, "\n", "
")
- sp = strings.ReplaceAll(sp, " ", " ")
- sp = stringLiteralRe.ReplaceAllStringFunc(sp, func(stringLiteral string) string {
- return `` + stringLiteral + ""
- })
- sp = fieldNameRe.ReplaceAllStringFunc(sp, func(fieldName string) string {
- return `` + fieldName + ""
- })
- fmt.Fprintf(w, "%s", sp)
+ debugHTML(w, r, prefix, qrch)
}
// TODO: add cache control headers
if _, err := io.Copy(w, bytes.NewReader(b)); err != nil {
- log.Print(err)
+ log.Printf("%s %s", prefix, err)
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) {
if r.URL.Path != "/" {
http.Error(w, "not found", http.StatusNotFound)
return
}
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
fmt.Fprintf(w, "")
fmt.Fprintf(w, `- PNG referenz: qr.png`+"\n")
fmt.Fprintf(w, `
- SVG scalable: qr.svg`+"\n")
- fmt.Fprintf(w, `
- debug: qr.txt`+"\n")
+ fmt.Fprintf(w, `
- debug: qr.html, or qr.txt`+"\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)
}
diff --git a/cmd/qrbill-api/debughtml.go b/cmd/qrbill-api/debughtml.go
new file mode 100644
index 0000000..3107bc7
--- /dev/null
+++ b/cmd/qrbill-api/debughtml.go
@@ -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(`
( )*([^:]+):`)
+ stringLiteralRe = regexp.MustCompile(`"([^"]*)"`)
+ parenRe = regexp.MustCompile(`\(([^)]+)\) `)
+)
+
+var tmpl = template.Must(template.New("").Parse(`
+
+
+ QR Bill HTML Debug Page
+
+
+
+
+
+
URL parameters
+
+
+ | Parameter |
+ Value |
+
+
+
+ | criban |
+ {{ .Criban }} |
+
+
+
+ | crname |
+ {{ .Crname }} |
+
+
+
+ | craddr1 |
+ {{ .Craddr1 }} |
+
+
+
+ | craddr2 |
+ {{ .Craddr2 }} |
+
+
+
+ | crpost |
+ {{ .Crpost }} |
+
+
+
+ | crcity |
+ {{ .Crcity }} |
+
+
+
+ | crcountry |
+ {{ .Crcountry }} |
+
+
+
+
+ | udname |
+ {{ .Udname }} |
+
+
+
+ | udaddr1 |
+ {{ .Udaddr1 }} |
+
+
+
+ | udaddr2 |
+ {{ .Udaddr2 }} |
+
+
+
+ | udpost |
+ {{ .Udpost }} |
+
+
+
+ | udcity |
+ {{ .Udcity }} |
+
+
+
+ | udcountry |
+ {{ .Udcountry }} |
+
+
+
+ | message |
+ {{ .Message }} |
+
+
+
+
+
+`))
+
+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", "
")
+ sp = strings.ReplaceAll(sp, " ", " ")
+ sp = parenRe.ReplaceAllString(sp, "")
+ sp = stringLiteralRe.ReplaceAllStringFunc(sp, func(stringLiteral string) string {
+ return `
` + stringLiteral + ""
+ })
+ sp = fieldNameRe.ReplaceAllStringFunc(sp, func(fieldName string) string {
+ return `
` + fieldName + ""
+ })
+ return sp
+ }
+ fmt.Fprintf(w, `
input
%s`, spew(qrch))
+
+ fmt.Fprintf(w, `
validated
%s`, spew(qrch.Fill()))
+
+ r.URL.Path = "/qr"
+ v := r.URL.Query()
+ v.Set("format", "png")
+ r.URL.RawQuery = v.Encode()
+ fmt.Fprintf(w, `
QR Bill

`, r.URL.String())
+}