config.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 (for terminal access)
  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. // Dashboard Tunnel settings (for web dashboard access)
  41. DashboardTunnel struct {
  42. Enabled bool `json:"enabled"`
  43. Server string `json:"server"`
  44. Port int `json:"port"`
  45. User string `json:"user"`
  46. RemotePort int `json:"remote_port"`
  47. KeepaliveInterval int `json:"keepalive_interval"`
  48. ReconnectDelay int `json:"reconnect_delay"`
  49. } `json:"dashboard_tunnel"`
  50. // Network settings (eth0 is ALWAYS local, never from server)
  51. Network struct {
  52. NTPServers []string `json:"ntp_servers"`
  53. Eth0 struct {
  54. Static bool `json:"static"`
  55. Address string `json:"address"`
  56. Gateway string `json:"gateway"`
  57. DNS string `json:"dns"`
  58. } `json:"eth0"`
  59. } `json:"network"`
  60. // AP Fallback settings (when no network available for 120s)
  61. APFallback struct {
  62. Password string `json:"password"` // Default: "mybeacon123"
  63. } `json:"ap_fallback"`
  64. // Dashboard settings
  65. Dashboard struct {
  66. Enabled bool `json:"enabled"`
  67. } `json:"dashboard"`
  68. // Local-only settings (never from server)
  69. ZMQAddrBLE string `json:"zmq_addr_ble"`
  70. ZMQAddrWiFi string `json:"zmq_addr_wifi"`
  71. SpoolDir string `json:"spool_dir"`
  72. WiFiIface string `json:"wifi_iface"`
  73. Debug bool `json:"debug"`
  74. }
  75. // DefaultConfig returns a configuration with default values
  76. func DefaultConfig() *Config {
  77. cfg := &Config{
  78. Mode: "cloud",
  79. APIBase: "http://localhost:5000/api/v1",
  80. ZMQAddrBLE: "tcp://127.0.0.1:5555",
  81. ZMQAddrWiFi: "tcp://127.0.0.1:5556",
  82. SpoolDir: "/var/spool/mybeacon",
  83. }
  84. cfg.BLE.Enabled = true
  85. cfg.BLE.BatchIntervalMs = 2500
  86. cfg.WiFi.MonitorEnabled = false
  87. cfg.WiFi.BatchIntervalMs = 10000
  88. cfg.SSHTunnel.Port = 22
  89. cfg.SSHTunnel.KeepaliveInterval = 30
  90. cfg.SSHTunnel.ReconnectDelay = 5
  91. cfg.DashboardTunnel.Port = 22
  92. cfg.DashboardTunnel.KeepaliveInterval = 30
  93. cfg.DashboardTunnel.ReconnectDelay = 5
  94. cfg.Network.NTPServers = []string{"pool.ntp.org"}
  95. cfg.APFallback.Password = "mybeacon"
  96. cfg.Dashboard.Enabled = true
  97. return cfg
  98. }
  99. // LoadConfig loads configuration from a JSON file
  100. func LoadConfig(path string) (*Config, error) {
  101. cfg := DefaultConfig()
  102. data, err := os.ReadFile(path)
  103. if err != nil {
  104. if os.IsNotExist(err) {
  105. return cfg, nil // Use defaults
  106. }
  107. return nil, err
  108. }
  109. if err := json.Unmarshal(data, cfg); err != nil {
  110. return nil, err
  111. }
  112. return cfg, nil
  113. }
  114. // SaveConfig saves configuration to a JSON file
  115. func SaveConfig(path string, cfg *Config) error {
  116. dir := filepath.Dir(path)
  117. if err := os.MkdirAll(dir, 0755); err != nil {
  118. return err
  119. }
  120. data, err := json.MarshalIndent(cfg, "", " ")
  121. if err != nil {
  122. return err
  123. }
  124. return os.WriteFile(path, data, 0600)
  125. }
  126. // DeviceState holds persistent device state
  127. type DeviceState struct {
  128. DeviceID string `json:"device_id"`
  129. DeviceToken string `json:"device_token"`
  130. DevicePassword string `json:"device_password,omitempty"`
  131. }
  132. // LoadDeviceState loads device state from file
  133. func LoadDeviceState(path string) (*DeviceState, error) {
  134. state := &DeviceState{}
  135. data, err := os.ReadFile(path)
  136. if err != nil {
  137. if os.IsNotExist(err) {
  138. return state, nil
  139. }
  140. return nil, err
  141. }
  142. if err := json.Unmarshal(data, state); err != nil {
  143. return nil, err
  144. }
  145. return state, nil
  146. }
  147. // SaveDeviceState saves device state to file
  148. func SaveDeviceState(path string, state *DeviceState) error {
  149. dir := filepath.Dir(path)
  150. if err := os.MkdirAll(dir, 0755); err != nil {
  151. return err
  152. }
  153. data, err := json.MarshalIndent(state, "", " ")
  154. if err != nil {
  155. return err
  156. }
  157. return os.WriteFile(path, data, 0600)
  158. }