diff --git a/pkg/rest/talkgroups.go b/pkg/rest/talkgroups.go index 0520af7..c8f7786 100644 --- a/pkg/rest/talkgroups.go +++ b/pkg/rest/talkgroups.go @@ -20,6 +20,7 @@ func (tga *talkgroupAPI) Subrouter() http.Handler { r.Put("/{system:\\d+}/{id:\\d+}", tga.put) r.Get("/{system:\\d+}/", tga.get) r.Get("/", tga.get) + r.Put("/import", tga.tgImport) return r } @@ -106,3 +107,19 @@ func (tga *talkgroupAPI) put(w http.ResponseWriter, r *http.Request) { respond(w, r, record) } + +func (tga *talkgroupAPI) tgImport(w http.ResponseWriter, r *http.Request) { + var impJob talkgroups.ImportJob + err := forms.Unmarshal(r, &impJob, forms.WithTag("json"), forms.WithAcceptBlank(), forms.WithOmitEmpty()) + if err != nil { + wErr(w, r, badRequest(err)) + return + } + recs, err := impJob.Import() + if err != nil { + wErr(w, r, autoError(err)) + return + } + + respond(w, r, recs) +} diff --git a/pkg/talkgroups/import.go b/pkg/talkgroups/import.go new file mode 100644 index 0000000..6fdf041 --- /dev/null +++ b/pkg/talkgroups/import.go @@ -0,0 +1,125 @@ +package talkgroups + +import ( + "bufio" + "bytes" + "errors" + "io" + "encoding/json" + "regexp" + "strconv" + "strings" + + "dynatron.me/x/stillbox/pkg/database" +) + +type ImportSource string + +const ( + ImportSrcRadioReference ImportSource = "radioreference" +) + +var ( + ErrBadImportType = errors.New("unknown import type") +) + +type importer interface { + importTalkgroups(sys int, r io.Reader) ([]Talkgroup, error) +} + +type ImportJob struct { + Type ImportSource `json:"type"` + SystemID int `json:"systemID"` + Body string `json:"body"` + + importer `json:"-"` +} + +func (ij *ImportJob) Import() ([]Talkgroup, error) { + r := bytes.NewReader([]byte(ij.Body)) + + switch ij.Type { + case ImportSrcRadioReference: + ij.importer = &radioReferenceImporter{} + default: + return nil, ErrBadImportType + } + return ij.importTalkgroups(ij.SystemID, r) +} + +type radioReferenceImporter struct { +} + +type rrState int +const ( + rrsInitial rrState = iota + rrsGroupDesc + rrsTG +) + +var rrRE = regexp.MustCompile(`DEC\s+HEX\s+Mode\s+Alpha Tag\s+Description\s+Tag`) + +func (rr *radioReferenceImporter) importTalkgroups(sys int, r io.Reader) ([]Talkgroup, error) { + sc := bufio.NewScanner(r) + tgs := make([]Talkgroup, 0, 8) + + var groupName string + state := rrsInitial + for sc.Scan() { + ln := strings.Trim(sc.Text(), " \t\r\n") + + switch state { + case rrsInitial: + groupName = ln + state++ + case rrsGroupDesc: + if rrRE.MatchString(ln) { + state++ + } + case rrsTG: + fields := strings.Split(ln, "\t") + if len(fields) < 6 { + state = rrsGroupDesc + groupName = ln + continue + } + tgid, err := strconv.Atoi(fields[0]) + if err != nil { + continue + } + var metadata []byte + tgt := TG(sys, tgid) + mode := fields[2] + if strings.Contains(mode, "E") { + metadata, _ = json.Marshal(&struct{ + Encrypted bool `json:"encrypted"` + }{true}) + } + tags := []string{fields[5]} + tgs = append(tgs, Talkgroup{ + Talkgroup: database.Talkgroup{ + ID: tgt.Pack(), + Tgid: int32(tgt.Talkgroup), + SystemID: int32(tgt.System), + Name: &fields[4], + AlphaTag: &fields[3], + TgGroup: &groupName, + Metadata: metadata, + Tags: tags, + Weight: 1.0, + }, + System: database.System{ + ID: sys, + Name: "", + }, + }) + + } + } + + if err := sc.Err(); err != nil { + return tgs, err + } + + return tgs, nil +}