Skip to content

Commit

Permalink
✨ (flipper) [NO-ISSUE]: Implement basic Flipper plugin for logs (#375)
Browse files Browse the repository at this point in the history
  • Loading branch information
ofreyssinet-ledger authored Oct 22, 2024
2 parents e36237a + bb6beca commit f80ebf8
Show file tree
Hide file tree
Showing 21 changed files with 582 additions and 19 deletions.
7 changes: 7 additions & 0 deletions .changeset/nine-tools-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ledgerhq/device-management-kit-flipper-plugin-client": patch
"@ledgerhq/device-management-kit": patch
"@ledgerhq/device-sdk-sample": patch
---

Implement basic Flipper client for the Ledger Device Management Kit
1 change: 1 addition & 0 deletions apps/sample/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"@ledgerhq/context-module": "workspace:*",
"@ledgerhq/device-management-kit": "workspace:*",
"@ledgerhq/device-management-kit-flipper-plugin-client": "workspace:*",
"@ledgerhq/device-signer-kit-ethereum": "workspace:*",
"@ledgerhq/device-sdk-transport-mock": "workspace:*",
"@ledgerhq/react-ui": "^0.16.2",
Expand Down
74 changes: 57 additions & 17 deletions apps/sample/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React, { useCallback, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { BuiltinTransports } from "@ledgerhq/device-management-kit";
import { FlipperPluginManager } from "@ledgerhq/device-management-kit-flipper-plugin-client";
import {
Button,
Divider,
DropdownGeneric,
Flex,
Icons,
Input,
Switch,
Text,
} from "@ledgerhq/react-ui";
import styled, { DefaultTheme } from "styled-components";

Expand Down Expand Up @@ -49,7 +52,7 @@ export const Header = () => {
: BuiltinTransports.MOCK_SERVER,
},
});
}, [transport]);
}, [dispatch, transport]);
const [mockServerStateUrl, setMockServerStateUrl] =
useState<string>(mockServerUrl);
const mockServerEnabled = transport === BuiltinTransports.MOCK_SERVER;
Expand All @@ -60,8 +63,32 @@ export const Header = () => {
type: "set_mock_server_url",
payload: { mockServerUrl: mockServerStateUrl },
}),
[mockServerStateUrl],
[dispatch, mockServerStateUrl],
);

const onClickConnectFlipperClient = useCallback(() => {
/**
* This is useful in case the Flipper server is started after the app and
* we want to connect to it without reloading the app, to keep the app state
* and the logs.
* */
FlipperPluginManager.getInstance().attemptInitialization();
}, []);

const [flipperClientConnected, setFlipperClientConnected] =
useState<boolean>(false);

useEffect(() => {
const subscription = FlipperPluginManager.getInstance()
.observeIsConnected()
.subscribe((connected: boolean) => {
setFlipperClientConnected(connected);
});
return () => {
subscription.unsubscribe();
};
}, []);

return (
<Root>
<Actions>
Expand All @@ -74,7 +101,8 @@ export const Header = () => {
</Actions>
<div data-testid="dropdown_mock-server-switch">
<DropdownGeneric closeOnClickOutside label="" placement="bottom">
<Flex my={5} py={6} px={5} width={280}>
<Flex p={5} flexDirection="column" rowGap={5}>
<Text>Mock server:</Text>
<div data-testid="switch_mock-server">
<Switch
onChange={onToggleMockServer}
Expand All @@ -83,20 +111,32 @@ export const Header = () => {
label="Enable Mock server"
/>
</div>

{mockServerEnabled && (
<UrlInput
value={mockServerStateUrl}
onChange={(url: string) => setMockServerStateUrl(url)}
renderRight={() => (
<Flex alignItems="center" justifyContent="stretch">
<Button iconButton onClick={validateServerUrl}>
<Icons.CheckmarkCircleFill size="S" />
</Button>
</Flex>
)}
/>
)}
<Divider />
<Text>
Flipper ({flipperClientConnected ? "Connected" : "Disconnected"}):
</Text>
<Button
onClick={onClickConnectFlipperClient}
disabled={flipperClientConnected}
variant="shade"
>
Connect Flipper client
</Button>
</Flex>
{mockServerEnabled && (
<UrlInput
value={mockServerStateUrl}
onChange={(url: string) => setMockServerStateUrl(url)}
renderRight={() => (
<Flex alignItems="center" justifyContent="stretch">
<Button iconButton onClick={validateServerUrl}>
<Icons.CheckmarkCircleFill size="S" />
</Button>
</Flex>
)}
/>
)}
</DropdownGeneric>
</div>
</Root>
Expand Down
6 changes: 6 additions & 0 deletions apps/sample/src/providers/DeviceSdkProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
DeviceSdkBuilder,
WebLogsExporterLogger,
} from "@ledgerhq/device-management-kit";
import { FlipperSdkLogger } from "@ledgerhq/device-management-kit-flipper-plugin-client";

import { usePrevious } from "@/hooks/usePrevious";
import { useSdkConfigContext } from "@/providers/SdkConfig";
Expand All @@ -18,6 +19,7 @@ const defaultSdk = new DeviceSdkBuilder()
.addTransport(BuiltinTransports.BLE)
.addTransport(BuiltinTransports.USB)
.addLogger(webLogsExporterLogger)
.addLogger(new FlipperSdkLogger())
.build();

const SdkContext = createContext<DeviceSdk>(defaultSdk);
Expand All @@ -36,6 +38,8 @@ export const SdkProvider: React.FC<PropsWithChildren> = ({ children }) => {
.addLogger(new ConsoleLogger())
.addTransport(BuiltinTransports.MOCK_SERVER)
.addConfig({ mockUrl: mockServerUrl })
.addLogger(webLogsExporterLogger)
.addLogger(new FlipperSdkLogger())
.build(),
);
} else if (previousTransport === BuiltinTransports.MOCK_SERVER) {
Expand All @@ -45,6 +49,8 @@ export const SdkProvider: React.FC<PropsWithChildren> = ({ children }) => {
.addLogger(new ConsoleLogger())
.addTransport(BuiltinTransports.BLE)
.addTransport(BuiltinTransports.USB)
.addLogger(webLogsExporterLogger)
.addLogger(new FlipperSdkLogger())
.build(),
);
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"transport-mock": "pnpm --filter @ledgerhq/device-sdk-transport-mock",
"trusted-apps": "pnpm --filter @ledgerhq/device-sdk-trusted-apps",
"ui": "pnpm --filter @ledgerhq/device-sdk-ui",
"flipper": "pnpm --filter @ledgerhq/device-management-kit-flipper-plugin-client",
"sample": "pnpm --filter @ledgerhq/device-sdk-sample",
"bump": "changeset version",
"prerelease": "pnpm recursive exec -- pnpm pack",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import { LogSubscriberOptions } from "@api/logger-subscriber/model/LogSubscriber
* Implement this interface and use `LedgerDeviceSdkBuilder.addLogger` to
* receive logs from the SDK.
*/
export type LogParams = [
level: LogLevel,
message: string,
options: LogSubscriberOptions,
];

export interface LoggerSubscriberService {
log(level: LogLevel, message: string, options: LogSubscriberOptions): void;
log(...logParams: LogParams): void;
}
5 changes: 4 additions & 1 deletion packages/core/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ export type { DeviceId } from "./device/DeviceModel";
export type { ConnectionType } from "./discovery/ConnectionType";
export type { CommandErrorArgs } from "./Error";
export type { LogSubscriberOptions } from "./logger-subscriber/model/LogSubscriberOptions";
export type { LoggerSubscriberService } from "./logger-subscriber/service/LoggerSubscriberService";
export type {
LoggerSubscriberService,
LogParams,
} from "./logger-subscriber/service/LoggerSubscriberService";
export type { DiscoveredDevice } from "./transport/model/DiscoveredDevice";
export type { Transport } from "./transport/model/Transport";
export type { TransportIdentifier } from "./transport/model/TransportIdentifier";
Expand Down
1 change: 1 addition & 0 deletions packages/flipper-plugin-client/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib/*
3 changes: 3 additions & 0 deletions packages/flipper-plugin-client/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
...require("@ledgerhq/prettier-config-dsdk"),
};
19 changes: 19 additions & 0 deletions packages/flipper-plugin-client/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import config from "@ledgerhq/eslint-config-dsdk";

export default [
...config,
{
ignores: ["eslint.config.mjs", "scripts/*.mjs"],
languageOptions: {
parserOptions: {
project: "./tsconfig.json",
},
},
},
{
files: ["**/*.ts"],
rules: {
"no-restricted-imports": ["off"],
},
},
];
1 change: 1 addition & 0 deletions packages/flipper-plugin-client/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./src";
15 changes: 15 additions & 0 deletions packages/flipper-plugin-client/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint no-restricted-syntax: 0 */
import type { JestConfigWithTsJest } from "ts-jest";

const config: JestConfigWithTsJest = {
preset: "@ledgerhq/jest-config-dsdk",
testPathIgnorePatterns: ["<rootDir>/lib/esm", "<rootDir>/lib/cjs"],
collectCoverageFrom: [
"src/**/*.ts",
"!src/**/*.stub.ts",
"!src/index.ts",
"!src/api/index.ts",
],
};

export default config;
51 changes: 51 additions & 0 deletions packages/flipper-plugin-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "@ledgerhq/device-management-kit-flipper-plugin-client",
"version": "1.0.0",
"license": "MIT",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/types/index.d.ts",
"import": "./lib/esm/index.js",
"require": "./lib/cjs/index.js"
},
"./*": {
"types": "./lib/types/*",
"import": "./lib/esm/*",
"require": "./lib/cjs/*"
}
},
"files": [
"./lib"
],
"scripts": {
"prebuild": "rimraf lib",
"build": "pnpm lmdk-build --entryPoints index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
"dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"",
"watch:builds": "pnpm lmdk-watch --entryPoints index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
"watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\"",
"lint": "eslint",
"lint:fix": "pnpm lint --fix",
"prettier": "prettier . --check",
"prettier:fix": "prettier . --write",
"typecheck": "tsc --noEmit",
"test": "jest --passWithNoTests",
"test:coverage": "pnpm test -- --coverage"
},
"dependencies": {
"js-flipper": "^0.270.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@ledgerhq/esbuild-tools": "workspace:*",
"@ledgerhq/tsconfig-dsdk": "workspace:*",
"@ledgerhq/eslint-config-dsdk": "workspace:*",
"@ledgerhq/jest-config-dsdk": "workspace:*",
"@ledgerhq/prettier-config-dsdk": "workspace:*",
"@ledgerhq/device-management-kit": "workspace:*"
},
"peerDependencies": {
"@ledgerhq/device-management-kit": "workspace:*"
}
}
21 changes: 21 additions & 0 deletions packages/flipper-plugin-client/scripts/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env zx
import path from "node:path";

const root = path.join(__dirname, "..");
const tsconfigEsm = path.join(root, "tsconfig.esm.json");
const tsconfigCjs = path.join(root, "tsconfig.cjs.json");

const buildEsm = async () => {
await $`tsc --project ${tsconfigEsm} --incremental`;
};

const builCjs = async () => {
await $`tsc --project ${tsconfigCjs} --incremental`;
};

const run = async () => await Promise.all([buildEsm(), builCjs()]);

run().catch((e) => {
console.error(e);
process.exit(e.errorCode);
});
Loading

0 comments on commit f80ebf8

Please sign in to comment.