This commit is contained in:
2026-03-21 08:22:24 -04:00
parent 47aeebd86f
commit c5a563f047
5 changed files with 229 additions and 28 deletions

View File

@@ -157,12 +157,14 @@ class LocationSimulationState:
self.queue_data: Dict = {}
self.queue_status: Optional[asyncio.Event] = asyncio.Event()
self.queue_state: str = "STOPPED"
self.test_mode: bool = False
self.test_mode: bool = True
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
self.icloud_monitor = FindMyMonitor(self.fmf_queue)
self.icloud_monitor_task = None
class TunneldRunnerSio:
@@ -205,6 +207,7 @@ class TunneldRunnerSio:
@asynccontextmanager
async def lifespan(app: FastAPI):
self._tunneld_core.start()
await start_icloud_monitor()
yield
logger.info("Closing tunneld tasks...")
await empty_simulation_queue()
@@ -384,16 +387,17 @@ class TunneldRunnerSio:
async def start_icloud_monitor()
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))
self.context.icloud_monitor_task = asyncio.create_task(self.context.icloud_monitor.run_monitor(interval=30))
while True:
updated_location = await self.context.fmf_queue.get()
if self.context.fmf_location !== updated_location:
if self.context.fmf_location != updated_location:
self.context.fmf_location = update_location
self.context.sio.emit("fmf_update", updated_location, namespace="/",)
async def end_icloud_monitor():
self.context.icloud_monitor.end()
async def pause_simulation_queue():
"""Pauses asyncio.Queue playback"""
@@ -444,7 +448,7 @@ class TunneldRunnerSio:
async def end_simulation_queue() -> bool:
"""Ends asyncio.Queue playback and closes tunnel"""
logger.info("End location simulation request from %s", sid)
logger.info("End location simulation request")
try:
if self.context.test_mode:
q = self.context.queue
@@ -503,6 +507,7 @@ class TunneldRunnerSio:
"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,
"fmf_location": self.context.fmf_location,
}
return data
@@ -636,6 +641,7 @@ class TunneldRunnerSio:
async def app_add_location(data: SimulationRequestData) -> fastapi.Response:
""" Add a location to the simulation queue"""
logger.info("Request to add new location to 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)
@@ -644,28 +650,27 @@ class TunneldRunnerSio:
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:
now_time = datetime.now(timezone.utc)
new_time = now_time + timedelta(seconds=delay)
start_time = new_time.isoformat()
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=accrued_delay) + timedelta(seconds=delay)
start_time = new_time.isoformat()
location_item = {
loc_id: {
"loc_id": loc_id,
"latitude": latitude,
"longitude": longitude,
"delay": delay,
"start": start_time
}
"loc_id": loc_id,
"latitude": latitude,
"longitude": longitude,
"delay": delay,
"start": start_time
}
self.context.queue_list.append(location_item)
resp = {
"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)
else:
resp = {"status": "error", "message": "Invalid location data"}
return generate_http_response(resp)
@@ -1040,8 +1045,9 @@ class LocationSimulationTestQueue(LocationSimulationBase):
async def play_queue(self, disable_sleep: bool = False, timing_randomness_range: int = 0) -> None:
while True:
while self.context.queue_state == "PAUSED":
if self.context.queue_state == "PAUSED":
await asyncio.sleep(0.1)
continue
if self.context.queue_state == "SHUTDOWN":
break
loc_id = await self.context.queue.get()
@@ -1051,6 +1057,7 @@ class LocationSimulationTestQueue(LocationSimulationBase):
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:
@@ -1075,9 +1082,7 @@ class LocationSimulationTestQueue(LocationSimulationBase):
await self.set(latitude, longitude)
self.context.latitude = latitude
self.context.longitude = longitude
self.context.loc_id = loc_id
await self.context.sio.emit(
"simulation_status",
{
"status": self.context.simulation_active,