Этот коммит содержится в:
Alexander UR6LKW
2025-05-19 16:51:57 +03:00
родитель 058607fe5b
Коммит 65914bc653
16 изменённых файлов: 1430 добавлений и 0 удалений
+138
Просмотреть файл
@@ -0,0 +1,138 @@
import asyncio
import logging
import traceback
from time import time
from .app import AppKeeper, IAppDispatcher
from .call import Call, CallKeeper
from .dmrproto import DMRPPacketData, DMRPPacketTalkerAlias
from .dmrproto import DMRPPacketFactory, DMRPBasePacket, DMRPBasePeerPacket
from .network import IDatagramReceiver, IDatagramSender
from .peer import Peer, PeerKeeper
from .peer_controller import IPCDispatcher, PeerController
from .auth import IPeerAuth, DenyAllPeerAuth
from .pphex import hexdump
class Dispatcher(IDatagramReceiver, IAppDispatcher, IPCDispatcher):
MAINTENANCE_PERIOD = 10
def __init__(self, sender: IDatagramSender) -> None:
self.sender: IDatagramSender = sender
self.peer_auth: IPeerAuth = DenyAllPeerAuth() # Default policy to deny
self.peer_keeper: PeerKeeper = PeerKeeper()
self.call_keeper: CallKeeper = CallKeeper()
self.app_keeper: AppKeeper = AppKeeper(self)
sender.set_receiver(self)
asyncio.create_task(self.maintain_task())
def maintain(self) -> None:
self.peer_keeper.maintain()
self.call_keeper.maintain()
async def maintain_task(self) -> None:
logging.debug("Dispatcher: periodic maintenance task scheduled")
while True:
await asyncio.sleep(self.MAINTENANCE_PERIOD)
self.maintain()
def shutdown(self) -> None:
logging.info("Dispatcher: shutting down")
for peer in self.peer_keeper.get_all():
controller: PeerController = PeerController(peer, self)
controller.send_close()
def dispatch_data_packet(self, p: DMRPPacketData, orig_addr: tuple) -> None:
logging.debug(f"Dispatching packet from {orig_addr}:\n{p}\n")
call_id = p.stream_id
if (call := self.call_keeper.by_call_id(call_id)) is None:
call = Call(p.stream_id, p.src_id, p.dst_id,
p.peer_id, p.call_type)
self.call_keeper.add(call)
if call.call_type == DMRPPacketData.CallType.UNIT:
# get peers location and rout unit call
peers = self.peer_keeper.get_by_unit(p.dst_id)
if len(peers) > 0:
call.route_to = peers
call.packet_received()
if p.is_voice_term:
call.end()
self.app_keeper.process_call_packet(call, p)
if isinstance(p, DMRPBasePeerPacket):
self.distribute_by_peers(p, orig_addr, call.route_to)
def dispatch_ta_packet(self, p: DMRPPacketTalkerAlias,
orig_addr: tuple) -> None:
self.distribute_by_peers(p, orig_addr)
def distribute_by_peers(self, p: DMRPBasePeerPacket,
orig_addr: tuple,
peers: set[Peer]|None = None) -> None:
sendp = p.copy()
if peers is None:
peers = self.peer_keeper.get_active()
for peer in peers:
if orig_addr == peer.addr: # skip myself
continue
sendp.peer_id = peer.peer_id
# logging.debug(f" - sending to {peer.logname}"
# f"\n{hexdump(sendp.get_data())}\n{sendp}\n")
self.sender.send_dg(sendp.get_data(), peer.addr)
#-------------------------------
# IDatagramReceiver implementation
def recv_dg(self, data: bytes, addr: tuple) -> None:
peer: Peer = self.peer_keeper.get_by_addr(addr)
p: DMRPBasePacket|None = None
try:
p = DMRPPacketFactory.fd(data)
logging.debug(f"Got packet "
f"from {peer.logname} | {len(data)} bytes:\n"
f"{hexdump(data)}\n"
f"{str(p)}\n")
except Exception as e:
logging.error(f"Exception with packet "
f"from {peer.logname} | {len(data)} bytes:\n"
f"{hexdump(data)}\n"
f"{traceback.format_exc()}")
return
# process in context of the peer by controller
controller: PeerController = PeerController(peer, self)
if not controller.process_packet(p):
return
if type(p) is DMRPPacketData:
self.dispatch_data_packet(p, addr)
if type(p) is DMRPPacketTalkerAlias:
self.dispatch_ta_packet(p, addr)
#-------------------------------
# IAppDispatcher implementation
def inject_packet(self, p: DMRPPacketData) -> None:
logging.debug(f"Injecting packet from app")
self.dispatch_data_packet(p, (None, None))
#-------------------------------
# IPCDispatcher implementation
def send_dg(self, data: bytes, addr: tuple) -> None:
self.sender.send_dg(data, addr)
def get_peer_keeper(self) -> PeerKeeper:
return self.peer_keeper
def get_peer_auth(self) -> IPeerAuth:
return self.peer_auth