refactor: Update AFTN message parsing logic
The code changes in `aviation_parser_test.go` update the AFTN message parsing logic. The `ParseHeader` function now returns an additional error value, allowing for better error handling. The tests have been updated to reflect this change, ensuring that the parsing function handles errors correctly. This refactor improves the reliability and maintainability of the AFTN message parsing functionality.
This commit is contained in:
@@ -2,67 +2,37 @@ package parsers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"caatsm/internal/domain"
|
"caatsm/internal/domain"
|
||||||
|
"errors" // Import errors package to handle errors
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
StartIndicatorPrefix = "ZCZC"
|
||||||
|
EndHeaderMarker = "."
|
||||||
|
BeginPartMarker = "BEGIN PART"
|
||||||
|
)
|
||||||
|
|
||||||
// ParseHeader parses the header of the message and returns a ParsedMessage struct
|
// ParseHeader parses the header of the message and returns a ParsedMessage struct
|
||||||
func ParseHeader(fullMessage string) domain.ParsedMessage {
|
func ParseHeader(fullMessage string) (domain.ParsedMessage, error) {
|
||||||
var (
|
fullMessage = strings.TrimSpace(fullMessage) // Trim leading and trailing spaces
|
||||||
startIndicator string
|
lines := strings.Split(fullMessage, "\n") // Split the message into lines
|
||||||
messageID string
|
|
||||||
dateTime string
|
|
||||||
priorityIndicator string
|
|
||||||
primaryAddress string
|
|
||||||
secondaryAddresses []string
|
|
||||||
originator string
|
|
||||||
originatorDateTime string
|
|
||||||
bodyAndFooter strings.Builder
|
|
||||||
headerEnded bool
|
|
||||||
)
|
|
||||||
|
|
||||||
fullMessage = strings.TrimSpace(fullMessage)
|
// Parse the start indicator line
|
||||||
lines := strings.Split(fullMessage, "\n")
|
startIndicator, messageID, dateTime, err := parseStartIndicator(lines[0])
|
||||||
|
if err != nil {
|
||||||
for lineCounter, line := range lines {
|
return domain.ParsedMessage{}, err // Return error if parsing fails
|
||||||
switch lineCounter {
|
|
||||||
case 0:
|
|
||||||
if strings.HasPrefix(line, "ZCZC") {
|
|
||||||
parts := strings.Fields(line)
|
|
||||||
if len(parts) >= 3 {
|
|
||||||
startIndicator = parts[0]
|
|
||||||
messageID = parts[1]
|
|
||||||
dateTime = parts[2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
parts := strings.Fields(line)
|
|
||||||
if len(parts) >= 2 {
|
|
||||||
priorityIndicator = parts[0]
|
|
||||||
primaryAddress = parts[1]
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if !headerEnded {
|
|
||||||
if strings.TrimSpace(line) == "." {
|
|
||||||
continue
|
|
||||||
} else if strings.HasPrefix(line, ".") {
|
|
||||||
originatorInfo := strings.Fields(line[1:])
|
|
||||||
if len(originatorInfo) >= 2 {
|
|
||||||
originator = originatorInfo[0]
|
|
||||||
originatorDateTime = originatorInfo[1]
|
|
||||||
}
|
|
||||||
headerEnded = true
|
|
||||||
} else if strings.HasPrefix(line, "BEGIN PART") || strings.HasPrefix(line, "(") {
|
|
||||||
headerEnded = true
|
|
||||||
bodyAndFooter.WriteString(line + "\n")
|
|
||||||
} else {
|
|
||||||
secondaryAddresses = append(secondaryAddresses, line)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bodyAndFooter.WriteString(line + "\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the priority indicator and primary address line
|
||||||
|
priorityIndicator, primaryAddress, err := parsePriorityAndPrimary(lines[1])
|
||||||
|
if err != nil {
|
||||||
|
return domain.ParsedMessage{}, err // Return error if parsing fails
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the remaining lines
|
||||||
|
secondaryAddresses, originator, originatorDateTime, bodyAndFooter := parseRemainingLines(lines[2:])
|
||||||
|
|
||||||
|
// Return the parsed message as a domain.ParsedMessage struct
|
||||||
return domain.ParsedMessage{
|
return domain.ParsedMessage{
|
||||||
StartIndicator: startIndicator,
|
StartIndicator: startIndicator,
|
||||||
MessageID: messageID,
|
MessageID: messageID,
|
||||||
@@ -72,6 +42,67 @@ func ParseHeader(fullMessage string) domain.ParsedMessage {
|
|||||||
SecondaryAddresses: secondaryAddresses,
|
SecondaryAddresses: secondaryAddresses,
|
||||||
Originator: originator,
|
Originator: originator,
|
||||||
OriginatorDateTime: originatorDateTime,
|
OriginatorDateTime: originatorDateTime,
|
||||||
BodyAndFooter: bodyAndFooter.String(),
|
BodyAndFooter: bodyAndFooter,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseStartIndicator parses the start indicator line
|
||||||
|
func parseStartIndicator(line string) (string, string, string, error) {
|
||||||
|
if strings.HasPrefix(line, StartIndicatorPrefix) {
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
if len(parts) >= 3 {
|
||||||
|
return parts[0], parts[1], parts[2], nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return "", "", "", errors.New("invalid start indicator line format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePriorityAndPrimary parses the priority indicator and primary address line
|
||||||
|
func parsePriorityAndPrimary(line string) (string, string, error) {
|
||||||
|
parts := strings.Fields(line)
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
return parts[0], parts[1], nil
|
||||||
|
}
|
||||||
|
return "", "", errors.New("invalid priority indicator line format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseRemainingLines parses the remaining lines of the message
|
||||||
|
func parseRemainingLines(lines []string) ([]string, string, string, string) {
|
||||||
|
var (
|
||||||
|
secondaryAddresses []string
|
||||||
|
originator string
|
||||||
|
originatorDateTime string
|
||||||
|
bodyAndFooter strings.Builder
|
||||||
|
headerEnded bool
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if headerEnded {
|
||||||
|
// Append line to body and footer if header has ended
|
||||||
|
bodyAndFooter.WriteString(line + "\n")
|
||||||
|
} else {
|
||||||
|
switch {
|
||||||
|
case line == EndHeaderMarker:
|
||||||
|
// Ignore end header marker
|
||||||
|
case strings.HasPrefix(line, "."):
|
||||||
|
// Parse originator and originatorDateTime
|
||||||
|
originatorInfo := strings.Fields(line[1:])
|
||||||
|
if len(originatorInfo) >= 2 {
|
||||||
|
originator = originatorInfo[0]
|
||||||
|
originatorDateTime = originatorInfo[1]
|
||||||
|
}
|
||||||
|
headerEnded = true
|
||||||
|
case strings.HasPrefix(line, BeginPartMarker) || strings.HasPrefix(line, "("):
|
||||||
|
// Mark header as ended and append line to body and footer
|
||||||
|
headerEnded = true
|
||||||
|
bodyAndFooter.WriteString(line + "\n")
|
||||||
|
default:
|
||||||
|
// Append line to secondary addresses
|
||||||
|
secondaryAddresses = append(secondaryAddresses, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return secondaryAddresses, originator, originatorDateTime, bodyAndFooter.String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package parsers
|
package parsers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
@@ -26,7 +28,8 @@ THUNDERSTORMS EXPECTED
|
|||||||
ALTERNATE ROUTES ADVISED)
|
ALTERNATE ROUTES ADVISED)
|
||||||
|
|
||||||
NNNN`
|
NNNN`
|
||||||
parsedHeader := ParseHeader(message)
|
parsedHeader, err := ParseHeader(message)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(parsedHeader.StartIndicator).To(Equal("ZCZC"))
|
Expect(parsedHeader.StartIndicator).To(Equal("ZCZC"))
|
||||||
Expect(parsedHeader.MessageID).To(Equal("TAF6789"))
|
Expect(parsedHeader.MessageID).To(Equal("TAF6789"))
|
||||||
Expect(parsedHeader.DateTime).To(Equal("160530"))
|
Expect(parsedHeader.DateTime).To(Equal("160530"))
|
||||||
@@ -68,7 +71,8 @@ SEVERE THUNDERSTORM FORECASTED
|
|||||||
ALL DEPARTURES/ARRIVALS EXPECTED TO BE DELAYED)
|
ALL DEPARTURES/ARRIVALS EXPECTED TO BE DELAYED)
|
||||||
|
|
||||||
NNNN`
|
NNNN`
|
||||||
parsedHeader := ParseHeader(message)
|
parsedHeader, err := ParseHeader(message)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(parsedHeader.StartIndicator).To(Equal("ZCZC"))
|
Expect(parsedHeader.StartIndicator).To(Equal("ZCZC"))
|
||||||
Expect(parsedHeader.MessageID).To(Equal("NOTAM1122"))
|
Expect(parsedHeader.MessageID).To(Equal("NOTAM1122"))
|
||||||
Expect(parsedHeader.DateTime).To(Equal("171000"))
|
Expect(parsedHeader.DateTime).To(Equal("171000"))
|
||||||
@@ -94,10 +98,12 @@ Q) EDMM/QOATT/IV/BO/A/000/999/4814N01120E005
|
|||||||
A) EDDM
|
A) EDDM
|
||||||
B) 2307150600 C) 2307151800
|
B) 2307150600 C) 2307151800
|
||||||
E) AERODROME CONTROL TOWER HOURS OF SERVICE
|
E) AERODROME CONTROL TOWER HOURS OF SERVICE
|
||||||
0600-1800 DUE TO MAINTENANCE
|
0600-1800 DUE TO MAINTENANCE
|
||||||
NNNN`
|
NNNN
|
||||||
|
`
|
||||||
|
|
||||||
parsedMessage := ParseHeader(message)
|
parsedMessage, err := ParseHeader(message)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(parsedMessage.StartIndicator).To(Equal("ZCZC"))
|
Expect(parsedMessage.StartIndicator).To(Equal("ZCZC"))
|
||||||
Expect(parsedMessage.MessageID).To(Equal("NOTAM1234"))
|
Expect(parsedMessage.MessageID).To(Equal("NOTAM1234"))
|
||||||
Expect(parsedMessage.DateTime).To(Equal("230715"))
|
Expect(parsedMessage.DateTime).To(Equal("230715"))
|
||||||
@@ -106,7 +112,15 @@ NNNN`
|
|||||||
Expect(parsedMessage.SecondaryAddresses).To(Equal([]string{"GG EDDNYNYX"}))
|
Expect(parsedMessage.SecondaryAddresses).To(Equal([]string{"GG EDDNYNYX"}))
|
||||||
Expect(parsedMessage.Originator).To(Equal("BERLINTWR"))
|
Expect(parsedMessage.Originator).To(Equal("BERLINTWR"))
|
||||||
Expect(parsedMessage.OriginatorDateTime).To(Equal("230714"))
|
Expect(parsedMessage.OriginatorDateTime).To(Equal("230714"))
|
||||||
Expect(parsedMessage.BodyAndFooter).To(ContainSubstring("Q) EDMM/QOATT/IV/BO/A/000/999/4814N01120E005\nA) EDDM\nB) 2307150600 C) 2307151800\nE) AERODROME CONTROL TOWER HOURS OF SERVICE\n 0600-1800 DUE TO MAINTENANCE\nNNNN"))
|
fmt.Print(parsedMessage.BodyAndFooter)
|
||||||
|
Expect(parsedMessage.BodyAndFooter).To(Equal(`
|
||||||
|
Q) EDMM/QOATT/IV/BO/A/000/999/4814N01120E005
|
||||||
|
A) EDDM
|
||||||
|
B) 2307150600 C) 2307151800
|
||||||
|
E) AERODROME CONTROL TOWER HOURS OF SERVICE
|
||||||
|
0600-1800 DUE TO MAINTENANCE
|
||||||
|
NNNN
|
||||||
|
`))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user