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:
committed by
Facebook Github Bot
parent
992ad68517
commit
5bbfa58909
@@ -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:
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ using WrapperPlugin = facebook::flipper::FlipperCppWrapperPlugin;
|
|||||||
_cppClient->start();
|
_cppClient->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)stop
|
- (void)stop
|
||||||
{
|
{
|
||||||
_cppClient->stop();
|
_cppClient->stop();
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(^{
|
||||||
|
|||||||
@@ -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}>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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());
|
||||||
plugin->didConnect(conn);
|
if (!plugin.get()->runInBackground()) {
|
||||||
|
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);
|
||||||
disconnect(plugin);
|
if (!plugin.get()->runInBackground()) {
|
||||||
|
disconnect(plugin);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ void FlipperConnectionManagerImpl::start() {
|
|||||||
folly::makeFuture()
|
folly::makeFuture()
|
||||||
.via(flipperEventBase_->getEventBase())
|
.via(flipperEventBase_->getEventBase())
|
||||||
.delayed(std::chrono::milliseconds(0))
|
.delayed(std::chrono::milliseconds(0))
|
||||||
.thenValue([this, step](auto&&){ step->complete(); startSync(); });
|
.thenValue([this, step](auto&&){ step->complete(); startSync();});
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlipperConnectionManagerImpl::startSync() {
|
void FlipperConnectionManagerImpl::startSync() {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user