rdio-scanner/server/system.go
2021-12-01 09:22:49 -05:00

452 lines
10 KiB
Go

// Copyright (C) 2019-2021 Chrystian Huot <chrystian.huot@saubeo.solutions>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>
package main
import (
"database/sql"
"fmt"
"sort"
"strconv"
"strings"
)
type System struct {
Id uint `json:"id"`
AutoPopulate bool `json:"autoPopulate"`
Blacklists Blacklists `json:"blacklists"`
Label string `json:"label"`
Led interface{} `json:"led"`
Order interface{} `json:"order"`
RowId interface{} `json:"_id"`
Talkgroups Talkgroups `json:"talkgroups"`
Units Units `json:"units"`
}
func (system *System) FromMap(m map[string]interface{}) {
switch v := m["_id"].(type) {
case float64:
system.RowId = uint(v)
}
switch v := m["id"].(type) {
case float64:
system.Id = uint(v)
}
switch v := m["autoPopulate"].(type) {
case bool:
system.AutoPopulate = v
}
switch v := m["blacklists"].(type) {
case string:
system.Blacklists = Blacklists(v)
}
switch v := m["label"].(type) {
case string:
system.Label = v
}
switch v := m["led"].(type) {
case string:
system.Led = v
}
switch v := m["order"].(type) {
case float64:
system.Order = uint(v)
}
switch v := m["talkgroups"].(type) {
case []interface{}:
system.Talkgroups.FromMap(v)
}
switch v := m["units"].(type) {
case []interface{}:
system.Units.FromMap(v)
}
}
type SystemMap map[string]interface{}
type Systems []*System
func (systems *Systems) FromMap(f []interface{}) {
*systems = Systems{}
for _, r := range f {
switch m := r.(type) {
case map[string]interface{}:
system := &System{}
system.FromMap(m)
*systems = append(*systems, system)
}
}
}
func (systems *Systems) GetNewSystemId() uint {
NextId:
for i := uint(1); i < 65535; i++ {
for _, s := range *systems {
if s.Id == i {
continue NextId
}
}
return i
}
return 0
}
func (systems *Systems) GetSystem(f interface{}) (system *System, ok bool) {
switch v := f.(type) {
case uint:
for _, system := range *systems {
if system.Id == v {
return system, true
}
}
case string:
for _, system := range *systems {
if system.Label == v {
return system, true
}
}
}
return nil, false
}
func (systems *Systems) GetScopedSystems(client *Client, groups *Groups, tags *Tags, sortTalkgroups bool) *SystemsMap {
var (
rawSystems = Systems{}
systemsMap = SystemsMap{}
)
if client.Access == nil {
rawSystems = append(rawSystems, *systems...)
} else {
switch v := client.Access.Systems.(type) {
case nil:
rawSystems = append(rawSystems, *systems...)
case string:
if v == "*" {
rawSystems = append(rawSystems, *systems...)
}
case []interface{}:
for _, fSystem := range v {
switch v := fSystem.(type) {
case map[string]interface{}:
var (
mSystemId = v["id"]
mTalkgroups = v["talkgroups"]
systemId uint
)
switch v := mSystemId.(type) {
case float64:
systemId = uint(v)
default:
continue
}
system, ok := systems.GetSystem(systemId)
if !ok {
continue
}
switch v := mTalkgroups.(type) {
case string:
if mTalkgroups == "*" {
rawSystems = append(rawSystems, system)
continue
}
case []interface{}:
rawSystem := system
rawSystem.Talkgroups = Talkgroups{}
for _, fTalkgroupId := range v {
switch v := fTalkgroupId.(type) {
case float64:
talkgroupId := uint(v)
rawTalkgroup, ok := system.Talkgroups.GetTalkgroup(talkgroupId)
if !ok {
continue
}
rawSystem.Talkgroups = append(rawSystem.Talkgroups, rawTalkgroup)
default:
continue
}
}
rawSystems = append(rawSystems, rawSystem)
}
}
}
}
}
for i, rawSystem := range rawSystems {
talkgroupsMap := TalkgroupsMap{}
if sortTalkgroups {
sort.Slice(rawSystem.Talkgroups, func(i int, j int) bool {
return rawSystem.Talkgroups[i].Label < rawSystem.Talkgroups[j].Label
})
for i := range rawSystem.Talkgroups {
rawSystem.Talkgroups[i].Order = uint(i + 1)
}
}
for j, rawTalkgroup := range rawSystem.Talkgroups {
group, ok := groups.GetGroup(rawTalkgroup.GroupId)
if !ok {
continue
}
rawSystems[i].Talkgroups[j].group = group.Label
tag, ok := tags.GetTag(rawTalkgroup.TagId)
if !ok {
continue
}
rawSystems[i].Talkgroups[j].tag = tag.Label
talkgroupMap := TalkgroupMap{
"id": rawTalkgroup.Id,
"group": group.Label,
"label": rawTalkgroup.Label,
"name": rawTalkgroup.Name,
"order": rawTalkgroup.Order,
"tag": tag.Label,
}
if rawTalkgroup.Frequency != nil {
talkgroupMap["frequency"] = rawTalkgroup.Frequency
}
if rawTalkgroup.Led != nil {
talkgroupMap["led"] = rawTalkgroup.Led
}
talkgroupsMap = append(talkgroupsMap, talkgroupMap)
}
sort.Slice(talkgroupsMap, func(i int, j int) bool {
if a, err := strconv.Atoi(fmt.Sprintf("%v", talkgroupsMap[i]["order"])); err == nil {
if b, err := strconv.Atoi(fmt.Sprintf("%v", talkgroupsMap[j]["order"])); err == nil {
return a < b
}
}
return false
})
systemMap := SystemMap{
"id": rawSystem.Id,
"label": rawSystem.Label,
"talkgroups": talkgroupsMap,
"units": rawSystem.Units,
}
if rawSystem.Led != nil {
systemMap["led"] = rawSystem.Led
}
if rawSystem.Order != nil {
systemMap["order"] = rawSystem.Order
}
systemsMap = append(systemsMap, systemMap)
}
sort.Slice(systemsMap, func(i int, j int) bool {
if a, err := strconv.Atoi(fmt.Sprintf("%v", systemsMap[i]["order"])); err == nil {
if b, err := strconv.Atoi(fmt.Sprintf("%v", systemsMap[j]["order"])); err == nil {
return a < b
}
}
return false
})
return &systemsMap
}
func (systems *Systems) Read(db *Database) error {
var (
err error
rows *sql.Rows
)
*systems = Systems{}
formatError := func(err error) error {
return fmt.Errorf("systems.read: %v", err)
}
if rows, err = db.Sql.Query("select `_id`, `autoPopulate`, `blacklists`, `id`, `label`, `led`, `order`, `talkgroups`, `units` from `rdioScannerSystems`"); err != nil {
return formatError(err)
}
for rows.Next() {
var (
blacklists interface{}
talkgroups interface{}
units interface{}
)
system := &System{}
if err = rows.Scan(&system.RowId, &system.AutoPopulate, &blacklists, &system.Id, &system.Label, &system.Led, &system.Order, &talkgroups, &units); err != nil {
break
}
switch v := blacklists.(type) {
case string:
v = strings.ReplaceAll(v, "[", "")
v = strings.ReplaceAll(v, "]", "")
system.Blacklists = Blacklists(v)
}
switch v := system.RowId.(type) {
case int64:
system.RowId = uint(v)
}
switch v := talkgroups.(type) {
case []uint8:
system.Talkgroups = Talkgroups{}
if err = system.Talkgroups.FromJson(string(v)); err != nil {
break
}
case string:
system.Talkgroups = Talkgroups{}
if err = system.Talkgroups.FromJson(v); err != nil {
break
}
default:
system.Talkgroups = Talkgroups{}
}
switch v := units.(type) {
case []uint8:
system.Units = Units{}
if err = system.Units.FromJson(string(v)); err != nil {
break
}
case string:
system.Units = Units{}
if err = system.Units.FromJson(v); err != nil {
break
}
default:
system.Units = Units{}
}
*systems = append(*systems, system)
}
if err != nil {
return formatError(err)
}
if err = rows.Close(); err != nil {
return formatError(err)
}
return nil
}
func (systems *Systems) Write(db *Database) error {
var (
blacklists string
count uint
err error
rows *sql.Rows
talkgroups string
units string
)
formatError := func(err error) error {
return fmt.Errorf("systems.write: %v", err)
}
for _, system := range *systems {
if len(system.Blacklists) > 0 {
blacklists = strings.Join([]string{"[", system.Blacklists.String(), "]"}, "")
} else {
blacklists = "[]"
}
if talkgroups, err = system.Talkgroups.ToJson(); err != nil {
return formatError(err)
}
if units, err = system.Units.ToJson(); err != nil {
return formatError(err)
}
if err = db.Sql.QueryRow("select count(*) from `rdioScannerSystems` where `_id` = ?", system.RowId).Scan(&count); err != nil {
break
}
if count == 0 {
if _, err = db.Sql.Exec("insert into `rdioScannerSystems` (`_id`, `autoPopulate`, `blacklists`, `id`, `label`, `led`, `order`, `talkgroups`, `units`) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", system.RowId, system.AutoPopulate, blacklists, system.Id, system.Label, system.Led, system.Order, talkgroups, units); err != nil {
break
}
} else if _, err = db.Sql.Exec("update `rdioScannerSystems` set `_id` = ?, `autoPopulate` = ?, `blacklists` = ?, `id` = ?, `label` = ?, `led` = ?, `order` = ?, `talkgroups` = ?, `units` = ? where `_id` = ?", system.RowId, system.AutoPopulate, blacklists, system.Id, system.Label, system.Led, system.Order, talkgroups, units, system.RowId); err != nil {
break
}
}
if err != nil {
return formatError(err)
}
if rows, err = db.Sql.Query("select `_id` from `rdioScannerSystems`"); err != nil {
return formatError(err)
}
for rows.Next() {
var rowId uint
rows.Scan(&rowId)
remove := true
for _, system := range *systems {
if system.RowId == nil || system.RowId == rowId {
remove = false
break
}
}
if remove {
if _, err = db.Sql.Exec("delete from `rdioScannerSystems` where `_id` = ?", rowId); err != nil {
break
}
}
}
if err != nil {
return formatError(err)
}
if err = rows.Close(); err != nil {
return formatError(err)
}
return nil
}
type SystemsMap []SystemMap