Setup sdk for background plugin

Summary:
This diff sets up flipper for running plugins in background. This diff does the following

- Adds a function named `runInBackground` to the interface `FlipperPlugin` to make the plugins opt in to be run in background, default is false
- Changes the javascript side of the flipper to store the messages received by the plugins in background
- Process the stored messages when the plugin in background becomes active
- Currently I have just turned on network plugin to be in background mode.

- Remove the buffering from the network plugin, as it will run in background
- Write a batching layer to batch the messages and send to flipper.

Note: I haven't tested the wilde app yet, but the sample app works. I will remove the "[WIP]" from the title once I have tested it in wilde

Reviewed By: danielbuechele

Differential Revision: D10301403

fbshipit-source-id: 034eebf659a545d6b480a4ac1b73b0aa4b2f9797
This commit is contained in:
Pritesh Nandgaonkar
2018-10-11 15:19:19 -07:00
committed by Facebook Github Bot
parent 992ad68517
commit 5bbfa58909
11 changed files with 104 additions and 5 deletions

View File

@@ -38,6 +38,13 @@ public:
void didDisconnect() override { [_objCPlugin didDisconnect]; } void didDisconnect() override { [_objCPlugin didDisconnect]; }
bool runInBackground() override {
if ([_objCPlugin respondsToSelector:@selector(runInBackground)]) {
return [_objCPlugin runInBackground];
}
return false;
}
ObjCPlugin getObjCPlugin() { return _objCPlugin; } ObjCPlugin getObjCPlugin() { return _objCPlugin; }
private: private:

View File

@@ -124,6 +124,7 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
_cppClient->start(); _cppClient->start();
} }
- (void)stop - (void)stop
{ {
_cppClient->stop(); _cppClient->stop();

View File

@@ -36,4 +36,10 @@ longer valid to use.
*/ */
- (void)didDisconnect; - (void)didDisconnect;
/**
Returns true if the plugin is meant to be run in background too, otherwise it returns false.
*/
@optional
- (BOOL)runInBackground;
@end @end

View File

@@ -58,6 +58,11 @@ static const NSUInteger bufferSize = 500;
}); });
} }
- (BOOL)runInBackground {
return YES;
}
- (void)send:(NSString *)method - (void)send:(NSString *)method
sonarObject:(NSDictionary<NSString *, id> *)sonarObject { sonarObject:(NSDictionary<NSString *, id> *)sonarObject {
_connectionAccessQueue->async(^{ _connectionAccessQueue->async(^{

View File

@@ -43,6 +43,7 @@ export default class Client extends EventEmitter {
this.messageIdCounter = 0; this.messageIdCounter = 0;
this.logger = logger; this.logger = logger;
this.bufferedMessages = new Map();
this.broadcastCallbacks = new Map(); this.broadcastCallbacks = new Map();
this.requestCallbacks = new Map(); this.requestCallbacks = new Map();
@@ -77,6 +78,7 @@ export default class Client extends EventEmitter {
connection: ReactiveSocket; connection: ReactiveSocket;
responder: PartialResponder; responder: PartialResponder;
bufferedMessages: Map<string, Array<Object>>;
broadcastCallbacks: Map<?string, Map<string, Set<Function>>>; broadcastCallbacks: Map<?string, Map<string, Set<Function>>>;
requestCallbacks: Map< requestCallbacks: Map<
@@ -163,7 +165,11 @@ export default class Client extends EventEmitter {
} }
const methodCallbacks: ?Set<Function> = apiCallbacks.get(params.method); const methodCallbacks: ?Set<Function> = apiCallbacks.get(params.method);
if (methodCallbacks) { if (this.selectedPlugin != params.api) {
this.bufferMessage(params);
return;
}
if (methodCallbacks && methodCallbacks.size > 0) {
for (const callback of methodCallbacks) { for (const callback of methodCallbacks) {
callback(params.params); callback(params.params);
} }
@@ -188,6 +194,39 @@ 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<Function> = 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() { toJSON() {
return `<Client#${this.id}>`; return `<Client#${this.id}>`;
} }

View File

@@ -119,6 +119,9 @@ class PluginContainer extends Component<Props, State> {
if (ref && target) { if (ref && target) {
activateMenuItems(ref); activateMenuItems(ref);
ref._init(); ref._init();
if (target instanceof Client) {
target.readBufferedMessages(ref.constructor.id);
}
this.props.logger.trackTimeSince(`activePlugin-${ref.constructor.id}`); this.props.logger.trackTimeSince(`activePlugin-${ref.constructor.id}`);
this.plugin = ref; this.plugin = ref;
} }
@@ -136,7 +139,13 @@ class PluginContainer extends Component<Props, State> {
key: pluginKey, key: pluginKey,
logger: this.props.logger, logger: this.props.logger,
persistedState: pluginStates[pluginKey] || {}, persistedState: pluginStates[pluginKey] || {},
setPersistedState: state => setPluginState({pluginKey, state}), setPersistedState: state => {
// We are using setTimout here to wait for previous state updated to
// finish before triggering a new state update. Otherwise this can
// cause race conditions, with multiple state updates happening at the
// same time.
setTimeout(() => setPluginState({pluginKey, state}), 0);
},
target, target,
deepLinkPayload: this.props.deepLinkPayload, deepLinkPayload: this.props.deepLinkPayload,
ref: this.refChanged, ref: this.refChanged,

View File

@@ -13,6 +13,12 @@ import type Client from '../Client.js';
export default (store: Store, logger: Logger) => { export default (store: Store, logger: Logger) => {
const server = new Server(logger); const server = new Server(logger);
store.subscribe(() => {
let currentState = store.getState();
currentState.connections.clients.forEach((client: Client) => {
client.selectedPlugin = currentState.connections.selectedPlugin;
});
});
server.addListener('new-client', (client: Client) => { server.addListener('new-client', (client: Client) => {
store.dispatch({ store.dispatch({
type: 'NEW_CLIENT', type: 'NEW_CLIENT',

View File

@@ -79,6 +79,19 @@ void FlipperClient::removePlugin(std::shared_ptr<FlipperPlugin> plugin) {
}); });
} }
void FlipperClient::startBackgroundPlugins() {
std::cout << "Activating Background Plugins..." << std::endl;
for (std::map<std::string, std::shared_ptr<FlipperPlugin>>::iterator it=plugins_.begin(); it!=plugins_.end(); ++it) {
std::cout << it->first << std::endl;
if (it->second.get()->runInBackground()) {
auto& conn = connections_[it->first];
conn = std::make_shared<FlipperConnectionImpl>(socket_.get(),it->first);
it->second.get()->didConnect(conn);
}
}
}
std::shared_ptr<FlipperPlugin> FlipperClient::getPlugin( std::shared_ptr<FlipperPlugin> FlipperClient::getPlugin(
const std::string& identifier) { const std::string& identifier) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
@@ -113,6 +126,7 @@ void FlipperClient::onConnected() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
connected_ = true; connected_ = true;
startBackgroundPlugins();
} }
void FlipperClient::onDisconnected() { void FlipperClient::onDisconnected() {
@@ -161,7 +175,9 @@ void FlipperClient::onMessageReceived(const dynamic& message) {
auto& conn = connections_[plugin->identifier()]; auto& conn = connections_[plugin->identifier()];
conn = std::make_shared<FlipperConnectionImpl>( conn = std::make_shared<FlipperConnectionImpl>(
socket_.get(), plugin->identifier()); socket_.get(), plugin->identifier());
if (!plugin.get()->runInBackground()) {
plugin->didConnect(conn); plugin->didConnect(conn);
}
return; return;
} }
@@ -173,7 +189,9 @@ void FlipperClient::onMessageReceived(const dynamic& message) {
method.getString()); method.getString());
} }
const auto plugin = plugins_.at(identifier); const auto plugin = plugins_.at(identifier);
if (!plugin.get()->runInBackground()) {
disconnect(plugin); disconnect(plugin);
}
return; return;
} }

View File

@@ -98,6 +98,7 @@ class FlipperClient : public FlipperConnectionManager::Callbacks {
void performAndReportError(const std::function<void()>& func); void performAndReportError(const std::function<void()>& func);
void disconnect(std::shared_ptr<FlipperPlugin> plugin); void disconnect(std::shared_ptr<FlipperPlugin> plugin);
void startBackgroundPlugins();
}; };
} // namespace flipper } // namespace flipper

View File

@@ -36,6 +36,13 @@ class FlipperPlugin {
provided in didConnect is no longer valid to use. provided in didConnect is no longer valid to use.
*/ */
virtual void didDisconnect() = 0; virtual void didDisconnect() = 0;
/**
Returns true if the plugin is meant to be run in background too, otherwise it returns false.
*/
virtual bool runInBackground() {
return false;
}
}; };
} // namespace flipper } // namespace flipper