193 lines
4.9 KiB
Go
193 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/tarm/serial"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/bootstrap"
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/config"
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/dispenser"
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/handlers"
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/lockserver"
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/logging"
|
|
"gitea.futuresens.co.uk/futuresens/hardlink/printer"
|
|
)
|
|
|
|
const (
|
|
buildVersion = "1.0.28"
|
|
serviceName = "hardlink"
|
|
)
|
|
|
|
func main() {
|
|
// Load config
|
|
config := config.ReadHardlinkConfig()
|
|
printer.Layout = readTicketLayout()
|
|
printer.PrinterName = config.PrinterName
|
|
lockserver.Cert = config.Cert
|
|
lockserver.LockServerURL = config.LockserverUrl
|
|
dispHandle := &serial.Port{}
|
|
|
|
// Setup logging and get file handle
|
|
logFile, err := logging.SetupLogging(config.LogDir, serviceName, buildVersion)
|
|
if err != nil {
|
|
log.Printf("Failed to set up logging: %v\n", err)
|
|
}
|
|
defer logFile.Close()
|
|
|
|
// Initialize dispenser
|
|
if !config.TestMode {
|
|
dispenser.SerialPort = config.DispenserPort
|
|
dispenser.Address = []byte(config.DispenserAdrr)
|
|
dispHandle, err = dispenser.InitializeDispenser()
|
|
if err != nil {
|
|
handlers.FatalError(err)
|
|
}
|
|
defer dispHandle.Close()
|
|
|
|
status, err := dispenser.CheckDispenserStatus(dispHandle)
|
|
if err != nil {
|
|
if len(status) == 0 {
|
|
err = fmt.Errorf("%s; wrong dispenser address: %s", err, config.DispenserAdrr)
|
|
handlers.FatalError(err)
|
|
} else {
|
|
fmt.Println(status)
|
|
fmt.Println(err.Error())
|
|
}
|
|
}
|
|
if status, err = dispenser.DispenserSequence(dispHandle); err != nil {
|
|
handlers.FatalError(err)
|
|
}
|
|
log.Infof("Dispenser initialized on port %s, %s", config.DispenserPort, status)
|
|
}
|
|
|
|
// Test lock-server connection
|
|
switch strings.ToLower(config.LockType) {
|
|
case lockserver.TLJ:
|
|
|
|
default:
|
|
lockConn, err := lockserver.InitializeServerConnection(config.LockserverUrl)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
log.Errorf(err.Error())
|
|
} else {
|
|
fmt.Printf("Connected to the lock server successfuly at %s\n", config.LockserverUrl)
|
|
log.Infof("Connected to the lock server successfuly at %s", config.LockserverUrl)
|
|
lockConn.Close()
|
|
}
|
|
}
|
|
|
|
database, err := bootstrap.OpenDB(&config)
|
|
if err != nil {
|
|
log.Warnf("DB init failed: %v", err)
|
|
}
|
|
defer database.Close()
|
|
|
|
if config.IsPayment {
|
|
fmt.Println("Payment processing is enabled")
|
|
log.Info("Payment processing is enabled")
|
|
startChipDnaClient()
|
|
} else {
|
|
fmt.Println("Payment processing is disabled")
|
|
log.Info("Payment processing is disabled")
|
|
}
|
|
|
|
// Create App and wire routes
|
|
app := handlers.NewApp(dispHandle, config.LockType, config.EncoderAddress, database, config.IsPayment)
|
|
|
|
mux := http.NewServeMux()
|
|
app.RegisterRoutes(mux)
|
|
|
|
addr := fmt.Sprintf(":%d", config.Port)
|
|
log.Infof("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 {
|
|
handlers.FatalError(err)
|
|
}
|
|
}
|
|
|
|
func readTicketLayout() printer.LayoutOptions {
|
|
const layoutName = "TicketLayout.xml"
|
|
var layout printer.LayoutOptions
|
|
|
|
// 1) Read the file
|
|
data, err := os.ReadFile(layoutName)
|
|
if err != nil {
|
|
handlers.FatalError(fmt.Errorf("failed to read %s: %v", layoutName, err))
|
|
}
|
|
|
|
// 2) Unmarshal into your struct
|
|
if err := xml.Unmarshal(data, &layout); err != nil {
|
|
handlers.FatalError(fmt.Errorf("failed to parse %s: %v", layoutName, err))
|
|
}
|
|
|
|
return layout
|
|
}
|
|
|
|
func startChipDnaClient() {
|
|
startClient := func() (*exec.Cmd, error) {
|
|
cmd := exec.Command("./ChipDNAClient/ChipDnaClient.exe")
|
|
err := cmd.Start()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to start ChipDnaClient: %v", err)
|
|
}
|
|
log.Infof("ChipDnaClient started with PID %d", cmd.Process.Pid)
|
|
return cmd, nil
|
|
}
|
|
|
|
cmd, err := startClient()
|
|
if err != nil {
|
|
handlers.FatalError(err)
|
|
}
|
|
|
|
// Restart loop
|
|
go func() {
|
|
for {
|
|
err := cmd.Wait()
|
|
if err != nil {
|
|
log.Errorf("ChipDnaClient exited unexpectedly: %v", err)
|
|
time.Sleep(2 * time.Second)
|
|
cmd, err = startClient()
|
|
if err != nil {
|
|
log.Errorf("Restart failed: %v", err)
|
|
return
|
|
}
|
|
log.Info("ChipDnaClient restarted successfully")
|
|
}
|
|
}
|
|
}()
|
|
|
|
// Handle shutdown signals
|
|
sigs := make(chan os.Signal, 1)
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
go func() {
|
|
<-sigs
|
|
log.Info("Shutting down...")
|
|
if cmd.Process != nil {
|
|
log.Info("Sending SIGTERM to ChipDnaClient...")
|
|
_ = cmd.Process.Signal(syscall.SIGTERM)
|
|
// wait up to 5s for graceful shutdown
|
|
done := make(chan error, 1)
|
|
go func() { done <- cmd.Wait() }()
|
|
select {
|
|
case <-time.After(5 * time.Second):
|
|
log.Warn("ChipDnaClient did not exit in time, killing...")
|
|
_ = cmd.Process.Kill()
|
|
case err := <-done:
|
|
log.Infof("ChipDnaClient exited cleanly: %v", err)
|
|
}
|
|
}
|
|
os.Exit(0)
|
|
}()
|
|
}
|