100 lines
2.5 KiB
Go
100 lines
2.5 KiB
Go
package aprs
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Message struct {
|
|
ID int `json:"id"`
|
|
IsAcknowledge bool `json:"is_ack"`
|
|
IsRejection bool `json:"is_rejection"`
|
|
IsBulletin bool `json:"is_bulletin"`
|
|
Recipient string `json:"recipient"`
|
|
AnnoucementID byte `json:"announcement_id,omitempty"`
|
|
Group string `json:"group,omitempty"`
|
|
Severity string `json:"severity,omitempty"`
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
func (msg *Message) String() string {
|
|
return fmt.Sprintf("%s: %q", msg.Recipient, msg.Text)
|
|
}
|
|
|
|
type messageDecoder struct{}
|
|
|
|
func (messageDecoder) CanDecode(frame *Frame) bool {
|
|
var (
|
|
maybeMessage = len(frame.Raw) >= 11 && frame.Raw[10] == ':'
|
|
maybeBulletin = len(frame.Raw) >= 10 && frame.Raw[9] == ':'
|
|
)
|
|
return frame.Raw.Type() == ':' && (maybeMessage || maybeBulletin)
|
|
}
|
|
|
|
func (messageDecoder) Decode(frame *Frame) (data Data, err error) {
|
|
var (
|
|
msg = new(Message)
|
|
text string
|
|
size = len(text)
|
|
)
|
|
if len(frame.Raw) >= 10 && frame.Raw[9] == ':' {
|
|
msg.Recipient, text = strings.TrimSpace(string(frame.Raw[1:9])), string(frame.Raw[9:])
|
|
} else {
|
|
msg.Recipient, text = strings.TrimSpace(string(frame.Raw[1:10])), string(frame.Raw[10:])
|
|
}
|
|
|
|
switch {
|
|
case strings.HasPrefix(msg.Recipient, "BLN"):
|
|
// Bulletin
|
|
kind := msg.Recipient[3:]
|
|
if id, err := strconv.Atoi(kind); err == nil {
|
|
// General bulletin
|
|
msg.IsBulletin = true
|
|
msg.ID = id
|
|
} else if len(kind) >= 2 && isDigit(kind[0]) {
|
|
// Group Bulletin Format
|
|
msg.IsBulletin = true
|
|
msg.ID = int(kind[0] - '0')
|
|
msg.Group = kind[1:]
|
|
} else if len(kind) == 1 {
|
|
// Announcement
|
|
msg.IsBulletin = true
|
|
msg.AnnoucementID = kind[0]
|
|
}
|
|
|
|
case strings.HasPrefix(msg.Recipient, "NWS-"):
|
|
// National Weather Service Bulletins
|
|
msg.IsBulletin = true
|
|
msg.Severity = msg.Recipient[4:]
|
|
|
|
default:
|
|
if i := strings.LastIndexByte(text, '{'); i != -1 && i > (size-6) {
|
|
// Plain message ID: {XXXXX (where there are 1-5 X)
|
|
msg.ID, _ = strconv.Atoi(text[i+1:])
|
|
text = text[:i]
|
|
}
|
|
|
|
if i := strings.LastIndex(text, ":ack"); i != -1 && i > (size-9) {
|
|
// Message acknowledgement: :ackXXXXX (where there are 1-5 X)
|
|
msg.IsAcknowledge = true
|
|
msg.ID, _ = strconv.Atoi(text[i+4:])
|
|
text = text[:i]
|
|
}
|
|
|
|
if i := strings.LastIndex(text, ":rej"); i != -1 && i > (size-9) {
|
|
// Message acknowledgement: :rejXXXXX (where there are 1-5 X)
|
|
msg.IsRejection = true
|
|
msg.ID, _ = strconv.Atoi(text[i+4:])
|
|
text = text[:i]
|
|
}
|
|
}
|
|
|
|
if len(text) > 0 && text[0] == ':' {
|
|
text = text[1:]
|
|
}
|
|
|
|
msg.Text = text
|
|
return msg, nil
|
|
}
|