mirror of https://github.com/DJ2LS/FreeDATA.git
287 lines
10 KiB
Python
287 lines
10 KiB
Python
import base64
|
|
import json
|
|
import structlog
|
|
|
|
|
|
class EventManager:
|
|
"""Manages and broadcasts events within the FreeDATA server.
|
|
|
|
This class handles the broadcasting of various events, including PTT
|
|
changes, scatter changes, buffer overflows, custom events, ARQ session
|
|
updates, and freedata_server status changes, to multiple queues. It
|
|
provides a centralized mechanism for distributing event information
|
|
throughout the application.
|
|
"""
|
|
|
|
def __init__(self, ctx, queues):
|
|
"""Initializes the EventManager with a list of queues.
|
|
|
|
Args:
|
|
queues (list): A list of queues to which events will be broadcast.
|
|
"""
|
|
self.queues = queues
|
|
self.ctx = ctx
|
|
self.logger = structlog.get_logger("Event Manager")
|
|
self.lastpttstate = False
|
|
|
|
def broadcast(self, data):
|
|
"""Broadcasts an event to all registered queues.
|
|
|
|
This method broadcasts the given event data to all queues registered
|
|
with the EventManager. It clears a queue if its size exceeds 10 to
|
|
prevent excessive queue buildup.
|
|
|
|
Args:
|
|
data: The event data to broadcast.
|
|
"""
|
|
if self.ctx.TESTMODE:
|
|
self.ctx.TESTMODE_EVENTS.put(data)
|
|
|
|
for q in self.queues:
|
|
self.logger.debug("Event: ", ev=data)
|
|
if q.qsize() > 10:
|
|
q.queue.clear()
|
|
q.put(data)
|
|
|
|
def send_ptt_change(self, on: bool = False):
|
|
"""Sends a PTT change event.
|
|
|
|
This method broadcasts a "ptt" event indicating whether the Push-to-Talk
|
|
(PTT) is activated or deactivated. It avoids sending duplicate events
|
|
by checking the last PTT state.
|
|
|
|
Args:
|
|
on (bool, optional): True if PTT is activated, False otherwise. Defaults to False.
|
|
"""
|
|
if on == self.lastpttstate:
|
|
return
|
|
self.lastpttstate = on
|
|
self.broadcast({"ptt": bool(on)})
|
|
|
|
def send_scatter_change(self, data):
|
|
"""Sends a scatter change event.
|
|
|
|
This method broadcasts a "scatter" event containing the provided
|
|
scatter data as a JSON string.
|
|
|
|
Args:
|
|
data: The scatter data to send.
|
|
"""
|
|
self.broadcast({"scatter": json.dumps(data)})
|
|
|
|
def send_buffer_overflow(self, data):
|
|
"""Sends a buffer overflow event.
|
|
|
|
This method broadcasts a "buffer-overflow" event, indicating that a
|
|
buffer overflow has occurred. The event data includes the provided
|
|
data converted to a string.
|
|
|
|
Args:
|
|
data: The buffer overflow data to send.
|
|
"""
|
|
self.broadcast({"buffer-overflow": str(data)})
|
|
|
|
def send_custom_event(self, **event_data):
|
|
"""Sends a custom event.
|
|
|
|
This method broadcasts a custom event with the provided keyword
|
|
arguments as the event data. This allows for flexible creation and
|
|
distribution of application-specific events.
|
|
|
|
Args:
|
|
**event_data: Keyword arguments representing the event data.
|
|
"""
|
|
self.broadcast(event_data)
|
|
|
|
def send_arq_session_new(self, outbound: bool, session_id, dxcall, total_bytes, state):
|
|
"""Sends an event for a new ARQ session.
|
|
|
|
This method broadcasts an event indicating the start of a new ARQ
|
|
(Automatic Repeat reQuest) session. The event includes information
|
|
about the session's direction (inbound or outbound), session ID,
|
|
destination callsign, total bytes to be transferred, and initial
|
|
state.
|
|
|
|
Args:
|
|
outbound (bool): True if the session is outbound (sending data),
|
|
False if it's inbound (receiving data).
|
|
session_id: The unique ID of the ARQ session.
|
|
dxcall (str): The callsign of the remote station.
|
|
total_bytes (int): The total number of bytes to be transferred.
|
|
state (str): The initial state of the ARQ session.
|
|
"""
|
|
direction = "outbound" if outbound else "inbound"
|
|
event = {
|
|
"type": "arq",
|
|
f"arq-transfer-{direction}": {
|
|
"session_id": session_id,
|
|
"dxcall": dxcall,
|
|
"total_bytes": total_bytes,
|
|
"state": state,
|
|
},
|
|
}
|
|
self.broadcast(event)
|
|
|
|
def send_arq_session_progress(
|
|
self,
|
|
outbound: bool,
|
|
session_id,
|
|
dxcall,
|
|
received_bytes,
|
|
total_bytes,
|
|
state,
|
|
speed_level,
|
|
statistics=None,
|
|
):
|
|
"""Sends an ARQ session progress update event.
|
|
|
|
This method broadcasts an event indicating the progress of an ARQ
|
|
session. The event includes the session ID, destination callsign,
|
|
received and total bytes, current state, speed level, and any
|
|
relevant statistics.
|
|
|
|
Args:
|
|
outbound (bool): True if the session is outbound, False otherwise.
|
|
session_id: The ID of the ARQ session.
|
|
dxcall (str): The callsign of the remote station.
|
|
received_bytes (int): The number of bytes received so far.
|
|
total_bytes (int): The total number of bytes to be transferred.
|
|
state (str): The current state of the ARQ session.
|
|
speed_level: The current speed level of the ARQ session.
|
|
statistics (dict, optional): A dictionary containing session statistics. Defaults to None.
|
|
"""
|
|
if statistics is None:
|
|
statistics = {}
|
|
|
|
direction = "outbound" if outbound else "inbound"
|
|
event = {
|
|
"type": "arq",
|
|
f"arq-transfer-{direction}": {
|
|
"session_id": session_id,
|
|
"dxcall": dxcall,
|
|
"received_bytes": received_bytes,
|
|
"total_bytes": total_bytes,
|
|
"state": state,
|
|
"speed_level": speed_level,
|
|
"statistics": statistics,
|
|
},
|
|
}
|
|
self.broadcast(event)
|
|
|
|
def send_arq_session_finished(
|
|
self,
|
|
outbound: bool,
|
|
session_id,
|
|
dxcall,
|
|
success: bool,
|
|
state: bool,
|
|
data=False,
|
|
statistics=None,
|
|
):
|
|
"""Sends an ARQ session finished event.
|
|
|
|
This method broadcasts an event indicating the completion of an ARQ
|
|
session. The event includes information about the session's direction,
|
|
ID, destination callsign, success status, final state, data
|
|
(if any), and statistics. It base64-encodes any data included in
|
|
the event.
|
|
|
|
Args:
|
|
outbound (bool): True if the session was outbound, False otherwise.
|
|
session_id: The ID of the ARQ session.
|
|
dxcall (str): The callsign of the remote station.
|
|
success (bool): True if the session completed successfully, False otherwise.
|
|
state (str): The final state of the ARQ session.
|
|
data (any, optional): The data transferred during the session. Defaults to False.
|
|
statistics (dict, optional): A dictionary of session statistics. Defaults to None.
|
|
"""
|
|
if statistics is None:
|
|
statistics = {}
|
|
if data:
|
|
if isinstance(data, dict):
|
|
data = json.dumps(data).encode("utf-8")
|
|
# Base64 encode the bytes-like object
|
|
data = base64.b64encode(data).decode("UTF-8")
|
|
direction = "outbound" if outbound else "inbound"
|
|
event = {
|
|
"type": "arq",
|
|
f"arq-transfer-{direction}": {
|
|
"session_id": session_id,
|
|
"dxcall": dxcall,
|
|
"statistics": statistics,
|
|
"success": bool(success),
|
|
"state": state,
|
|
"data": data,
|
|
},
|
|
}
|
|
self.broadcast(event)
|
|
|
|
def modem_started(self):
|
|
"""Sends a freedata_server started event.
|
|
|
|
This method broadcasts an event indicating that the FreeDATA freedata_server
|
|
has started successfully.
|
|
"""
|
|
event = {"freedata_server": "started"}
|
|
self.broadcast(event)
|
|
|
|
def modem_restarted(self):
|
|
"""Sends a freedata_server restarted event.
|
|
|
|
This method broadcasts an event indicating that the FreeDATA freedata_server
|
|
has been restarted.
|
|
"""
|
|
event = {"freedata_server": "restarted"}
|
|
self.broadcast(event)
|
|
|
|
def modem_stopped(self):
|
|
"""Sends a freedata_server stopped event.
|
|
|
|
This method broadcasts an event indicating that the FreeDATA freedata_server
|
|
has stopped.
|
|
"""
|
|
event = {"freedata_server": "stopped"}
|
|
self.broadcast(event)
|
|
|
|
def modem_failed(self):
|
|
"""Sends a freedata_server failed event.
|
|
|
|
This method broadcasts an event indicating that the FreeDATA freedata_server
|
|
has failed to start or has encountered an error.
|
|
"""
|
|
event = {"freedata_server": "failed"}
|
|
self.broadcast(event)
|
|
|
|
def freedata_message_db_change(self, message_id=None):
|
|
"""Sends a FreeDATA message database change event.
|
|
|
|
This method broadcasts an event indicating that the FreeDATA message
|
|
database has been changed. The event includes the ID of the message
|
|
that triggered the change, if available.
|
|
|
|
Args:
|
|
message_id (any, optional): The ID of the changed message. Defaults to None.
|
|
"""
|
|
self.broadcast({"message-db": "changed", "message_id": message_id})
|
|
|
|
def freedata_logging(self, type, status, message):
|
|
"""Broadcasts a FreeDATA logging event.
|
|
|
|
This method broadcasts an event related to FreeDATA logging,
|
|
indicating the type of logging endpoint and its status. It is
|
|
used to inform other parts of the application about logging
|
|
activities.
|
|
|
|
Args:
|
|
type (str): The type of logging endpoint (e.g., "file", "websocket").
|
|
status (any): The status of the logging operation.
|
|
message (str): The message to be displayed
|
|
"""
|
|
|
|
self.broadcast({
|
|
"type": "message-logging",
|
|
"endpoint": type,
|
|
"status": status,
|
|
"message": message,
|
|
})
|