234 lines
6.7 KiB
Go
234 lines
6.7 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"errors"
|
|
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.espin.casa/albert/cml04-falcon-system/internal/types"
|
|
"github.com/google/uuid"
|
|
|
|
"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 `json:"date_time"`
|
|
L2PackageId int32 `json:"l2_package_id"`
|
|
L3PackageId [6]byte `json:"l3_package_id"`
|
|
ProductionOrderNo int32 `json:"production_order_no"`
|
|
CustomerOrderNo int32 `json:"customer_order_no"`
|
|
CustomerName [30]byte `json:"customer_name"`
|
|
LogoCode [3]byte `json:"logo_code"`
|
|
SteelGrade [15]byte `json:"steel_grade"`
|
|
MaterialCode [18]byte `json:"material_code"`
|
|
HeatId [10]byte `json:"heat_id"`
|
|
SectionType [20]byte `json:"section_type"`
|
|
PackageDimensions [3]float32 `json:"package_dimensions"`
|
|
PackageWeight float32 `json:"package_weight"`
|
|
SectionDimensions [3]float32 `json:"section_dimensions"`
|
|
NumberSections int32 `json:"number_sections"`
|
|
NumberLayers int32 `json:"number_layers"`
|
|
NumberSectionsInLayer int32 `json:"number_sections_last_layer"`
|
|
FreeTxtLp [180]byte `json:"free_txt_lp"`
|
|
}
|
|
|
|
func cleanNonPrintable(input []byte) string {
|
|
var result strings.Builder
|
|
|
|
for _, b := range input {
|
|
if strconv.IsPrint(rune(b)) {
|
|
result.WriteByte(b)
|
|
}
|
|
}
|
|
|
|
return result.String()
|
|
}
|
|
|
|
func (pmd *LabelData) DateTimeAsString() string {
|
|
s := cleanNonPrintable(pmd.DateTime[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) L3PackageIdAsString() string {
|
|
s := cleanNonPrintable(pmd.L3PackageId[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) CustomerNameAsString() string {
|
|
s := cleanNonPrintable(pmd.CustomerName[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) LogoCodeAsString() string {
|
|
s := cleanNonPrintable(pmd.LogoCode[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) SteelGradeAsString() string {
|
|
s := cleanNonPrintable(pmd.SteelGrade[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) MaterialCodeAsString() string {
|
|
s := cleanNonPrintable(pmd.MaterialCode[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) HeatIdAsString() string {
|
|
s := cleanNonPrintable(pmd.HeatId[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) SectionTypeAsString() string {
|
|
s := cleanNonPrintable(pmd.SectionType[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
func (pmd *LabelData) FreeTxtLpAsString() string {
|
|
s := cleanNonPrintable(pmd.FreeTxtLp[:])
|
|
return strings.TrimRight(string(s), "\x00")
|
|
}
|
|
|
|
type Server struct {
|
|
address string
|
|
log logger.LoggerAdapter
|
|
svc service.Service
|
|
}
|
|
|
|
type Client struct {
|
|
conn net.Conn
|
|
log logger.LoggerAdapter
|
|
svc service.Service
|
|
}
|
|
|
|
func (client *Client) handleRequest() {
|
|
// telegram bytes buffer holder 4096 maximun telegram size defined by SMS
|
|
telegramBytes := bytes.NewBuffer(make([]byte, 4096))
|
|
for {
|
|
pl, err := client.conn.Read(telegramBytes.Bytes())
|
|
if err != nil {
|
|
client.log.Error("reading telegram failed", err, logger.LogFields{})
|
|
return
|
|
}
|
|
// interpret first 24 bytes as header
|
|
header := &Header{}
|
|
headerReader := bytes.NewReader(telegramBytes.Bytes()[:24])
|
|
if err := binary.Read(headerReader, binary.LittleEndian, header); err != nil {
|
|
client.log.Error("interpreting telegram header failed", err, logger.LogFields{})
|
|
return
|
|
}
|
|
// switch telegram id
|
|
switch header.TelegramID {
|
|
// handle telegram data
|
|
case 6500:
|
|
if header.MessageLength != int16(pl) {
|
|
client.log.Error("message length mismatch telegram defined length", errors.New(""), logger.LogFields{
|
|
"telegram_defined_length": header.MessageLength,
|
|
"received_length": pl,
|
|
})
|
|
return
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
// read telegram data
|
|
telegramData := &LabelData{}
|
|
if err := binary.Read(telegramBytes, binary.LittleEndian, telegramData); err != nil {
|
|
client.log.Error("reading telegram content failed", err, logger.LogFields{})
|
|
return
|
|
}
|
|
if err := client.handlePublishPrintData(ctx, telegramData); err != nil {
|
|
client.log.Error("publish print data failed", err, logger.LogFields{})
|
|
return
|
|
}
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
func (client *Client) handlePublishPrintData(ctx context.Context, data *LabelData) error {
|
|
// set label data
|
|
label := &types.Label{
|
|
ID: uuid.NewString(),
|
|
DateTime: data.DateTimeAsString(),
|
|
L2PackageId: int16(data.L2PackageId),
|
|
L3PackageId: data.L3PackageIdAsString(),
|
|
ProductionOrderNo: data.ProductionOrderNo,
|
|
CustomerOrderNo: data.CustomerOrderNo,
|
|
CustomerName: data.CustomerNameAsString(),
|
|
LogoCode: data.LogoCodeAsString(),
|
|
SteelGrade: data.SteelGradeAsString(),
|
|
MaterialCode: data.MaterialCodeAsString(),
|
|
HeatId: data.HeatIdAsString(),
|
|
SectionType: data.SectionTypeAsString(),
|
|
PackageDimenA: data.PackageDimensions[0],
|
|
PackageDimenB: data.PackageDimensions[1],
|
|
PackageDimenC: data.PackageDimensions[2],
|
|
PackageWeight: data.PackageWeight,
|
|
SectionDimenA: data.SectionDimensions[0],
|
|
SectionDimenB: data.SectionDimensions[1],
|
|
SectionDimenC: data.SectionDimensions[2],
|
|
NumberSections: data.NumberSections,
|
|
NumberLayers: data.NumberLayers,
|
|
NumberSectionsInLayer: data.NumberSectionsInLayer,
|
|
FreeTxtLp: data.FreeTxtLpAsString(),
|
|
}
|
|
// store new label data received
|
|
if err := client.svc.StoreLabelData(ctx, label); err != nil {
|
|
return err
|
|
}
|
|
// publish new label data event
|
|
if err := client.svc.PublishNewLabelData(ctx, label.ID); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (server *Server) Run() error {
|
|
// create tcp listener
|
|
listener, err := net.Listen("tcp", server.address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// close on exit
|
|
defer listener.Close()
|
|
// accept incoming connections
|
|
for {
|
|
// accept connection
|
|
conn, err := listener.Accept()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// create new client
|
|
client := &Client{
|
|
conn: conn,
|
|
log: server.log,
|
|
svc: server.svc,
|
|
}
|
|
// handle client
|
|
go client.handleRequest()
|
|
}
|
|
}
|
|
|
|
func New(address string, svc service.Service, log logger.LoggerAdapter) *Server {
|
|
return &Server{
|
|
address: address,
|
|
svc: svc,
|
|
log: log,
|
|
}
|
|
}
|