feat: add global flood policy configuration and API endpoint for updates

This commit is contained in:
Lloyd
2025-11-16 21:43:35 +00:00
parent deaed4b376
commit 9e65a02273
3 changed files with 111 additions and 1 deletions
+7
View File
@@ -34,6 +34,13 @@ repeater:
# Recommended: 10 hours for typical deployments
send_advert_interval_hours: 10
# Mesh Network Configuration
mesh:
# Global flood policy - controls whether the repeater allows or denies flooding by default
# true = allow flooding globally, false = deny flooding globally
# Individual transport keys can override this setting
global_flood_allow: false
radio:
# Frequency in Hz (869.618 MHz for EU)
frequency: 869618000
+64
View File
@@ -45,6 +45,70 @@ def load_config(config_path: Optional[str] = None) -> Dict[str, Any]:
return config
def save_config(config_data: Dict[str, Any], config_path: Optional[str] = None) -> bool:
"""
Save configuration to YAML file.
Args:
config_data: Configuration dictionary to save
config_path: Path to config file (uses default if None)
Returns:
True if successful, False otherwise
"""
if config_path is None:
config_path = os.getenv("PYMC_REPEATER_CONFIG", "/etc/pymc_repeater/config.yaml")
try:
# Create backup of existing config
config_file = Path(config_path)
if config_file.exists():
backup_path = config_file.with_suffix('.yaml.backup')
config_file.rename(backup_path)
logger.info(f"Created backup at {backup_path}")
# Save new config
with open(config_path, 'w') as f:
yaml.safe_dump(config_data, f, default_flow_style=False, sort_keys=False)
logger.info(f"Saved configuration to {config_path}")
return True
except Exception as e:
logger.error(f"Failed to save configuration: {e}")
return False
def update_global_flood_policy(allow: bool, config_path: Optional[str] = None) -> bool:
"""
Update the global flood policy in the configuration.
Args:
allow: True to allow flooding globally, False to deny
config_path: Path to config file (uses default if None)
Returns:
True if successful, False otherwise
"""
try:
# Load current config
config = load_config(config_path)
# Ensure mesh section exists
if "mesh" not in config:
config["mesh"] = {}
# Set global flood policy
config["mesh"]["global_flood_allow"] = allow
# Save updated config
return save_config(config, config_path)
except Exception as e:
logger.error(f"Failed to update global flood policy: {e}")
return False
def _load_or_create_identity_key(path: Optional[str] = None) -> bytes:
if path is None:
+40 -1
View File
@@ -5,6 +5,7 @@ from datetime import datetime
from typing import Callable, Optional
import cherrypy
from repeater import __version__
from repeater.config import update_global_flood_policy
from .cad_calibration_engine import CADCalibrationEngine
logger = logging.getLogger("HTTPServer")
@@ -804,4 +805,42 @@ class APIEndpoints:
return self._error("Invalid key_id format")
except Exception as e:
logger.error(f"Error deleting transport key: {e}")
return self._error(e)
return self._error(e)
@cherrypy.expose
@cors_enabled
@cherrypy.tools.json_in()
def global_flood_policy(self):
"""
Update global flood policy configuration
POST /global_flood_policy
Body: {"global_flood_allow": true/false}
"""
if cherrypy.request.method == "POST":
try:
data = cherrypy.request.json or {}
global_flood_allow = data.get("global_flood_allow")
if global_flood_allow is None:
return self._error("Missing required field: global_flood_allow")
if not isinstance(global_flood_allow, bool):
return self._error("global_flood_allow must be a boolean value")
# Update the configuration
success = update_global_flood_policy(global_flood_allow)
if success:
return self._success(
{"global_flood_allow": global_flood_allow},
message=f"Global flood policy updated to {'allow' if global_flood_allow else 'deny'}"
)
else:
return self._error("Failed to update global flood policy configuration")
except Exception as e:
logger.error(f"Error updating global flood policy: {e}")
return self._error(e)
else:
return self._error("Method not supported")