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 }