config.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package main
  2. import (
  3. "encoding/json"
  4. "os"
  5. "path/filepath"
  6. )
  7. // Config holds the daemon configuration
  8. type Config struct {
  9. // Mode: "cloud" (server settings priority) or "lan" (local settings priority)
  10. Mode string `json:"mode"`
  11. // Server settings
  12. APIBase string `json:"api_base"`
  13. // Device identity (persisted)
  14. DeviceID string `json:"device_id,omitempty"`
  15. DeviceToken string `json:"device_token,omitempty"`
  16. // BLE settings
  17. BLE struct {
  18. Enabled bool `json:"enabled"`
  19. BatchIntervalMs int `json:"batch_interval_ms"`
  20. } `json:"ble"`
  21. // WiFi settings
  22. WiFi struct {
  23. MonitorEnabled bool `json:"monitor_enabled"`
  24. ClientEnabled bool `json:"client_enabled"`
  25. SSID string `json:"ssid"`
  26. PSK string `json:"psk"`
  27. BatchIntervalMs int `json:"batch_interval_ms"`
  28. } `json:"wifi"`
  29. // SSH Tunnel settings
  30. SSHTunnel struct {
  31. Enabled bool `json:"enabled"`
  32. Server string `json:"server"`
  33. Port int `json:"port"`
  34. User string `json:"user"`
  35. KeyPath string `json:"key_path"`
  36. RemotePort int `json:"remote_port"`
  37. KeepaliveInterval int `json:"keepalive_interval"`
  38. ReconnectDelay int `json:"reconnect_delay"`
  39. } `json:"ssh_tunnel"`
  40. // Network settings (eth0 is ALWAYS local, never from server)
  41. Network struct {
  42. NTPServers []string `json:"ntp_servers"`
  43. Eth0 struct {
  44. Static bool `json:"static"`
  45. Address string `json:"address"`
  46. Gateway string `json:"gateway"`
  47. DNS string `json:"dns"`
  48. } `json:"eth0"`
  49. } `json:"network"`
  50. // AP Fallback settings (when no network available for 120s)
  51. APFallback struct {
  52. Password string `json:"password"` // Default: "mybeacon123"
  53. } `json:"ap_fallback"`
  54. // Dashboard settings
  55. Dashboard struct {
  56. Enabled bool `json:"enabled"`
  57. } `json:"dashboard"`
  58. // Local-only settings (never from server)
  59. ZMQAddrBLE string `json:"zmq_addr_ble"`
  60. ZMQAddrWiFi string `json:"zmq_addr_wifi"`
  61. SpoolDir string `json:"spool_dir"`
  62. WiFiIface string `json:"wifi_iface"`
  63. Debug bool `json:"debug"`
  64. }
  65. // DefaultConfig returns a configuration with default values
  66. func DefaultConfig() *Config {
  67. cfg := &Config{
  68. Mode: "cloud",
  69. APIBase: "http://localhost:5000/api/v1",
  70. ZMQAddrBLE: "tcp://127.0.0.1:5555",
  71. ZMQAddrWiFi: "tcp://127.0.0.1:5556",
  72. SpoolDir: "/var/spool/mybeacon",
  73. }
  74. cfg.BLE.Enabled = true
  75. cfg.BLE.BatchIntervalMs = 2500
  76. cfg.WiFi.MonitorEnabled = false
  77. cfg.WiFi.BatchIntervalMs = 10000
  78. cfg.SSHTunnel.Port = 22
  79. cfg.SSHTunnel.KeepaliveInterval = 30
  80. cfg.SSHTunnel.ReconnectDelay = 5
  81. cfg.Network.NTPServers = []string{"pool.ntp.org"}
  82. cfg.APFallback.Password = "mybeacon"
  83. cfg.Dashboard.Enabled = true
  84. return cfg
  85. }
  86. // LoadConfig loads configuration from a JSON file
  87. func LoadConfig(path string) (*Config, error) {
  88. cfg := DefaultConfig()
  89. data, err := os.ReadFile(path)
  90. if err != nil {
  91. if os.IsNotExist(err) {
  92. return cfg, nil // Use defaults
  93. }
  94. return nil, err
  95. }
  96. if err := json.Unmarshal(data, cfg); err != nil {
  97. return nil, err
  98. }
  99. return cfg, nil
  100. }
  101. // SaveConfig saves configuration to a JSON file
  102. func SaveConfig(path string, cfg *Config) error {
  103. dir := filepath.Dir(path)
  104. if err := os.MkdirAll(dir, 0755); err != nil {
  105. return err
  106. }
  107. data, err := json.MarshalIndent(cfg, "", " ")
  108. if err != nil {
  109. return err
  110. }
  111. return os.WriteFile(path, data, 0600)
  112. }
  113. // DeviceState holds persistent device state
  114. type DeviceState struct {
  115. DeviceID string `json:"device_id"`
  116. DeviceToken string `json:"device_token"`
  117. DevicePassword string `json:"device_password,omitempty"`
  118. }
  119. // LoadDeviceState loads device state from file
  120. func LoadDeviceState(path string) (*DeviceState, error) {
  121. state := &DeviceState{}
  122. data, err := os.ReadFile(path)
  123. if err != nil {
  124. if os.IsNotExist(err) {
  125. return state, nil
  126. }
  127. return nil, err
  128. }
  129. if err := json.Unmarshal(data, state); err != nil {
  130. return nil, err
  131. }
  132. return state, nil
  133. }
  134. // SaveDeviceState saves device state to file
  135. func SaveDeviceState(path string, state *DeviceState) error {
  136. dir := filepath.Dir(path)
  137. if err := os.MkdirAll(dir, 0755); err != nil {
  138. return err
  139. }
  140. data, err := json.MarshalIndent(state, "", " ")
  141. if err != nil {
  142. return err
  143. }
  144. return os.WriteFile(path, data, 0600)
  145. }