milestones
This commit is contained in:
@@ -0,0 +1,782 @@
|
||||
import json
|
||||
import asyncio
|
||||
import os
|
||||
import signal
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Awaitable, Callable
|
||||
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
|
||||
from .json_formatter import logger
|
||||
from .models import LatLng
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class SocketIOEventHandlers:
|
||||
context: Any
|
||||
tunneld_core: Any
|
||||
get_status: Callable[[], dict]
|
||||
get_simulation_status: Callable[[], dict]
|
||||
device_shutdown: Callable[[Any], Awaitable[Any]]
|
||||
device_reboot: Callable[[Any], Awaitable[Any]]
|
||||
advance_simulation_queue: Callable[[], Awaitable[Any]]
|
||||
toggle_test_mode: Callable[[], dict]
|
||||
add_location_to_simulation_queue: Callable[[Any], Awaitable[dict]]
|
||||
delete_location_from_simulation_queue: Callable[[Any], Awaitable[dict]]
|
||||
clear_future_items: Callable[[], Any]
|
||||
reset_queue: Callable[[], Any]
|
||||
pause_simulation_queue: Callable[[], Awaitable[Any]]
|
||||
resume_simulation_queue: Callable[[], Awaitable[Any]]
|
||||
end_simulation_queue: Callable[[], Awaitable[Any]]
|
||||
start_simulation_queue: Callable[[], Awaitable[dict]]
|
||||
restart_simulation_queue: Callable[[], Awaitable[dict]]
|
||||
toggle_gps_noise: Callable[[], dict]
|
||||
update_queue_times: Callable[[], Awaitable[Any]]
|
||||
start_icloud_monitor: Callable[[], Awaitable[Any]]
|
||||
end_icloud_monitor: Callable[[], Awaitable[Any]]
|
||||
is_icloud_monitor_running: Callable[[], bool]
|
||||
refresh_icloud_location: Callable[[], Awaitable[dict]]
|
||||
start_tunnel_watcher: Callable[[], Awaitable[Any]]
|
||||
end_tunnel_watcher: Callable[[], Awaitable[Any]]
|
||||
get_reverse_geocode: Callable[[Any], Awaitable[Any]]
|
||||
set_favorite: Callable[[Any], Awaitable[tuple[str, str]]]
|
||||
clear_favorite: Callable[[Any], Awaitable[tuple[str, str]]]
|
||||
get_favorites: Callable[[], Awaitable[Any]]
|
||||
get_categories: Callable[[], Awaitable[Any]]
|
||||
add_category: Callable[[Any], Awaitable[dict]]
|
||||
delete_category: Callable[[Any], Awaitable[tuple[str, str]]]
|
||||
|
||||
def register(self) -> None:
|
||||
sio = self.context.sio
|
||||
|
||||
async def emit_test_prompt(test_prompt_data):
|
||||
prompt_name = (
|
||||
test_prompt_data.get("prompt_name")
|
||||
if isinstance(test_prompt_data, dict)
|
||||
else getattr(test_prompt_data, "prompt_name", None)
|
||||
)
|
||||
client_id = (
|
||||
test_prompt_data.get("client_id")
|
||||
if isinstance(test_prompt_data, dict)
|
||||
else getattr(test_prompt_data, "client_id", None)
|
||||
)
|
||||
logger.info(
|
||||
"Sending test prompt %s sent to client %s", prompt_name, client_id
|
||||
)
|
||||
try:
|
||||
response = await sio.call(
|
||||
"test_prompt",
|
||||
{"prompt_name": prompt_name},
|
||||
namespace="/",
|
||||
to=client_id,
|
||||
timeout=60,
|
||||
)
|
||||
if response and response.get("confirmed"):
|
||||
await do_positive_action(prompt_name, client_id)
|
||||
else:
|
||||
await do_negative_action(prompt_name, client_id)
|
||||
except asyncio.TimeoutError:
|
||||
print(f"Client {client_id} failed to respond in time.")
|
||||
|
||||
async def do_positive_action(prompt_name, client_id):
|
||||
logger.info(
|
||||
"Confirmation received from client %s fpr prompt %s",
|
||||
prompt_name,
|
||||
client_id,
|
||||
)
|
||||
|
||||
async def do_negative_action(prompt_name, client_id):
|
||||
logger.info(
|
||||
"Client %s denied confirmation for prompt %s", client_id, prompt_name
|
||||
)
|
||||
|
||||
async def sio_send_status(sid):
|
||||
"""Send Current Status"""
|
||||
if sid in self.context.connected_clients:
|
||||
logger.info("Sending status to: %s", sid)
|
||||
await sio.emit(
|
||||
"status", jsonable_encoder(self.get_status()), namespace="/", to=sid
|
||||
)
|
||||
else:
|
||||
logger.info("Sending status to all clients, not only: %s", sid)
|
||||
await sio.emit(
|
||||
"status", jsonable_encoder(self.get_status()), namespace="/"
|
||||
)
|
||||
|
||||
def json_fallback(obj):
|
||||
if hasattr(obj, "__dict__"):
|
||||
return obj.__dict__
|
||||
if hasattr(obj, "as_dict"):
|
||||
return obj.as_dict()
|
||||
if hasattr(obj, "to_dict"):
|
||||
return obj.to_dict()
|
||||
return str(obj)
|
||||
|
||||
@sio.event
|
||||
async def connect(sid, environ):
|
||||
"""Client connection event handler."""
|
||||
self.context.connected_clients.add(sid)
|
||||
logger.info("Client connected: %s", sid)
|
||||
await sio_send_status(sid)
|
||||
return "%s connected" % sid
|
||||
|
||||
@sio.event
|
||||
async def disconnect(sid):
|
||||
"""Client disconnection event handler."""
|
||||
self.context.connected_clients.discard(sid)
|
||||
logger.info("Client disconnected: %s", sid)
|
||||
|
||||
@sio.event
|
||||
async def send_test_prompt(sid, data):
|
||||
"""Send test prompt"""
|
||||
prompt_name = (
|
||||
data.get("prompt_name")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "prompt_name", None)
|
||||
)
|
||||
logger.info(
|
||||
"Received request from %s to send test prompt %s", sid, prompt_name
|
||||
)
|
||||
test_prompt_data = {"prompt_name": prompt_name, "client_id": sid}
|
||||
sio.start_background_task(emit_test_prompt, test_prompt_data)
|
||||
return {
|
||||
"prompt_name": prompt_name,
|
||||
"command_status": "OK",
|
||||
"message": "Test prompt requested.",
|
||||
}
|
||||
|
||||
@sio.event
|
||||
async def request_update(sid):
|
||||
status_update = jsonable_encoder(self.get_status())
|
||||
logger.info("Update request from %s sending %s", sid, status_update)
|
||||
return status_update
|
||||
|
||||
@sio.event
|
||||
async def message(sid, data):
|
||||
logger.info("Received message from %s: %s", sid, data)
|
||||
return True, "Message received"
|
||||
|
||||
@sio.event
|
||||
async def device_control(sid, data):
|
||||
"""Device Control"""
|
||||
command = (
|
||||
data.get("command")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "command", None)
|
||||
)
|
||||
delay = (
|
||||
data.get("delay")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "delay", None)
|
||||
)
|
||||
if delay is None:
|
||||
delay = 5
|
||||
match command:
|
||||
case "shutdown":
|
||||
logger.info(
|
||||
"Shutdown command received from %s with delay %s", sid, delay
|
||||
)
|
||||
await self.device_shutdown(delay)
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "device_control",
|
||||
"command": "shutdown",
|
||||
"message": f"Device shutdown initiated with {delay} seconds delay",
|
||||
}
|
||||
|
||||
case "reboot":
|
||||
logger.info(
|
||||
"Reboot command received from %s with delay %s", sid, delay
|
||||
)
|
||||
await self.device_reboot(delay)
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "device_control",
|
||||
"command": "reboot",
|
||||
"message": f"Device reboot initiated with {delay} seconds delay",
|
||||
}
|
||||
|
||||
case _:
|
||||
return {
|
||||
"command_status": "ERROR",
|
||||
"command_class": "device_control",
|
||||
"command": command,
|
||||
"message": f"Invalid command: {command}",
|
||||
}
|
||||
|
||||
@sio.event
|
||||
async def simulation_control(sid, data):
|
||||
"""Simulation Control"""
|
||||
command = (
|
||||
data.get("command")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "command", None)
|
||||
)
|
||||
logger.info(
|
||||
"Simulation Control command: %s requested from %s", command, sid
|
||||
)
|
||||
try:
|
||||
match command:
|
||||
case "next":
|
||||
await self.advance_simulation_queue()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "simulation_control",
|
||||
"command_status": "OK",
|
||||
"message": "Advanced simulation queue",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "test-mode":
|
||||
self.toggle_test_mode()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "simulation_control",
|
||||
"command_status": "OK",
|
||||
"message": "test-mode toggled",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "add":
|
||||
return await self.add_location_to_simulation_queue(data)
|
||||
|
||||
case "delete":
|
||||
return await self.delete_location_from_simulation_queue(data)
|
||||
|
||||
case "clear":
|
||||
self.clear_future_items()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "simulation_control",
|
||||
"command_status": "OK",
|
||||
"message": "Simulation cleared",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "reset":
|
||||
self.reset_queue()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "simulation_control",
|
||||
"command_status": "OK",
|
||||
"message": "Simulation queue reset",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "pause":
|
||||
await self.pause_simulation_queue()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "simulation_control",
|
||||
"command_status": "OK",
|
||||
"message": "Simulation paused",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "resume":
|
||||
await self.resume_simulation_queue()
|
||||
return {
|
||||
"command": command,
|
||||
"command_status": "OK",
|
||||
"command_class": "simulation_control",
|
||||
"message": "Simulation resumed",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "end":
|
||||
logger.info("End location simulation request from %s", sid)
|
||||
cstat = "OK" if await self.end_simulation_queue() else "ERROR"
|
||||
return {
|
||||
"command_status": cstat,
|
||||
"command_class": "simulation_control",
|
||||
"command": command,
|
||||
"message": "Simulation ended",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
|
||||
case "start":
|
||||
logger.info("Start location simulation request from %s", sid)
|
||||
return await self.start_simulation_queue()
|
||||
|
||||
case "gps-noise":
|
||||
before_toggle = self.context.simulation_noise
|
||||
self.toggle_gps_noise()
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "simulation_control",
|
||||
"command": command,
|
||||
"message": f"GPS noise toggled from {before_toggle} to {self.context.simulation_noise}",
|
||||
"data": {
|
||||
"simulation": self.get_simulation_status(),
|
||||
},
|
||||
}
|
||||
case "restart":
|
||||
logger.info("Restart location simulation request from %s", sid)
|
||||
return await self.restart_simulation_queue()
|
||||
|
||||
case _:
|
||||
logger.warning(
|
||||
"Invalid command received from %s: %s", sid, command
|
||||
)
|
||||
return {"command_status": "ERROR", "message": "Invalid command"}
|
||||
finally:
|
||||
logger.info(
|
||||
"Simulation Control command: %s completed, sending status update...",
|
||||
command,
|
||||
)
|
||||
await sio_send_status(sid)
|
||||
|
||||
@sio.event
|
||||
async def location_item_update(sid, data):
|
||||
"""Location Item Control"""
|
||||
loc_id = (
|
||||
data.get("loc_id")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "loc_id", None)
|
||||
)
|
||||
key = (
|
||||
data.get("key")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "key", None)
|
||||
)
|
||||
value = (
|
||||
data.get("value")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "value", None)
|
||||
)
|
||||
error_data = {
|
||||
"command_status": "ERROR",
|
||||
"command": "update",
|
||||
"command_class": "location_item",
|
||||
"message": "Invalid request, Location Item Unchanged",
|
||||
"data": self.context.simulation_queue_data[loc_id],
|
||||
}
|
||||
|
||||
if value is not None:
|
||||
if loc_id and key:
|
||||
old_val = self.context.simulation_queue_data[loc_id][key]
|
||||
self.context.simulation_queue_data[loc_id][key] = value
|
||||
if key == "delay":
|
||||
await self.update_queue_times()
|
||||
logger.info(
|
||||
"Location Item Update: %s: %s changed from %s to %s",
|
||||
loc_id,
|
||||
key,
|
||||
old_val,
|
||||
value,
|
||||
)
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command": "update",
|
||||
"command_class": "location_item",
|
||||
"message": "Location Item Updated",
|
||||
"data": {
|
||||
"simulation": {
|
||||
"data": {
|
||||
loc_id: self.context.simulation_queue_data[loc_id],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
else:
|
||||
return error_data
|
||||
else:
|
||||
return error_data
|
||||
|
||||
@sio.event
|
||||
async def queue_order_update(sid, data):
|
||||
logger.info("Queue order update received: %s", data)
|
||||
new_simulation_queue_order = []
|
||||
new_order = (
|
||||
data.get("newOrder")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "newOrder", None)
|
||||
)
|
||||
if new_order:
|
||||
for item in new_order:
|
||||
if item in self.context.simulation_queue_data:
|
||||
new_simulation_queue_order.append(item)
|
||||
self.context.simulation_queue_order = new_simulation_queue_order
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command": "queue_order_update",
|
||||
"command_class": "queue_order",
|
||||
"message": "Queue Order Updated",
|
||||
"data": {
|
||||
"simulation": {
|
||||
"order" : self.context.simulation_queue_order,
|
||||
},
|
||||
},
|
||||
}
|
||||
return {
|
||||
"command_status": "ERROR",
|
||||
"command": "queue_order_update",
|
||||
"command_class": "queue_order",
|
||||
"message": "Invalid request, Queue Order Unchanged",
|
||||
"data": {
|
||||
"simulation": {
|
||||
"order": self.context.simulation_queue_order,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@sio.event
|
||||
async def icloud_monitor_control(sid, data):
|
||||
command = (
|
||||
data.get("command")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "command", None)
|
||||
)
|
||||
logger.info(
|
||||
"iCloud Monitor control command: %s requested from %s", command, sid
|
||||
)
|
||||
try:
|
||||
match command:
|
||||
case "start":
|
||||
await self.start_icloud_monitor()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "icloud_monitor_control",
|
||||
"command_status": "OK",
|
||||
"data": {
|
||||
"icloud": {
|
||||
"icloud_monitor_enabled": self.context.icloud_monitor_enabled,
|
||||
"icloud_monitor_running": self.is_icloud_monitor_running(),
|
||||
},
|
||||
},
|
||||
}
|
||||
case "stop":
|
||||
await self.end_icloud_monitor()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "icloud_monitor_control",
|
||||
"command_status": "OK",
|
||||
"data": {
|
||||
"icloud": {
|
||||
"icloud_monitor_enabled": self.context.icloud_monitor_enabled,
|
||||
"icloud_monitor_running": self.is_icloud_monitor_running(),
|
||||
},
|
||||
},
|
||||
}
|
||||
case "status":
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "icloud_monitor_control",
|
||||
"command_status": "OK",
|
||||
"data": {
|
||||
"icloud": {
|
||||
"icloud_monitor_enabled": self.context.icloud_monitor_enabled,
|
||||
"icloud_monitor_running": self.is_icloud_monitor_running(),
|
||||
},
|
||||
},
|
||||
}
|
||||
case "refresh":
|
||||
resp = {
|
||||
"command": command,
|
||||
"command_class": "icloud_monitor_control",
|
||||
"command_status": "OK",
|
||||
"data": {
|
||||
"icloud": {
|
||||
"icloud_monitor_enabled": self.context.icloud_monitor_enabled,
|
||||
"icloud_monitor_running": self.is_icloud_monitor_running(),
|
||||
"fmf_location": json.dumps(
|
||||
await self.refresh_icloud_location(),
|
||||
default=json_fallback,
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
return resp
|
||||
case _:
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "icloud_monitor_control",
|
||||
"command_status": "ERROR",
|
||||
"message": "Invalid command",
|
||||
}
|
||||
finally:
|
||||
await sio_send_status(sid)
|
||||
|
||||
@sio.event
|
||||
async def tunneld_control(sid, data):
|
||||
command = (
|
||||
data.get("command")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "command", None)
|
||||
)
|
||||
logger.info("Tunneld Control command: %s requested from %s", command, sid)
|
||||
match command:
|
||||
case "start":
|
||||
logger.info("Start tunneld request from %s: %s", sid, data)
|
||||
try:
|
||||
self.tunneld_core.start()
|
||||
logger.info("Tunneld started successfully")
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "tunneld_control",
|
||||
"command": command,
|
||||
"message": "Tunneld started successfully",
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Error starting tunneld: %s", e)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Error starting tunneld: {e}",
|
||||
}
|
||||
case "restart":
|
||||
logger.info("Restart tunneld request from %s: %s", sid, data)
|
||||
try:
|
||||
self.tunneld_core.clear()
|
||||
await asyncio.sleep(2)
|
||||
self.tunneld_core.start()
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "tunneld_control",
|
||||
"command": command,
|
||||
"message": "Tunneld started successfully",
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Error restarting tunneld: %s", e)
|
||||
return {
|
||||
"command_status": "ERROR",
|
||||
"command_class": "tunneld_control",
|
||||
"command": command,
|
||||
"message": f"Error starting tunneld: {e}",
|
||||
}
|
||||
|
||||
case "start-watcher":
|
||||
logger.info("Start tunneld watcher request from %s: %s", sid, data)
|
||||
await self.start_tunnel_watcher()
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "tunneld_control",
|
||||
"command": command,
|
||||
"message": "Tunneld watcher started successfully",
|
||||
}
|
||||
|
||||
case "end-watcher":
|
||||
logger.info("End tunneld watcher request from %s: %s", sid, data)
|
||||
await self.end_tunnel_watcher()
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "tunneld_control",
|
||||
"command": command,
|
||||
"message": "Tunneld watcher stopped successfully",
|
||||
}
|
||||
|
||||
case "shutdown":
|
||||
logger.info("Shutdown tunneld request from %s: %s", sid, data)
|
||||
try:
|
||||
os.kill(os.getpid(), signal.SIGINT)
|
||||
return {
|
||||
"command_status": "OK",
|
||||
"command_class": "tunneld_control",
|
||||
"command": command,
|
||||
"message": "Server shutting down...",
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Error shutting down tunneld: %s", e)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Error shutting down tunneld: {e}",
|
||||
}
|
||||
|
||||
case "clear":
|
||||
logger.info("Clearing tunnels...")
|
||||
try:
|
||||
self.tunneld_core.clear()
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "OK",
|
||||
"message": "Cleared tunnels...",
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Error clearing tunnels: %s", e)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Error clearing tunnels: {e}",
|
||||
}
|
||||
|
||||
case "cancel":
|
||||
logger.info("Canceling tunnel request from %s: %s", sid, data)
|
||||
try:
|
||||
udid = (
|
||||
data.get("udid")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "udid", self.context.udid)
|
||||
)
|
||||
if udid is None:
|
||||
udid = self.context.udid
|
||||
self.tunneld_core.cancel(udid=udid)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "OK",
|
||||
"udid": udid,
|
||||
"message": f"tunnel {udid} Canceled ...",
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Error canceling tunnel: %s", e)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Error canceling tunnel: {e}",
|
||||
}
|
||||
|
||||
case _:
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "tunneld_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Unknown operation: {command}",
|
||||
}
|
||||
|
||||
@sio.event
|
||||
async def reverse_geocode(sid, data: LatLng):
|
||||
logger.info("OSM Proxy Request from %s, data: %s", sid, data)
|
||||
return await self.get_reverse_geocode(data)
|
||||
|
||||
@sio.event
|
||||
async def favorite_control(sid, data: dict):
|
||||
command = (
|
||||
data.get("command")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "command", None)
|
||||
)
|
||||
logger.info("Favorite Control command: %s requested from %s", command, sid)
|
||||
match command:
|
||||
case "set":
|
||||
cstat, cmessage = await self.set_favorite(data)
|
||||
if cstat == "ERROR":
|
||||
logger.error("Favorite set failed: %s", cmessage)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "favorite_control",
|
||||
"command_status": cstat,
|
||||
"message": cmessage,
|
||||
"data": {
|
||||
"favorites": await self.get_favorites(),
|
||||
},
|
||||
}
|
||||
|
||||
case "clear":
|
||||
cstat, cmessage = await self.clear_favorite(data)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "favorite_control",
|
||||
"command_status": cstat,
|
||||
"message": cmessage,
|
||||
"data": {
|
||||
"favorites": await self.get_favorites(),
|
||||
},
|
||||
}
|
||||
|
||||
case "get":
|
||||
favs = await self.get_favorites()
|
||||
if favs:
|
||||
cstat = "OK"
|
||||
cmessage = "Favorites retrieved successfully"
|
||||
else:
|
||||
cstat = "ERROR"
|
||||
cmessage = "No favorites found"
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "favorite_control",
|
||||
"command_status": cstat,
|
||||
"message": cmessage,
|
||||
"data": {
|
||||
"favorites": favs,
|
||||
},
|
||||
}
|
||||
|
||||
case _:
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "favorite_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Invalid command: {command}",
|
||||
}
|
||||
|
||||
@sio.event
|
||||
async def category_control(sid, data: dict):
|
||||
command = (
|
||||
data.get("command")
|
||||
if isinstance(data, dict)
|
||||
else getattr(data, "command", None)
|
||||
)
|
||||
logger.info("Category Control command: %s requested from %s", command, sid)
|
||||
match command:
|
||||
case "add":
|
||||
cstat, cmessage = await self.add_category(data)
|
||||
if cstat == "ERROR":
|
||||
logger.error("Category set failed: %s", cmessage)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "category_control",
|
||||
"command_status": cstat,
|
||||
"message": cmessage,
|
||||
"data": {
|
||||
"categories": await self.get_categories(),
|
||||
},
|
||||
}
|
||||
|
||||
case "delete":
|
||||
cstat, cmessage = await self.delete_category(data)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "category_control",
|
||||
"command_status": cstat,
|
||||
"message": cmessage,
|
||||
"data": {
|
||||
"categories": await self.get_categories(),
|
||||
},
|
||||
}
|
||||
|
||||
case "get":
|
||||
cats = await self.get_categories()
|
||||
if cats:
|
||||
cstat = "OK"
|
||||
cmessage = "Categories retrieved successfully"
|
||||
else:
|
||||
cstat = "ERROR"
|
||||
cmessage = "No categories found"
|
||||
logger.info("Categories: %s", cats)
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "category_control",
|
||||
"command_status": cstat,
|
||||
"message": cmessage,
|
||||
"data": {
|
||||
"categories": cats,
|
||||
},
|
||||
}
|
||||
|
||||
case _:
|
||||
return {
|
||||
"command": command,
|
||||
"command_class": "category_control",
|
||||
"command_status": "ERROR",
|
||||
"message": f"Invalid command: {command}",
|
||||
}
|
||||
Reference in New Issue
Block a user