Linting + touches
CI / lint (push) Successful in 8s
Build edge-node / build (push) Failing after 22s
Build icecast / build (push) Failing after 23s
CI / test (push) Successful in 23s
Build op25 / build (push) Failing after 16s

This commit is contained in:
Logan
2026-04-21 00:56:50 -04:00
parent c5984f6318
commit d0e4734cf9
7 changed files with 27 additions and 23 deletions
+9 -9
View File
@@ -10,10 +10,10 @@ from app.config import settings
from app.internal import credentials
from app.internal.logger import logger
MAX_RECORDING_SECONDS = 600 # safety cap; drop call if it runs this long
PRE_BUFFER_SECONDS = 1.0 # seconds of audio to include before call_start
RING_BUFFER_SECONDS = 60 # how much history to keep when no call is active
READ_CHUNK_BYTES = 4096 # bytes per httpx read
MAX_RECORDING_SECONDS = 600 # safety cap; drop call if it runs this long
PRE_BUFFER_SECONDS = 1.0 # seconds of audio to include before call_start
RING_BUFFER_SECONDS = 60 # how much history to keep when no call is active
READ_CHUNK_BYTES = 4096 # bytes per httpx read
class CallRecorder:
@@ -119,9 +119,9 @@ class CallRecorder:
if not self._call_id:
return None
call_id = self._call_id
call_start = self._call_start_mono
self._call_id = None
call_id = self._call_id
call_start = self._call_start_mono
self._call_id = None
self._call_start_mono = None
# Slice: everything from (call_start - pre_buffer) to now
@@ -180,8 +180,8 @@ class CallRecorder:
return None
upload_url = f"{settings.c2_url}/upload"
api_key = credentials.get_api_key()
headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
api_key = credentials.get_api_key()
headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
form: dict = {"call_id": call_id, "node_id": settings.node_id}
if talkgroup_id is not None:
@@ -1,6 +1,5 @@
import json
from pathlib import Path
from typing import Optional
from app.config import settings
from app.models import NodeConfig, SystemConfig
from app.internal.logger import logger
+3 -2
View File
@@ -6,7 +6,7 @@ from app.internal.logger import logger
BOT_READY_TIMEOUT = 15 # seconds to wait for Discord bot to become ready
WATCHDOG_INTERVAL = 30 # seconds between voice-connection health checks
REJOIN_DELAY = 5 # seconds to wait before attempting a rejoin
REJOIN_DELAY = 5 # seconds to wait before attempting a rejoin
class RadioBot:
@@ -116,7 +116,8 @@ class RadioBot:
def _on_stream_end(self, error):
if error:
logger.error(f"Stream ended with error: {error}")
if not (self._loop and self._voice_client and self._voice_client.is_connected() and not self._voice_client.is_playing()):
vc = self._voice_client
if not (self._loop and vc and vc.is_connected() and not vc.is_playing()):
return
if error:
# Back off before retrying — prevents tight loop when PulseAudio is unavailable
+9 -9
View File
@@ -24,14 +24,14 @@ class MQTTManager:
self.on_api_key: Optional[ApiKeyCallback] = None
nid = settings.node_id
self._t_checkin = f"nodes/{nid}/checkin"
self._t_status = f"nodes/{nid}/status"
self._t_metadata = f"nodes/{nid}/metadata"
self._t_commands = f"nodes/{nid}/commands"
self._t_config = f"nodes/{nid}/config"
self._t_api_key = f"nodes/{nid}/api_key"
self._t_checkin = f"nodes/{nid}/checkin"
self._t_status = f"nodes/{nid}/status"
self._t_metadata = f"nodes/{nid}/metadata"
self._t_commands = f"nodes/{nid}/commands"
self._t_config = f"nodes/{nid}/config"
self._t_api_key = f"nodes/{nid}/api_key"
self._t_key_request = f"nodes/{nid}/key_request"
self._t_discovery = "nodes/discovery/request"
self._t_discovery = "nodes/discovery/request"
def _build_client(self) -> mqtt.Client:
client = mqtt.Client(
@@ -49,9 +49,9 @@ class MQTTManager:
client.will_set(self._t_status, lwt, qos=1, retain=True)
client.reconnect_delay_set(min_delay=2, max_delay=60)
client.on_connect = self._on_connect
client.on_connect = self._on_connect
client.on_disconnect = self._on_disconnect
client.on_message = self._on_message
client.on_message = self._on_message
return client
def _on_connect(self, client, userdata, flags, reason_code, properties):
+4 -1
View File
@@ -44,7 +44,10 @@ async def on_call_end(data: dict):
else:
logger.error(f"Audio upload failed for call {data['call_id']}. Verify C2_URL and Node API Key.")
else:
logger.warning(f"No recording file generated for call {data['call_id']} — call may have been too short or Icecast unreachable.")
logger.warning(
f"No recording file generated for call {data['call_id']} "
"— call may have been too short or Icecast unreachable."
)
await mqtt_manager.publish_metadata("call_end", data)
await mqtt_manager.publish_status("online")
+1
View File
@@ -1,3 +1,4 @@
# Icecast streaming server
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
+1 -1
View File
@@ -1,4 +1,4 @@
## OP25 Core Container
# OP25 Core Container
FROM python:slim-trixie
# Set environment variables