Preserve client state after disconnect

Summary:
This diff introduces support for keeping clients around after they have disconnected. This is a pretty important debugging improvement, that will allow inspecting a device / app after it crashed for example.

With this diff, the current client is just kept around until it connects again, instead of throwing clients immediately away if they disconnect. After this change, ArchivedClients will only be created by imports / exports, and no longer by disconnects. Initially I played with improving the creation of archived devices, by migrating all plugin state over from the original client to the archive, but I discovered that is very prone, as it would be a lot of pointer redistribution (plugins would point to a different client / device etc). While in contrast, disconnected clients is already an existing concept in Flipper, so reusing that keeps all the changes relatively simple.

Note that we could potentially still reuse old clients around after reconnected, but it would become much harder to reason about how plugins would behave if they missed updates for a while, so throwing away the device / clients and starting with a fresh slate sounds safer. So I figured that chance to be too risky for now, but would probably be good follow up work.

Issues with import / export, UX, and making calls to to a disconnected client will be addressed in follow up diffs

Changelog: Clients will retain their state after being disconnected, until they reconnect again

Reviewed By: nikoant

Differential Revision: D26224677

fbshipit-source-id: feb9d241df2304341c2847fe7fd751ac54c045f6
This commit is contained in:
Michel Weststrate
2021-02-09 04:12:09 -08:00
committed by Facebook GitHub Bot
parent c43049d881
commit 7e1bf0f58b
18 changed files with 232 additions and 72 deletions

View File

@@ -35,7 +35,7 @@ import {processMessagesLater} from './utils/messageQueue';
import {emitBytesReceived} from './dispatcher/tracking';
import {debounce} from 'lodash';
import {batch} from 'react-redux';
import {_SandyPluginInstance} from 'flipper-plugin';
import {createState, _SandyPluginInstance} from 'flipper-plugin';
import {flipperMessagesClientPlugin} from './utils/self-inspection/plugins/FlipperMessagesClientPlugin';
import {getFlipperLibImplementation} from './utils/flipperLibImplementation';
import {freeze} from 'immer';
@@ -123,7 +123,7 @@ export interface FlipperClientConnection<D, M> {
}
export default class Client extends EventEmitter {
connected: boolean;
connected = createState(false);
id: string;
query: ClientQuery;
sdkVersion: number;
@@ -175,7 +175,7 @@ export default class Client extends EventEmitter {
device: BaseDevice,
) {
super();
this.connected = true;
this.connected.set(true);
this.plugins = plugins ? plugins : [];
this.backgroundPlugins = [];
this.connection = conn;
@@ -197,7 +197,7 @@ export default class Client extends EventEmitter {
conn.connectionStatus().subscribe({
onNext(payload) {
if (payload.kind == 'ERROR' || payload.kind == 'CLOSED') {
client.connected = false;
client.connected.set(false);
}
},
onSubscribe(subscription) {
@@ -324,8 +324,19 @@ export default class Client extends EventEmitter {
}
}
close() {
// connection lost, but Client might live on
disconnect() {
this.sandyPluginStates.forEach((instance) => {
instance.disconnect();
});
this.emit('close');
this.connected.set(false);
this.connection = undefined;
}
// clean up this client
destroy() {
this.disconnect();
this.plugins.forEach((pluginId) => this.stopPluginIfNeeded(pluginId, true));
}