lots of changes
This commit is contained in:
Binary file not shown.
Binary file not shown.
27
database.py
Normal file
27
database.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from sqlalchemy import create_engine
|
||||
from dqlalchemy.orm import sessionmaker, declaritive_base
|
||||
|
||||
DATABASE_URL = "sqlite:///./locations.db"
|
||||
|
||||
engine = create_engine(
|
||||
DATABASE_URL, connect_engine("check_same_thread": false}
|
||||
)
|
||||
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
def get_db():
|
||||
"""Dependency for getting database session."""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
def create_all_tables():
|
||||
"""Creates all tables defined with Base in the database."""
|
||||
# Note: import models before calling create_all_tables()
|
||||
Base.metadata_create_all(bind=engine)
|
||||
print("Database and tables created.")
|
||||
|
||||
58
db_models.py
Normal file
58
db_models.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from sqlalchemy import Column, Integer, String, Float, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from .database import Base
|
||||
|
||||
|
||||
class Location(Base):
|
||||
"""
|
||||
SQLAlchemy model for the 'locations' table.
|
||||
"""
|
||||
__tablename__ = "locations"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, unique=False, index=True)
|
||||
address = Column(String, unique=False, index=True)
|
||||
latitude = Column(Float, unique=False, index=True)
|
||||
longitude = Column(Float, unique=False, index=True)
|
||||
is_favorite = Column(Boolean, unique=False, index=True)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Location(name='{self.name}', address='{self.address}', latitude='{self.latitude}', longitude='{self.longitude}', is_favorite='{self.is_favorite}')>"
|
||||
|
||||
class Route(Base):
|
||||
"""
|
||||
SQLAlchemy model for the 'routes' table.
|
||||
"""
|
||||
__tablename__ = "routes"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String, index=True)
|
||||
|
||||
# Start and Endpoints (One-to-Many relationship)
|
||||
start_location_id = Column(Integer, ForeignKey('locations.id'))
|
||||
end_location_id = Column(Integer, ForeignKey('locations.id'))
|
||||
|
||||
start_location = relationship("Location", foreign_keys=[start_id])
|
||||
end_location = relationship("Location", foreign_keys=[end_id])
|
||||
|
||||
# Relationship to get waypoints ordered
|
||||
waypoints = relationship("Waypoint", order_by="Waypoint.order", back_populates="route")
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Route(name='{self.name}', start='{self.start_location.name}', end='{self.end_location.name}')>"
|
||||
|
||||
# Association Table for Many-to-Many relationsjip (Routes <-> Waypoints)
|
||||
class Waypoint(Base):
|
||||
"""
|
||||
SQLAlchemy model for the 'waypoints' table.
|
||||
"""
|
||||
__tablename__ = 'waypoints'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
route_id = Column(Integer, ForeignKey('routes.id'))
|
||||
location_id = Column(Integer, ForeignKey('locations.id'))
|
||||
order = Column(Integer, nullable=False)
|
||||
|
||||
route = relationship("Route", back_populates="waypoints")
|
||||
location = relationship("Location")
|
||||
88
icloud.py
Normal file
88
icloud.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from pyicloud import PyiCloudService
|
||||
from pyicloud.exceptions import PyiCloud2FARequiredException
|
||||
|
||||
class FindMyMonitor:
|
||||
def __init__(self, username, password, queue: asyncio.Queue, token_file="icloud_token.txt"):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.token_file = token_file
|
||||
self.queue = queue
|
||||
self.api = None
|
||||
self.device = None
|
||||
self.running = True
|
||||
|
||||
async def authenticate(self):
|
||||
"""Authenticates with iCloud, handling 2FA and token storage."""
|
||||
if os.path.exists(self.token_file):
|
||||
print("Loading stored session...")
|
||||
self.api = PyiCloudService(self.username, cookie_directory="./cookies")
|
||||
else:
|
||||
print("No stored session. Authenticating...")
|
||||
self.api = PyiCloudService(self.username, self.password, cookie_directory="./cookies")
|
||||
|
||||
if self.api.requires_2fa:
|
||||
print("Two-factor authentication required.")
|
||||
code = input("Enter the code you received: ")
|
||||
result = self.api.validate_2fa_code(code)
|
||||
print(f"Code validation result: {result}")
|
||||
if not result:
|
||||
print("Failed to verify 2FA code")
|
||||
return False
|
||||
|
||||
# Trust the session
|
||||
self.api.trust_session()
|
||||
|
||||
print("Successfully authenticated.")
|
||||
return True
|
||||
|
||||
async def get_location(self):
|
||||
"""Fetches the latest latitude and longitude."""
|
||||
if not self.api:
|
||||
await self.authenticate()
|
||||
|
||||
# Refresh API data
|
||||
self.api.refresh_client()
|
||||
|
||||
# Find the device (modify name to match your iPhone name in iCloud)
|
||||
if not self.device:
|
||||
# Assuming you have devices, pick the first or match by name
|
||||
self.device = self.api.devices[0]
|
||||
print(f"Monitoring device: {self.device.name()}")
|
||||
|
||||
location = self.device.location()
|
||||
if location:
|
||||
return location['latitude'], location['longitude'], location['timeStamp']
|
||||
return None
|
||||
|
||||
def start(self):
|
||||
self.running = True
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
async def run_monitor(self, interval=60):
|
||||
"""Runs the monitor loop."""
|
||||
if not await self.authenticate():
|
||||
return
|
||||
|
||||
if not self.running:
|
||||
self.start()
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
lat, lon, ts = await self.get_location()
|
||||
print(f"[{ts}] Location: {lat}, {lon}")
|
||||
# Add your logic to update database/API here
|
||||
await self.queue.put(lat, lng, ts)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
# Re-authenticate if session expired
|
||||
await self.authenticate()
|
||||
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
|
||||
323
server.py
323
server.py
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
|
||||
from icloud import FindMyMonitor
|
||||
from datetime import datetime, timezone, timedelta
|
||||
import json
|
||||
import uuid
|
||||
@@ -9,11 +10,13 @@ import signal
|
||||
import traceback
|
||||
import warnings
|
||||
import random
|
||||
from operator import truediv
|
||||
|
||||
from pydantic import BaseModel, RootModel
|
||||
import socketio
|
||||
from contextlib import asynccontextmanager, suppress
|
||||
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict
|
||||
|
||||
from pymobiledevice3.services.dvt.instruments.location_simulation_base import LocationSimulationBase
|
||||
|
||||
@@ -129,24 +132,37 @@ class SimulationRequestResponse(BaseModel):
|
||||
status: bool
|
||||
data: Optional[SimulationRequestResponseData]
|
||||
|
||||
class SimulationQueueDict(BaseModel):
|
||||
location_id: Dict[str, SimulationRequestResponseData]
|
||||
|
||||
class iCloudLocationData(BaseModel):
|
||||
latitude: number
|
||||
longitude: number
|
||||
timestamp: string
|
||||
|
||||
|
||||
class LocationSimulationState:
|
||||
def __init__(self):
|
||||
self.current_location: Optional[Dict[str, SimulationRequestResponseData]] = None
|
||||
self.next_location: Optional[Dict[str, SimulationRequestResponseData]] = None
|
||||
self.loc_id: Optional[str] = None
|
||||
self.latitude: Optional[float] = None
|
||||
self.longitude: Optional[float] = None
|
||||
self.next_move: Optional[float] = None
|
||||
self.udid: Optional[str] = None
|
||||
self.simulation_active: bool = False
|
||||
self.loc_id: Optional[str] = None
|
||||
self.set_location_enabled: bool = True
|
||||
self.queue: asyncio.Queue = asyncio.Queue()
|
||||
self.queue_list: list[SimulationRequestResponseData] = []
|
||||
self.queue_order: list[str] = []
|
||||
self.queue_data: Dict = {}
|
||||
self.queue_status: Optional[asyncio.Event] = asyncio.Event()
|
||||
self.queue_state: str = "STOPPED"
|
||||
self.test_mode: bool = True
|
||||
self.test_mode: bool = False
|
||||
self.simulation_task: Optional[asyncio.Task] = None
|
||||
self.sio: socketio.AsyncServer = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
||||
self.tunnel: Optional[RemoteServiceDiscoveryService] = None
|
||||
self.fmf_queue: asyncio.Queue = asyncio.Queue
|
||||
self.fmf_location: Optional[iCloudLocationData] = None
|
||||
|
||||
|
||||
class TunneldRunnerSio:
|
||||
@@ -325,10 +341,7 @@ class TunneldRunnerSio:
|
||||
return
|
||||
|
||||
logger.info("Simulation worker: acquiring tunnel (udid=%s)", self.context.udid)
|
||||
# tun = await asyncio.wait_for(
|
||||
# get_tun(self.context.udid),
|
||||
# timeout=TUNNEL_ACQUIRE_TIMEOUT_SECONDS,
|
||||
# )
|
||||
|
||||
tun = await get_tun(self.context.udid)
|
||||
logger.info("Simulation worker: tunnel acquired, connecting DVT provider")
|
||||
dvt_provider = DvtProvider(tun)
|
||||
@@ -369,6 +382,19 @@ class TunneldRunnerSio:
|
||||
self.context.simulation_active = False
|
||||
self.context.simulation_task = None
|
||||
|
||||
|
||||
|
||||
async def start_icloud_monitor()
|
||||
"""Start Apple iCloud Find My Monitor to retreive actual reported device location"""
|
||||
monitor = FindMyMonitor(apple_id, apple_pw, self.context.fmf_queue)
|
||||
monitor_task = asyncio.create_task(monitor.run_monitor(interval=30))
|
||||
while True:
|
||||
updated_location = await self.context.fmf_queue.get()
|
||||
if self.context.fmf_location !== updated_location:
|
||||
self.context.fmf_location = update_location
|
||||
self.context.sio.emit("fmf_update", updated_location, namespace="/",)
|
||||
|
||||
|
||||
async def pause_simulation_queue():
|
||||
"""Pauses asyncio.Queue playback"""
|
||||
self.context.queue_state = "PAUSED"
|
||||
@@ -390,23 +416,95 @@ class TunneldRunnerSio:
|
||||
except asyncio.QueueEmpty:
|
||||
break
|
||||
|
||||
async def end_simulation_queue() -> str:
|
||||
def add_item(item_id, payload):
|
||||
self.context.queue_data[item_id] = payload
|
||||
self.context.queue_order.append(item_id)
|
||||
|
||||
def remove_item(item_id):
|
||||
if item_id in self.context.queue_order:
|
||||
self.context.queue_order.remove(item_id)
|
||||
|
||||
def get_item(item_id):
|
||||
return self.context.queue_data[item_id]
|
||||
|
||||
def update_item(item_id, **updates):
|
||||
if item_id in self.context.queue_data:
|
||||
self.context.queue_data[item_id].update(updates)
|
||||
|
||||
def get_item_index(item_id):
|
||||
return self.context.queue_order.index(item_id)
|
||||
|
||||
def get_item_id_by_index(index):
|
||||
return self.context.queue_order[index]
|
||||
|
||||
def get_items_in_order():
|
||||
return [self.context.queue_data[i] for i in self.context.queue_order]
|
||||
|
||||
|
||||
|
||||
async def end_simulation_queue() -> bool:
|
||||
"""Ends asyncio.Queue playback and closes tunnel"""
|
||||
logger.info("End location simulation request from %s", sid)
|
||||
if self.context.simulation_task is not None and not self.context.simulation_task.done():
|
||||
q = self.context.queue
|
||||
if q.qsize() > 0:
|
||||
await empty_simulation_queue()
|
||||
while q.empty() and q.qsize() == 0:
|
||||
try:
|
||||
if self.context.test_mode:
|
||||
q = self.context.queue
|
||||
if q.qsize() > 0:
|
||||
self.context.set_location_enabled = False
|
||||
while not q.empty():
|
||||
try:
|
||||
item = q.get_nowait()
|
||||
q.task_done()
|
||||
logger.info("Discarding item from queue: %s", item)
|
||||
except asyncio.QueueEmpty:
|
||||
break
|
||||
|
||||
await q.join()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await self.context.simulation_task
|
||||
if self.context.tunnel is not None:
|
||||
async with DvtProvider(self.context.tunnel) as dvt, LocationSimulation(dvt) as locate_simulation:
|
||||
await locate_simulation.clear()
|
||||
self.context.simulation_active = False
|
||||
self.context.queue_state = "SHUTDOWN"
|
||||
return "ended"
|
||||
# with suppress(asyncio.CancelledError):
|
||||
# await self.context.simulation_task
|
||||
self.context.simulation_active = False
|
||||
self.context.queue_state = "SHUTDOWN"
|
||||
return True
|
||||
if not self.context.test_mode:
|
||||
if self.context.simulation_task is not None and not self.context.simulation_task.done():
|
||||
q = self.context.queue
|
||||
if q.qsize() > 0:
|
||||
await empty_simulation_queue()
|
||||
while q.empty() and q.qsize() == 0:
|
||||
await q.join()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await self.context.simulation_task
|
||||
if self.context.tunnel is not None:
|
||||
async with DvtProvider(self.context.tunnel) as dvt, LocationSimulation(dvt) as locate_simulation:
|
||||
await locate_simulation.clear()
|
||||
self.context.simulation_active = False
|
||||
self.context.queue_state = "SHUTDOWN"
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error ending simulation queue: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def get_status():
|
||||
data = {
|
||||
"current_location": self.context.current_location,
|
||||
"next_location": self.context.next_location,
|
||||
"latitude": self.context.latitude,
|
||||
"longitude": self.context.longitude,
|
||||
"next_move": self.context.next_move,
|
||||
"udid": self.context.udid,
|
||||
"simulation_active": self.context.simulation_active,
|
||||
"loc_id": self.context.loc_id,
|
||||
"set_location_enable": self.context.set_location_enabled,
|
||||
"queue_length": self.context.queue.qsize() if self.context.queue else 0,
|
||||
"queue_state": self.context.queue_state,
|
||||
"queue_order": self.context.queue_order,
|
||||
"queue_data": self.context.queue_data,
|
||||
"queue_status": self.context.queue_status.is_set() if self.context.queue_status else False,
|
||||
"test_mode": self.context.test_mode,
|
||||
"simulation_task": self.context.simulation_task.get_name() if self.context.simulation_task else None,
|
||||
"tunnel": self.context.tunnel.service.address[0] if self.context.tunnel else None,
|
||||
}
|
||||
return data
|
||||
|
||||
""" FastAPI HTTP Functions"""
|
||||
def generate_http_response(
|
||||
@@ -646,27 +744,22 @@ class TunneldRunnerSio:
|
||||
|
||||
@self._app.get("/context-status")
|
||||
async def app_context_status() -> fastapi.Response:
|
||||
data = {
|
||||
"latitude": self.context.latitude,
|
||||
"longitude": self.context.longitude,
|
||||
"next_more": self.context.next_move,
|
||||
"udid": self.context.udid,
|
||||
"simulation_active": self.context.simulation_active,
|
||||
"loc_id": self.context.loc_id,
|
||||
"set_location_enable": self.context.set_location_enabled,
|
||||
"queue_state": self.context.queue_state,
|
||||
"queue_list": self.context.queue_list
|
||||
}
|
||||
data = get_status()
|
||||
return generate_http_response(data)
|
||||
|
||||
""" Socket.IO Functions"""
|
||||
|
||||
async def sio_send_status(sid):
|
||||
""" Send Current Status"""
|
||||
await self.context.sio.emit("status", get_status(), namespace="/", to=sid)
|
||||
|
||||
"""Socket.IO Connection Events"""
|
||||
@self.context.sio.event
|
||||
async def connect(sid, environ):
|
||||
"""Client connection event handler."""
|
||||
logger.info("Client connected: %s", sid)
|
||||
return('%s connected' % sid)
|
||||
await sio_send_status(sid)
|
||||
return '%s connected' % sid
|
||||
|
||||
@self.context.sio.event
|
||||
async def disconnect(sid):
|
||||
@@ -680,8 +773,9 @@ class TunneldRunnerSio:
|
||||
|
||||
@self.context.sio.event
|
||||
async def message(sid, data):
|
||||
logger.info("Received message from %s: %s", data, sid)
|
||||
await self.context.sio.emit("message", f"Received message from {sid}: {data}", namespace="/")
|
||||
logger.info("Received message from %s: %s", sid, data)
|
||||
return True, "Message received"
|
||||
# await self.context.sio.emit("message", f"Received message from {sid}: {data}", namespace="/")
|
||||
|
||||
""" Device Control"""
|
||||
@self.context.sio.event
|
||||
@@ -708,83 +802,86 @@ class TunneldRunnerSio:
|
||||
return { "command": command, "status": "error", "message": f"Invalid command: {command}" }
|
||||
|
||||
@self.context.sio.event
|
||||
async def simulate_control(sid, data):
|
||||
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)
|
||||
match command:
|
||||
case "add":
|
||||
""" Add a location to the simulation queue"""
|
||||
loc_id = str(uuid.uuid4())
|
||||
latitude = data.get("latitude") if isinstance(data, dict) else getattr(data, "latitude", None)
|
||||
longitude = data.get("longitude") if isinstance(data, dict) else getattr(data, "longitude", None)
|
||||
delay = data.get("delay", 0) if isinstance(data, dict) else getattr(data, "delay", 0)
|
||||
delay = 0 if delay is None else delay
|
||||
if latitude is not None and longitude is not None:
|
||||
logger.info("Adding location %s (%s, %s) with %s delay to the queue", loc_id, latitude, longitude,
|
||||
delay)
|
||||
await self.context.queue.put((loc_id, latitude, longitude, delay))
|
||||
if delay == 0:
|
||||
start_time = datetime.now(timezone.utc).isoformat()
|
||||
else:
|
||||
try:
|
||||
match command:
|
||||
case "add":
|
||||
""" Add a location to the simulation queue"""
|
||||
loc_id = str(uuid.uuid4())
|
||||
latitude = data.get("latitude") if isinstance(data, dict) else getattr(data, "latitude", None)
|
||||
longitude = data.get("longitude") if isinstance(data, dict) else getattr(data, "longitude", None)
|
||||
delay = data.get("delay", 0) if isinstance(data, dict) else getattr(data, "delay", 0)
|
||||
delay = 0 if delay is None else delay
|
||||
if latitude is not None and longitude is not None:
|
||||
logger.info("Adding location %s (%s, %s) with %s delay to the queue", loc_id, latitude, longitude,
|
||||
delay)
|
||||
accrued_delay = 0
|
||||
if self.context.queue_data:
|
||||
accrued_delay = sum(item.get('delay', 0) for item in self.context.queue_data.values())
|
||||
now_time = datetime.now(timezone.utc)
|
||||
new_time = now_time + timedelta(seconds=delay)
|
||||
new_time = now_time + timedelta(seconds=accrued_delay) + timedelta(seconds=delay)
|
||||
start_time = new_time.isoformat()
|
||||
|
||||
location_item = {
|
||||
loc_id: {
|
||||
location_item = {
|
||||
"loc_id": loc_id,
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
"delay": delay,
|
||||
"start": start_time
|
||||
}
|
||||
}
|
||||
ack = {
|
||||
"command": command,
|
||||
"status": "added",
|
||||
"message": f"Location {loc_id} added to the queue",
|
||||
"item": location_item
|
||||
}
|
||||
self.context.queue_list.append(location_item)
|
||||
logger.info("Location %s added to the queue", loc_id)
|
||||
return ack
|
||||
else:
|
||||
logger.warning("Invalid location data received from %s: %s", sid, data)
|
||||
return {"command": command, "status": "error", "message": "Invalid location data"}
|
||||
case "clear":
|
||||
""" Clear the simulation queue"""
|
||||
await empty_simulation_queue()
|
||||
return {"command": command, "status": "cleared", "message": "Simulation cleared"}
|
||||
case "pause":
|
||||
""" Pause the simulation queue"""
|
||||
await pause_simulation_queue()
|
||||
return {"command": command, "status": "paused", "message": "Simulation paused"}
|
||||
case "resume":
|
||||
""" Resume the simulation queue"""
|
||||
await resume_simulation_queue()
|
||||
return {"command": command, "status": "resumed", "message": "Simulation resumed"}
|
||||
case "end":
|
||||
""" End the simulation queue"""
|
||||
logger.info("End location simulation request from %s", sid)
|
||||
end_task = asyncio.create_task(end_simulation_queue(), name="end-simulation-worker")
|
||||
result = await end_task
|
||||
return {"command": command, "status": result, "message": "Simulation ended"}
|
||||
case "start":
|
||||
""" Start the simulation queue"""
|
||||
logger.info("Start location simulation request from %s", sid)
|
||||
if self.context.simulation_task is None or self.context.simulation_task.done():
|
||||
self.context.simulation_active = True
|
||||
self.context.simulation_task = asyncio.create_task(
|
||||
start_simulation_queue(),
|
||||
name="location-simulation-worker",
|
||||
)
|
||||
return {"command": command, "status": "started", "message": "Simulation started"}
|
||||
else:
|
||||
return {"command": command, "status": "error", "message": "Simulation already running"}
|
||||
case _:
|
||||
logger.warning("Invalid command received from %s: %s", sid, command)
|
||||
return {"status": "error", "message": "Invalid command"}
|
||||
ack = {
|
||||
"command": command,
|
||||
"status": "added",
|
||||
"message": f"Location {loc_id} added to the queue",
|
||||
"item": location_item
|
||||
}
|
||||
await self.context.queue.put(loc_id)
|
||||
add_item(loc_id, location_item)
|
||||
logger.info("Location %s added to the queue", loc_id)
|
||||
return ack
|
||||
else:
|
||||
logger.warning("Invalid location data received from %s: %s", sid, data)
|
||||
return {"command": command, "status": "error", "message": "Invalid location data", "data": location_item}
|
||||
case "clear":
|
||||
""" Clear the simulation queue"""
|
||||
await empty_simulation_queue()
|
||||
return {"command": command, "status": "cleared", "message": "Simulation cleared"}
|
||||
case "pause":
|
||||
""" Pause the simulation queue"""
|
||||
await pause_simulation_queue()
|
||||
return {"command": command, "status": "paused", "message": "Simulation paused"}
|
||||
case "resume":
|
||||
""" Resume the simulation queue"""
|
||||
await resume_simulation_queue()
|
||||
return {"command": command, "status": "resumed", "message": "Simulation resumed"}
|
||||
case "end":
|
||||
""" End the simulation queue"""
|
||||
logger.info("End location simulation request from %s", sid)
|
||||
end_task = asyncio.create_task(end_simulation_queue(), name="end-simulation-worker")
|
||||
result = await end_task
|
||||
simstatus = not result
|
||||
return {"command": command, "status": simstatus, "message": "Simulation ended"}
|
||||
case "start":
|
||||
""" Start the simulation queue"""
|
||||
logger.info("Start location simulation request from %s", sid)
|
||||
if self.context.simulation_task is None or self.context.simulation_task.done():
|
||||
self.context.simulation_active = True
|
||||
self.context.queue_state = "RUNNING"
|
||||
self.context.simulation_task = asyncio.create_task(
|
||||
start_simulation_queue(),
|
||||
name="location-simulation-worker",
|
||||
)
|
||||
return {"command": command, "status": self.context.queue_state, "message": "Simulation started"}
|
||||
else:
|
||||
return {"command": command, "status": "error", "message": "Simulation already running"}
|
||||
case _:
|
||||
logger.warning("Invalid command received from %s: %s", sid, command)
|
||||
return {"status": "error", "message": "Invalid command"}
|
||||
finally:
|
||||
await sio_send_status(sid)
|
||||
|
||||
|
||||
""" Tunnel Control """
|
||||
@self.context.sio.event
|
||||
@@ -798,7 +895,7 @@ class TunneldRunnerSio:
|
||||
try:
|
||||
self._tunneld_core.start()
|
||||
logger.info("Tunneld started successfully")
|
||||
return {"status": "started", "message": "Tunneld started successfully"}
|
||||
return {"status": "running", "message": "Tunneld started successfully"}
|
||||
except Exception as e:
|
||||
logger.error("Error starting tunneld: %s", e)
|
||||
return {"command": command, "status": "error", "message": f"Error starting tunneld: {e}"}
|
||||
@@ -855,9 +952,15 @@ class LocationSimulationQueue(LocationSimulation):
|
||||
continue
|
||||
if self.context.queue_state == "SHUTDOWN":
|
||||
break
|
||||
loc_id, latitude, longitude, delay = await self.context.queue.get()
|
||||
if (loc_id, latitude, longitude, delay) == (None, None, None, None):
|
||||
loc_id = await self.context.queue.get()
|
||||
if loc_id == None:
|
||||
break
|
||||
location_item = self.context.queue_data.get(loc_id)
|
||||
latitude = location_item.get("latitude")
|
||||
longitude = location_item.get("longitude")
|
||||
delay = location_item.get("delay")
|
||||
delay = 0 if delay is None else delay
|
||||
start_time = location_item.get("start_time")
|
||||
if self.context.set_location_enabled:
|
||||
if delay > 0 and not disable_sleep:
|
||||
if timing_randomness_range > 0:
|
||||
@@ -941,9 +1044,14 @@ class LocationSimulationTestQueue(LocationSimulationBase):
|
||||
await asyncio.sleep(0.1)
|
||||
if self.context.queue_state == "SHUTDOWN":
|
||||
break
|
||||
loc_id, latitude, longitude, delay = await self.context.queue.get()
|
||||
if (loc_id, latitude, longitude, delay) == (None, None, None, None):
|
||||
loc_id = await self.context.queue.get()
|
||||
if loc_id == None:
|
||||
break
|
||||
location_item = self.context.queue_data.get(loc_id)
|
||||
latitude = location_item.get("latitude")
|
||||
longitude = location_item.get("longitude")
|
||||
delay = location_item.get("delay")
|
||||
start_time = location_item.get("start_time")
|
||||
if self.context.set_location_enabled:
|
||||
if delay > 0 and not disable_sleep:
|
||||
if timing_randomness_range > 0:
|
||||
@@ -969,6 +1077,7 @@ class LocationSimulationTestQueue(LocationSimulationBase):
|
||||
self.context.longitude = longitude
|
||||
self.context.loc_id = loc_id
|
||||
await self.context.sio.emit(
|
||||
|
||||
"simulation_status",
|
||||
{
|
||||
"status": self.context.simulation_active,
|
||||
|
||||
1074
server_recover.py
Normal file
1074
server_recover.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user