0DMRMaster version 0.4
Этот коммит содержится в:
Executable
+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
|
||||
Ссылка в новой задаче
Block a user