Files
go-caatsm/internal/parsers/sita_parser.go
T

208 lines
5.6 KiB
Go
Raw Normal View History

package parsers
import (
"caatsm/internal/config"
"caatsm/internal/domain"
"caatsm/pkg/utils"
"fmt"
"regexp"
"strings"
"time"
)
var (
sitaTextPattern = regexp.MustCompile(`\(([A-Z]{3})(.*)\)`)
validSitaPriority = regexp.MustCompile(`^(SS|DD|FF|GG|KK)$`)
validSitaAddress = regexp.MustCompile(`^[A-Z]{8}$`)
)
// SITAParser is responsible for parsing SITA messages.
type SITAParser struct {
bodyPattern map[string]config.BodyConfig // Injected configuration for body patterns.
}
// NewSITAParser creates a new instance of SITAParser.
func NewSITAParser(myPatterns map[string]config.BodyConfig) *SITAParser {
return &SITAParser{bodyPattern: myPatterns}
}
// DefaultSITAParser creates a new instance of SITAParser with default patterns.
func DefaultSITAParser() *SITAParser {
return &SITAParser{bodyPattern: config.GetBodyPatterns()}
}
func (p *SITAParser) GetBodyPatterns() map[string]config.BodyConfig {
return p.bodyPattern
}
// Parse is the main method to parse a SITA message.
func (p *SITAParser) Parse(rawMessage string) (*domain.SITA, error) {
cleanedText := removeEmptyLines(rawMessage)
lines := strings.Split(cleanedText, "\n")
if len(lines) < 4 {
return nil, fmt.Errorf("invalid SITA message format: insufficient lines")
}
header, err := parseSITAHeader(lines[0])
if err != nil {
return nil, err
}
priorityAndSender, err := parseSITAPriorityAndSender(lines[1])
if err != nil {
return nil, err
}
timeAndReceiver, err := parseSITATimeAndReceiver(lines[2])
if err != nil {
return nil, err
}
text, bodyType, err := parseSITATextInfo(strings.Join(lines[3:], "\n"))
if err != nil {
return nil, err
}
bodyData, err := p.extractBodyData(text)
if err != nil {
return nil, err
}
sita, err := p.createSITA(bodyData)
if err != nil {
return nil, err
}
return &domain.SITA{
Header: header,
PriorityAndSender: priorityAndSender,
TimeAndReceiver: timeAndReceiver,
Text: text,
Category: bodyType,
BodyData: sita,
ReceivedTime: time.Now(),
}, nil
}
// parseSITAHeader parses the header line of a SITA message.
func parseSITAHeader(line string) (domain.SITAHeader, error) {
parts := strings.Fields(line)
if len(parts) < 3 {
return domain.SITAHeader{}, fmt.Errorf("invalid header format: %s", line)
}
return domain.SITAHeader{
StartSignal: parts[0],
SendID: parts[1],
SendTime: parts[2],
}, nil
}
// parseSITAPriorityAndSender parses the priority and sender line of a SITA message.
func parseSITAPriorityAndSender(line string) (domain.PrioritySender, error) {
parts := strings.Fields(line)
if len(parts) < 2 {
return domain.PrioritySender{}, fmt.Errorf("invalid priority and sender format: %s", line)
}
return domain.PrioritySender{
Priority: parts[0],
Sender: parts[1],
}, nil
}
// parseSITATimeAndReceiver parses the time and receiver line of a SITA message.
func parseSITATimeAndReceiver(line string) (domain.TimeReceiver, error) {
parts := strings.Fields(line)
if len(parts) < 2 {
return domain.TimeReceiver{}, fmt.Errorf("invalid time and receiver format: %s", line)
}
return domain.TimeReceiver{
Time: parts[0],
Receiver: parts[1],
}, nil
}
// parseSITATextInfo parses the text and extracts the body type from a SITA message.
func parseSITATextInfo(text string) (string, string, error) {
match := sitaTextPattern.FindStringSubmatch(text)
if len(match) > 1 {
return match[0], match[1], nil
}
return "", "", fmt.Errorf("invalid text format: %s", text)
}
func (p *SITAParser) ParseBody(body string) (interface{}, error) {
bodyData, err := p.extractBodyData(body)
if err != nil {
return nil, err
}
sita, err := p.createSITA(bodyData)
if err != nil {
return nil, err
}
return sita, nil
}
// createSITA parses the body data of a SITA message.
func (p *SITAParser) createSITA(data map[string]string) (interface{}, error) {
switch data["type"] {
default:
return nil, fmt.Errorf("invalid message type: %s", data["type"])
}
}
// extractBodyData extracts the body data from a SITA message.
func (p *SITAParser) extractBodyData(text string) (map[string]string, error) {
log := utils.Logger
data := make(map[string]string)
for _, pattern := range p.GetBodyPatterns() {
for i, p := range pattern.Patterns {
log.Debugf("Trying pattern %d: %s\n %s\n", i, p.Comments, p.Pattern)
re := p.Expression
match := re.FindStringSubmatch(text)
if match != nil {
log.Debugf("Matched : %v \n", match)
for i, name := range re.SubexpNames() {
if i != 0 && name != "" {
data[name] = match[i]
}
}
return data, nil
}
log.Debugf("No match for pattern %d\n", i)
}
}
log.Errorf("No matching pattern found for text: %s", text)
return nil, fmt.Errorf("no matching pattern found for text: %s", text)
}
// ValidateSITA validates the fields of a SITA message.
func ValidateSITA(msg *domain.SITA) error {
if missingSitaFields(msg) {
return fmt.Errorf("invalid SITA message: missing fields")
}
if !validSitaPriority.MatchString(msg.PriorityAndSender.Priority) {
return fmt.Errorf("invalid priority code: %s", msg.PriorityAndSender.Priority)
}
if !validSitaAddress.MatchString(msg.TimeAndReceiver.Receiver) || !validSitaAddress.MatchString(msg.PriorityAndSender.Sender) {
return fmt.Errorf("invalid address format")
}
return nil
}
func missingSitaFields(msg *domain.SITA) bool {
if msg.Header.StartSignal == "" || msg.Header.SendID == "" || msg.Header.SendTime == "" ||
msg.PriorityAndSender.Priority == "" || msg.PriorityAndSender.Sender == "" ||
msg.TimeAndReceiver.Time == "" || msg.TimeAndReceiver.Receiver == "" ||
msg.Category == "" {
return true
}
return false
}