diff --git a/src/Client.js b/src/Client.js index 19296a909..73a808e12 100644 --- a/src/Client.js +++ b/src/Client.js @@ -8,6 +8,7 @@ import type {FlipperPlugin} from './plugin.js'; import type {App} from './App.js'; import type Logger from './fb-stubs/Logger.js'; +import type {Store} from './reducers/index.js'; import {clientPlugins} from './plugins/index.js'; import {ReactiveSocket, PartialResponder} from 'rsocket-core'; @@ -32,6 +33,7 @@ export default class Client extends EventEmitter { query: ClientQuery, conn: ReactiveSocket, logger: Logger, + store: Store, ) { super(); @@ -42,8 +44,8 @@ export default class Client extends EventEmitter { this.query = query; this.messageIdCounter = 0; this.logger = logger; + this.store = store; - this.bufferedMessages = new Map(); this.broadcastCallbacks = new Map(); this.requestCallbacks = new Map(); @@ -77,8 +79,8 @@ export default class Client extends EventEmitter { plugins: Plugins; connection: ReactiveSocket; responder: PartialResponder; + store: Store; - bufferedMessages: Map>; broadcastCallbacks: Map>>; requestCallbacks: Map< @@ -159,19 +161,38 @@ export default class Client extends EventEmitter { const params = data.params; invariant(params, 'expected params'); - const apiCallbacks = this.broadcastCallbacks.get(params.api); - if (!apiCallbacks) { - return; - } + const persistingPlugin: ?Class> = clientPlugins.find( + (p: Class>) => + p.id === params.api && p.persistedStateReducer, + ); - const methodCallbacks: ?Set = apiCallbacks.get(params.method); - if (this.selectedPlugin != params.api) { - this.bufferMessage(params); - return; - } - if (methodCallbacks && methodCallbacks.size > 0) { - for (const callback of methodCallbacks) { - callback(params.params); + if (persistingPlugin) { + const pluginKey = `${this.id}#${params.api}`; + const persistedState = this.store.getState().pluginStates[pluginKey]; + this.store.dispatch({ + type: 'SET_PLUGIN_STATE', + payload: { + pluginKey, + // $FlowFixMe: We checked persistedStateReducer exists + state: persistingPlugin.persistedStateReducer( + persistedState, + params.params, + ), + }, + }); + } else { + const apiCallbacks = this.broadcastCallbacks.get(params.api); + if (!apiCallbacks) { + return; + } + + const methodCallbacks: ?Set = apiCallbacks.get( + params.method, + ); + if (methodCallbacks) { + for (const callback of methodCallbacks) { + callback(params.params); + } } } } @@ -194,39 +215,6 @@ export default class Client extends EventEmitter { } } - readBufferedMessages(id: string) { - const paramsArray = this.bufferedMessages.get(id); - if (!paramsArray) { - return; - } - paramsArray.forEach((params, i) => - setTimeout(() => { - const apiCallbacks = this.broadcastCallbacks.get(params.api); - if (!apiCallbacks) { - return; - } - - const methodCallbacks: ?Set = apiCallbacks.get(params.method); - if (methodCallbacks) { - for (const callback of methodCallbacks) { - callback(params.params); - } - } - }, i * 20), - ); - this.bufferedMessages.delete(id); - } - - bufferMessage(msg: Object) { - const arr = this.bufferedMessages.get(msg.api); - if (arr) { - arr.push(msg); - this.bufferedMessages.set(msg.api, arr); - } else { - this.bufferedMessages.set(msg.api, [msg]); - } - } - toJSON() { return ``; } diff --git a/src/PluginContainer.js b/src/PluginContainer.js index 283660666..e008b0ac7 100644 --- a/src/PluginContainer.js +++ b/src/PluginContainer.js @@ -6,6 +6,7 @@ */ import type {FlipperPlugin, FlipperBasePlugin} from './plugin.js'; import type LogManager from './fb-stubs/Logger'; +import type Client from './Client.js'; import type BaseDevice from './devices/BaseDevice.js'; import type {Props as PluginProps} from './plugin'; @@ -19,7 +20,6 @@ import { styled, } from 'flipper'; import React from 'react'; -import Client from './Client.js'; import {connect} from 'react-redux'; import {setPluginState} from './reducers/pluginStates.js'; import {setActiveNotifications} from './reducers/notifications.js'; @@ -119,9 +119,6 @@ class PluginContainer extends Component { if (ref && target) { activateMenuItems(ref); ref._init(); - if (target instanceof Client) { - target.readBufferedMessages(ref.constructor.id); - } this.props.logger.trackTimeSince(`activePlugin-${ref.constructor.id}`); this.plugin = ref; } diff --git a/src/__tests__/server.electron.js b/src/__tests__/server.electron.js index dae62eac0..557bd4751 100644 --- a/src/__tests__/server.electron.js +++ b/src/__tests__/server.electron.js @@ -7,11 +7,14 @@ import Server, {SECURE_PORT, INSECURE_PORT} from '../server.js'; import LogManager from '../fb-stubs/Logger'; +import reducers from '../reducers/index.js'; +import configureStore from 'redux-mock-store'; import path from 'path'; import os from 'os'; import fs from 'fs'; let server; +const mockStore = configureStore([])(reducers(undefined, {type: 'INIT'})); beforeAll(() => { // create config directory, which is usually created by static/index.js @@ -20,7 +23,7 @@ beforeAll(() => { fs.mkdirSync(flipperDir); } - server = new Server(new LogManager()); + server = new Server(new LogManager(), mockStore); }); test('servers starting at ports', done => { diff --git a/src/dispatcher/server.js b/src/dispatcher/server.js index a2f996f84..8eab4b1cf 100644 --- a/src/dispatcher/server.js +++ b/src/dispatcher/server.js @@ -12,13 +12,8 @@ import type Logger from '../fb-stubs/Logger.js'; import type Client from '../Client.js'; export default (store: Store, logger: Logger) => { - const server = new Server(logger); - store.subscribe(() => { - let currentState = store.getState(); - currentState.connections.clients.forEach((client: Client) => { - client.selectedPlugin = currentState.connections.selectedPlugin; - }); - }); + const server = new Server(logger, store); + server.addListener('new-client', (client: Client) => { store.dispatch({ type: 'NEW_CLIENT', diff --git a/src/plugin.js b/src/plugin.js index 53f92c6f5..5a67ff781 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -113,6 +113,8 @@ export class FlipperPlugin extends FlipperBasePlugin< A, P, > { + static persistedStateReducer: ?(persistedState: P, data: Object) => $Shape

; + constructor(props: Props<*>) { super(props); const {id} = this.constructor; @@ -163,6 +165,10 @@ export class FlipperPlugin extends FlipperBasePlugin< } _teardown() { + if (this.constructor.persistedStateReducer) { + // do not tear down when persistedStateReducer is set + return; + } // automatically unsubscribe subscriptions for (const {method, callback} of this.subscriptions) { this.realClient.unsubscribe(this.constructor.id, method, callback); diff --git a/src/server.js b/src/server.js index c95b90d2d..f07018b20 100644 --- a/src/server.js +++ b/src/server.js @@ -8,6 +8,7 @@ import type {SecureServerConfig} from './utils/CertificateProvider'; import type Logger from './fb-stubs/Logger'; import type {ClientQuery} from './Client.js'; +import type {Store} from './reducers/index.js'; import CertificateProvider from './utils/CertificateProvider'; import {RSocketServer, ReactiveSocket} from 'rsocket-core'; @@ -42,13 +43,15 @@ export default class Server extends EventEmitter { certificateProvider: CertificateProvider; connectionTracker: ConnectionTracker; logger: Logger; + store: Store; - constructor(logger: Logger) { + constructor(logger: Logger, store: Store) { super(); this.logger = logger; this.connections = new Map(); this.certificateProvider = new CertificateProvider(this, logger); this.connectionTracker = new ConnectionTracker(logger); + this.store = store; this.init(); } @@ -244,7 +247,7 @@ export default class Server extends EventEmitter { const id = `${query.app}-${query.os}-${query.device}-${query.device_id}`; console.debug(`Device connected: ${id}`, 'server'); - const client = new Client(id, query, conn, this.logger); + const client = new Client(id, query, conn, this.logger, this.store); const info = { client,