Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ (core) [DSDK-180]: Add new USB discovery module #15

Merged
merged 10 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions apps/sample/src/components/MainView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React from "react";
import React, { useCallback, useEffect, useState } from "react";
import type { DiscoveredDevice } from "@ledgerhq/device-sdk-core";
import { Button, Flex, Icons, Text } from "@ledgerhq/react-ui";
import Image from "next/image";
import styled, { DefaultTheme } from "styled-components";

import { useSdk } from "@/providers/DeviceSdkProvider";

const Root = styled(Flex)`
flex-direction: column;
flex: 1;
Expand Down Expand Up @@ -41,6 +44,45 @@ const NanoLogo = styled(Image).attrs({ mb: 8 })`
`;

export const MainView: React.FC = () => {
const sdk = useSdk();
const [discoveredDevice, setDiscoveredDevice] =
useState<null | DiscoveredDevice>(null);

// Example starting the discovery on a user action
const onSelectDeviceClicked = useCallback(() => {
sdk.startDiscovering().subscribe({
next: (device) => {
console.log(`πŸ¦– Discovered device: `, device);
setDiscoveredDevice(device);
},
error: (error) => {
console.error(error);
},
});
}, [sdk]);

useEffect(() => {
return () => {
// Example cleaning up the discovery
sdk.stopDiscovering();
};
}, [sdk]);

useEffect(() => {
if (discoveredDevice) {
sdk.connect({ deviceId: discoveredDevice.id }).subscribe({
next: (connectedDevice) => {
console.log(
`πŸ¦– Response from connect: ${JSON.stringify(connectedDevice)} πŸŽ‰`,
);
},
error: (error) => {
console.error(`Error from connection or get-version`, error);
},
});
}
}, [sdk, discoveredDevice]);

return (
<Root>
<Header>
Expand Down Expand Up @@ -72,7 +114,12 @@ export const MainView: React.FC = () => {
Use this application to test Ledger hardware device features.
</Description>

<Button variant="main" backgroundColor="main" size="large">
<Button
onClick={onSelectDeviceClicked}
variant="main"
backgroundColor="main"
size="large"
>
Select a device
</Button>
</Container>
Expand Down
37 changes: 0 additions & 37 deletions packages/config/eslint/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,42 +81,5 @@ module.exports = {
],
},
},
{
files: ["**/*.mjs"],
env: {
es6: true,
node: true,
},
globals: {
log: true,
$: true,
argv: true,
cd: true,
chalk: true,
echo: true,
expBackoff: true,
fs: true,
glob: true,
globby: true,
nothrow: true,
os: true,
path: true,
question: true,
quiet: true,
quote: true,
quotePowerShell: true,
retry: true,
sleep: true,
spinner: true,
ssh: true,
stdin: true,
which: true,
within: true,
},
parserOptions: {
ecmaVersion: 2018,
sourceType: "module",
},
},
],
};
1 change: 0 additions & 1 deletion packages/config/typescript/sdk.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"compilerOptions": {
"target": "esnext",
"lib": ["esnext", "dom"],
"types": ["reflect-metadata", "jest", "node"],
Copy link
Contributor Author

@alexandremgo alexandremgo Feb 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was discussed with @valpinkman :

It was making it mandatory to list all added types packages, which was not practical and causing issues with @types/w3c-web-hid

"sourceMap": true,
"declaration": true,
"declarationMap": true,
Expand Down
37 changes: 37 additions & 0 deletions packages/core/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,42 @@ module.exports = {
"@typescript-eslint/unbound-method": 0,
},
},
{
files: ["**/*.mjs"],
env: {
es6: true,
node: true,
},
globals: {
log: true,
$: true,
argv: true,
cd: true,
chalk: true,
echo: true,
expBackoff: true,
fs: true,
glob: true,
globby: true,
nothrow: true,
os: true,
path: true,
question: true,
quiet: true,
quote: true,
quotePowerShell: true,
retry: true,
sleep: true,
spinner: true,
ssh: true,
stdin: true,
which: true,
within: true,
},
parserOptions: {
ecmaVersion: 2018,
sourceType: "module",
},
},
],
};
10 changes: 8 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"lint:fix": "eslint --cache --fix --ext .ts \"src\"",
"prettier": "prettier . --check",
"prettier:fix": "prettier . --write",
"test": "jest src",
"test": "jest",
"test:watch": "pnpm test -- --watch",
"test:coverage": "pnpm test -- --coverage",
"typecheck": "tsc --noEmit",
Expand All @@ -24,9 +24,15 @@
"inversify": "^6.0.2",
"inversify-logger-middleware": "^3.1.0",
"purify-ts": "^2.0.3",
"reflect-metadata": "^0.2.1"
"reflect-metadata": "^0.2.1",
"rxjs": "^7.8.1",
"semver": "^7.5.4",
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/semver": "^7.5.6",
"@types/uuid": "^9.0.8",
"@types/w3c-web-hid": "^1.0.6",
"@ledgerhq/eslint-config-dsdk": "workspace:*",
"@ledgerhq/jest-config-dsdk": "workspace:*",
"@ledgerhq/tsconfig-dsdk": "workspace:*",
Expand Down
12 changes: 6 additions & 6 deletions packages/core/scripts/add-module.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ import { basename } from "node:path";
const modules = argv._;

if (!modules.length) {
console.error(`Usage: ${basename(__filename)} <feature1> [<feature2> ...]`);
console.error(`Usage: ${basename(__filename)} <module1> [<module2> ...]`);
process.exit(1);
}

within(async () => {
cd("src/internal");
for (const mod of modules) {
const rootFolderName = `${mod}`;
const featureUppercased = mod.charAt(0).toUpperCase() + mod.slice(1);
const moduleUppercased = mod.charAt(0).toUpperCase() + mod.slice(1);
await $`mkdir ${rootFolderName}`;
within(async () => {
cd(rootFolderName);
await $`mkdir data di model service usecase`;
const files = [
`data/${featureUppercased}DataSource.ts`,
`data/${moduleUppercased}DataSource.ts`,
`di/${mod}Module.test.ts`,
`di/${mod}Module.ts`,
`di/${mod}Types.ts`,
`model/.gitkeep`,
`service/${featureUppercased}Service.ts`,
`service/Default${featureUppercased}Service.test.ts`,
`service/Default${featureUppercased}Service.ts`,
`service/${moduleUppercased}Service.ts`,
`service/Default${moduleUppercased}Service.test.ts`,
`service/Default${moduleUppercased}Service.ts`,
`usecase/.gitkeep`,
];
for (const file of files) {
Expand Down
27 changes: 27 additions & 0 deletions packages/core/src/api/DeviceSdk.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { Container } from "inversify";
import { Observable } from "rxjs";

import { types as ConfigTypes } from "@internal/config/di/configTypes";
import { GetSdkVersionUseCase } from "@internal/config/usecase/GetSdkVersionUseCase";
import { discoveryDiTypes } from "@internal/discovery/di/discoveryDiTypes";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ASK] discoveryDiTypes is not consistent with other examples like configTypes. The DI information is already in path @internal/discovery/di/discoveryDiTypes so maybe we don't need to add it as a suffix. Or we can add it to other files as well.

import {
ConnectUseCase,
ConnectUseCaseArgs,
} from "@internal/discovery/use-case/ConnectUseCase";
import type { StartDiscoveringUseCase } from "@internal/discovery/use-case/StartDiscoveringUseCase";
import type { StopDiscoveringUseCase } from "@internal/discovery/use-case/StopDiscoveringUseCase";
import { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice";
import { makeContainer, MakeContainerProps } from "@root/src/di";

export class DeviceSdk {
Expand All @@ -27,4 +36,22 @@ export class DeviceSdk {
.get<GetSdkVersionUseCase>(ConfigTypes.GetSdkVersionUseCase)
.getSdkVersion();
}

startDiscovering(): Observable<DiscoveredDevice> {
return this.container
.get<StartDiscoveringUseCase>(discoveryDiTypes.StartDiscoveringUseCase)
.execute();
}

stopDiscovering() {
return this.container
.get<StopDiscoveringUseCase>(discoveryDiTypes.StopDiscoveringUseCase)
.execute();
}

connect(args: ConnectUseCaseArgs) {
return this.container
.get<ConnectUseCase>(discoveryDiTypes.ConnectUseCase)
.execute(args);
}
}
3 changes: 3 additions & 0 deletions packages/core/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ export type {
export { ConsoleLogger, Log } from "./ConsoleLogger";
export { DeviceSdk } from "./DeviceSdk";
export { LedgerDeviceSdkBuilder as DeviceSdkBuilder } from "./DeviceSdkBuilder";

// [SHOULD] be exported from another file
export type { DiscoveredDevice } from "@internal/usb/model/DiscoveredDevice";
6 changes: 6 additions & 0 deletions packages/core/src/di.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import { Container } from "inversify";
// Uncomment this line to enable the logger middleware
// import { makeLoggerMiddleware } from "inversify-logger-middleware";
import { configModuleFactory } from "@internal/config/di/configModule";
import { deviceModelModuleFactory } from "@internal/device-model/di/deviceModelModule";
import { discoveryModuleFactory } from "@internal/discovery/di/discoveryModule";
import { loggerModuleFactory } from "@internal/logger/di/loggerModule";
import { LoggerSubscriber } from "@internal/logger/service/Log";
import { usbModuleFactory } from "@internal/usb/di/usbModule";

// Uncomment this line to enable the logger middleware
// const logger = makeLoggerMiddleware();
Expand All @@ -25,6 +28,9 @@ export const makeContainer = ({

container.load(
configModuleFactory({ stub }),
deviceModelModuleFactory({ stub }),
usbModuleFactory({ stub }),
discoveryModuleFactory({ stub }),
loggerModuleFactory({ subscribers: loggers }),
// modules go here
);
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import "reflect-metadata";

export * from "./api";
export * from "./transport";
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {
DeviceModel,
DeviceModelId,
} from "@internal/device-model/model/DeviceModel";

/**
* Source of truth for the device models
*/
export interface DeviceModelDataSource {
getAllDeviceModels(): DeviceModel[];

getDeviceModel(params: { id: DeviceModelId }): DeviceModel;

filterDeviceModels(params: Partial<DeviceModel>): DeviceModel[];
}
Loading
Loading