Make flipper messages generally available, remove self inspection infra structure

Summary:
Changelog: Flipper message debugging moved from a separate device to the console tab

This makes message debugging easier accessible, and in production (recently requested at GH). Also it clears up a lot of infra that was created just to make flipper a self recursive inspection device + a separate plugin. While fun, a hardcoded setup is just a bit more simpler (no exception rules and better static verification)

Reviewed By: nikoant

Differential Revision: D29487811

fbshipit-source-id: b412adc3ef5bd831001333443b432b6c0f934a5e
This commit is contained in:
Michel Weststrate
2021-07-01 01:58:41 -07:00
committed by Facebook GitHub Bot
parent 8da7495a1a
commit 328ba9513c
15 changed files with 332 additions and 550 deletions

View File

@@ -9,7 +9,7 @@
import {notification, Typography} from 'antd';
import React from 'react';
import {ConsoleLogs} from '../chrome/ConsoleLogs';
import {FlipperDevTools} from '../chrome/FlipperDevTools';
import {setStaticView} from '../reducers/connections';
import {getStore} from '../store';
import {Layout} from '../ui';
@@ -29,7 +29,7 @@ export function showErrorNotification(message: string, description?: string) {
See{' '}
<Link
onClick={() => {
getStore().dispatch(setStaticView(ConsoleLogs));
getStore().dispatch(setStaticView(FlipperDevTools));
notification.close(key);
}}>
logs

View File

@@ -1,54 +0,0 @@
/**
* 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 {FlipperConnection, FlipperPlugin} from 'flipper-client-sdk';
export type MessageInfo = {
device?: string;
app: string;
flipperInternalMethod?: string;
plugin?: string;
pluginMethod?: string;
payload?: any;
direction:
| 'toClient:call'
| 'toClient:send'
| 'toFlipper:message'
| 'toFlipper:response';
};
export class FlipperMessagesClientPlugin implements FlipperPlugin {
protected connection: FlipperConnection | null = null;
onConnect(connection: FlipperConnection): void {
this.connection = connection;
}
onDisconnect(): void {
this.connection = null;
}
getId(): string {
return 'flipper-messages';
}
runInBackground(): boolean {
return true;
}
newMessage(message: MessageInfo) {
this.connection?.send('newMessage', message);
}
isConnected() {
return this.connection != null;
}
}
export const flipperMessagesClientPlugin = new FlipperMessagesClientPlugin();

View File

@@ -1,117 +0,0 @@
/**
* 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 {FlipperClientConnection} from '../../Client';
import {Flowable, Single} from 'rsocket-flowable';
import {Payload, ConnectionStatus, ISubscriber} from 'rsocket-types';
import {FlipperClient} from 'flipper-client-sdk';
// somehow linter isn't happy with next import so type definitions are copied
// import {IFutureSubject} from 'rsocket-flowable/Single';
type CancelCallback = () => void;
interface IFutureSubject<T> {
onComplete: (value: T) => void;
onError: (error: Error) => void;
onSubscribe: (cancel: CancelCallback | null | undefined) => void;
}
export class SelfInspectionFlipperClient<M>
extends FlipperClient
implements FlipperClientConnection<string, M>
{
connStatusSubscribers: Set<ISubscriber<ConnectionStatus>> = new Set();
connStatus: ConnectionStatus = {kind: 'CONNECTED'};
connectionStatus(): Flowable<ConnectionStatus> {
return new Flowable<ConnectionStatus>((subscriber) => {
subscriber.onSubscribe({
cancel: () => {
this.connStatusSubscribers.delete(subscriber);
},
request: (_) => {
this.connStatusSubscribers.add(subscriber);
subscriber.onNext(this.connStatus);
},
});
});
}
close(): void {
this.connStatus = {kind: 'CLOSED'};
this.connStatusSubscribers.forEach((subscriber) => {
subscriber.onNext(this.connStatus);
});
}
fireAndForget(payload: Payload<string, M>): void {
if (payload.data == null) {
return;
}
const message = JSON.parse(payload.data) as {
method: string;
id: number;
params: any;
};
this.onMessageReceived(message);
}
activeRequests = new Map<number, IFutureSubject<Payload<string, M>>>();
requestResponse(payload: Payload<string, M>): Single<Payload<string, M>> {
return new Single((subscriber) => {
subscriber.onSubscribe(() => {});
if (payload.data == null) {
subscriber.onError(new Error('empty payload'));
return;
}
const message = JSON.parse(payload.data) as {
method: string;
id: number;
params: any;
};
this.activeRequests.set(message.id, subscriber);
this.onMessageReceived(message);
});
}
// Client methods
messagesHandler: ((message: any) => void) | undefined;
start(_appName: string): void {
this.onConnect();
}
stop(): void {}
sendData(payload: any): void {
if (payload['success'] != null) {
const message = payload as {id: number; success: unknown};
const sub = this.activeRequests.get(message.id);
sub?.onComplete({data: JSON.stringify(message)});
this.activeRequests.delete(message.id);
return;
}
this.messagesHandler && this.messagesHandler(payload);
}
isAvailable(): boolean {
return true;
}
subscibeForClientMessages(handler: (message: any) => void) {
this.messagesHandler = handler;
}
}
export const selfInspectionClient = new SelfInspectionFlipperClient();

View File

@@ -1,94 +0,0 @@
/**
* 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 {FlipperClientConnection} from '../../Client';
import {Store} from '../../reducers';
import {Logger} from '../../fb-interfaces/Logger';
import Server from '../../server';
import {buildClientId} from '../clientUtils';
import {selfInspectionClient} from './selfInspectionClient';
import {flipperMessagesClientPlugin} from './plugins/FlipperMessagesClientPlugin';
import {destroyDevice} from '../../reducers/connections';
export function initSelfInpector(
store: Store,
logger: Logger,
flipperServer: Server,
flipperConnections: Map<
string,
{
connection: FlipperClientConnection<any, any> | null | undefined;
client: Client;
}
>,
) {
const appName = 'Flipper';
selfInspectionClient.addPlugin(flipperMessagesClientPlugin);
const hostDevice = store
.getState()
.connections.devices.find((d) => d.serial === '');
if (!hostDevice) {
console.error('Failed to find host device for self inspector');
return;
}
const query: ClientQuery = {
app: appName,
os: 'MacOS',
device: 'emulator',
device_id: '',
sdk_version: 4,
};
const clientId = buildClientId(query);
const client = new Client(
clientId,
query,
selfInspectionClient,
logger,
store,
undefined,
hostDevice,
);
flipperConnections.set(clientId, {
connection: selfInspectionClient,
client: client,
});
selfInspectionClient.connectionStatus().subscribe({
onNext(payload) {
if (payload.kind == 'ERROR' || payload.kind == 'CLOSED') {
console.debug(`Device disconnected ${client.id}`, 'server');
flipperServer.removeConnection(client.id);
destroyDevice(store, logger, client.id);
}
},
onSubscribe(subscription) {
subscription.request(Number.MAX_SAFE_INTEGER);
},
});
client.init().then(() => {
flipperServer.emit('new-client', client);
flipperServer.emit('clients-change');
client.emit('plugins-change');
selfInspectionClient.subscibeForClientMessages((payload: any) => {
// let's break the possible recursion problems here
// for example we want to send init plugin message, but store state is being updated when we enable plugins
setImmediate(() => {
client.onMessage(JSON.stringify(payload));
});
});
});
}