refactor: Replace env-based config and version.py with config.yaml
Move all configuration to config.yaml with live-reload (file watcher). Version is now managed in config.yaml instead of version.py. Remove pre-commit hook for automatic version bumping. Pin meshtastic dependency to >=2.7.7. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
6e5573aa0b
commit
a6c09b19eb
15
config.yaml
Normal file
15
config.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
version: "0.1.2"
|
||||||
|
|
||||||
|
bot:
|
||||||
|
name: "MeshDD-Bot"
|
||||||
|
|
||||||
|
meshtastic:
|
||||||
|
host: "192.168.11.11"
|
||||||
|
port: 4403
|
||||||
|
|
||||||
|
web:
|
||||||
|
host: "0.0.0.0"
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
database:
|
||||||
|
path: "meshdd.db"
|
||||||
11
main.py
11
main.py
|
|
@ -3,7 +3,7 @@ import logging
|
||||||
import signal
|
import signal
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from meshbot import config, VERSION
|
from meshbot import config
|
||||||
from meshbot.database import Database
|
from meshbot.database import Database
|
||||||
from meshbot.bot import MeshBot
|
from meshbot.bot import MeshBot
|
||||||
from meshbot.webserver import WebServer, WebSocketManager
|
from meshbot.webserver import WebServer, WebSocketManager
|
||||||
|
|
@ -16,10 +16,10 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
logger.info("Starting %s v%s", config.BOT_NAME, VERSION)
|
logger.info("Starting %s v%s", config.get("bot.name"), config.get("version"))
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
db = Database(config.DB_PATH)
|
db = Database(config.get("database.path", "meshdd.db"))
|
||||||
await db.connect()
|
await db.connect()
|
||||||
|
|
||||||
# WebSocket Manager
|
# WebSocket Manager
|
||||||
|
|
@ -32,12 +32,15 @@ async def main():
|
||||||
|
|
||||||
# Webserver
|
# Webserver
|
||||||
webserver = WebServer(db, ws_manager)
|
webserver = WebServer(db, ws_manager)
|
||||||
runner = await webserver.start(config.WEB_HOST, config.WEB_PORT)
|
runner = await webserver.start(config.get("web.host", "0.0.0.0"), config.get("web.port", 8080))
|
||||||
|
|
||||||
# Connect Meshtastic in a thread (blocking call)
|
# Connect Meshtastic in a thread (blocking call)
|
||||||
connect_thread = threading.Thread(target=bot.connect, daemon=True)
|
connect_thread = threading.Thread(target=bot.connect, daemon=True)
|
||||||
connect_thread.start()
|
connect_thread.start()
|
||||||
|
|
||||||
|
# Watch config for changes
|
||||||
|
asyncio.create_task(config.watch())
|
||||||
|
|
||||||
# Wait for shutdown
|
# Wait for shutdown
|
||||||
stop_event = asyncio.Event()
|
stop_event = asyncio.Event()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
from meshbot.version import VERSION
|
from meshbot import config
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ from meshtastic.tcp_interface import TCPInterface
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
|
|
||||||
from meshbot import config
|
from meshbot import config
|
||||||
from meshbot.version import VERSION
|
|
||||||
from meshbot.database import Database
|
from meshbot.database import Database
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -23,8 +22,10 @@ class MeshBot:
|
||||||
self.ws_manager = None # set by main.py
|
self.ws_manager = None # set by main.py
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
logger.info("Connecting to Meshtastic at %s:%s", config.MESHTASTIC_HOST, config.MESHTASTIC_PORT)
|
host = config.get("meshtastic.host", "localhost")
|
||||||
self.interface = TCPInterface(hostname=config.MESHTASTIC_HOST, portNumber=config.MESHTASTIC_PORT)
|
port = config.get("meshtastic.port", 4403)
|
||||||
|
logger.info("Connecting to Meshtastic at %s:%s", host, port)
|
||||||
|
self.interface = TCPInterface(hostname=host, portNumber=port)
|
||||||
pub.subscribe(self._on_receive, "meshtastic.receive")
|
pub.subscribe(self._on_receive, "meshtastic.receive")
|
||||||
pub.subscribe(self._on_connection, "meshtastic.connection.established")
|
pub.subscribe(self._on_connection, "meshtastic.connection.established")
|
||||||
pub.subscribe(self._on_node_updated, "meshtastic.node.updated")
|
pub.subscribe(self._on_node_updated, "meshtastic.node.updated")
|
||||||
|
|
@ -143,7 +144,7 @@ class MeshBot:
|
||||||
|
|
||||||
elif cmd == "!info":
|
elif cmd == "!info":
|
||||||
uptime = self._format_uptime()
|
uptime = self._format_uptime()
|
||||||
response = f"ℹ️ {config.BOT_NAME} v{VERSION}\nUptime: {uptime}"
|
response = f"ℹ️ {config.get('bot.name', 'MeshDD-Bot')} v{config.get('version', '0.0.0')}\nUptime: {uptime}"
|
||||||
|
|
||||||
elif cmd == "!help":
|
elif cmd == "!help":
|
||||||
response = (
|
response = (
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,65 @@
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
MESHTASTIC_HOST = os.environ.get("MESHTASTIC_HOST", "localhost")
|
import yaml
|
||||||
MESHTASTIC_PORT = int(os.environ.get("MESHTASTIC_PORT", "4403"))
|
|
||||||
|
|
||||||
WEB_HOST = os.environ.get("WEB_HOST", "0.0.0.0")
|
logger = logging.getLogger(__name__)
|
||||||
WEB_PORT = int(os.environ.get("WEB_PORT", "8080"))
|
|
||||||
|
|
||||||
DB_PATH = os.environ.get("DB_PATH", "meshdd.db")
|
CONFIG_PATH = os.environ.get("CONFIG_PATH", os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.yaml"))
|
||||||
|
|
||||||
BOT_NAME = os.environ.get("BOT_NAME", "MeshDD-Bot")
|
_config = {}
|
||||||
|
_mtime = 0.0
|
||||||
|
_callbacks = []
|
||||||
|
|
||||||
|
|
||||||
|
def _load():
|
||||||
|
global _config, _mtime
|
||||||
|
with open(CONFIG_PATH, "r") as f:
|
||||||
|
_config = yaml.safe_load(f)
|
||||||
|
_mtime = os.path.getmtime(CONFIG_PATH)
|
||||||
|
logger.info("Config loaded from %s", CONFIG_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
def _reload_if_changed():
|
||||||
|
global _mtime
|
||||||
|
try:
|
||||||
|
current_mtime = os.path.getmtime(CONFIG_PATH)
|
||||||
|
if current_mtime != _mtime:
|
||||||
|
old_config = _config.copy()
|
||||||
|
_load()
|
||||||
|
logger.info("Config reloaded (changed)")
|
||||||
|
for cb in _callbacks:
|
||||||
|
try:
|
||||||
|
cb(old_config, _config)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Error in config reload callback")
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Error checking config file")
|
||||||
|
|
||||||
|
|
||||||
|
def on_reload(callback):
|
||||||
|
_callbacks.append(callback)
|
||||||
|
|
||||||
|
|
||||||
|
async def watch(interval: float = 2.0):
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(interval)
|
||||||
|
_reload_if_changed()
|
||||||
|
|
||||||
|
|
||||||
|
def get(key: str, default=None):
|
||||||
|
keys = key.split(".")
|
||||||
|
val = _config
|
||||||
|
for k in keys:
|
||||||
|
if isinstance(val, dict):
|
||||||
|
val = val.get(k)
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
if val is None:
|
||||||
|
return default
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
# Load on import
|
||||||
|
_load()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
MAJOR = 0
|
|
||||||
MINOR = 1
|
|
||||||
PATCH = 2
|
|
||||||
|
|
||||||
VERSION = f"{MAJOR}.{MINOR}.{PATCH}"
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
meshtastic>=2.3.0
|
meshtastic>=2.7.7
|
||||||
aiohttp>=3.9.0
|
aiohttp>=3.9.0
|
||||||
aiosqlite>=0.19.0
|
aiosqlite>=0.19.0
|
||||||
|
pyyaml>=6.0
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Git pre-commit hook: Auto-increment patch version, optional minor bump
|
|
||||||
# Install: cp scripts/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
|
|
||||||
|
|
||||||
VERSION_FILE="meshbot/version.py"
|
|
||||||
CHANGELOG_FILE="CHANGELOG.md"
|
|
||||||
|
|
||||||
if [ ! -f "$VERSION_FILE" ]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Read current version
|
|
||||||
MAJOR=$(grep "^MAJOR" "$VERSION_FILE" | awk -F'= ' '{print $2}')
|
|
||||||
MINOR=$(grep "^MINOR" "$VERSION_FILE" | awk -F'= ' '{print $2}')
|
|
||||||
PATCH=$(grep "^PATCH" "$VERSION_FILE" | awk -F'= ' '{print $2}')
|
|
||||||
|
|
||||||
echo "Current version: $MAJOR.$MINOR.$PATCH"
|
|
||||||
|
|
||||||
# Ask for minor bump (only if interactive terminal)
|
|
||||||
if [ -t 0 ]; then
|
|
||||||
read -p "Minor-Version erhöhen? (y/N) " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
MINOR=$((MINOR + 1))
|
|
||||||
PATCH=0
|
|
||||||
else
|
|
||||||
PATCH=$((PATCH + 1))
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
PATCH=$((PATCH + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
|
|
||||||
echo "New version: $NEW_VERSION"
|
|
||||||
|
|
||||||
# Update version.py
|
|
||||||
cat > "$VERSION_FILE" << EOF
|
|
||||||
MAJOR = $MAJOR
|
|
||||||
MINOR = $MINOR
|
|
||||||
PATCH = $PATCH
|
|
||||||
|
|
||||||
VERSION = f"{MAJOR}.{MINOR}.{PATCH}"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Update CHANGELOG.md - add entry after first "## " line
|
|
||||||
DATE=$(date +%Y-%m-%d)
|
|
||||||
COMMIT_MSG=$(git log --format=%B -1 HEAD 2>/dev/null || echo "Update")
|
|
||||||
|
|
||||||
# Get staged files for changelog context
|
|
||||||
STAGED_FILES=$(git diff --cached --name-only)
|
|
||||||
|
|
||||||
# Add changelog entry
|
|
||||||
TEMP_FILE=$(mktemp)
|
|
||||||
HEADER_DONE=false
|
|
||||||
|
|
||||||
while IFS= read -r line; do
|
|
||||||
echo "$line" >> "$TEMP_FILE"
|
|
||||||
if [[ "$line" == "# Changelog" ]] && [ "$HEADER_DONE" = false ]; then
|
|
||||||
echo "" >> "$TEMP_FILE"
|
|
||||||
echo "## [$NEW_VERSION] - $DATE" >> "$TEMP_FILE"
|
|
||||||
echo "### Changed" >> "$TEMP_FILE"
|
|
||||||
echo "- Auto-commit update" >> "$TEMP_FILE"
|
|
||||||
HEADER_DONE=true
|
|
||||||
fi
|
|
||||||
done < "$CHANGELOG_FILE"
|
|
||||||
|
|
||||||
mv "$TEMP_FILE" "$CHANGELOG_FILE"
|
|
||||||
|
|
||||||
# Stage updated files
|
|
||||||
git add "$VERSION_FILE" "$CHANGELOG_FILE"
|
|
||||||
|
|
||||||
echo "Version updated to $NEW_VERSION"
|
|
||||||
Loading…
Reference in a new issue