Move flipper-server client to flipper-frontend-core
Summary: ^ Reviewed By: aigoncharov Differential Revision: D36410944 fbshipit-source-id: 2adb5904cd0f5f15d08be22c611d6774e7533f94
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ce83f2c01b
commit
bfcdb82b43
@@ -16,7 +16,8 @@
|
|||||||
"immer": "^9.0.12",
|
"immer": "^9.0.12",
|
||||||
"js-base64": "^3.7.2",
|
"js-base64": "^3.7.2",
|
||||||
"p-map": "^5.3.0",
|
"p-map": "^5.3.0",
|
||||||
"semver": "^7.3.7"
|
"semver": "^7.3.7",
|
||||||
|
"reconnecting-websocket": "^4.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"flipper-test-utils": "0.0.0"
|
"flipper-test-utils": "0.0.0"
|
||||||
|
|||||||
163
desktop/flipper-frontend-core/src/client/FlipperServerClient.tsx
Normal file
163
desktop/flipper-frontend-core/src/client/FlipperServerClient.tsx
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and 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 EventEmitter from 'eventemitter3';
|
||||||
|
import {
|
||||||
|
ExecWebSocketMessage,
|
||||||
|
FlipperServer,
|
||||||
|
ServerWebSocketMessage,
|
||||||
|
} from 'flipper-common';
|
||||||
|
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||||
|
|
||||||
|
const CONNECTION_TIMEOUT = 30 * 1000;
|
||||||
|
const EXEC_TIMOUT = 30 * 1000;
|
||||||
|
|
||||||
|
export enum FlipperServerState {
|
||||||
|
CONNECTING,
|
||||||
|
CONNECTED,
|
||||||
|
DISCONNECTED,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFlipperServer(
|
||||||
|
onStateChange: (state: FlipperServerState) => void,
|
||||||
|
): Promise<FlipperServer> {
|
||||||
|
onStateChange(FlipperServerState.CONNECTING);
|
||||||
|
|
||||||
|
return new Promise<FlipperServer>((resolve, reject) => {
|
||||||
|
let initialConnectionTimeout: number | undefined = window.setTimeout(() => {
|
||||||
|
reject(
|
||||||
|
new Error('Failed to connect to flipper-server in a timely manner'),
|
||||||
|
);
|
||||||
|
}, CONNECTION_TIMEOUT);
|
||||||
|
|
||||||
|
const eventEmitter = new EventEmitter();
|
||||||
|
|
||||||
|
const socket = new ReconnectingWebSocket(`ws://${location.host}`);
|
||||||
|
const pendingRequests: Map<
|
||||||
|
number,
|
||||||
|
{
|
||||||
|
resolve: (data: any) => void;
|
||||||
|
reject: (data: any) => void;
|
||||||
|
timeout: ReturnType<typeof setTimeout>;
|
||||||
|
}
|
||||||
|
> = new Map();
|
||||||
|
let requestId = 0;
|
||||||
|
let connected = false;
|
||||||
|
|
||||||
|
socket.addEventListener('open', () => {
|
||||||
|
if (initialConnectionTimeout) {
|
||||||
|
resolve(flipperServer);
|
||||||
|
clearTimeout(initialConnectionTimeout);
|
||||||
|
initialConnectionTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
onStateChange(FlipperServerState.CONNECTED);
|
||||||
|
connected = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener('close', () => {
|
||||||
|
onStateChange(FlipperServerState.DISCONNECTED);
|
||||||
|
connected = false;
|
||||||
|
pendingRequests.forEach((r) =>
|
||||||
|
r.reject(new Error('flipper-server disconnected')),
|
||||||
|
);
|
||||||
|
pendingRequests.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener('message', ({data}) => {
|
||||||
|
const {event, payload} = JSON.parse(
|
||||||
|
data.toString(),
|
||||||
|
) as ServerWebSocketMessage;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case 'exec-response': {
|
||||||
|
console.debug('flipper-server: exec <<<', payload);
|
||||||
|
const entry = pendingRequests.get(payload.id);
|
||||||
|
if (!entry) {
|
||||||
|
console.warn(`Unknown request id `, payload.id);
|
||||||
|
} else {
|
||||||
|
pendingRequests.delete(payload.id);
|
||||||
|
clearTimeout(entry.timeout);
|
||||||
|
entry.resolve(payload.data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'exec-response-error': {
|
||||||
|
// TODO: Deserialize error
|
||||||
|
console.debug(
|
||||||
|
'flipper-server: exec <<< [SERVER ERROR]',
|
||||||
|
payload.id,
|
||||||
|
payload.data,
|
||||||
|
);
|
||||||
|
const entry = pendingRequests.get(payload.id);
|
||||||
|
if (!entry) {
|
||||||
|
console.warn(`flipper-server: Unknown request id `, payload.id);
|
||||||
|
} else {
|
||||||
|
pendingRequests.delete(payload.id);
|
||||||
|
clearTimeout(entry.timeout);
|
||||||
|
entry.reject(payload.data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'server-event': {
|
||||||
|
eventEmitter.emit(payload.event, payload.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.warn(
|
||||||
|
'flipper-server: received unknown message type',
|
||||||
|
data.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const flipperServer: FlipperServer = {
|
||||||
|
async connect() {},
|
||||||
|
close() {},
|
||||||
|
exec(command, ...args): any {
|
||||||
|
if (connected) {
|
||||||
|
const id = ++requestId;
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
console.debug('flipper-server: exec >>>', id, command, args);
|
||||||
|
|
||||||
|
pendingRequests.set(id, {
|
||||||
|
resolve,
|
||||||
|
reject,
|
||||||
|
timeout: setInterval(() => {
|
||||||
|
pendingRequests.delete(id);
|
||||||
|
reject(
|
||||||
|
new Error(`flipper-server: timeout for command '${command}'`),
|
||||||
|
);
|
||||||
|
}, EXEC_TIMOUT),
|
||||||
|
});
|
||||||
|
|
||||||
|
const execMessage = {
|
||||||
|
event: 'exec',
|
||||||
|
payload: {
|
||||||
|
id,
|
||||||
|
command,
|
||||||
|
args,
|
||||||
|
},
|
||||||
|
} as ExecWebSocketMessage;
|
||||||
|
socket.send(JSON.stringify(execMessage));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error('Not connected to Flipper server');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
on(event, callback) {
|
||||||
|
eventEmitter.on(event, callback);
|
||||||
|
},
|
||||||
|
off(event, callback) {
|
||||||
|
eventEmitter.off(event, callback);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -14,3 +14,4 @@ export {default as BaseDevice} from './devices/BaseDevice';
|
|||||||
export * from './globalObject';
|
export * from './globalObject';
|
||||||
export * from './plugins';
|
export * from './plugins';
|
||||||
export * from './flipperLibImplementation';
|
export * from './flipperLibImplementation';
|
||||||
|
export * from './client/FlipperServerClient';
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"flipper-common": "0.0.0",
|
"flipper-common": "0.0.0",
|
||||||
|
"flipper-frontend-core": "0.0.0",
|
||||||
"flipper-ui-core": "0.0.0",
|
"flipper-ui-core": "0.0.0",
|
||||||
"invariant": "^2.2.4",
|
"invariant": "^2.2.4",
|
||||||
"metro-runtime": "^0.70.2",
|
"metro-runtime": "^0.70.2",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import {getLogger, Logger, setLoggerInstance} from 'flipper-common';
|
import {getLogger, Logger, setLoggerInstance} from 'flipper-common';
|
||||||
import {initializeRenderHost} from './initializeRenderHost';
|
import {initializeRenderHost} from './initializeRenderHost';
|
||||||
import {createFlipperServer} from './flipperServerConnection';
|
import {createFlipperServer, FlipperServerState} from 'flipper-frontend-core';
|
||||||
|
|
||||||
document.getElementById('root')!.innerText = 'flipper-ui-browser started';
|
document.getElementById('root')!.innerText = 'flipper-ui-browser started';
|
||||||
|
|
||||||
@@ -27,7 +27,21 @@ async function start() {
|
|||||||
const logger = createDelegatedLogger();
|
const logger = createDelegatedLogger();
|
||||||
setLoggerInstance(logger);
|
setLoggerInstance(logger);
|
||||||
|
|
||||||
const flipperServer = await createFlipperServer();
|
const flipperServer = await createFlipperServer(
|
||||||
|
(state: FlipperServerState) => {
|
||||||
|
switch (state) {
|
||||||
|
case FlipperServerState.CONNECTING:
|
||||||
|
window.flipperShowError?.('Connecting to flipper-server...');
|
||||||
|
break;
|
||||||
|
case FlipperServerState.CONNECTED:
|
||||||
|
window?.flipperHideError?.();
|
||||||
|
break;
|
||||||
|
case FlipperServerState.DISCONNECTED:
|
||||||
|
window?.flipperShowError?.('Lost connection to flipper-server');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
await flipperServer.connect();
|
await flipperServer.connect();
|
||||||
const flipperServerConfig = await flipperServer.exec('get-config');
|
const flipperServerConfig = await flipperServer.exec('get-config');
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
{
|
{
|
||||||
"path": "../flipper-common"
|
"path": "../flipper-common"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "../flipper-frontend-core"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "../flipper-ui-core"
|
"path": "../flipper-ui-core"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user