Created a proof of concept flipper-dump
Summary: Created a quick-and-dirty flipper-dump command, to verify that the stand alone flipper-server-core can do it's job without the Electron Flipper Reviewed By: passy Differential Revision: D31543516 fbshipit-source-id: ce8e37316ab5f09700421bcf1c7830266e02c999
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d88b28330a
commit
598bdeb12a
@@ -36,13 +36,13 @@ export interface Logger {
|
||||
data?: any,
|
||||
): void;
|
||||
|
||||
info(data: any, category: string): void;
|
||||
info(...args: any[]): void;
|
||||
|
||||
warn(data: any, category: string): void;
|
||||
warn(...args: any[]): void;
|
||||
|
||||
error(data: any, category: string): void;
|
||||
error(...args: any[]): void;
|
||||
|
||||
debug(data: any, category: string): void;
|
||||
debug(...args: any[]): void;
|
||||
}
|
||||
|
||||
let instance: Logger | null = null;
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
# flipper-dump (TBD)
|
||||
# flipper-dump
|
||||
|
||||
Stand alone Flipper command, that uses flipper-server-core to connect to apps and dump all incoming messages.
|
||||
|
||||
This package is currently a proof of concept and can be used like:
|
||||
|
||||
`yarn start --device='iPhone 12' --client='Instagram' --plugin='AnalyticsLogging'`
|
||||
|
||||
Or to capture all output to a file (meta messages will be printed on STDERR):
|
||||
|
||||
`yarn --silent start --device='iPhone 12' --client='Instagram' --plugin='AnalyticsLogging' > out.txt`
|
||||
|
||||
Future features:
|
||||
|
||||
* [ ] Package so that it can be run using `npx`
|
||||
* [ ] Support filter & transformation functions
|
||||
* [ ] See `TODO`s in code
|
||||
* [ ] Support better configuration
|
||||
* [ ] Custom formatting
|
||||
* [ ] [FB] Support Certificate Exchange clients
|
||||
|
||||
@@ -9,10 +9,16 @@
|
||||
"types": "lib/index.d.ts",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/facebook/flipper/issues",
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"flipper-common": "0.0.0",
|
||||
"flipper-server-core": "0.0.0",
|
||||
"ts-node": "^10.2.1",
|
||||
"yargs": "^17.2.1"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"peerDependencies": {},
|
||||
"scripts": {
|
||||
"start": "ts-node src/index.tsx",
|
||||
"reset": "rimraf lib *.tsbuildinfo",
|
||||
"build": "tsc -b",
|
||||
"prepack": "yarn reset && yarn build"
|
||||
|
||||
@@ -7,6 +7,239 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
export function helloWorld() {
|
||||
return true;
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import yargs from 'yargs';
|
||||
import {FlipperServerImpl, setFlipperServerConfig} from 'flipper-server-core';
|
||||
import {
|
||||
ClientDescription,
|
||||
Logger,
|
||||
DeviceDescription,
|
||||
setLoggerInstance,
|
||||
} from 'flipper-common';
|
||||
import path from 'path';
|
||||
import {stdout} from 'process';
|
||||
|
||||
// eslint-disable-next-line
|
||||
const packageJson = JSON.parse(fs.readFileSync('../package.json', 'utf-8'));
|
||||
|
||||
const argv = yargs
|
||||
.usage('$0 [args]')
|
||||
.options({
|
||||
device: {
|
||||
describe: 'The device name to listen to',
|
||||
type: 'string',
|
||||
},
|
||||
client: {
|
||||
describe: 'The application name to listen to',
|
||||
type: 'string',
|
||||
},
|
||||
plugin: {
|
||||
describe: 'Plugin id to listen to',
|
||||
type: 'string',
|
||||
},
|
||||
// TODO: support filtering events
|
||||
// TODO: support verbose mode
|
||||
// TODO: support post processing messages
|
||||
})
|
||||
.version(packageJson.version)
|
||||
.help()
|
||||
// .strict()
|
||||
.parse(process.argv.slice(1));
|
||||
|
||||
async function start(deviceTitle: string, appName: string, pluginId: string) {
|
||||
return new Promise((_resolve, reject) => {
|
||||
let device: DeviceDescription | undefined;
|
||||
let deviceResolver: () => void;
|
||||
const devicePromise: Promise<void> = new Promise((resolve) => {
|
||||
deviceResolver = resolve;
|
||||
});
|
||||
let client: ClientDescription | undefined;
|
||||
|
||||
const logger = createLogger();
|
||||
setLoggerInstance(logger);
|
||||
// avoid logging to STDOUT!
|
||||
console.log = console.error;
|
||||
console.debug = () => {};
|
||||
console.info = console.error;
|
||||
|
||||
// TODO: make these better overridable
|
||||
setFlipperServerConfig({
|
||||
enableAndroid: true,
|
||||
androidHome: process.env.ANDROID_HOME || '/opt/android_sdk',
|
||||
idbPath: '/usr/local/bin/idb',
|
||||
enableIOS: true,
|
||||
enablePhysicalIOS: true,
|
||||
staticPath: path.resolve(__dirname, '..', '..', 'static'),
|
||||
tmpPath: os.tmpdir(),
|
||||
validWebSocketOrigins: [],
|
||||
});
|
||||
// TODO: initialise FB user manager to be able to do certificate exchange
|
||||
|
||||
const server = new FlipperServerImpl(logger);
|
||||
|
||||
logger.info(
|
||||
`Waiting for device '${deviceTitle}' client '${appName}' plugin '${pluginId}' ...`,
|
||||
);
|
||||
|
||||
server.on('notification', ({type, title, description}) => {
|
||||
if (type === 'error') {
|
||||
reject(new Error(`${title}: ${description}`));
|
||||
}
|
||||
});
|
||||
|
||||
server.on('server-error', reject);
|
||||
|
||||
server.on('device-connected', (deviceInfo) => {
|
||||
logger.info(
|
||||
`Detected device [${deviceInfo.os}] ${deviceInfo.title} ${deviceInfo.serial}`,
|
||||
);
|
||||
if (deviceInfo.title === deviceTitle) {
|
||||
logger.info('Device matched');
|
||||
device = deviceInfo;
|
||||
deviceResolver();
|
||||
}
|
||||
});
|
||||
|
||||
server.on('device-disconnected', (deviceInfo) => {
|
||||
if (device && deviceInfo.serial === device.serial) {
|
||||
reject(new Error('Device disconnected: ' + deviceInfo.serial));
|
||||
}
|
||||
});
|
||||
|
||||
server.on('client-setup', (client) => {
|
||||
logger.info(
|
||||
`Connection attempt: ${client.appName} on ${client.deviceName}`,
|
||||
);
|
||||
});
|
||||
|
||||
server.on(
|
||||
'client-connected',
|
||||
async (clientDescription: ClientDescription) => {
|
||||
// device matching is promisified, as we clients can arrive before device is detected
|
||||
await devicePromise;
|
||||
if (clientDescription.query.app === appName) {
|
||||
if (clientDescription.query.device_id === device!.serial) {
|
||||
logger.info(`Client matched: ${clientDescription.id}`);
|
||||
client = clientDescription;
|
||||
try {
|
||||
// fetch plugins
|
||||
const response = await server.exec(
|
||||
'client-request-response',
|
||||
client.id,
|
||||
{
|
||||
method: 'getPlugins',
|
||||
},
|
||||
);
|
||||
logger.info(JSON.stringify(response));
|
||||
if (response.error) {
|
||||
reject(response.error);
|
||||
return;
|
||||
}
|
||||
const plugins: string[] = (response.success as any).plugins;
|
||||
logger.info('Detected plugins ' + plugins.join(','));
|
||||
if (!plugins.includes(pluginId)) {
|
||||
// TODO: what if it only registers later?
|
||||
throw new Error(
|
||||
`Plugin ${pluginId} was not registered on client ${client.id}`,
|
||||
);
|
||||
}
|
||||
logger.info(`Starting plugin ` + pluginId);
|
||||
const response2 = await server.exec(
|
||||
'client-request-response',
|
||||
client.id,
|
||||
{
|
||||
method: 'init',
|
||||
params: {plugin: pluginId},
|
||||
},
|
||||
);
|
||||
if (response2.error) {
|
||||
reject(response2.error);
|
||||
}
|
||||
logger.info('Plugin initialised');
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
server.on('client-disconnected', ({id}) => {
|
||||
if (id === client?.id) {
|
||||
reject(new Error('Application disconnected'));
|
||||
}
|
||||
});
|
||||
|
||||
server.on('client-message', ({id, message}) => {
|
||||
if (id === client?.id) {
|
||||
const parsed = JSON.parse(message);
|
||||
if (parsed.method === 'execute') {
|
||||
if (parsed.params.api === pluginId) {
|
||||
// TODO: customizable format
|
||||
stdout.write(
|
||||
`\n\n\n[${parsed.params.method}]\n${JSON.stringify(
|
||||
parsed.params.params,
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
logger.warn('Dropping message ', message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server
|
||||
.start()
|
||||
.then(() => {
|
||||
logger.info(
|
||||
'Flipper server started and accepting device / client connections',
|
||||
);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
function createLogger(): Logger {
|
||||
return {
|
||||
track() {
|
||||
// no-op
|
||||
},
|
||||
trackTimeSince() {
|
||||
// no-op
|
||||
},
|
||||
debug() {
|
||||
// TODO: support this with a --verbose flag
|
||||
},
|
||||
error(...args: any[]) {
|
||||
console.error(...args);
|
||||
},
|
||||
warn(...args: any[]) {
|
||||
console.warn(...args);
|
||||
},
|
||||
info(...args: any[]) {
|
||||
// we want to redirect info level logging to STDERR! So that STDOUT is used merely for plugin output
|
||||
console.error(...args);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (!argv.device) {
|
||||
console.error('--device not specified');
|
||||
process.exit(1);
|
||||
}
|
||||
if (!argv.client) {
|
||||
console.error('--client not specified');
|
||||
process.exit(1);
|
||||
}
|
||||
if (!argv.plugin) {
|
||||
console.error('--plugin not specified');
|
||||
process.exit(1);
|
||||
}
|
||||
start(argv.device!, argv.client!, argv.plugin!).catch((e) => {
|
||||
// eslint-disable-next-line
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -8,5 +8,8 @@
|
||||
{
|
||||
"path": "../flipper-server-core"
|
||||
}
|
||||
]
|
||||
],
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1669,6 +1669,18 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@cspotcode/source-map-consumer@0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
|
||||
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
|
||||
|
||||
"@cspotcode/source-map-support@0.6.1":
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960"
|
||||
integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-consumer" "0.8.0"
|
||||
|
||||
"@ctrl/tinycolor@^3.4.0":
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f"
|
||||
@@ -2597,6 +2609,26 @@
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
|
||||
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
|
||||
|
||||
"@tsconfig/node12@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
|
||||
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
|
||||
|
||||
"@tsconfig/node14@^1.0.0":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
|
||||
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
|
||||
|
||||
"@tsconfig/node16@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
|
||||
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
|
||||
|
||||
"@types/adobe__node-fetch-retry@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/adobe__node-fetch-retry/-/adobe__node-fetch-retry-1.0.2.tgz#4f9f174da6fc4775cbe209dcb087f7e7f763bf81"
|
||||
@@ -3541,6 +3573,11 @@ acorn-walk@^7.1.1:
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
|
||||
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
|
||||
|
||||
acorn-walk@^8.1.1:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||
|
||||
acorn@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
|
||||
@@ -3556,6 +3593,11 @@ acorn@^8.2.4:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.3.0.tgz#1193f9b96c4e8232f00b11a9edff81b2c8b98b88"
|
||||
integrity sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==
|
||||
|
||||
acorn@^8.4.1:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||
|
||||
adbkit-logcat@^1.1.0, adbkit-logcat@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/adbkit-logcat/-/adbkit-logcat-2.0.1.tgz#d4986b9fc7cfda42733389d46a52124abef43ca5"
|
||||
@@ -13007,6 +13049,24 @@ ts-jest@^26.5.6:
|
||||
semver "7.x"
|
||||
yargs-parser "20.x"
|
||||
|
||||
ts-node@^10.2.1:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5"
|
||||
integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==
|
||||
dependencies:
|
||||
"@cspotcode/source-map-support" "0.6.1"
|
||||
"@tsconfig/node10" "^1.0.7"
|
||||
"@tsconfig/node12" "^1.0.7"
|
||||
"@tsconfig/node14" "^1.0.0"
|
||||
"@tsconfig/node16" "^1.0.2"
|
||||
acorn "^8.4.1"
|
||||
acorn-walk "^8.1.1"
|
||||
arg "^4.1.0"
|
||||
create-require "^1.1.0"
|
||||
diff "^4.0.1"
|
||||
make-error "^1.1.1"
|
||||
yn "3.1.1"
|
||||
|
||||
ts-node@^9.1.1:
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
|
||||
@@ -13791,6 +13851,19 @@ yargs@^17.0.1:
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^20.2.2"
|
||||
|
||||
yargs@^17.2.1:
|
||||
version "17.2.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea"
|
||||
integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==
|
||||
dependencies:
|
||||
cliui "^7.0.2"
|
||||
escalade "^3.1.1"
|
||||
get-caller-file "^2.0.5"
|
||||
require-directory "^2.1.1"
|
||||
string-width "^4.2.0"
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^20.2.2"
|
||||
|
||||
yauzl@^2.10.0, yauzl@^2.4.2:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
||||
|
||||
Reference in New Issue
Block a user