From cc69ee55be3f82faf45cd334123b3ae96d3ad1ee Mon Sep 17 00:00:00 2001 From: Diogo Silva Date: Thu, 11 Aug 2016 22:39:45 -0300 Subject: [PATCH] Initial commit --- .gitignore | 3 + Dockerfile | 9 ++ Makefile | 23 +++++ README.md | 38 ++++++++ barcodeserver.go | 207 ++++++++++++++++++++++++++++++++++++++++++++ public/.placeholder | 1 + 6 files changed, 281 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 barcodeserver.go create mode 100644 public/.placeholder diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e9e2b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/public +barcodeserver +*.swp diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b4385c8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:3.1 + +RUN mkdir -p /opt/barcode/public +VOLUME /opt/barcode/public + +RUN apk add --update ca-certificates +COPY ./barcodeserver /opt/barcode/barcodeserver +CMD ["/opt/barcode/barcodeserver"] + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..21f0928 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +project = barcodeserver + +all: build + +arm: + CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -a -tags netgo -ldflags '-w' + +build: + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-w' + +clean: + rm petals + +docker: build + docker build -t diogok/$(project) . + +docker-arm: arm + docker build -t diogok/$(project):arm . + +push: + docker push diogok/$(project) + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..80ee065 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# BarCodeServer + +Simple HTTP API around [https://github.com/boombuler/barcode](https://github.com/boombuler/barcode). + +## Api Usage + +Simply issue a get using the type of barcode desired as path and the content as queryString content and it will return a redirect to generated png. + + $ curl -X GET http://localhost:8080/datamatrix?content=Whatever%20data + +Available types: + +* codabar +* code128 +* code39 +* ean +* datamatrix +* qr +* 2of5 + +In case of error it will return Bad Request 400 and error in plain/text. + +## Deploy + +Using the binary, download from the release page and run the binary and it will bind to port 8080. + +Using docker: + + $ docker run -p 8080:8080 -v /tmp/barcodes:/opt/barcode/public diogok/barcodeserver + + +It will save generated code at public folder. You can delete generated artefacts and if requested server will regenerate. + + +## License + +MIT , same as [https://github.com/boombuler/barcode](https://github.com/boombuler/barcode). + diff --git a/barcodeserver.go b/barcodeserver.go new file mode 100644 index 0000000..b8fd51d --- /dev/null +++ b/barcodeserver.go @@ -0,0 +1,207 @@ +package main + +import ( + "bufio" + "crypto/sha1" + "encoding/hex" + "fmt" + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/codabar" + "github.com/boombuler/barcode/code128" + "github.com/boombuler/barcode/code39" + "github.com/boombuler/barcode/datamatrix" + "github.com/boombuler/barcode/ean" + "github.com/boombuler/barcode/qr" + "github.com/boombuler/barcode/twooffive" + "github.com/julienschmidt/httprouter" + "image/png" + "log" + "net/http" + "os" + "strconv" +) + +func IdToPath(id string) string { + hasher := sha1.New() + hasher.Write([]byte(id)) + hash := hex.EncodeToString(hasher.Sum(nil)) + path := fmt.Sprintf("%s/%s/%s.png", hash[0:2], hash[2:4], hash) + os.MkdirAll(fmt.Sprintf("public/%s/%s", hash[0:2], hash[2:4]), 0755) + return path +} + +func Get(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + bartype := p.ByName("type") + content := r.URL.Query().Get("content") + + swidth := r.URL.Query().Get("width") + sheight := r.URL.Query().Get("height") + + if swidth == "" { + swidth = "0" + } + if sheight == "" { + sheight = "0" + } + + width, werr := strconv.Atoi(swidth) + if werr != nil { + log.Println(werr) + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, "Error: %s", werr) + return + } + height, herr := strconv.Atoi(sheight) + if herr != nil { + log.Println(herr) + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, "Error: %s", herr) + return + } + + id := fmt.Sprintf("%s:%s:%d:%d", bartype, content, width, height) + path := IdToPath(id) + realPath := fmt.Sprintf("public/%s", path) + + if _, err := os.Stat(realPath); err == nil { + http.Redirect(w, r, fmt.Sprintf("/%s", path), 307) + return + } + + var err error + var initialBarcode barcode.Barcode + + switch bartype { + case "datamatrix": + initialBarcode, err = datamatrix.Encode(content) + if width == 0 { + width = 256 + } + if height == 0 { + height = 256 + } + case "qr": + initialBarcode, err = qr.Encode(content, qr.Q, qr.Auto) + if width == 0 { + width = 256 + } + if height == 0 { + height = 256 + } + case "codabar": + initialBarcode, err = codabar.Encode(content) + if width == 0 { + width = 256 + } + if height == 0 { + height = 50 + } + case "code128": + initialBarcode, err = code128.Encode(content) + if width == 0 { + width = 256 + } + if height == 0 { + height = 25 + } + case "code39": + initialBarcode, err = code39.Encode(content, true, true) + if width == 0 { + width = 256 + } + if height == 0 { + height = 25 + } + case "ean": + initialBarcode, err = ean.Encode(content) + if width == 0 { + width = 256 + } + if height == 0 { + height = 25 + } + case "2of5": + initialBarcode, err = twooffive.Encode(content, true) + if width == 0 { + width = 256 + } + if height == 0 { + height = 25 + } + case "twooffive": + initialBarcode, err = twooffive.Encode(content, true) + if width == 0 { + width = 256 + } + if height == 0 { + height = 25 + } + } + + if err != nil { + log.Println(err) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error: %s", err) + return + } else if bartype == "" || initialBarcode == nil { + log.Println("Bad type") + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintf(w, "Error: %s", "Bad bar type") + return + } else { + var serr error + var finalBarcode barcode.Barcode + if width != 0 && height != 0 { + finalBarcode, serr = barcode.Scale(initialBarcode, width, height) + } else { + finalBarcode = initialBarcode + } + if serr != nil { + log.Println(serr) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error: %s", serr) + return + } + + file, ferr := os.Create(realPath) + if ferr != nil { + log.Println(ferr) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error: %s", ferr) + return + } + defer file.Close() + + writer := bufio.NewWriter(file) + perr := png.Encode(writer, finalBarcode) + if perr != nil { + log.Println(perr) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error: %s", perr) + return + } + writer.Flush() + + http.Redirect(w, r, fmt.Sprintf("/%s", path), 307) + } +} + +func main() { + sport := os.Getenv("PORT") + var port string + if len(sport) > 2 { + port = sport + } else { + port = "8080" + } + + log.Printf("Binding at 0.0.0.0:%s", port) + + router := httprouter.New() + router.NotFound = http.FileServer(http.Dir("public")) + + router.GET("/", Get) + router.GET("/:type", Get) + + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), router)) +} diff --git a/public/.placeholder b/public/.placeholder new file mode 100644 index 0000000..48cdce8 --- /dev/null +++ b/public/.placeholder @@ -0,0 +1 @@ +placeholder