Plugin Marketplace state refresh and cache
Summary: Separate dispatcher for periodic refreshing available plugins data from the Marketplace backend and caching it locally. The plugin auto update downloader subscribes to these state refreshes and automatically schedules plugin update downloads when required. Reviewed By: passy Differential Revision: D25360897 fbshipit-source-id: 5b6d95b63ff47b8ae9ad8b12e2480d1fed524ca5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5b26f36672
commit
f3e1a48ff3
@@ -56,6 +56,7 @@ Object {
|
|||||||
"disabledPlugins": Array [],
|
"disabledPlugins": Array [],
|
||||||
"failedPlugins": Array [],
|
"failedPlugins": Array [],
|
||||||
"gatekeepedPlugins": Array [],
|
"gatekeepedPlugins": Array [],
|
||||||
|
"marketplacePlugins": Array [],
|
||||||
"selectedPlugins": Array [],
|
"selectedPlugins": Array [],
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
12
desktop/app/src/dispatcher/fb-stubs/pluginMarketplace.tsx
Normal file
12
desktop/app/src/dispatcher/fb-stubs/pluginMarketplace.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
// Marketplace is not implemented in public version of Flipper
|
||||||
|
};
|
||||||
@@ -21,6 +21,7 @@ import user from './user';
|
|||||||
import pluginManager from './pluginManager';
|
import pluginManager from './pluginManager';
|
||||||
import reactNative from './reactNative';
|
import reactNative from './reactNative';
|
||||||
import pluginAutoUpdate from './fb-stubs/pluginAutoUpdate';
|
import pluginAutoUpdate from './fb-stubs/pluginAutoUpdate';
|
||||||
|
import pluginMarketplace from './fb-stubs/pluginMarketplace';
|
||||||
|
|
||||||
import {Logger} from '../fb-interfaces/Logger';
|
import {Logger} from '../fb-interfaces/Logger';
|
||||||
import {Store} from '../reducers/index';
|
import {Store} from '../reducers/index';
|
||||||
@@ -33,7 +34,6 @@ export default function (store: Store, logger: Logger): () => Promise<void> {
|
|||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
remote.globalShortcut.unregisterAll();
|
remote.globalShortcut.unregisterAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
const dispatchers: Array<Dispatcher> = [
|
const dispatchers: Array<Dispatcher> = [
|
||||||
application,
|
application,
|
||||||
store.getState().settingsState.enableAndroid ? androidDevice : null,
|
store.getState().settingsState.enableAndroid ? androidDevice : null,
|
||||||
@@ -48,6 +48,7 @@ export default function (store: Store, logger: Logger): () => Promise<void> {
|
|||||||
pluginManager,
|
pluginManager,
|
||||||
reactNative,
|
reactNative,
|
||||||
pluginAutoUpdate,
|
pluginAutoUpdate,
|
||||||
|
pluginMarketplace,
|
||||||
].filter(notNull);
|
].filter(notNull);
|
||||||
const globalCleanup = dispatchers
|
const globalCleanup = dispatchers
|
||||||
.map((dispatcher) => dispatcher(store, logger))
|
.map((dispatcher) => dispatcher(store, logger))
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ test('add clientPlugin', () => {
|
|||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
selectedPlugins: [],
|
selectedPlugins: [],
|
||||||
|
marketplacePlugins: [],
|
||||||
},
|
},
|
||||||
registerPlugins([testPlugin]),
|
registerPlugins([testPlugin]),
|
||||||
);
|
);
|
||||||
@@ -50,6 +51,7 @@ test('add devicePlugin', () => {
|
|||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
selectedPlugins: [],
|
selectedPlugins: [],
|
||||||
|
marketplacePlugins: [],
|
||||||
},
|
},
|
||||||
registerPlugins([testDevicePlugin]),
|
registerPlugins([testDevicePlugin]),
|
||||||
);
|
);
|
||||||
@@ -65,6 +67,7 @@ test('do not add plugin twice', () => {
|
|||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
selectedPlugins: [],
|
selectedPlugins: [],
|
||||||
|
marketplacePlugins: [],
|
||||||
},
|
},
|
||||||
registerPlugins([testPlugin, testPlugin]),
|
registerPlugins([testPlugin, testPlugin]),
|
||||||
);
|
);
|
||||||
@@ -95,6 +98,7 @@ test('add gatekeeped plugin', () => {
|
|||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
selectedPlugins: [],
|
selectedPlugins: [],
|
||||||
|
marketplacePlugins: [],
|
||||||
},
|
},
|
||||||
addGatekeepedPlugins(gatekeepedPlugins),
|
addGatekeepedPlugins(gatekeepedPlugins),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export type State = {
|
|||||||
pluginStates: PluginStatesState;
|
pluginStates: PluginStatesState;
|
||||||
pluginMessageQueue: PluginMessageQueueState;
|
pluginMessageQueue: PluginMessageQueueState;
|
||||||
notifications: NotificationsState & PersistPartial;
|
notifications: NotificationsState & PersistPartial;
|
||||||
plugins: PluginsState;
|
plugins: PluginsState & PersistPartial;
|
||||||
user: UserState & PersistPartial;
|
user: UserState & PersistPartial;
|
||||||
settingsState: SettingsState & PersistPartial;
|
settingsState: SettingsState & PersistPartial;
|
||||||
launcherSettingsState: LauncherSettingsState & PersistPartial;
|
launcherSettingsState: LauncherSettingsState & PersistPartial;
|
||||||
@@ -141,7 +141,14 @@ export default combineReducers<State, Actions>({
|
|||||||
},
|
},
|
||||||
notifications,
|
notifications,
|
||||||
),
|
),
|
||||||
|
plugins: persistReducer<PluginsState, Actions>(
|
||||||
|
{
|
||||||
|
key: 'plugins',
|
||||||
|
storage,
|
||||||
|
whitelist: ['marketplacePlugins'],
|
||||||
|
},
|
||||||
plugins,
|
plugins,
|
||||||
|
),
|
||||||
supportForm,
|
supportForm,
|
||||||
pluginManager,
|
pluginManager,
|
||||||
user: persistReducer(
|
user: persistReducer(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {DevicePluginMap, ClientPluginMap, PluginDefinition} from '../plugin';
|
import {DevicePluginMap, ClientPluginMap, PluginDefinition} from '../plugin';
|
||||||
import {PluginDetails} from 'flipper-plugin-lib';
|
import {PluginDetails, DownloadablePluginDetails} from 'flipper-plugin-lib';
|
||||||
import {Actions} from '.';
|
import {Actions} from '.';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
||||||
@@ -20,6 +20,7 @@ export type State = {
|
|||||||
disabledPlugins: Array<PluginDetails>;
|
disabledPlugins: Array<PluginDetails>;
|
||||||
failedPlugins: Array<[PluginDetails, string]>;
|
failedPlugins: Array<[PluginDetails, string]>;
|
||||||
selectedPlugins: Array<string>;
|
selectedPlugins: Array<string>;
|
||||||
|
marketplacePlugins: Array<DownloadablePluginDetails>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RegisterPluginAction = {
|
export type RegisterPluginAction = {
|
||||||
@@ -44,6 +45,10 @@ export type Action =
|
|||||||
| {
|
| {
|
||||||
type: 'SELECTED_PLUGINS';
|
type: 'SELECTED_PLUGINS';
|
||||||
payload: Array<string>;
|
payload: Array<string>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'MARKETPLACE_PLUGINS';
|
||||||
|
payload: Array<DownloadablePluginDetails>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const INITIAL_STATE: State = {
|
const INITIAL_STATE: State = {
|
||||||
@@ -53,6 +58,7 @@ const INITIAL_STATE: State = {
|
|||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
selectedPlugins: [],
|
selectedPlugins: [],
|
||||||
|
marketplacePlugins: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function reducer(
|
export default function reducer(
|
||||||
@@ -94,6 +100,11 @@ export default function reducer(
|
|||||||
...state,
|
...state,
|
||||||
selectedPlugins: action.payload,
|
selectedPlugins: action.payload,
|
||||||
};
|
};
|
||||||
|
} else if (action.type === 'MARKETPLACE_PLUGINS') {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
marketplacePlugins: action.payload,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@@ -127,3 +138,10 @@ export const addFailedPlugins = (
|
|||||||
type: 'FAILED_PLUGINS',
|
type: 'FAILED_PLUGINS',
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const registerMarketplacePlugins = (
|
||||||
|
payload: Array<DownloadablePluginDetails>,
|
||||||
|
): Action => ({
|
||||||
|
type: 'MARKETPLACE_PLUGINS',
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|||||||
@@ -766,6 +766,7 @@ test('test determinePluginsToProcess for mutilple clients having plugins present
|
|||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
selectedPlugins: ['TestPlugin'],
|
selectedPlugins: ['TestPlugin'],
|
||||||
|
marketplacePlugins: [],
|
||||||
};
|
};
|
||||||
const op = determinePluginsToProcess(
|
const op = determinePluginsToProcess(
|
||||||
[client1, client2, client3],
|
[client1, client2, client3],
|
||||||
@@ -831,6 +832,7 @@ test('test determinePluginsToProcess for no selected plugin present in any clien
|
|||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
selectedPlugins: ['RandomPlugin'],
|
selectedPlugins: ['RandomPlugin'],
|
||||||
|
marketplacePlugins: [],
|
||||||
};
|
};
|
||||||
const op = determinePluginsToProcess([client1, client2], device1, plugins);
|
const op = determinePluginsToProcess([client1, client2], device1, plugins);
|
||||||
expect(op).toBeDefined();
|
expect(op).toBeDefined();
|
||||||
@@ -874,6 +876,7 @@ test('test determinePluginsToProcess for multiple clients on same device', async
|
|||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
selectedPlugins: ['TestPlugin'],
|
selectedPlugins: ['TestPlugin'],
|
||||||
|
marketplacePlugins: [],
|
||||||
};
|
};
|
||||||
const op = determinePluginsToProcess([client1, client2], device1, plugins);
|
const op = determinePluginsToProcess([client1, client2], device1, plugins);
|
||||||
expect(op).toBeDefined();
|
expect(op).toBeDefined();
|
||||||
@@ -955,6 +958,7 @@ test('test determinePluginsToProcess for multiple clients on different device',
|
|||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
selectedPlugins: ['TestPlugin'],
|
selectedPlugins: ['TestPlugin'],
|
||||||
|
marketplacePlugins: [],
|
||||||
};
|
};
|
||||||
const op = determinePluginsToProcess(
|
const op = determinePluginsToProcess(
|
||||||
[client1Device1, client2Device1, client1Device2, client2Device2],
|
[client1Device1, client2Device1, client1Device2, client2Device2],
|
||||||
@@ -1033,6 +1037,7 @@ test('test determinePluginsToProcess to ignore archived clients', async () => {
|
|||||||
disabledPlugins: [],
|
disabledPlugins: [],
|
||||||
failedPlugins: [],
|
failedPlugins: [],
|
||||||
selectedPlugins: ['TestPlugin'],
|
selectedPlugins: ['TestPlugin'],
|
||||||
|
marketplacePlugins: [],
|
||||||
};
|
};
|
||||||
const op = determinePluginsToProcess(
|
const op = determinePluginsToProcess(
|
||||||
[client, archivedClient],
|
[client, archivedClient],
|
||||||
|
|||||||
@@ -56,7 +56,11 @@ export default async function loadDynamicPlugins(): Promise<PluginDetails[]> {
|
|||||||
const compiledDynamicPlugins = (await compilations).filter(
|
const compiledDynamicPlugins = (await compilations).filter(
|
||||||
(c) => c !== null,
|
(c) => c !== null,
|
||||||
) as PluginDetails[];
|
) as PluginDetails[];
|
||||||
console.log('✅ Loaded all plugins.');
|
console.log(
|
||||||
|
`✅ Loaded ${dynamicPlugins.length} dynamic plugins: ${dynamicPlugins
|
||||||
|
.map((x) => x.title)
|
||||||
|
.join(', ')}.`,
|
||||||
|
);
|
||||||
return compiledDynamicPlugins;
|
return compiledDynamicPlugins;
|
||||||
}
|
}
|
||||||
async function loadPlugin(
|
async function loadPlugin(
|
||||||
|
|||||||
@@ -104,8 +104,12 @@ if (argv['fast-refresh'] === true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// By default plugin auto-update is disabled in dev mode,
|
// By default plugin auto-update is disabled in dev mode,
|
||||||
// but it is possible to enable it using this command line argument.
|
// but it is possible to enable it using this command line
|
||||||
if (argv['plugin-auto-update'] === true) {
|
// argument or env var.
|
||||||
|
if (
|
||||||
|
argv['plugin-auto-update'] === true ||
|
||||||
|
process.env.FLIPPER_PLUGIN_AUTO_UPDATE
|
||||||
|
) {
|
||||||
delete process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE;
|
delete process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE;
|
||||||
} else {
|
} else {
|
||||||
process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE = 'true';
|
process.env.FLIPPER_DISABLE_PLUGIN_AUTO_UPDATE = 'true';
|
||||||
|
|||||||
Reference in New Issue
Block a user