Make client -> device connection synchronous

Summary:
devices not always being readily available is causes a lot of complication in the api,
figured to resolve devices first before construction clients,
since clients not attached to a device are shown uncategorized anyway, making them practically un-interactable.
For more background info, see following chat.

{F344388883}

This diff will make it possible to only expose a synchronous api in Sandy

n.b. didn't update Navigation plugin, as that is done in a next diff

Reviewed By: jknoxville

Differential Revision: D24858332

fbshipit-source-id: 8339f831fbbc9c219add56a199364fde67adafc7
This commit is contained in:
Michel Weststrate
2020-11-11 07:57:14 -08:00
committed by Facebook GitHub Bot
parent fd8065eb7a
commit 9b4e7e873c
9 changed files with 124 additions and 102 deletions

View File

@@ -13,7 +13,7 @@ import {
} from './utils/CertificateProvider';
import {Logger} from './fb-interfaces/Logger';
import {ClientQuery} from './Client';
import {Store} from './reducers/index';
import {Store, State} from './reducers/index';
import CertificateProvider from './utils/CertificateProvider';
import {RSocketServer} from 'rsocket-core';
import RSocketTCPServer from 'rsocket-tcp-server';
@@ -38,6 +38,8 @@ import {IncomingMessage} from 'http';
import ws from 'ws';
import {initSelfInpector} from './utils/self-inspection/selfInspectionUtils';
import ClientDevice from './devices/ClientDevice';
import BaseDevice from './devices/BaseDevice';
import {sideEffect} from './utils/sideEffect';
type ClientInfo = {
connection: FlipperClientConnection<any, any> | null | undefined;
@@ -529,7 +531,7 @@ class Server extends EventEmitter {
);
})
: Promise.resolve(query.device_id)
).then((csrId) => {
).then(async (csrId) => {
query.device_id = csrId;
query.app = appNameWithUpdateHint(query);
@@ -541,7 +543,18 @@ class Server extends EventEmitter {
});
console.debug(`Device connected: ${id}`, 'server');
const client = new Client(id, query, conn, this.logger, this.store);
const device =
getDeviceBySerial(this.store.getState(), query.device_id) ??
(await findDeviceForConnection(this.store, query.app, query.device_id));
const client = new Client(
id,
query,
conn,
this.logger,
this.store,
undefined,
device,
);
const info = {
client,
@@ -627,4 +640,54 @@ class ConnectionTracker {
}
}
function getDeviceBySerial(
state: State,
serial: string,
): BaseDevice | undefined {
return state.connections.devices.find((device) => device.serial === serial);
}
async function findDeviceForConnection(
store: Store,
clientId: string,
serial: string,
): Promise<BaseDevice> {
let lastSeenDeviceList: BaseDevice[] = [];
/* All clients should have a corresponding Device in the store.
However, clients can connect before a device is registered, so wait a
while for the device to be registered if it isn't already. */
return reportPlatformFailures(
new Promise<BaseDevice>((resolve, reject) => {
let unsubscribe: () => void = () => {};
const timeout = setTimeout(() => {
unsubscribe();
const error = `Timed out waiting for device ${serial} for client ${clientId}`;
console.error(error);
reject(error);
}, 5000);
unsubscribe = sideEffect(
store,
{name: 'waitForDevice', throttleMs: 100},
(state) => state.connections.devices,
(newDeviceList) => {
if (newDeviceList === lastSeenDeviceList) {
return;
}
lastSeenDeviceList = newDeviceList;
const matchingDevice = newDeviceList.find(
(device) => device.serial === serial,
);
if (matchingDevice) {
clearTimeout(timeout);
resolve(matchingDevice);
unsubscribe();
}
},
);
}),
'client-setMatchingDevice',
);
}
export default Server;