Organise files per device

Summary:
Moved all logic per device type we support to its own dir, including tools and utilities around it, which makes it easier to consolidate logic and decouple in turn per device type.

Per type, all logic can be found in

`server/devices/(desktop|metro|android|ios|webapp)`

Reviewed By: timur-valiev

Differential Revision: D30277817

fbshipit-source-id: 2b5339c363d5d31ceeba07cec03826fc67cf3748
This commit is contained in:
Michel Weststrate
2021-08-13 04:01:06 -07:00
committed by Facebook GitHub Bot
parent 6175424d16
commit c0cd32564a
37 changed files with 78 additions and 82 deletions

View File

@@ -0,0 +1,211 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import Client, {ClientQuery} from '../../../Client';
import {
ClientConnection,
ConnectionStatus,
ConnectionStatusChange,
ResponseType,
} from '../../comms/ClientConnection';
import {ipcRenderer, remote, IpcRendererEvent} from 'electron';
import JSDevice from './JSDevice';
import {Store} from '../../../reducers';
import {Logger} from '../../../fb-interfaces/Logger';
import ServerController from '../../comms/ServerController';
import {buildClientId} from '../../../utils/clientUtils';
import {destroyDevice} from '../../../reducers/connections';
const connections: Map<number, JSClientFlipperConnection> = new Map();
const availablePlugins: Map<number, Array<string>> = new Map();
function jsDeviceId(windowId: number): string {
return 'test_js_device' + windowId;
}
export function initJsEmulatorIPC(
store: Store,
logger: Logger,
flipperServer: ServerController,
flipperConnections: Map<
string,
{
connection: ClientConnection | null | undefined;
client: Client;
}
>,
) {
ipcRenderer.on(
'from-js-emulator-init-client',
(_event: IpcRendererEvent, message: any) => {
const {windowId} = message;
const {plugins, appName} = message.payload;
const device = new JSDevice(jsDeviceId(windowId), 'jsEmulator', windowId);
store.dispatch({
type: 'REGISTER_DEVICE',
payload: device,
});
const connection = new JSClientFlipperConnection(windowId);
connections.set(windowId, connection);
availablePlugins.set(windowId, plugins);
const query: ClientQuery = {
app: appName,
os: 'JSWebApp',
device: 'jsEmulator',
device_id: jsDeviceId(windowId),
sdk_version: 2, // hack to bybass callbacks in Client, will be fixed when JS Connection will be fully implemented
};
const clientId = buildClientId(query);
const client = new Client(
clientId,
query,
connection,
logger,
store,
plugins,
device,
);
flipperConnections.set(clientId, {
connection: connection,
client: client,
});
connection.subscribeToEvents((status) => {
if (
status == ConnectionStatus.ERROR ||
status == ConnectionStatus.CLOSED
) {
console.debug(`Device disconnected ${client.id}`, 'server');
flipperServer.removeConnection(client.id);
destroyDevice(store, logger, jsDeviceId(windowId));
connections.delete(windowId);
availablePlugins.delete(windowId);
}
});
client
.init()
.then(() => {
console.log(client);
flipperServer.emit('new-client', client);
flipperServer.emit('clients-change');
client.emit('plugins-change');
ipcRenderer.on(
'from-js-emulator',
(_event: IpcRendererEvent, message: any) => {
const {command, payload} = message;
if (command === 'sendFlipperObject') {
client.onMessage(
JSON.stringify({
params: {
api: payload.api,
method: payload.method,
params: JSON.parse(payload.params),
},
method: 'execute',
}),
);
}
},
);
})
.catch((_) => {});
},
);
}
export function launchJsEmulator(url: string, height: number, width: number) {
const BrowserWindow = remote.BrowserWindow;
const win = new BrowserWindow({
height: height,
width: width,
webPreferences: {
enableRemoteModule: true,
preload: require('path').join(
remote.app.getAppPath(),
'SupportJSClientPreload.js',
),
nodeIntegration: false,
contextIsolation: false,
allowRunningInsecureContent: true,
},
});
win.webContents.on('preload-error', (_event, path, error) => {
console.log(path, error);
});
win.loadURL(url);
win.webContents.on('did-finish-load', () => {
win.webContents.send('parent-window-id', remote.getCurrentWebContents().id);
const childWindowId = win.webContents.id;
win.on('closed', () => {
connections.get(childWindowId)?.close();
});
});
}
export class JSClientFlipperConnection implements ClientConnection {
webContentsId: number;
connStatusSubscribers: Set<ConnectionStatusChange> = new Set();
connStatus: ConnectionStatus;
constructor(webContentsId: number) {
this.webContentsId = webContentsId;
this.connStatus = ConnectionStatus.CONNECTED;
}
subscribeToEvents(subscriber: ConnectionStatusChange): void {
this.connStatusSubscribers.add(subscriber);
}
send(data: any): void {
ipcRenderer.sendTo(
this.webContentsId,
'message-to-plugin',
JSON.parse(data != null ? data : '{}'),
);
}
// TODO: fully implement and return actual result
sendExpectResponse(data: any): Promise<ResponseType> {
return new Promise((resolve, _) => {
const method = data != null ? JSON.parse(data).method : 'not-defined';
if (method !== 'getPlugins') {
this.send(data);
}
if (method === 'getPlugins') {
resolve({
success: {
plugins: availablePlugins.get(this.webContentsId),
},
length: 0,
});
} else {
resolve({
success: undefined,
length: 0,
});
}
});
}
close(): void {
this.connStatus = ConnectionStatus.CLOSED;
this.connStatusSubscribers.forEach((subscriber) => {
subscriber(this.connStatus);
});
}
}