153 lines
3.9 KiB
Go
153 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
// mappingFile is the structure of the JSON config file.
|
|
// Campus names map to the list of gateway IDs that belong to them.
|
|
// Room names map to the list of node IDs that belong to them.
|
|
type mappingFile struct {
|
|
Campus map[string][]string `json:"campus"`
|
|
Room map[string][]string `json:"room"`
|
|
}
|
|
|
|
// MappingConfig holds the reverse lookup maps built from the config file:
|
|
//
|
|
// gateway_id -> campus name
|
|
// node_id -> room name
|
|
type MappingConfig struct {
|
|
gatewayToCampus map[string]string
|
|
nodeToRoom map[string]string
|
|
}
|
|
|
|
// DynamicMapping reloads the mapping file on every access so that changes
|
|
// to the JSON file take effect without restarting the programme.
|
|
type DynamicMapping struct {
|
|
path string
|
|
}
|
|
|
|
// NewDynamicMapping creates a DynamicMapping that reads from the given path.
|
|
func NewDynamicMapping(path string) *DynamicMapping {
|
|
return &DynamicMapping{path: path}
|
|
}
|
|
|
|
func (d *DynamicMapping) load() *MappingConfig {
|
|
cfg, err := LoadMapping(d.path)
|
|
if err != nil {
|
|
return EmptyMapping()
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
func (d *DynamicMapping) GetCampus(gatewayID string) (string, bool) {
|
|
return d.load().GetCampus(gatewayID)
|
|
}
|
|
|
|
func (d *DynamicMapping) GetRoom(nodeID string) (string, bool) {
|
|
return d.load().GetRoom(nodeID)
|
|
}
|
|
|
|
func (d *DynamicMapping) NodesForRoom(room string) []string {
|
|
return d.load().NodesForRoom(room)
|
|
}
|
|
|
|
func (d *DynamicMapping) AllNodes() []string {
|
|
return d.load().AllNodes()
|
|
}
|
|
|
|
func (d *DynamicMapping) Rooms() []string {
|
|
return d.load().Rooms()
|
|
}
|
|
|
|
// EmptyMapping returns a MappingConfig with no entries.
|
|
// GetCampus and GetRoom will return their "unknown_*" fallback values.
|
|
func EmptyMapping() *MappingConfig {
|
|
return &MappingConfig{
|
|
gatewayToCampus: make(map[string]string),
|
|
nodeToRoom: make(map[string]string),
|
|
}
|
|
}
|
|
|
|
// LoadMapping reads the mapping configuration from a JSON file and builds
|
|
// the internal reverse-lookup tables.
|
|
func LoadMapping(path string) (*MappingConfig, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read mapping file %q: %w", path, err)
|
|
}
|
|
|
|
var raw mappingFile
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return nil, fmt.Errorf("failed to parse mapping JSON: %w", err)
|
|
}
|
|
|
|
cfg := &MappingConfig{
|
|
gatewayToCampus: make(map[string]string),
|
|
nodeToRoom: make(map[string]string),
|
|
}
|
|
|
|
for campus, gateways := range raw.Campus {
|
|
for _, gwID := range gateways {
|
|
cfg.gatewayToCampus[gwID] = campus
|
|
}
|
|
}
|
|
|
|
for room, nodes := range raw.Room {
|
|
for _, nodeID := range nodes {
|
|
cfg.nodeToRoom[nodeID] = room
|
|
}
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// GetCampus returns the campus name for a given gateway ID.
|
|
// The boolean is false if the gateway ID has no mapping.
|
|
func (c *MappingConfig) GetCampus(gatewayID string) (string, bool) {
|
|
campus, ok := c.gatewayToCampus[gatewayID]
|
|
return campus, ok
|
|
}
|
|
|
|
// GetRoom returns the room name for a given node ID.
|
|
// The boolean is false if the node ID has no mapping.
|
|
func (c *MappingConfig) GetRoom(nodeID string) (string, bool) {
|
|
room, ok := c.nodeToRoom[nodeID]
|
|
return room, ok
|
|
}
|
|
|
|
// NodesForRoom returns the list of node IDs that belong to the given room.
|
|
func (c *MappingConfig) NodesForRoom(room string) []string {
|
|
var nodes []string
|
|
for nodeID, r := range c.nodeToRoom {
|
|
if r == room {
|
|
nodes = append(nodes, nodeID)
|
|
}
|
|
}
|
|
return nodes
|
|
}
|
|
|
|
// AllNodes returns all node IDs defined in the mapping.
|
|
func (c *MappingConfig) AllNodes() []string {
|
|
nodes := make([]string, 0, len(c.nodeToRoom))
|
|
for nodeID := range c.nodeToRoom {
|
|
nodes = append(nodes, nodeID)
|
|
}
|
|
return nodes
|
|
}
|
|
|
|
// Rooms returns the list of all room names defined in the mapping.
|
|
func (c *MappingConfig) Rooms() []string {
|
|
seen := make(map[string]struct{})
|
|
for _, room := range c.nodeToRoom {
|
|
seen[room] = struct{}{}
|
|
}
|
|
rooms := make([]string, 0, len(seen))
|
|
for room := range seen {
|
|
rooms = append(rooms, room)
|
|
}
|
|
return rooms
|
|
}
|