forked from LedgerHQ/ledger-live-common
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrunner.js
75 lines (70 loc) · 2.13 KB
/
runner.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// @flow
import { Observable, from, of, defer, concat } from "rxjs";
import {
map,
materialize,
reduce,
ignoreElements,
throttleTime
} from "rxjs/operators";
import type { Exec, State, AppOp, RunnerEvent } from "./types";
import { reducer, getActionPlan, getNextAppOp } from "./logic";
import { delay } from "../promise";
import { getEnv } from "../env";
export const runAppOp = (
{ appByName, deviceInfo }: State,
appOp: AppOp,
exec: Exec
): Observable<RunnerEvent> => {
const app = appByName[appOp.name];
if (!app) {
// app not in list, we skip it.
return from([
{ type: "runStart", appOp },
{ type: "runSuccess", appOp }
]);
}
return concat(
of({ type: "runStart", appOp }),
// we need to allow a 1s delay for the action to be achieved without glitch (bug in old firmware when you do things too closely)
defer(() => delay(getEnv("MANAGER_INSTALL_DELAY"))).pipe(ignoreElements()),
defer(() => exec(appOp, deviceInfo.targetId, app)).pipe(
throttleTime(100),
materialize(),
map(n => {
switch (n.kind) {
case "N":
return { type: "runProgress", appOp, progress: n.value.progress };
case "E":
return { type: "runError", appOp, error: n.error };
case "C":
return { type: "runSuccess", appOp };
default:
throw new Error("invalid notification of kind=" + n.kind);
}
})
)
);
};
// use for CLI, no change of the state over time
export const runAll = (state: State, exec: Exec): Observable<State> =>
concat(
...getActionPlan(state).map(appOp => runAppOp(state, appOp, exec))
).pipe(
map(event => ({ type: "onRunnerEvent", event })),
reduce(reducer, state)
);
export const runOneAppOp = (
state: State,
appOp: AppOp,
exec: Exec
): Observable<State> =>
runAppOp(state, appOp, exec).pipe(
map(event => ({ type: "onRunnerEvent", event })),
reduce(reducer, state)
);
export const runOne = (state: State, exec: Exec): Observable<State> => {
const next = getNextAppOp(state);
if (!next) return of(state);
return runOneAppOp(state, next, exec);
};