fix: retry macOS robot hotspot scans

This commit is contained in:
2026-08-17 20:43:24 +08:00
parent 7e8d9e3811
commit 55e61b7d8f
3 changed files with 201 additions and 8 deletions

View File

@@ -10,6 +10,7 @@ const LOCATION_AUTHORIZED_ALWAYS = 3;
const LOCATION_AUTHORIZED_WHEN_IN_USE = 4;
const CORE_WLAN_PERMISSION_DENIED = -3930;
const CORE_WLAN_UNSUPPORTED = -3903;
const SCAN_RETRY_DELAY_MS = 250;
type StableReason = 'unsupported' | 'permission_denied' | 'scan_failed' | 'connect_failed';
type ObjcId = unknown;
@@ -21,6 +22,36 @@ interface WorkerCandidate {
open: boolean;
}
export interface MacosScanNetwork {
ssid: string | null;
rssi: number;
open: boolean;
}
export function scanMacosCandidatesWithRetry(
readNetworks: () => MacosScanNetwork[],
currentSsid: string | null,
waitBeforeRetry: () => void,
): WorkerCandidate[] {
let networks = readNetworks();
if (networks.length === 0 || networks.every((network) => !network.ssid)) {
waitBeforeRetry();
networks = readNetworks();
}
if (networks.length > 0 && networks.every((network) => !network.ssid)) {
throw new RobotHotspotAdapterError('permission_denied');
}
return networks.flatMap((network): WorkerCandidate[] => {
if (!network.open || !network.ssid) return [];
return [{
ssid: network.ssid,
signalPercent: Math.max(0, Math.min(100, Math.round((network.rssi + 100) * 2))),
connected: currentSsid === network.ssid,
open: true,
}];
});
}
type WorkerRequest = { id: number; operation: 'scan' } | { id: number; operation: 'connect'; ssid: string };
type WorkerResponse = { id: number; ok: true; result: WorkerCandidate[] | { ssid: string } } | { id: number; ok: false; reason: StableReason };
@@ -219,13 +250,16 @@ async function runCoreWlanWorker(): Promise<void> {
return withPool(() => {
const wifi = wifiInterface('scan');
const current = stringValue(sendId(wifi, selectors.ssid));
return scanNetworks('scan').flatMap((network): WorkerCandidate[] => {
if (!sendSupportsSecurity(network, selectors.supportsSecurity, 0)) return [];
const ssid = stringValue(sendId(network, selectors.ssid));
if (!ssid) return [];
const rssi = Number(sendLong(network, selectors.rssiValue));
return [{ ssid, signalPercent: Math.max(0, Math.min(100, Math.round((rssi + 100) * 2))), connected: current === ssid, open: true }];
});
const readNetworks = (): MacosScanNetwork[] => scanNetworks('scan').map((network) => ({
ssid: stringValue(sendId(network, selectors.ssid)),
rssi: Number(sendLong(network, selectors.rssiValue)),
open: sendSupportsSecurity(network, selectors.supportsSecurity, 0),
}));
return scanMacosCandidatesWithRetry(
readNetworks,
current,
() => { Atomics.wait(pollSleep, 0, 0, SCAN_RETRY_DELAY_MS); },
);
});
}