290 lines
7.1 KiB
Go
290 lines
7.1 KiB
Go
package config
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// Device represents a device configuration in tellstick.conf
|
|
type Device struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Protocol string `json:"protocol"`
|
|
Model string `json:"model"`
|
|
Parameters map[string]string `json:"parameters"`
|
|
}
|
|
|
|
// Controller represents a controller configuration
|
|
type Controller struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Serial string `json:"serial,omitempty"`
|
|
}
|
|
|
|
// Config represents the entire tellstick.conf structure
|
|
type Config struct {
|
|
User string `json:"user,omitempty"`
|
|
Group string `json:"group,omitempty"`
|
|
DevicePath string `json:"devicePath,omitempty"`
|
|
IgnoreControllerConfirmation int `json:"ignoreControllerConfirmation,omitempty"`
|
|
Controllers []Controller `json:"controllers"`
|
|
Devices []Device `json:"devices"`
|
|
}
|
|
|
|
// Parser handles parsing and writing tellstick.conf files
|
|
type Parser struct {
|
|
filePath string
|
|
}
|
|
|
|
// NewParser creates a new config parser
|
|
func NewParser(filePath string) *Parser {
|
|
return &Parser{filePath: filePath}
|
|
}
|
|
|
|
// Parse reads and parses the tellstick.conf file
|
|
func (p *Parser) Parse() (*Config, error) {
|
|
file, err := os.Open(p.filePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
config := &Config{
|
|
Controllers: []Controller{},
|
|
Devices: []Device{},
|
|
}
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
var currentSection string
|
|
var currentDevice *Device
|
|
var currentController *Controller
|
|
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
|
|
// Skip empty lines and comments
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
|
|
// Check for section headers
|
|
if strings.HasPrefix(line, "user") {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) == 2 {
|
|
config.User = strings.Trim(strings.TrimSpace(parts[1]), "\"")
|
|
}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "group") {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) == 2 {
|
|
config.Group = strings.Trim(strings.TrimSpace(parts[1]), "\"")
|
|
}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "deviceNode") {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) == 2 {
|
|
config.DevicePath = strings.Trim(strings.TrimSpace(parts[1]), "\"")
|
|
}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "ignoreControllerConfirmation") {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) == 2 {
|
|
fmt.Sscanf(strings.TrimSpace(parts[1]), "%d", &config.IgnoreControllerConfirmation)
|
|
}
|
|
continue
|
|
}
|
|
|
|
// Section detection
|
|
if strings.HasPrefix(line, "controller {") || strings.HasPrefix(line, "controller{") {
|
|
currentSection = "controller"
|
|
currentController = &Controller{}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "device {") || strings.HasPrefix(line, "device{") {
|
|
currentSection = "device"
|
|
currentDevice = &Device{
|
|
Parameters: make(map[string]string),
|
|
}
|
|
continue
|
|
}
|
|
|
|
// End of section
|
|
if line == "}" {
|
|
if currentSection == "device" && currentDevice != nil {
|
|
config.Devices = append(config.Devices, *currentDevice)
|
|
currentDevice = nil
|
|
}
|
|
if currentSection == "controller" && currentController != nil {
|
|
config.Controllers = append(config.Controllers, *currentController)
|
|
currentController = nil
|
|
}
|
|
currentSection = ""
|
|
continue
|
|
}
|
|
|
|
// Parse device/controller properties
|
|
if currentSection == "device" && currentDevice != nil {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) == 2 {
|
|
key := strings.TrimSpace(parts[0])
|
|
value := strings.Trim(strings.TrimSpace(parts[1]), "\"")
|
|
|
|
switch key {
|
|
case "id":
|
|
fmt.Sscanf(value, "%d", ¤tDevice.ID)
|
|
case "name":
|
|
currentDevice.Name = value
|
|
case "protocol":
|
|
currentDevice.Protocol = value
|
|
case "model":
|
|
currentDevice.Model = value
|
|
default:
|
|
currentDevice.Parameters[key] = value
|
|
}
|
|
}
|
|
}
|
|
|
|
if currentSection == "controller" && currentController != nil {
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) == 2 {
|
|
key := strings.TrimSpace(parts[0])
|
|
value := strings.Trim(strings.TrimSpace(parts[1]), "\"")
|
|
|
|
switch key {
|
|
case "id":
|
|
fmt.Sscanf(value, "%d", ¤tController.ID)
|
|
case "name":
|
|
currentController.Name = value
|
|
case "type":
|
|
currentController.Type = value
|
|
case "serial":
|
|
currentController.Serial = value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// Write writes the configuration to the tellstick.conf file
|
|
func (p *Parser) Write(config *Config) error {
|
|
file, err := os.Create(p.filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
w := bufio.NewWriter(file)
|
|
|
|
// Write global settings
|
|
if config.User != "" {
|
|
fmt.Fprintf(w, "user = \"%s\"\n", config.User)
|
|
}
|
|
if config.Group != "" {
|
|
fmt.Fprintf(w, "group = \"%s\"\n", config.Group)
|
|
}
|
|
if config.DevicePath != "" {
|
|
fmt.Fprintf(w, "deviceNode = \"%s\"\n", config.DevicePath)
|
|
}
|
|
if config.IgnoreControllerConfirmation > 0 {
|
|
fmt.Fprintf(w, "ignoreControllerConfirmation = %d\n", config.IgnoreControllerConfirmation)
|
|
}
|
|
|
|
w.WriteString("\n")
|
|
|
|
// Write controllers
|
|
for _, ctrl := range config.Controllers {
|
|
w.WriteString("controller {\n")
|
|
fmt.Fprintf(w, " id = %d\n", ctrl.ID)
|
|
if ctrl.Name != "" {
|
|
fmt.Fprintf(w, " name = \"%s\"\n", ctrl.Name)
|
|
}
|
|
if ctrl.Type != "" {
|
|
fmt.Fprintf(w, " type = \"%s\"\n", ctrl.Type)
|
|
}
|
|
if ctrl.Serial != "" {
|
|
fmt.Fprintf(w, " serial = \"%s\"\n", ctrl.Serial)
|
|
}
|
|
w.WriteString("}\n\n")
|
|
}
|
|
|
|
// Write devices
|
|
for _, dev := range config.Devices {
|
|
w.WriteString("device {\n")
|
|
fmt.Fprintf(w, " id = %d\n", dev.ID)
|
|
fmt.Fprintf(w, " name = \"%s\"\n", dev.Name)
|
|
fmt.Fprintf(w, " protocol = \"%s\"\n", dev.Protocol)
|
|
if dev.Model != "" {
|
|
fmt.Fprintf(w, " model = \"%s\"\n", dev.Model)
|
|
}
|
|
|
|
// Write parameters
|
|
for key, value := range dev.Parameters {
|
|
fmt.Fprintf(w, " %s = \"%s\"\n", key, value)
|
|
}
|
|
|
|
w.WriteString("}\n\n")
|
|
}
|
|
|
|
return w.Flush()
|
|
}
|
|
|
|
// GetDevice returns a device by ID
|
|
func (c *Config) GetDevice(id int) *Device {
|
|
for i := range c.Devices {
|
|
if c.Devices[i].ID == id {
|
|
return &c.Devices[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddDevice adds a new device to the configuration
|
|
func (c *Config) AddDevice(device Device) {
|
|
c.Devices = append(c.Devices, device)
|
|
}
|
|
|
|
// UpdateDevice updates an existing device
|
|
func (c *Config) UpdateDevice(device Device) bool {
|
|
for i := range c.Devices {
|
|
if c.Devices[i].ID == device.ID {
|
|
c.Devices[i] = device
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// DeleteDevice removes a device by ID
|
|
func (c *Config) DeleteDevice(id int) bool {
|
|
for i := range c.Devices {
|
|
if c.Devices[i].ID == id {
|
|
c.Devices = append(c.Devices[:i], c.Devices[i+1:]...)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetNextDeviceID returns the next available device ID
|
|
func (c *Config) GetNextDeviceID() int {
|
|
maxID := 0
|
|
for _, dev := range c.Devices {
|
|
if dev.ID > maxID {
|
|
maxID = dev.ID
|
|
}
|
|
}
|
|
return maxID + 1
|
|
}
|