db reconnect
This commit is contained in:
parent
895849376e
commit
7f6262b470
@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/handlers"
|
"gitea.futuresens.co.uk/futuresens/hardlink/errorhandlers"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
@ -49,7 +49,7 @@ func ReadHardlinkConfig() ConfigRec {
|
|||||||
|
|
||||||
if cfg.LockType == "" {
|
if cfg.LockType == "" {
|
||||||
err = fmt.Errorf("LockType is required in %s", configName)
|
err = fmt.Errorf("LockType is required in %s", configName)
|
||||||
handlers.FatalError(err)
|
errorhandlers.FatalError(err)
|
||||||
}
|
}
|
||||||
cfg.LockType = strings.ToLower(cfg.LockType)
|
cfg.LockType = strings.ToLower(cfg.LockType)
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ func ReadPreauthReleaserConfig() ConfigRec {
|
|||||||
|
|
||||||
if cfg.Dbport <= 0 || cfg.Dbuser == "" || cfg.Dbname == "" || cfg.Dbpassword == "" {
|
if cfg.Dbport <= 0 || cfg.Dbuser == "" || cfg.Dbname == "" || cfg.Dbpassword == "" {
|
||||||
err = fmt.Errorf("Database config (dbport, dbuser, dbname, dbpassword) are required in %s", configName)
|
err = fmt.Errorf("Database config (dbport, dbuser, dbname, dbpassword) are required in %s", configName)
|
||||||
handlers.FatalError(err)
|
errorhandlers.FatalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.LogDir == "" {
|
if cfg.LogDir == "" {
|
||||||
|
|||||||
1
db/db.go
1
db/db.go
@ -198,3 +198,4 @@ WHERE TxnReference = @TxnReference AND Released = 0;
|
|||||||
log.Infof("Marked preauth %s released at %s", txnReference, releasedAt.Format(time.RFC3339))
|
log.Infof("Marked preauth %s released at %s", txnReference, releasedAt.Format(time.RFC3339))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
32
errorhandlers/errorhandlers.go
Normal file
32
errorhandlers/errorhandlers.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package errorhandlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gitea.futuresens.co.uk/futuresens/cmstypes"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const serviceName = "hardlink"
|
||||||
|
|
||||||
|
// writeError is a helper to send a JSON error and HTTP status in one go.
|
||||||
|
func WriteError(w http.ResponseWriter, status int, msg string) {
|
||||||
|
theResponse := cmstypes.StatusRec{
|
||||||
|
Code: status,
|
||||||
|
Message: msg,
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(status)
|
||||||
|
json.NewEncoder(w).Encode(theResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FatalError(err error) {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
log.Errorf(err.Error())
|
||||||
|
fmt.Println(". Press Enter to exit...")
|
||||||
|
fmt.Scanln()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
54
handlers/db_helpers.go
Normal file
54
handlers/db_helpers.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.futuresens.co.uk/futuresens/hardlink/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (app *App) getDB(ctx context.Context) (*sql.DB, error) {
|
||||||
|
app.dbMu.Lock()
|
||||||
|
defer app.dbMu.Unlock()
|
||||||
|
|
||||||
|
// Fast path: db exists and is alive
|
||||||
|
if app.db != nil {
|
||||||
|
pingCtx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := app.db.PingContext(pingCtx); err == nil {
|
||||||
|
return app.db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// stale handle
|
||||||
|
_ = app.db.Close()
|
||||||
|
app.db = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconnect once, bounded
|
||||||
|
dialCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
dbConn, err := db.InitMSSQL(
|
||||||
|
app.cfg.Dbport,
|
||||||
|
app.cfg.Dbuser,
|
||||||
|
app.cfg.Dbpassword,
|
||||||
|
app.cfg.Dbname,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional ping (InitMSSQL already pings, but this keeps semantics explicit)
|
||||||
|
pingCtx, cancel2 := context.WithTimeout(dialCtx, 1*time.Second)
|
||||||
|
defer cancel2()
|
||||||
|
|
||||||
|
if err := dbConn.PingContext(pingCtx); err != nil {
|
||||||
|
_ = dbConn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
app.db = dbConn
|
||||||
|
return app.db, nil
|
||||||
|
}
|
||||||
@ -8,13 +8,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tarm/serial"
|
"github.com/tarm/serial"
|
||||||
|
|
||||||
"gitea.futuresens.co.uk/futuresens/cmstypes"
|
"gitea.futuresens.co.uk/futuresens/cmstypes"
|
||||||
|
"gitea.futuresens.co.uk/futuresens/hardlink/config"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/db"
|
"gitea.futuresens.co.uk/futuresens/hardlink/db"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/dispenser"
|
"gitea.futuresens.co.uk/futuresens/hardlink/dispenser"
|
||||||
|
"gitea.futuresens.co.uk/futuresens/hardlink/errorhandlers"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/lockserver"
|
"gitea.futuresens.co.uk/futuresens/hardlink/lockserver"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/payment"
|
"gitea.futuresens.co.uk/futuresens/hardlink/payment"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/printer"
|
"gitea.futuresens.co.uk/futuresens/hardlink/printer"
|
||||||
@ -28,14 +31,17 @@ type App struct {
|
|||||||
lockserver lockserver.LockServer
|
lockserver lockserver.LockServer
|
||||||
isPayment bool
|
isPayment bool
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
cfg *config.ConfigRec
|
||||||
|
dbMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApp(dispPort *serial.Port, lockType, encoderAddress string, db *sql.DB, isPayment bool) *App {
|
func NewApp(dispPort *serial.Port, lockType, encoderAddress string, db *sql.DB, cfg *config.ConfigRec) *App {
|
||||||
return &App{
|
return &App{
|
||||||
isPayment: isPayment,
|
isPayment: cfg.IsPayment,
|
||||||
dispPort: dispPort,
|
dispPort: dispPort,
|
||||||
lockserver: lockserver.NewLockServer(lockType, encoderAddress, FatalError),
|
lockserver: lockserver.NewLockServer(lockType, encoderAddress, errorhandlers.FatalError),
|
||||||
db: db,
|
db: db,
|
||||||
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,8 +137,16 @@ func (app *App) takePreauthorization(w http.ResponseWriter, r *http.Request) {
|
|||||||
theResponse.Status = result.Status
|
theResponse.Status = result.Status
|
||||||
theResponse.Data, save = payment.BuildPreauthRedirectURL(result.Fields)
|
theResponse.Data, save = payment.BuildPreauthRedirectURL(result.Fields)
|
||||||
if save {
|
if save {
|
||||||
db.InsertPreauth(r.Context(), app.db, result.Fields, theRequest.CheckoutDate)
|
dbConn, err := app.getDB(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Warn("DB unavailable; preauth not stored")
|
||||||
|
} else {
|
||||||
|
if err := db.InsertPreauth(r.Context(), dbConn, result.Fields, theRequest.CheckoutDate); err != nil {
|
||||||
|
log.WithError(err).Warn("Failed to store preauth in DB")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeTransactionResult(w, http.StatusOK, theResponse)
|
writeTransactionResult(w, http.StatusOK, theResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,19 +255,19 @@ func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
log.Println("issueDoorCard called")
|
log.Println("issueDoorCard called")
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
writeError(w, http.StatusMethodNotAllowed, "Method not allowed; use POST")
|
errorhandlers.WriteError(w, http.StatusMethodNotAllowed, "Method not allowed; use POST")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
if ct := r.Header.Get("Content-Type"); ct != "application/json" {
|
if ct := r.Header.Get("Content-Type"); ct != "application/json" {
|
||||||
writeError(w, http.StatusUnsupportedMediaType, "Content-Type must be application/json")
|
errorhandlers.WriteError(w, http.StatusUnsupportedMediaType, "Content-Type must be application/json")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&doorReq); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&doorReq); err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "ReadJSON", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "ReadJSON", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusBadRequest, "Invalid JSON payload: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusBadRequest, "Invalid JSON payload: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,13 +275,13 @@ func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
checkIn, err := time.Parse(types.CustomLayout, doorReq.CheckinTime)
|
checkIn, err := time.Parse(types.CustomLayout, doorReq.CheckinTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "Invalid checkinTime format", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "Invalid checkinTime format", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusBadRequest, "Invalid checkinTime format: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusBadRequest, "Invalid checkinTime format: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
checkOut, err := time.Parse(types.CustomLayout, doorReq.CheckoutTime)
|
checkOut, err := time.Parse(types.CustomLayout, doorReq.CheckoutTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "Invalid checkoutTime format", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "Invalid checkoutTime format", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusBadRequest, "Invalid checkoutTime format: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusBadRequest, "Invalid checkoutTime format: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,10 +289,10 @@ func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
if status, err := dispenser.DispenserSequence(app.dispPort); err != nil {
|
if status, err := dispenser.DispenserSequence(app.dispPort); err != nil {
|
||||||
if status != "" {
|
if status != "" {
|
||||||
logging.Error(serviceName, status, "Dispense error", string(op), "", "", 0)
|
logging.Error(serviceName, status, "Dispense error", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusServiceUnavailable, "Dispense error: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusServiceUnavailable, "Dispense error: "+err.Error())
|
||||||
} else {
|
} else {
|
||||||
logging.Error(serviceName, err.Error(), "Dispense error", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "Dispense error", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusServiceUnavailable, "Dispense error: "+err.Error()+"; check card stock")
|
errorhandlers.WriteError(w, http.StatusServiceUnavailable, "Dispense error: "+err.Error()+"; check card stock")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@ -292,7 +306,7 @@ func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
err = app.lockserver.LockSequence()
|
err = app.lockserver.LockSequence()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "Key encoding", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "Key encoding", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusBadGateway, err.Error())
|
errorhandlers.WriteError(w, http.StatusBadGateway, err.Error())
|
||||||
dispenser.CardOutOfMouth(app.dispPort)
|
dispenser.CardOutOfMouth(app.dispPort)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -300,7 +314,7 @@ func (app *App) issueDoorCard(w http.ResponseWriter, r *http.Request) {
|
|||||||
// final dispenser steps
|
// final dispenser steps
|
||||||
if status, err := dispenser.CardOutOfMouth(app.dispPort); err != nil {
|
if status, err := dispenser.CardOutOfMouth(app.dispPort); err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "Dispenser eject error", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "Dispenser eject error", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusServiceUnavailable, "Dispenser eject error: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusServiceUnavailable, "Dispenser eject error: "+err.Error())
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.Info(status)
|
log.Info(status)
|
||||||
@ -328,32 +342,32 @@ func (app *App) printRoomTicket(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
log.Println("printRoomTicket called")
|
log.Println("printRoomTicket called")
|
||||||
if r.Method != http.MethodPost {
|
if r.Method != http.MethodPost {
|
||||||
writeError(w, http.StatusMethodNotAllowed, "Method not allowed; use POST")
|
errorhandlers.WriteError(w, http.StatusMethodNotAllowed, "Method not allowed; use POST")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ct := r.Header.Get("Content-Type"); !strings.Contains(ct, "xml") {
|
if ct := r.Header.Get("Content-Type"); !strings.Contains(ct, "xml") {
|
||||||
writeError(w, http.StatusUnsupportedMediaType, "Content-Type must be application/xml")
|
errorhandlers.WriteError(w, http.StatusUnsupportedMediaType, "Content-Type must be application/xml")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
if err := xml.NewDecoder(r.Body).Decode(&roomDetails); err != nil {
|
if err := xml.NewDecoder(r.Body).Decode(&roomDetails); err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "ReadXML", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "ReadXML", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusBadRequest, "Invalid XML payload: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusBadRequest, "Invalid XML payload: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := printer.BuildRoomTicket(roomDetails)
|
data, err := printer.BuildRoomTicket(roomDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "BuildRoomTicket", string(op), "", "", 0)
|
logging.Error(serviceName, err.Error(), "BuildRoomTicket", string(op), "", "", 0)
|
||||||
writeError(w, http.StatusInternalServerError, "BuildRoomTicket failed: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusInternalServerError, "BuildRoomTicket failed: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send to the Windows Epson TM-T82II via the printer package
|
// Send to the Windows Epson TM-T82II via the printer package
|
||||||
if err := printer.SendToPrinter(data); err != nil {
|
if err := printer.SendToPrinter(data); err != nil {
|
||||||
logging.Error(serviceName, err.Error(), "printRoomTicket", "printRoomTicket", "", "", 0)
|
logging.Error(serviceName, err.Error(), "printRoomTicket", "printRoomTicket", "", "", 0)
|
||||||
writeError(w, http.StatusInternalServerError, "Print failed: "+err.Error())
|
errorhandlers.WriteError(w, http.StatusInternalServerError, "Print failed: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,28 +2,14 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
|
|
||||||
"gitea.futuresens.co.uk/futuresens/cmstypes"
|
"gitea.futuresens.co.uk/futuresens/cmstypes"
|
||||||
"gitea.futuresens.co.uk/futuresens/logging"
|
"gitea.futuresens.co.uk/futuresens/logging"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const serviceName = "hardlink"
|
const serviceName = "hardlink"
|
||||||
|
|
||||||
// writeError is a helper to send a JSON error and HTTP status in one go.
|
|
||||||
func writeError(w http.ResponseWriter, status int, msg string) {
|
|
||||||
theResponse := cmstypes.StatusRec{
|
|
||||||
Code: status,
|
|
||||||
Message: msg,
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(status)
|
|
||||||
json.NewEncoder(w).Encode(theResponse)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTransactionResult(w http.ResponseWriter, status int, theResponse cmstypes.ResponseRec) {
|
func writeTransactionResult(w http.ResponseWriter, status int, theResponse cmstypes.ResponseRec) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
@ -32,10 +18,3 @@ func writeTransactionResult(w http.ResponseWriter, status int, theResponse cmsty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FatalError(err error) {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
log.Errorf(err.Error())
|
|
||||||
fmt.Println(". Press Enter to exit...")
|
|
||||||
fmt.Scanln()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|||||||
15
main.go
15
main.go
@ -19,6 +19,7 @@ import (
|
|||||||
"gitea.futuresens.co.uk/futuresens/hardlink/config"
|
"gitea.futuresens.co.uk/futuresens/hardlink/config"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/dispenser"
|
"gitea.futuresens.co.uk/futuresens/hardlink/dispenser"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/handlers"
|
"gitea.futuresens.co.uk/futuresens/hardlink/handlers"
|
||||||
|
"gitea.futuresens.co.uk/futuresens/hardlink/errorhandlers"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/lockserver"
|
"gitea.futuresens.co.uk/futuresens/hardlink/lockserver"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/logging"
|
"gitea.futuresens.co.uk/futuresens/hardlink/logging"
|
||||||
"gitea.futuresens.co.uk/futuresens/hardlink/printer"
|
"gitea.futuresens.co.uk/futuresens/hardlink/printer"
|
||||||
@ -51,7 +52,7 @@ func main() {
|
|||||||
dispenser.Address = []byte(config.DispenserAdrr)
|
dispenser.Address = []byte(config.DispenserAdrr)
|
||||||
dispHandle, err = dispenser.InitializeDispenser()
|
dispHandle, err = dispenser.InitializeDispenser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlers.FatalError(err)
|
errorhandlers.FatalError(err)
|
||||||
}
|
}
|
||||||
defer dispHandle.Close()
|
defer dispHandle.Close()
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if len(status) == 0 {
|
if len(status) == 0 {
|
||||||
err = fmt.Errorf("%s; wrong dispenser address: %s", err, config.DispenserAdrr)
|
err = fmt.Errorf("%s; wrong dispenser address: %s", err, config.DispenserAdrr)
|
||||||
handlers.FatalError(err)
|
errorhandlers.FatalError(err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(status)
|
fmt.Println(status)
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
@ -100,7 +101,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create App and wire routes
|
// Create App and wire routes
|
||||||
app := handlers.NewApp(dispHandle, config.LockType, config.EncoderAddress, database, config.IsPayment)
|
app := handlers.NewApp(dispHandle, config.LockType, config.EncoderAddress, database, &config)
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
app.RegisterRoutes(mux)
|
app.RegisterRoutes(mux)
|
||||||
@ -109,7 +110,7 @@ func main() {
|
|||||||
log.Infof("Starting HTTP server on http://localhost%s", addr)
|
log.Infof("Starting HTTP server on http://localhost%s", addr)
|
||||||
fmt.Printf("Starting HTTP server on http://localhost%s", addr)
|
fmt.Printf("Starting HTTP server on http://localhost%s", addr)
|
||||||
if err := http.ListenAndServe(addr, mux); err != nil {
|
if err := http.ListenAndServe(addr, mux); err != nil {
|
||||||
handlers.FatalError(err)
|
errorhandlers.FatalError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +121,12 @@ func readTicketLayout() printer.LayoutOptions {
|
|||||||
// 1) Read the file
|
// 1) Read the file
|
||||||
data, err := os.ReadFile(layoutName)
|
data, err := os.ReadFile(layoutName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlers.FatalError(fmt.Errorf("failed to read %s: %v", layoutName, err))
|
errorhandlers.FatalError(fmt.Errorf("failed to read %s: %v", layoutName, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Unmarshal into your struct
|
// 2) Unmarshal into your struct
|
||||||
if err := xml.Unmarshal(data, &layout); err != nil {
|
if err := xml.Unmarshal(data, &layout); err != nil {
|
||||||
handlers.FatalError(fmt.Errorf("failed to parse %s: %v", layoutName, err))
|
errorhandlers.FatalError(fmt.Errorf("failed to parse %s: %v", layoutName, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return layout
|
return layout
|
||||||
@ -144,7 +145,7 @@ func startChipDnaClient() {
|
|||||||
|
|
||||||
cmd, err := startClient()
|
cmd, err := startClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlers.FatalError(err)
|
errorhandlers.FatalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart loop
|
// Restart loop
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user