forked from iarv/Akita-Meshtastic-Meshcore-Bridge
Update CHANGELOG, enhance configuration loading with default values, and add tests for missing defaults
This commit is contained in:
16
CHANGELOG.md
16
CHANGELOG.md
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
## Version 2.0.0 - Comprehensive Code Review and Enhancements (December 31, 2025)
|
## Version 2.0.0 - Comprehensive Code Review and Enhancements (December 31, 2025)
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### Bug Fixes
|
||||||
- **Fixed test file errors**: Corrected incomplete string in `test_config_handler.py` and wrong function name in `test_protocol.py`
|
- **Fixed test file errors**: Corrected incomplete string in `test_config_handler.py` and wrong function name in `test_protocol.py`
|
||||||
- **Fixed missing method**: Added `_on_log` method to `MQTTHandler` that was referenced but not defined
|
- **Fixed missing method**: Added `_on_log` method to `MQTTHandler` that was referenced but not defined
|
||||||
|
|
||||||
### ✨ New Features
|
### New Features
|
||||||
|
|
||||||
#### 1. Metrics and Statistics Collection
|
#### 1. Metrics and Statistics Collection
|
||||||
- **New Module**: `ammb/metrics.py`
|
- **New Module**: `ammb/metrics.py`
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
- Configurable insecure mode (for testing)
|
- Configurable insecure mode (for testing)
|
||||||
- Automatic TLS context creation
|
- Automatic TLS context creation
|
||||||
|
|
||||||
### 🔧 Enhancements
|
### Enhancements
|
||||||
|
|
||||||
#### Configuration System
|
#### Configuration System
|
||||||
- Added API configuration options:
|
- Added API configuration options:
|
||||||
@@ -111,32 +111,32 @@
|
|||||||
- Enhanced shutdown sequence
|
- Enhanced shutdown sequence
|
||||||
- Better error handling and logging
|
- Better error handling and logging
|
||||||
|
|
||||||
### 📊 Performance Optimizations
|
### Performance Optimizations
|
||||||
- Thread-safe metrics collection
|
- Thread-safe metrics collection
|
||||||
- Non-blocking message logging
|
- Non-blocking message logging
|
||||||
- Efficient rate limiting algorithm
|
- Efficient rate limiting algorithm
|
||||||
- Optimized health check intervals
|
- Optimized health check intervals
|
||||||
- Reduced lock contention
|
- Reduced lock contention
|
||||||
|
|
||||||
### 🛡️ Security Enhancements
|
### Security Enhancements
|
||||||
- Message validation prevents malformed data
|
- Message validation prevents malformed data
|
||||||
- Rate limiting prevents message flooding
|
- Rate limiting prevents message flooding
|
||||||
- TLS/SSL support for secure MQTT
|
- TLS/SSL support for secure MQTT
|
||||||
- Input sanitization prevents injection attacks
|
- Input sanitization prevents injection attacks
|
||||||
- Node ID validation prevents spoofing
|
- Node ID validation prevents spoofing
|
||||||
|
|
||||||
### 📝 Documentation
|
### Documentation
|
||||||
- Updated README.md with new features
|
- Updated README.md with new features
|
||||||
- Enhanced configuration examples
|
- Enhanced configuration examples
|
||||||
- Added API endpoint documentation
|
- Added API endpoint documentation
|
||||||
- Improved code comments and docstrings
|
- Improved code comments and docstrings
|
||||||
|
|
||||||
### 🧪 Testing
|
### Testing
|
||||||
- Fixed broken test files
|
- Fixed broken test files
|
||||||
- All modules compile successfully
|
- All modules compile successfully
|
||||||
- No linter errors
|
- No linter errors
|
||||||
|
|
||||||
### 🔄 Backward Compatibility
|
### Backward Compatibility
|
||||||
- All new features are optional and configurable
|
- All new features are optional and configurable
|
||||||
- Default behavior maintains backward compatibility
|
- Default behavior maintains backward compatibility
|
||||||
- Existing configurations continue to work
|
- Existing configurations continue to work
|
||||||
|
|||||||
@@ -100,14 +100,12 @@ def load_config(config_path: str = CONFIG_FILE) -> Optional[BridgeConfig]:
|
|||||||
|
|
||||||
if 'DEFAULT' not in config.sections():
|
if 'DEFAULT' not in config.sections():
|
||||||
logger.warning(f"Configuration file '{config_path}' lacks the [DEFAULT] section. Using only defaults.")
|
logger.warning(f"Configuration file '{config_path}' lacks the [DEFAULT] section. Using only defaults.")
|
||||||
cfg_section = config.defaults()
|
cfg_section = config['DEFAULT']
|
||||||
else:
|
|
||||||
cfg_section = config['DEFAULT']
|
|
||||||
|
|
||||||
meshtastic_port = cfg_section.get('MESHTASTIC_SERIAL_PORT')
|
meshtastic_port = cfg_section.get('MESHTASTIC_SERIAL_PORT', fallback=DEFAULT_CONFIG['MESHTASTIC_SERIAL_PORT'])
|
||||||
external_network_id = cfg_section.get('EXTERNAL_NETWORK_ID')
|
external_network_id = cfg_section.get('EXTERNAL_NETWORK_ID', fallback=DEFAULT_CONFIG['EXTERNAL_NETWORK_ID'])
|
||||||
bridge_node_id = cfg_section.get('BRIDGE_NODE_ID')
|
bridge_node_id = cfg_section.get('BRIDGE_NODE_ID', fallback=DEFAULT_CONFIG['BRIDGE_NODE_ID'])
|
||||||
log_level = cfg_section.get('LOG_LEVEL').upper()
|
log_level = cfg_section.get('LOG_LEVEL', fallback=DEFAULT_CONFIG['LOG_LEVEL']).upper()
|
||||||
|
|
||||||
if log_level not in VALID_LOG_LEVELS:
|
if log_level not in VALID_LOG_LEVELS:
|
||||||
logger.error(f"Invalid LOG_LEVEL '{log_level}'. Must be one of: {VALID_LOG_LEVELS}")
|
logger.error(f"Invalid LOG_LEVEL '{log_level}'. Must be one of: {VALID_LOG_LEVELS}")
|
||||||
@@ -121,7 +119,7 @@ def load_config(config_path: str = CONFIG_FILE) -> Optional[BridgeConfig]:
|
|||||||
logger.error(f"Invalid integer value for MESSAGE_QUEUE_SIZE: {e}")
|
logger.error(f"Invalid integer value for MESSAGE_QUEUE_SIZE: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
external_transport = cfg_section.get('EXTERNAL_TRANSPORT').lower()
|
external_transport = cfg_section.get('EXTERNAL_TRANSPORT', fallback=DEFAULT_CONFIG['EXTERNAL_TRANSPORT']).lower()
|
||||||
if external_transport not in VALID_TRANSPORTS:
|
if external_transport not in VALID_TRANSPORTS:
|
||||||
logger.error(f"Invalid EXTERNAL_TRANSPORT '{external_transport}'. Must be one of: {VALID_TRANSPORTS}")
|
logger.error(f"Invalid EXTERNAL_TRANSPORT '{external_transport}'. Must be one of: {VALID_TRANSPORTS}")
|
||||||
return None
|
return None
|
||||||
@@ -140,8 +138,8 @@ def load_config(config_path: str = CONFIG_FILE) -> Optional[BridgeConfig]:
|
|||||||
mqtt_retain_out = None
|
mqtt_retain_out = None
|
||||||
|
|
||||||
if external_transport == 'serial':
|
if external_transport == 'serial':
|
||||||
serial_port = cfg_section.get('SERIAL_PORT')
|
serial_port = cfg_section.get('SERIAL_PORT', fallback=DEFAULT_CONFIG['SERIAL_PORT'])
|
||||||
serial_protocol = cfg_section.get('SERIAL_PROTOCOL').lower()
|
serial_protocol = cfg_section.get('SERIAL_PROTOCOL', fallback=DEFAULT_CONFIG['SERIAL_PROTOCOL']).lower()
|
||||||
if not serial_port:
|
if not serial_port:
|
||||||
logger.error("SERIAL_PORT must be set when EXTERNAL_TRANSPORT is 'serial'.")
|
logger.error("SERIAL_PORT must be set when EXTERNAL_TRANSPORT is 'serial'.")
|
||||||
return None
|
return None
|
||||||
|
|||||||
14
tests/test_config_handler_missing_default.py
Normal file
14
tests/test_config_handler_missing_default.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import importlib.util
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_config_missing_default(tmp_path):
|
||||||
|
cfgfile = tmp_path / "no_default.ini"
|
||||||
|
cfgfile.write_text("[serial]\nSERIAL_PORT=/dev/ttyS1\n")
|
||||||
|
|
||||||
|
spec = importlib.util.spec_from_file_location('config_handler', 'ammb/config_handler.py')
|
||||||
|
mod = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(mod)
|
||||||
|
|
||||||
|
cfg = mod.load_config(str(cfgfile))
|
||||||
|
assert cfg is not None
|
||||||
|
assert cfg.log_level == 'INFO'
|
||||||
2
tmp_no_default.ini
Normal file
2
tmp_no_default.ini
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[serial]
|
||||||
|
SERIAL_PORT = /dev/ttyS1
|
||||||
6
tmp_run_load.py
Normal file
6
tmp_run_load.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import importlib.util
|
||||||
|
spec = importlib.util.spec_from_file_location('config_handler', 'ammb/config_handler.py')
|
||||||
|
mod = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(mod)
|
||||||
|
print('Using file: tmp_no_default.ini')
|
||||||
|
print(mod.load_config('tmp_no_default.ini'))
|
||||||
7
tmp_test_config.py
Normal file
7
tmp_test_config.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from ammb import config_handler
|
||||||
|
path='tmp_no_default.ini'
|
||||||
|
with open(path,'w') as f:
|
||||||
|
f.write('[serial]\nSERIAL_PORT=/dev/ttyS1\n')
|
||||||
|
print('Using file:', path)
|
||||||
|
cfg = config_handler.load_config(path)
|
||||||
|
print('Result:', cfg)
|
||||||
Reference in New Issue
Block a user