@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
120 lines (105 loc) • 3.48 kB
text/typescript
import { Observable, from, of, throwError, EMPTY } from "rxjs";
import { catchError, concatMap, delay, mergeMap } from "rxjs/operators";
import { DeviceOnDashboardExpected, TransportStatusError } from "@ledgerhq/errors";
import { withDevice } from "./deviceAccess";
import getDeviceInfo from "./getDeviceInfo";
import { Language, languageIds } from "@ledgerhq/types-live";
import { AppAndVersion } from "./connectApp";
import appSupportsQuitApp from "../appSupportsQuitApp";
import quitApp from "./quitApp";
import getAppAndVersion from "./getAppAndVersion";
import { isDashboardName } from "./isDashboardName";
export type UninstallLanguageEvent =
| {
type: "appDetected";
}
| {
type: "unresponsiveDevice";
}
| {
type: "languageUninstalled";
};
const attemptToQuitApp = (
transport,
appAndVersion?: AppAndVersion,
): Observable<UninstallLanguageEvent> =>
appAndVersion && appSupportsQuitApp(appAndVersion)
? from(quitApp(transport)).pipe(
concatMap(() =>
of(<UninstallLanguageEvent>{
type: "unresponsiveDevice",
}),
),
catchError(e => throwError(() => e)),
)
: of({
type: "appDetected",
});
export type UninstallLanguageRequest = {
deviceId: string;
language: Language;
};
export default function unistallLanguage({
deviceId,
language,
}: UninstallLanguageRequest): Observable<UninstallLanguageEvent> {
const sub = withDevice(deviceId)(
transport =>
new Observable<UninstallLanguageEvent>(subscriber => {
const timeoutSub = of<UninstallLanguageEvent>({
type: "unresponsiveDevice",
})
.pipe(delay(1000))
.subscribe(e => subscriber.next(e));
const sub = from(getDeviceInfo(transport))
.pipe(
mergeMap(async _ => {
timeoutSub.unsubscribe();
const id = languageIds[language];
await transport.send(
0xe0,
0x33,
id,
0x00,
undefined,
[0x9000, 0x5501], // Expected responses when uninstalling.
);
subscriber.next({
type: "languageUninstalled",
});
subscriber.complete();
}),
catchError((e: unknown) => {
if (
e instanceof DeviceOnDashboardExpected ||
(e &&
e instanceof TransportStatusError &&
[0x6e00, 0x6d00, 0x6e01, 0x6d01, 0x6d02].includes(e.statusCode))
) {
const quitAppObservable = from(getAppAndVersion(transport)).pipe(
concatMap(appAndVersion => {
return !isDashboardName(appAndVersion.name)
? attemptToQuitApp(transport, appAndVersion)
: of<UninstallLanguageEvent>({
type: "appDetected",
});
}),
);
quitAppObservable.subscribe(
event => subscriber.next(event),
error => subscriber.error(error),
);
}
subscriber.error(e);
return EMPTY;
}),
)
.subscribe();
return () => {
timeoutSub.unsubscribe();
sub.unsubscribe();
};
}),
);
return sub;
}