Decouple JS device from Store
Summary: Made a start with decoupling JS device. Incomplete as there are still Electron deps. Reviewed By: timur-valiev Differential Revision: D30309257 fbshipit-source-id: b8002170cbbe8d68e1795ce7c12ffce4c8eac853
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a9c6351cf0
commit
3736cbc480
@@ -10,14 +10,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Store} from '../reducers/index';
|
import {Store} from '../reducers/index';
|
||||||
import {Logger} from '../fb-interfaces/Logger';
|
import {Logger} from '../fb-interfaces/Logger';
|
||||||
import {startFlipperServer} from '../server/FlipperServer';
|
import {FlipperServer} from '../server/FlipperServer';
|
||||||
import {selectClient, selectDevice} from '../reducers/connections';
|
import {selectClient, selectDevice} from '../reducers/connections';
|
||||||
import Client from '../Client';
|
import Client from '../Client';
|
||||||
import {notification} from 'antd';
|
import {notification} from 'antd';
|
||||||
|
|
||||||
export default async (store: Store, logger: Logger) => {
|
export default async (store: Store, logger: Logger) => {
|
||||||
const {enableAndroid, androidHome} = store.getState().settingsState;
|
const {enableAndroid, androidHome} = store.getState().settingsState;
|
||||||
const server = startFlipperServer(
|
const server = new FlipperServer(
|
||||||
{
|
{
|
||||||
enableAndroid,
|
enableAndroid,
|
||||||
androidHome,
|
androidHome,
|
||||||
@@ -101,7 +101,7 @@ export default async (store: Store, logger: Logger) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
server
|
server
|
||||||
.waitForServerStarted()
|
.start()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(
|
console.log(
|
||||||
'Flipper server started and accepting device / client connections',
|
'Flipper server started and accepting device / client connections',
|
||||||
|
|||||||
@@ -48,18 +48,18 @@ export interface FlipperServerConfig {
|
|||||||
serverPorts: ServerPorts;
|
serverPorts: ServerPorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function startFlipperServer(
|
|
||||||
config: FlipperServerConfig,
|
|
||||||
store: Store,
|
|
||||||
logger: Logger,
|
|
||||||
): FlipperServer {
|
|
||||||
const server = new FlipperServer(config, store, logger);
|
|
||||||
server.start();
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerState = 'pending' | 'starting' | 'started' | 'error' | 'closed';
|
type ServerState = 'pending' | 'starting' | 'started' | 'error' | 'closed';
|
||||||
|
|
||||||
|
// defaultConfig should be used for testing only, and disables by default all features
|
||||||
|
const defaultConfig: FlipperServerConfig = {
|
||||||
|
androidHome: '',
|
||||||
|
enableAndroid: false,
|
||||||
|
serverPorts: {
|
||||||
|
insecure: -1,
|
||||||
|
secure: -1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FlipperServer takes care of all incoming device & client connections.
|
* FlipperServer takes care of all incoming device & client connections.
|
||||||
* It will set up managers per device type, and create the incoming
|
* It will set up managers per device type, and create the incoming
|
||||||
@@ -69,7 +69,10 @@ type ServerState = 'pending' | 'starting' | 'started' | 'error' | 'closed';
|
|||||||
* using '.on'. All events are strongly typed.
|
* using '.on'. All events are strongly typed.
|
||||||
*/
|
*/
|
||||||
export class FlipperServer {
|
export class FlipperServer {
|
||||||
|
public config: FlipperServerConfig;
|
||||||
|
|
||||||
private readonly events = new EventEmitter();
|
private readonly events = new EventEmitter();
|
||||||
|
// server handles the incoming RSocket / WebSocket connections from Flipper clients
|
||||||
readonly server: ServerController;
|
readonly server: ServerController;
|
||||||
readonly disposers: ((() => void) | void)[] = [];
|
readonly disposers: ((() => void) | void)[] = [];
|
||||||
private readonly devices = new Map<string, BaseDevice>();
|
private readonly devices = new Map<string, BaseDevice>();
|
||||||
@@ -78,60 +81,14 @@ export class FlipperServer {
|
|||||||
|
|
||||||
// TODO: remove store argument
|
// TODO: remove store argument
|
||||||
constructor(
|
constructor(
|
||||||
public config: FlipperServerConfig,
|
config: Partial<FlipperServerConfig>,
|
||||||
/** @deprecated remove! */
|
/** @deprecated remove! */
|
||||||
public store: Store,
|
public store: Store,
|
||||||
public logger: Logger,
|
public logger: Logger,
|
||||||
) {
|
) {
|
||||||
this.server = new ServerController(logger, store);
|
this.config = {...defaultConfig, ...config};
|
||||||
|
const server = (this.server = new ServerController(this));
|
||||||
this.android = new AndroidDeviceManager(this);
|
this.android = new AndroidDeviceManager(this);
|
||||||
}
|
|
||||||
|
|
||||||
setServerState(state: ServerState, error?: Error) {
|
|
||||||
this.state = state;
|
|
||||||
this.emit('server-state', {state, error});
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForServerStarted() {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
switch (this.state) {
|
|
||||||
case 'closed':
|
|
||||||
return reject(new Error('Server was closed already'));
|
|
||||||
case 'error':
|
|
||||||
return reject(new Error('Server has errored already'));
|
|
||||||
case 'started':
|
|
||||||
return resolve();
|
|
||||||
default: {
|
|
||||||
const listener = ({
|
|
||||||
state,
|
|
||||||
error,
|
|
||||||
}: {
|
|
||||||
state: ServerState;
|
|
||||||
error: Error;
|
|
||||||
}) => {
|
|
||||||
switch (state) {
|
|
||||||
case 'error':
|
|
||||||
return reject(error);
|
|
||||||
case 'started':
|
|
||||||
return resolve();
|
|
||||||
case 'closed':
|
|
||||||
return reject(new Error('Server closed'));
|
|
||||||
}
|
|
||||||
this.events.off('server-state', listener);
|
|
||||||
};
|
|
||||||
this.events.on('server-state', listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @private */
|
|
||||||
async start() {
|
|
||||||
if (this.state !== 'pending') {
|
|
||||||
throw new Error('Server already started');
|
|
||||||
}
|
|
||||||
this.setServerState('starting');
|
|
||||||
const server = this.server;
|
|
||||||
|
|
||||||
server.addListener('new-client', (client: Client) => {
|
server.addListener('new-client', (client: Client) => {
|
||||||
this.emit('client-connected', client);
|
this.emit('client-connected', client);
|
||||||
@@ -214,9 +171,24 @@ export class FlipperServer {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setServerState(state: ServerState, error?: Error) {
|
||||||
|
this.state = state;
|
||||||
|
this.emit('server-state', {state, error});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts listening to parts and watching for devices
|
||||||
|
*/
|
||||||
|
async start() {
|
||||||
|
if (this.state !== 'pending') {
|
||||||
|
throw new Error('Server already started');
|
||||||
|
}
|
||||||
|
this.setServerState('starting');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await server.init();
|
await this.server.init();
|
||||||
await this.startDeviceListeners();
|
await this.startDeviceListeners();
|
||||||
this.setServerState('started');
|
this.setServerState('started');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import ServerAdapter, {
|
|||||||
ServerEventsListener,
|
ServerEventsListener,
|
||||||
} from './ServerAdapter';
|
} from './ServerAdapter';
|
||||||
import {createBrowserServer, createServer} from './ServerFactory';
|
import {createBrowserServer, createServer} from './ServerFactory';
|
||||||
|
import {FlipperServer} from '../FlipperServer';
|
||||||
|
|
||||||
type ClientInfo = {
|
type ClientInfo = {
|
||||||
connection: ClientConnection | null | undefined;
|
connection: ClientConnection | null | undefined;
|
||||||
@@ -70,29 +71,38 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
|||||||
certificateProvider: CertificateProvider;
|
certificateProvider: CertificateProvider;
|
||||||
connectionTracker: ConnectionTracker;
|
connectionTracker: ConnectionTracker;
|
||||||
|
|
||||||
logger: Logger;
|
flipperServer: FlipperServer;
|
||||||
store: Store;
|
|
||||||
|
|
||||||
timeHandler: NodeJS.Timeout | undefined;
|
timeHandler: NodeJS.Timeout | undefined;
|
||||||
|
|
||||||
constructor(logger: Logger, store: Store) {
|
constructor(flipperServer: FlipperServer) {
|
||||||
super();
|
super();
|
||||||
this.logger = logger;
|
this.flipperServer = flipperServer;
|
||||||
this.connections = new Map();
|
this.connections = new Map();
|
||||||
this.certificateProvider = new CertificateProvider(
|
this.certificateProvider = new CertificateProvider(
|
||||||
this,
|
this,
|
||||||
logger,
|
this.logger,
|
||||||
store.getState().settingsState,
|
this.store.getState().settingsState,
|
||||||
);
|
);
|
||||||
this.connectionTracker = new ConnectionTracker(logger);
|
this.connectionTracker = new ConnectionTracker(this.logger);
|
||||||
this.secureServer = null;
|
this.secureServer = null;
|
||||||
this.insecureServer = null;
|
this.insecureServer = null;
|
||||||
this.browserServer = null;
|
this.browserServer = null;
|
||||||
this.initialized = null;
|
this.initialized = null;
|
||||||
this.store = store;
|
|
||||||
this.timeHandler = undefined;
|
this.timeHandler = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get logger(): Logger {
|
||||||
|
return this.flipperServer.logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
get store(): Store {
|
||||||
|
return this.flipperServer.store;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the secure server configuration and starts any necessary servers.
|
* Loads the secure server configuration and starts any necessary servers.
|
||||||
* Initialisation is complete once the initialized promise is fullfilled at
|
* Initialisation is complete once the initialized promise is fullfilled at
|
||||||
@@ -117,7 +127,7 @@ class ServerController extends EventEmitter implements ServerEventsListener {
|
|||||||
reportPlatformFailures(this.initialized, 'initializeServer');
|
reportPlatformFailures(this.initialized, 'initializeServer');
|
||||||
|
|
||||||
if (GK.get('flipper_js_client_emulator')) {
|
if (GK.get('flipper_js_client_emulator')) {
|
||||||
initJsEmulatorIPC(this.store, this.logger, this, this.connections);
|
initJsEmulatorIPC(this.flipperServer, this.connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.initialized;
|
return this.initialized;
|
||||||
|
|||||||
@@ -16,11 +16,8 @@ import {
|
|||||||
} from '../../comms/ClientConnection';
|
} from '../../comms/ClientConnection';
|
||||||
import {ipcRenderer, remote, IpcRendererEvent} from 'electron';
|
import {ipcRenderer, remote, IpcRendererEvent} from 'electron';
|
||||||
import JSDevice from './JSDevice';
|
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 {buildClientId} from '../../../utils/clientUtils';
|
||||||
import {destroyDevice} from '../../../reducers/connections';
|
import {FlipperServer} from '../../FlipperServer';
|
||||||
|
|
||||||
const connections: Map<number, JSClientFlipperConnection> = new Map();
|
const connections: Map<number, JSClientFlipperConnection> = new Map();
|
||||||
|
|
||||||
@@ -31,9 +28,7 @@ function jsDeviceId(windowId: number): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function initJsEmulatorIPC(
|
export function initJsEmulatorIPC(
|
||||||
store: Store,
|
flipperServer: FlipperServer,
|
||||||
logger: Logger,
|
|
||||||
flipperServer: ServerController,
|
|
||||||
flipperConnections: Map<
|
flipperConnections: Map<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
@@ -48,10 +43,7 @@ export function initJsEmulatorIPC(
|
|||||||
const {windowId} = message;
|
const {windowId} = message;
|
||||||
const {plugins, appName} = message.payload;
|
const {plugins, appName} = message.payload;
|
||||||
const device = new JSDevice(jsDeviceId(windowId), 'jsEmulator', windowId);
|
const device = new JSDevice(jsDeviceId(windowId), 'jsEmulator', windowId);
|
||||||
store.dispatch({
|
flipperServer.registerDevice(device);
|
||||||
type: 'REGISTER_DEVICE',
|
|
||||||
payload: device,
|
|
||||||
});
|
|
||||||
|
|
||||||
const connection = new JSClientFlipperConnection(windowId);
|
const connection = new JSClientFlipperConnection(windowId);
|
||||||
connections.set(windowId, connection);
|
connections.set(windowId, connection);
|
||||||
@@ -70,8 +62,8 @@ export function initJsEmulatorIPC(
|
|||||||
clientId,
|
clientId,
|
||||||
query,
|
query,
|
||||||
connection,
|
connection,
|
||||||
logger,
|
flipperServer.logger,
|
||||||
store,
|
flipperServer.store,
|
||||||
plugins,
|
plugins,
|
||||||
device,
|
device,
|
||||||
);
|
);
|
||||||
@@ -87,8 +79,8 @@ export function initJsEmulatorIPC(
|
|||||||
status == ConnectionStatus.CLOSED
|
status == ConnectionStatus.CLOSED
|
||||||
) {
|
) {
|
||||||
console.debug(`Device disconnected ${client.id}`, 'server');
|
console.debug(`Device disconnected ${client.id}`, 'server');
|
||||||
flipperServer.removeConnection(client.id);
|
flipperServer.server.removeConnection(client.id);
|
||||||
destroyDevice(store, logger, jsDeviceId(windowId));
|
flipperServer.unregisterDevice(jsDeviceId(windowId));
|
||||||
connections.delete(windowId);
|
connections.delete(windowId);
|
||||||
availablePlugins.delete(windowId);
|
availablePlugins.delete(windowId);
|
||||||
}
|
}
|
||||||
@@ -98,8 +90,8 @@ export function initJsEmulatorIPC(
|
|||||||
.init()
|
.init()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(client);
|
console.log(client);
|
||||||
flipperServer.emit('new-client', client);
|
flipperServer.server.emit('new-client', client);
|
||||||
flipperServer.emit('clients-change');
|
flipperServer.server.emit('clients-change');
|
||||||
client.emit('plugins-change');
|
client.emit('plugins-change');
|
||||||
|
|
||||||
ipcRenderer.on(
|
ipcRenderer.on(
|
||||||
|
|||||||
Reference in New Issue
Block a user