Persist device ID

Summary: Linked to https://github.com/facebook/flipper/issues/3319

Reviewed By: passy

Differential Revision: D36786952

fbshipit-source-id: f3214f35039845a8e35fa14e63f509a6fbdddb1f
This commit is contained in:
Andrey Goncharov
2022-06-01 02:49:25 -07:00
committed by Facebook GitHub Bot
parent ee64216725
commit 055b14c6dd
5 changed files with 40 additions and 6 deletions

View File

@@ -24,8 +24,8 @@ if the corresponding desktop plugin is selected in the Flipper Desktop. The full
plugin API is documented
[here](https://fbflipper.com/docs/extending/create-plugin).
- `start` method. It starts the client. It has two arguments:
- `appName` - (required) the name dsplayed in Flipper
- `options` which conforms to the infterface
- `appName` - (required) the name displayed in Flipper
- `options` which conforms to the interface
```ts
interface FlipperClientOptions {
// Make the client connect to a different URL
@@ -36,6 +36,8 @@ plugin API is documented
onError?: (e: unknown) => void;
// Timeout after which client tries to reconnect to Flipper
reconnectTimeout?: number;
// Set device ID. Default: random ID persisted to local storage.
getDeviceId?: () => Promise<string> | string
}
```
@@ -54,7 +56,7 @@ The sources of the corresponding Desktop plugin can be found
## Node.js
Node.js does not have a built-in WebSocket implementation. You need to install
any implmentation of WebSockets for Node.js that is compatible with the
any implementation of WebSockets for Node.js that is compatible with the
interface of the
[web version](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).

View File

@@ -11,7 +11,12 @@ import {FlipperConnection} from './connection';
import {FlipperRequest, FlipperResponse} from './message';
import {FlipperPlugin} from './plugin';
import {FlipperResponder} from './responder';
import {assert, detectDevice, detectOS} from './util';
import {
assert,
detectDevice,
detectOS,
getDeviceId as getDeviceIdDefault,
} from './util';
import {RECONNECT_TIMEOUT} from './consts';
// TODO: Share with flipper-server-core
@@ -133,13 +138,15 @@ interface FlipperClientOptions {
onError?: (e: unknown) => void;
// Timeout after which client tries to reconnect to Flipper
reconnectTimeout?: number;
// Set device ID. Default: random ID persisted to local storage.
getDeviceId?: () => Promise<string> | string;
}
export class FlipperClient {
private readonly plugins: Map<string, FlipperPlugin> = new Map();
private readonly connections: Map<string, FlipperConnection> = new Map();
private ws?: FlipperWebSocket;
private readonly devicePseudoId = `${Date.now()}.${Math.random()}`;
private deviceId!: string;
private readonly os = detectOS();
private readonly device = detectDevice();
private reconnectionTimer?: NodeJS.Timeout;
@@ -171,12 +178,14 @@ export class FlipperClient {
websocketFactory = (url) => new WebSocket(url) as FlipperWebSocket,
onError = (e) => console.error('WebSocket error', e),
reconnectTimeout = RECONNECT_TIMEOUT,
getDeviceId = getDeviceIdDefault,
}: FlipperClientOptions = {},
): Promise<void> {
if (this.ws) {
return;
}
this.deviceId = await getDeviceId();
this.appName = appName;
this.onError = onError;
this.urlBase = urlBase;
@@ -218,7 +227,7 @@ export class FlipperClient {
}
private connectToFlipper() {
const url = `ws://${this.urlBase}?device_id=${this.device}${this.devicePseudoId}&device=${this.device}&app=${this.appName}&os=${this.os}`;
const url = `ws://${this.urlBase}?device_id=${this.device}${this.deviceId}&device=${this.device}&app=${this.appName}&os=${this.os}`;
const encodedUrl = encodeURI(url);
this.ws = this.websocketFactory(encodedUrl);

View File

@@ -8,3 +8,4 @@
*/
export const RECONNECT_TIMEOUT = 1000;
export const DEVICE_ID_STORAGE_KEY = 'js-flipper-device-id';

View File

@@ -9,6 +9,7 @@
import {FlipperClient} from './client';
export * from './consts';
export * from './client';
export * from './plugin';

View File

@@ -7,6 +7,8 @@
* @format
*/
import {DEVICE_ID_STORAGE_KEY} from './consts';
// https://github.com/microsoft/TypeScript/issues/36931#issuecomment-846131999
type Assert = (condition: unknown) => asserts condition;
export const assert: Assert = (condition) => {
@@ -66,3 +68,22 @@ export const detectDevice = (): string => {
}
return require('os').release();
};
export const getDeviceId = () => {
// localStorage is not defined in Node.js env
const persistedId =
typeof localStorage === 'object'
? localStorage?.getItem(DEVICE_ID_STORAGE_KEY)
: undefined;
if (persistedId) {
return persistedId;
}
const newId = `${Date.now()}.${Math.random()}`;
if (typeof localStorage === 'object') {
localStorage?.setItem(DEVICE_ID_STORAGE_KEY, newId);
}
return newId;
};