From 95cd785c6a69460838f093fb17e87919f89f490b Mon Sep 17 00:00:00 2001 From: mpl Date: Wed, 19 Jun 2024 15:11:18 +0200 Subject: [PATCH 1/5] various fixes, and idiomatic Go --- notecard/Dockerfile.aarch64 | 3 +- notecard/Dockerfile.amd64 | 3 +- notecard/Dockerfile.armv7hf | 3 +- notecard/Dockerfile.template | 3 +- notecard/main.go | 99 ++++++++++++++++++++---------------- 5 files changed, 58 insertions(+), 53 deletions(-) diff --git a/notecard/Dockerfile.aarch64 b/notecard/Dockerfile.aarch64 index ace0386..7b0559d 100644 --- a/notecard/Dockerfile.aarch64 +++ b/notecard/Dockerfile.aarch64 @@ -3,8 +3,7 @@ FROM balenalib/aarch64-alpine-golang:3.18-build as builder WORKDIR /usr/src/app COPY . ./ -RUN go install && \ - go build -o bin/notecard +RUN go build -o bin/notecard FROM balenalib/aarch64-alpine:3.18-run as runner diff --git a/notecard/Dockerfile.amd64 b/notecard/Dockerfile.amd64 index 5dd5145..1b24981 100644 --- a/notecard/Dockerfile.amd64 +++ b/notecard/Dockerfile.amd64 @@ -3,8 +3,7 @@ FROM balenalib/amd64-alpine-golang:3.18-build as builder WORKDIR /usr/src/app COPY . ./ -RUN go install && \ - go build -o bin/notecard +RUN go build -o bin/notecard FROM balenalib/amd64-alpine:3.18-run as runner diff --git a/notecard/Dockerfile.armv7hf b/notecard/Dockerfile.armv7hf index 9abfcd2..6ec54ac 100644 --- a/notecard/Dockerfile.armv7hf +++ b/notecard/Dockerfile.armv7hf @@ -3,8 +3,7 @@ FROM balenalib/armv7hf-alpine-golang:3.18-build as builder WORKDIR /usr/src/app COPY . ./ -RUN go install && \ - go build -o bin/notecard +RUN go build -o bin/notecard FROM balenalib/armv7hf-alpine:3.18-run as runner diff --git a/notecard/Dockerfile.template b/notecard/Dockerfile.template index f36ec5c..cd8ab53 100644 --- a/notecard/Dockerfile.template +++ b/notecard/Dockerfile.template @@ -3,8 +3,7 @@ FROM balenalib/%%BALENA_ARCH%%-alpine-golang:3.18-build as builder WORKDIR /usr/src/app COPY . ./ -RUN go install && \ - go build -o bin/notecard +RUN go build -o bin/notecard FROM balenalib/%%BALENA_ARCH%%-alpine:3.18-run as runner diff --git a/notecard/main.go b/notecard/main.go index b29c5e0..67d1fcc 100644 --- a/notecard/main.go +++ b/notecard/main.go @@ -3,22 +3,27 @@ package main import ( "encoding/json" "fmt" + "io" + "log" "net/http" "os" "github.com/blues/note-go/notecard" ) -type Transport string - const ( - Serial Transport = "serial" - I2C Transport = "i2c" + Serial = "serial" + I2C = "i2c" ) -var card *notecard.Context +type server struct { + card *notecard.Context +} -func serveNotecard(w http.ResponseWriter, req *http.Request) { +func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if s.card == nil { + log.Fatal("notecard not initialized") + } if req.Method != http.MethodPost { w.WriteHeader(http.StatusMethodNotAllowed) @@ -26,9 +31,18 @@ func serveNotecard(w http.ResponseWriter, req *http.Request) { return } + body, err := io.ReadAll(req.Body) + if err != nil { + log.Printf("while reading request body: %v", err) + http.Error(w, "error reading request body", http.StatusInternalServerError) + return + } + req.Body.Close() + var data map[string]interface{} - if err := json.NewDecoder(req.Body).Decode(&data); err != nil { - http.Error(w, fmt.Sprintf("Error decoding JSON: %v", err), http.StatusBadRequest) + if err := json.Unmarshal(body, &data); err != nil { + log.Printf("while decoding request body: %v", err) + http.Error(w, "error decoding request", http.StatusInternalServerError) return } @@ -36,72 +50,67 @@ func serveNotecard(w http.ResponseWriter, req *http.Request) { fmt.Printf("%s: %v\n", key, value) } - jsonString, err := json.Marshal(data) - if err != nil { - fmt.Println("Error encoding JSON:", err) - w.WriteHeader(http.StatusInternalServerError) - panic(err) - } - // Print the resulting JSON string - fmt.Println(string(jsonString)) + fmt.Println(string(body)) - note_rsp, err := card.Transaction(data) + // TODO: ask Alex: is there any reason we're not directly using + // TransactionJSON on the request body? Which would also save us from doing + // the json encoding ourselves after the code. + note_rsp, err := s.card.Transaction(data) if err != nil { w.WriteHeader(http.StatusInternalServerError) - panic(err) + log.Printf("while doing a card transaction: %v", err) + return } note_rsp_json, err := json.Marshal(note_rsp) if err != nil { fmt.Println("Error encoding JSON:", err) w.WriteHeader(http.StatusInternalServerError) - panic(err) + log.Printf("while encoding transaction response: %v", err) + return } // Set the Content-Type header to application/json w.Header().Set("Content-Type", "application/json") w.Write(note_rsp_json) - - w.WriteHeader(http.StatusOK) } -func setupNotecard(protocol Transport) *notecard.Context { - var card *notecard.Context - var err error - +func setupNotecard(protocol string) (*notecard.Context, error) { fmt.Printf("Setting up Notecard with protocol: %s\n", protocol) - if protocol == Transport("serial") { - card, err = notecard.OpenSerial("/dev/tty.usbmodemNOTE1", 9600) - if err != nil { - fmt.Printf("Error opening Notecard: %v\n", err) - panic(err) - } - } else if protocol == Transport("i2c") { - card, err = notecard.OpenI2C("/dev/i2c-1", 0x17) + if protocol != Serial && protocol != I2C { + return nil, fmt.Errorf("unsupported transport protocol: %v", protocol) + } + + if protocol == Serial { + card, err := notecard.OpenSerial("/dev/tty.usbmodemNOTE1", 9600) if err != nil { - fmt.Printf("Error opening Notecard: %v\n", err) - panic(err) + return nil, fmt.Errorf("Error opening Notecard: %v", err) } - } else { - fmt.Printf("Missing transport protocol\n") + return card, nil } - return card + + card, err := notecard.OpenI2C("/dev/i2c-1", 0x17) + if err != nil { + return nil, fmt.Errorf("Error opening Notecard: %v", err) + } + return card, nil } func main() { - var i interface{} = os.Getenv("NOTECARD_TRANSPORT") - transport, err := i.(Transport) - - if !err { - fmt.Printf("Error getting transport protocol, defaulting to I2C...\n") + transport := os.Getenv("NOTECARD_TRANSPORT") + if transport == "" { + log.Printf("transport protocol not provided, defaulting to I2C...") transport = I2C } - card = setupNotecard(transport) + card, err := setupNotecard(transport) + if err != nil { + log.Fatalf("while setting up notecard: %v", err) + } defer card.Close() - http.HandleFunc("/", serveNotecard) + http.Handle("/", &server{card: card}) http.ListenAndServe(":3434", nil) } From 0ac685720e189bbefc4caa45f1e3d12cae235b6f Mon Sep 17 00:00:00 2001 From: mpl Date: Wed, 19 Jun 2024 15:44:00 +0200 Subject: [PATCH 2/5] tiny changes --- notecard/main.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/notecard/main.go b/notecard/main.go index 67d1fcc..ee32f5e 100644 --- a/notecard/main.go +++ b/notecard/main.go @@ -65,7 +65,6 @@ func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { note_rsp_json, err := json.Marshal(note_rsp) if err != nil { - fmt.Println("Error encoding JSON:", err) w.WriteHeader(http.StatusInternalServerError) log.Printf("while encoding transaction response: %v", err) return @@ -86,14 +85,14 @@ func setupNotecard(protocol string) (*notecard.Context, error) { if protocol == Serial { card, err := notecard.OpenSerial("/dev/tty.usbmodemNOTE1", 9600) if err != nil { - return nil, fmt.Errorf("Error opening Notecard: %v", err) + return nil, fmt.Errorf("error opening Notecard: %v", err) } return card, nil } card, err := notecard.OpenI2C("/dev/i2c-1", 0x17) if err != nil { - return nil, fmt.Errorf("Error opening Notecard: %v", err) + return nil, fmt.Errorf("error opening Notecard: %v", err) } return card, nil } From bf8e9370698355ff05b076b20e43bac3adc3360f Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 19 Jun 2024 15:32:31 +0100 Subject: [PATCH 3/5] Use TransactionJSON to avoid unnecessary unmarshal Change-type: minor Signed-off-by: Alex Bucknall --- notecard/main.go | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/notecard/main.go b/notecard/main.go index ee32f5e..6e097cf 100644 --- a/notecard/main.go +++ b/notecard/main.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "fmt" "io" "log" @@ -39,40 +38,19 @@ func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { } req.Body.Close() - var data map[string]interface{} - if err := json.Unmarshal(body, &data); err != nil { - log.Printf("while decoding request body: %v", err) - http.Error(w, "error decoding request", http.StatusInternalServerError) - return - } - - for key, value := range data { - fmt.Printf("%s: %v\n", key, value) - } - // Print the resulting JSON string fmt.Println(string(body)) - // TODO: ask Alex: is there any reason we're not directly using - // TransactionJSON on the request body? Which would also save us from doing - // the json encoding ourselves after the code. - note_rsp, err := s.card.Transaction(data) + note_rsp, err := s.card.TransactionJSON(body) if err != nil { w.WriteHeader(http.StatusInternalServerError) log.Printf("while doing a card transaction: %v", err) return } - note_rsp_json, err := json.Marshal(note_rsp) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - log.Printf("while encoding transaction response: %v", err) - return - } - // Set the Content-Type header to application/json w.Header().Set("Content-Type", "application/json") - w.Write(note_rsp_json) + w.Write(note_rsp) } func setupNotecard(protocol string) (*notecard.Context, error) { From 9699dd71f33d2f584b9d07b88f65e4f31b73c0cb Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 19 Jun 2024 16:47:47 +0100 Subject: [PATCH 4/5] Addresses logging changes Change-type: minor Signed-off-by: Alex Bucknall --- notecard/main.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/notecard/main.go b/notecard/main.go index 6e097cf..6f860ee 100644 --- a/notecard/main.go +++ b/notecard/main.go @@ -19,6 +19,12 @@ type server struct { card *notecard.Context } +func handleError(w http.ResponseWriter, err error, msg string) { + err_str := fmt.Sprintf("%s: %v", msg, err) + http.Error(w, err_str, http.StatusInternalServerError) + log.Print(err_str) +} + func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { if s.card == nil { log.Fatal("notecard not initialized") @@ -26,35 +32,34 @@ func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { if req.Method != http.MethodPost { w.WriteHeader(http.StatusMethodNotAllowed) - fmt.Fprintf(w, "Method not allowed") + log.Printf("%s: Method not allowed", w) return } body, err := io.ReadAll(req.Body) if err != nil { - log.Printf("while reading request body: %v", err) - http.Error(w, "error reading request body", http.StatusInternalServerError) + handleError(w, err, "while reading request body") return } req.Body.Close() - // Print the resulting JSON string - fmt.Println(string(body)) - note_rsp, err := s.card.TransactionJSON(body) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - log.Printf("while doing a card transaction: %v", err) + handleError(w, err, "while performing a card transaction") return } // Set the Content-Type header to application/json w.Header().Set("Content-Type", "application/json") - w.Write(note_rsp) + _, err = w.Write(note_rsp) + if err != nil { + log.Printf("error writing response: %v", err) + return + } } func setupNotecard(protocol string) (*notecard.Context, error) { - fmt.Printf("Setting up Notecard with protocol: %s\n", protocol) + log.Printf("Setting up Notecard with protocol: %s\n", protocol) if protocol != Serial && protocol != I2C { return nil, fmt.Errorf("unsupported transport protocol: %v", protocol) From 480a9b08f07fbf2008ca12ca50751299f5d07fec Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 19 Jun 2024 17:25:55 +0100 Subject: [PATCH 5/5] Report failed initialisation over HTTP Change-type: minor Signed-off-by: Alex Bucknall --- docker-compose.yml | 3 ++- notecard/main.go | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 786a7a5..b668d82 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,4 +8,5 @@ services: - "/dev/i2c-1:/dev/i2c-1" expose: - "3434" - privileged: true \ No newline at end of file + privileged: true + restart: always diff --git a/notecard/main.go b/notecard/main.go index 6f860ee..b923f66 100644 --- a/notecard/main.go +++ b/notecard/main.go @@ -16,9 +16,12 @@ const ( ) type server struct { - card *notecard.Context + card *notecard.Context + initError error } +var transport = os.Getenv("NOTECARD_TRANSPORT") + func handleError(w http.ResponseWriter, err error, msg string) { err_str := fmt.Sprintf("%s: %v", msg, err) http.Error(w, err_str, http.StatusInternalServerError) @@ -26,8 +29,9 @@ func handleError(w http.ResponseWriter, err error, msg string) { } func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if s.card == nil { - log.Fatal("notecard not initialized") + if s.card == nil || s.initError != nil { + handleError(w, s.initError, "while initialising notecard") + log.Fatal("Notecard not initialised, exiting...") } if req.Method != http.MethodPost { @@ -48,6 +52,7 @@ func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { handleError(w, err, "while performing a card transaction") return } + log.Printf("notecard response: %s", note_rsp) // Set the Content-Type header to application/json w.Header().Set("Content-Type", "application/json") @@ -73,15 +78,21 @@ func setupNotecard(protocol string) (*notecard.Context, error) { return card, nil } - card, err := notecard.OpenI2C("/dev/i2c-1", 0x17) + card, err := notecard.OpenI2C("", 0x17) if err != nil { return nil, fmt.Errorf("error opening Notecard: %v", err) } + + status := map[string]interface{}{ + "req": "card.status", + } + if _, err = card.Transaction(status); err != nil { + return nil, fmt.Errorf("error querying Notecard status: %v", err) + } return card, nil } func main() { - transport := os.Getenv("NOTECARD_TRANSPORT") if transport == "" { log.Printf("transport protocol not provided, defaulting to I2C...") transport = I2C @@ -89,10 +100,10 @@ func main() { card, err := setupNotecard(transport) if err != nil { - log.Fatalf("while setting up notecard: %v", err) + log.Printf("while setting up notecard: %v", err) } defer card.Close() - http.Handle("/", &server{card: card}) + http.Handle("/", &server{card: card, initError: err}) http.ListenAndServe(":3434", nil) }