Files

103 строки
3.2 KiB
Python
Исполняемый файл

import asyncio
import logging
import time
from .app import App, IAppCallInterceptor, AppException
from .call import Call
from .dmrproto import DMRPPacketData
class ParrotApp(App, IAppCallInterceptor):
"""
Simple parrot application
"""
def __init__(self, parrot_id: int = 9990, repeat_delay: int = 5,
enable_unit: bool = True, enable_group: bool = True) -> None:
# settings
self.parrot_id: int = parrot_id
self.repeat_delay: int = repeat_delay
self.enable_unit: bool = enable_unit
self.enable_group: bool = enable_group
super().__init__()
# internal state
self._mycalls: set[int] = set()
self._records: dict[int, list[DMRPPacketData]] = dict()
@property
def name(self) -> str:
return self.get_name()
async def repeat(self, packets: list[DMRPPacketData]) -> None:
if self.dispatcher is None:
raise AppException(
"send_packets called before dispatcher had been set")
if len(packets) == 0:
logging.debug(f"{self.name}: nothing to repeat, 0 packets in call")
return
await asyncio.sleep(self.repeat_delay)
logging.info(f"{self.name}: repeating call")
stream_id = packets[0].stream_id
self._mycalls.add(stream_id)
start_time = time.monotonic()
for i, p in enumerate(packets):
self.dispatcher.inject_packet(p)
if (delay := start_time + (i + 1) * 0.06 - time.monotonic()) > 0:
await asyncio.sleep(delay)
self._mycalls.discard(stream_id)
def record(self, call: Call, p: DMRPPacketData) -> None:
if p.src_id == self.parrot_id or p.dst_id != self.parrot_id:
return
if (p.call_type == DMRPPacketData.CallType.UNIT
and not self.enable_unit):
logging.debug(f"{self.name}: unit calls disabled")
return
if (p.call_type == DMRPPacketData.CallType.GROUP
and not self.enable_group):
logging.debug(f"{self.name}: group calls disabled")
return
if p.stream_id in self._mycalls:
logging.debug(f"{self.name}: skipping my own call")
return
if p.stream_id not in self._records:
logging.info(f"{self.name}: recording {call.call_id}")
self._records[p.stream_id] = []
ans_p = p.copy()
# invert source and dest for unit call
if p.call_type == DMRPPacketData.CallType.UNIT:
ans_p.src_id = self.parrot_id
ans_p.dst_id = p.src_id
ans_p.stream_id = p.stream_id + 1
self._records[p.stream_id].append(ans_p)
if call.is_ended:
packets: list[DMRPPacketData] = self._records[p.stream_id]
asyncio.create_task(self.repeat(packets))
del self._records[p.stream_id]
#------------------------------------
# App implementation
def get_name(self) -> str:
return f"Parrot {self.parrot_id}"
#------------------------------------
# IAppCallInterceptor implementation
def process_call_packet(self, call: Call, p: DMRPPacketData) -> None:
self.record(call, p)