From 61b089fe55bebc3c7dc89c83e40f7a7eaf448a90 Mon Sep 17 00:00:00 2001 From: yurii Date: Fri, 8 Aug 2025 11:31:48 +0100 Subject: [PATCH] updated workflow for TLJ locks --- lockserver/lockservercommon.go | 30 +++++++++------ lockserver/tljlockserver.go | 70 ++++++++++++++++++++++++++++++++++ main.go | 23 +++++++---- release notes.md | 5 ++- 4 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 lockserver/tljlockserver.go diff --git a/lockserver/lockservercommon.go b/lockserver/lockservercommon.go index 9ee83c5..d0049c6 100644 --- a/lockserver/lockservercommon.go +++ b/lockserver/lockservercommon.go @@ -24,6 +24,12 @@ const ( AssaAbloy = "assaabloy" Omnitec = "omnitec" Salto = "salto" + TLJ = "tlj" +) + +var ( + Cert string + LockServerURL string ) type ( @@ -33,29 +39,36 @@ type ( } AssaLockServer struct { - encoderAddr string - command string + encoderAddr string + command string } OmniLockServer struct { encoderAddr string // Encoder unit address - command []byte // Command to be sent to the lock server + command []byte // Command to be sent to the lock server } SaltoLockServer struct { - encoderAddr string - command []byte + encoderAddr string + command []byte + } + + TLJLockServer struct { + encoderAddr string + command string } ) func NewLockServer(lockType, encoderAddr string, fatalError func(error)) LockServer { - switch lockType { + switch strings.ToLower(lockType) { case AssaAbloy: return &AssaLockServer{encoderAddr: encoderAddr} case Omnitec: return &OmniLockServer{encoderAddr: encoderAddr} case Salto: return &SaltoLockServer{encoderAddr: encoderAddr} + case TLJ: + return &TLJLockServer{encoderAddr: encoderAddr} default: fatalError(fmt.Errorf("unsupported LockType: %s; must be 'assaabloy' or 'omnitec'", lockType)) return nil // This line will never be reached, but is needed to satisfy the compiler @@ -100,8 +113,3 @@ func sendAndReceive(conn net.Conn, command []byte) (string, error) { response := buf[:n] return string(response), nil } - - - - - diff --git a/lockserver/tljlockserver.go b/lockserver/tljlockserver.go new file mode 100644 index 0000000..ef63010 --- /dev/null +++ b/lockserver/tljlockserver.go @@ -0,0 +1,70 @@ +package lockserver + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "time" + + log "github.com/sirupsen/logrus" +) + +// GuestCardResponse represents the JSON response from the GuestCard API call. +type GuestCardResponse struct { + Code string `json:"code"` + CardID string `json:"CardID"` + CommandID int `json:"CommandID"` // optional + Msg string `json:"Msg"` // error message if Code != "0" +} + +func (lock *TLJLockServer) BuildCommand(doorReq DoorCardRequest, checkIn, checkOut time.Time) error { + params := url.Values{} + params.Set("cer", Cert) + params.Set("room", doorReq.RoomField) + params.Set("BeginTime", checkIn.Format("2006-01-02 15:04:05")) + params.Set("EndTime", checkOut.Format("2006-01-02 15:04:05")) + switch doorReq.FollowStr { + case "0": + params.Set("CheckInMode", "new") + case "1": + params.Set("CheckInMode", "follow") + } + lock.command = fmt.Sprintf("%s/GuestCard?%s", LockServerURL, params.Encode()) + return nil +} + +func (lock *TLJLockServer) LockSequence(conn net.Conn) error { + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Get(lock.command) + if err != nil { + return fmt.Errorf("HTTP request failed: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected HTTP status: %s", resp.Status) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed to read response: %v", err) + } + + // Parse response JSON + var result GuestCardResponse + err = json.Unmarshal(body, &result) + if err != nil { + return fmt.Errorf("invalid JSON response: %v", err) + } + + if result.Code != "0" { + log.Printf("API error %s: %s", result.Code, result.Msg) + return fmt.Errorf("API error %s: %s", result.Code, result.Msg) + } + + log.Printf("Guest card created successfully: CardID=%s, CommandID=%d", result.CardID, result.CommandID) + return nil +} diff --git a/main.go b/main.go index a027ffa..4faba84 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ import ( ) const ( - buildVersion = "1.0.8" + buildVersion = "1.0.9" serviceName = "hardlink" customLayout = "2006-01-02 15:04:05 -0700" transactionUrl = "http://127.0.0.1:18181/start-transaction/" @@ -42,6 +42,7 @@ type configRec struct { LockserverUrl string `yaml:"lockservUrl"` LockType string `yaml:"lockType"` EncoderAddress string `yaml:"encoderAddr"` + Cert string `yaml:"cert"` DispenserPort string `yaml:"dispensPort"` DispenserAdrr string `yaml:"dispensAddr"` PrinterName string `yaml:"printerName"` @@ -67,10 +68,13 @@ func newApp(dispPort *serial.Port, lockConn net.Conn, config configRec) *App { func main() { // Load config config := readConfig() - printer.Layout = readTicketLayout() printer.PrinterName = config.PrinterName + var lockConn net.Conn + lockserver.Cert = config.Cert + lockserver.LockServerURL = config.LockserverUrl + // Setup logging and get file handle logFile, err := setupLogging(config.LogDir) if err != nil { @@ -100,12 +104,17 @@ func main() { log.Infof("Dispenser initialized on port %s, %s", config.DispenserPort, status) // Initialize lock-server connection once - lockConn, err := lockserver.InitializeServerConnection(config.LockserverUrl) - if err != nil { - fatalError(err) + switch strings.ToLower(config.LockType) { + case lockserver.TLJ: + + default: + lockConn, err = lockserver.InitializeServerConnection(config.LockserverUrl) + if err != nil { + fatalError(err) + } + defer lockConn.Close() + log.Infof("Connected to lock server at %s", config.LockserverUrl) } - defer lockConn.Close() - log.Infof("Connected to lock server at %s", config.LockserverUrl) // db, err := payment.InitMSSQL(config.dbport, config.dbname, config.dbuser, config.dbpassword) // if err != nil { diff --git a/release notes.md b/release notes.md index 74fa6da..503b51c 100644 --- a/release notes.md +++ b/release notes.md @@ -2,7 +2,10 @@ builtVersion is a const in main.go -#### 1.0.8 - 1 August 2024 +#### 1.0.9 - 08 August 2024 +updated workflow for TLJ locks + +#### 1.0.8 - 01 August 2024 improved error handling and logging in Salto #### 1.0.7 - 25 July 2024