in desktop/flipper-ui-core/src/Client.tsx [339:447]
onMessage(msg: string) {
if (typeof msg !== 'string') {
return;
}
batch(() => {
let rawData;
try {
rawData = freeze(JSON.parse(msg), true);
} catch (err) {
console.error(`Invalid JSON: ${msg}`, 'clientMessage');
return;
}
const data: {
id?: number;
method?: string;
params?: Params;
success?: Object;
error?: ClientErrorType;
} = rawData;
const {id, method} = data;
if (isFlipperMessageDebuggingEnabled()) {
registerFlipperDebugMessage({
device: this.device?.displayTitle(),
app: this.query.app,
flipperInternalMethod: method,
plugin: data.params?.api,
pluginMethod: data.params?.method,
payload: data.params?.params,
direction: 'toFlipper:message',
});
}
if (id == null) {
const {error} = data;
if (error != null) {
console.error(
`Error received from device ${
method ? `when calling ${method}` : ''
}: ${error.message} + \nDevice Stack Trace: ${error.stacktrace}`,
'deviceError',
);
handleError(this.store, this.device, error);
} else if (method === 'refreshPlugins') {
this.refreshPlugins();
} else if (method === 'execute') {
if (!data.params) {
throw new Error('expected params');
}
const params: Params = data.params;
const bytes = msg.length * 2; // string lengths are measured in UTF-16 units (not characters), so 2 bytes per char
emitBytesReceived(params.api, bytes);
if (bytes > 5 * 1024 * 1024) {
console.warn(
`Plugin '${params.api}' received excessively large message for '${
params.method
}': ${Math.round(bytes / 1024)}kB`,
);
}
const persistingPlugin: PluginDefinition | undefined =
this.store.getState().plugins.clientPlugins.get(params.api) ||
this.store.getState().plugins.devicePlugins.get(params.api);
let handled = false; // This is just for analysis
if (
persistingPlugin &&
((persistingPlugin as any).persistedStateReducer ||
// only send messages to enabled sandy plugins
this.sandyPluginStates.has(params.api))
) {
handled = true;
const pluginKey = getPluginKey(
this.id,
{serial: this.query.device_id},
params.api,
);
if (!this.messageBuffer[pluginKey]) {
this.messageBuffer[pluginKey] = {
plugin: (this.sandyPluginStates.get(params.api) ??
persistingPlugin) as any,
messages: [params],
};
} else {
this.messageBuffer[pluginKey].messages.push(params);
}
this.flushMessageBufferDebounced();
}
const apiCallbacks = this.broadcastCallbacks.get(params.api);
if (apiCallbacks) {
const methodCallbacks = apiCallbacks.get(params.method);
if (methodCallbacks) {
for (const callback of methodCallbacks) {
handled = true;
callback(params.params);
}
}
}
if (!handled && !isProduction()) {
console.warn(`Unhandled message ${params.api}.${params.method}`);
}
}
return; // method === 'execute'
}
});
}