protocol/aprs: refactored
Some checks failed
Run tests / test (1.25) (push) Failing after 1m37s
Run tests / test (stable) (push) Failing after 1m37s

This commit is contained in:
2026-03-02 22:28:17 +01:00
parent 452f521866
commit 63040a44b3
24 changed files with 3506 additions and 1533 deletions

View File

@@ -1,126 +1,82 @@
package aprs
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
var (
ErrAddressInvalid = errors.New(`aprs: invalid address`)
)
import "strings"
type Address struct {
Call string `json:"call"`
SSID string `json:"ssid,omitempty"`
IsRepeated bool `json:"is_repeated,omitempty"`
IsRepeated bool `json:"is_repeated"`
}
func ParseAddress(s string) Address {
r := strings.HasSuffix(s, "*")
if r {
s = strings.TrimSuffix(s, "*")
}
i := strings.IndexByte(s, '-')
if i < 1 {
return Address{
Call: s,
IsRepeated: r,
}
}
return Address{
Call: s[:i],
SSID: s[i+1:],
IsRepeated: r,
}
}
func (a Address) EqualTo(b Address) bool {
return a.Call == b.Call && a.SSID == b.SSID
return strings.EqualFold(a.Call, b.Call) && a.SSID == b.SSID
}
func (a Address) IsQConstruct() bool {
return len(a.Call) == 3 && len(a.SSID) == 0 && a.Call[0] == 'q'
}
func (a Address) Passcode() int16 {
v := int16(0x73e2)
for i, l := 0, len(a.Call); i < l; i = i + 2 {
v ^= int16(a.Call[i]) << 8
if i+1 < len(a.Call) {
v ^= int16(a.Call[i+1])
}
}
return v & 0x7fff
}
func (a Address) String() string {
var r = ""
var b strings.Builder
b.WriteString(a.Call)
if a.SSID != "" {
b.WriteByte('-')
b.WriteString(a.SSID)
}
if a.IsRepeated {
r = "*"
b.WriteByte('*')
}
if a.SSID == "" {
return a.Call + r
}
return fmt.Sprintf("%s-%s%s", a.Call, a.SSID, r)
}
func (a Address) Secret() int16 {
var h = int16(0x73e2)
var c = a.Call
if len(c)%2 > 0 {
c += "\x00"
}
for i := 0; i < len(c); i += 2 {
h ^= int16(c[i]) << 8
h ^= int16(c[i+1])
}
return h & 0x7fff
}
func (a Address) MarshalJSON() ([]byte, error) {
return json.Marshal(a.String())
}
func (a *Address) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
p, err := ParseAddress(s)
if err != nil {
return err
}
a.Call = p.Call
a.SSID = p.SSID
a.IsRepeated = p.IsRepeated
return nil
}
func ParseAddress(s string) (Address, error) {
r := strings.HasSuffix(s, "*")
if r {
s = s[:len(s)-1]
}
p := strings.Split(s, "-")
if len(p) == 0 || len(p) > 2 {
return Address{}, ErrAddressInvalid
}
a := Address{Call: p[0], IsRepeated: r}
if len(p) == 2 {
a.SSID = p[1]
}
return a, nil
}
func MustParseAddress(s string) Address {
a, err := ParseAddress(s)
if err != nil {
panic(err)
}
return a
}
func IsQConstruct(call string) bool {
return len(call) == 3 && call[0] == 'q'
return b.String()
}
type Path []Address
func (p Path) String() string {
var s = make([]string, len(p))
for i, a := range p {
s[i] = a.String()
func (path Path) EqualTo(other Path) bool {
if len(path) != len(other) {
return false
}
return strings.Join(s, ",")
}
func ParsePath(p string) (Path, error) {
ss := strings.Split(p, ",")
if len(ss) == 0 {
return nil, nil
}
var err error
as := make(Path, len(ss))
for i, s := range ss {
as[i], err = ParseAddress(s)
if err != nil {
return nil, err
for i, a := range path {
if !a.EqualTo(other[i]) {
return false
}
}
return as, nil
return true
}
func (path Path) String() string {
part := make([]string, len(path))
for i, a := range path {
part[i] = a.String()
}
return strings.Join(part, ",")
}