package server import ( "encoding/binary" "fmt" "io" "net" "sync" "git.espin.casa/albert/cml04-falcon-system/labeler/service" "git.espin.casa/albert/logger" ) type Header struct { MessageLength int16 TelegramID int16 SequenceCounter int16 Flags int16 TimeStamp [8]int16 } type LabelData struct { Header Header DateTime [23]byte L2PackageId int16 L3PackageId [6]byte ProductionOrderNo int32 CustomerOrderNo int32 CustomerName [30]byte LogoCode [3]byte SteelGrade [15]byte MaterialCode [18]byte HeatId [10]byte SectionType [20]byte PackageDimensions [3]float32 PackageWeight float32 SectionDimensions [3]float32 NumberSections int32 NumberLayers int32 NumberSectionsInLayer int32 FreeTxtLp [180]byte } func (l *LabelData) FillTelegram(reader io.Reader) (int, error) { // Read into the LabelData struct and return the number of bytes read err := binary.Read(reader, binary.LittleEndian, l) if err != nil { return 0, err } // Calculate total number of bytes read based on struct size labelDataSize := binary.Size(l) return labelDataSize, nil } type Server struct { address string svc service.Service mu sync.Mutex log logger.LoggerAdapter } // Start begins the TCP server and listens for incoming connections func (s *Server) Start() error { listener, err := net.Listen("tcp", s.address) if err != nil { return fmt.Errorf("failed to start server: %v", err) } defer listener.Close() s.log.Info("server is listening", logger.LogFields{ "address": s.address, }) for { conn, err := listener.Accept() if err != nil { s.log.Error("accepting connections failed", err, logger.LogFields{}) continue } // Handle the connection concurrently go s.handleConnection(conn) } } // handleConnection reads telegram data from the TCP connection and keeps the connection open func (s *Server) handleConnection(conn net.Conn) { defer conn.Close() s.log.Info("new connection", logger.LogFields{ "from": conn.RemoteAddr(), }) for { // Initialize LabelData struct to hold the incoming telegram var labelData LabelData // Read the telegram from the connection and track the number of bytes read bytesRead, err := labelData.FillTelegram(conn) if err != nil { // If the client disconnects or there's a read error, exit the loop if err == io.EOF { s.log.Info("client disconnected", logger.LogFields{"client": conn.RemoteAddr()}) break } s.log.Error("reading telegram failed", err, logger.LogFields{}) continue // Keep reading from the connection } // Check if TelegramID is 6500, if not discard but keep connection if labelData.Header.TelegramID != 6500 { s.log.Error("invalid telegram id", fmt.Errorf("invalid telegram"), logger.LogFields{ "id": labelData.Header.TelegramID, "from": conn.RemoteAddr(), }) continue // Discard the content but keep reading from the connection } // Check if MessageLength matches the data received if labelData.Header.MessageLength != int16(bytesRead) { fmt.Printf("MessageLength mismatch: expected %d, got %d bytes from %s\n", labelData.Header.MessageLength, bytesRead, conn.RemoteAddr()) continue // Discard the content but keep reading from the connection } // Locking if necessary when interacting with shared resources (svc, etc.) s.mu.Lock() // Process the valid telegram s.log.Info("received valid label data", logger.LogFields{"from": conn.RemoteAddr()}) fmt.Printf("label: %+v\n", labelData) s.mu.Unlock() // Continue reading next telegrams from this connection } } // New creates a new Server instance func New(address string, svc service.Service, log logger.LoggerAdapter) *Server { return &Server{ address: address, svc: svc, mu: sync.Mutex{}, log: log, } }