Skip to content
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
6 changes: 5 additions & 1 deletion packages/wallet/src/Wallets/BaseWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ export interface BaseWalletDependencies {
readonly connectionStatusTracker$?: ConnectionStatusTracker;
readonly publicCredentialsManager: PublicCredentialsManager;
readonly inputResolver?: Cardano.InputResolver;
/** control whether tip tracker should be polling */
readonly pollController$?: Observable<boolean>;
}

export interface SubmitTxOptions {
Expand Down Expand Up @@ -327,7 +329,8 @@ export class BaseWallet implements ObservableWallet {
publicCredentialsManager,
stores = createInMemoryWalletStores(),
connectionStatusTracker$ = createSimpleConnectionStatusTracker(),
inputResolver
inputResolver,
pollController$ = of(true)
}: BaseWalletDependencies
) {
this.#logger = contextLogger(logger, name);
Expand Down Expand Up @@ -397,6 +400,7 @@ export class BaseWallet implements ObservableWallet {
logger: contextLogger(this.#logger, 'tip$'),
maxPollInterval: maxInterval,
minPollInterval: pollInterval,
pollController$,
provider$: pollProvider({
cancel$,
logger: contextLogger(this.#logger, 'tip$'),
Expand Down
26 changes: 20 additions & 6 deletions packages/wallet/src/services/TipTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export interface TipTrackerProps {
provider$: Observable<Cardano.Tip>;
syncStatus: SyncStatus;
connectionStatus$: Observable<ConnectionStatus>;
/** control whether tip tracker should be polling */
pollController$: Observable<boolean>;
store: DocumentStore<Cardano.Tip>;
/** Once */
minPollInterval: Milliseconds;
Expand All @@ -46,7 +48,16 @@ export class TipTracker extends PersistentDocumentTrackerSubject<Cardano.Tip> {
#logger: Logger;

constructor(
{ provider$, minPollInterval, maxPollInterval, store, syncStatus, connectionStatus$, logger }: TipTrackerProps,
{
provider$,
pollController$,
minPollInterval,
maxPollInterval,
store,
syncStatus,
connectionStatus$,
logger
}: TipTrackerProps,
{ externalTrigger$ = new Subject() }: TipTrackerInternals = {}
) {
super(
Expand All @@ -63,14 +74,17 @@ export class TipTracker extends PersistentDocumentTrackerSubject<Cardano.Tip> {
// trigger fetch on start
startWith(null)
),
connectionStatus$
connectionStatus$,
pollController$
]).pipe(
tap(([, connectionStatus]) => {
logger.debug(connectionStatus === ConnectionStatus.down ? 'Skipping fetch tip' : 'Fetching tip...');
tap(([, connectionStatus, poll]) => {
logger.debug(
connectionStatus === ConnectionStatus.down || !poll ? 'Skipping fetch tip' : 'Fetching tip...'
);
}),
// Throttle syncing by interval, cancel ongoing request on external trigger
exhaustMap(([, connectionStatus]) =>
connectionStatus === ConnectionStatus.down
exhaustMap(([, connectionStatus, poll]) =>
connectionStatus === ConnectionStatus.down || !poll
? EMPTY
: provider$.pipe(takeUntil(externalTrigger$.pipe(tap(() => logger.debug('Tip fetch canceled')))))
),
Expand Down
31 changes: 31 additions & 0 deletions packages/wallet/test/services/TipTracker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: pollInterval,
pollController$: of(true),
provider$,
store,
syncStatus: { isSettled$: NEVER } as unknown as SyncStatus
Expand All @@ -62,6 +63,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: poll,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand All @@ -84,6 +86,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: pollInterval,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand All @@ -105,6 +108,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: pollInterval,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand All @@ -131,6 +135,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: pollInterval,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand All @@ -154,6 +159,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: 6,
minPollInterval: pollInterval,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand All @@ -177,6 +183,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: 0,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand All @@ -185,6 +192,29 @@ describe('TipTracker', () => {
});
});

it('is not polling while last poll$ emission is false', () => {
createTestScheduler().run(({ cold, hot, expectObservable }) => {
const poll$ = hot('t----f----t|', trueFalse);
const syncStatus: Partial<SyncStatus> = { isSettled$: cold('tftft', trueFalse) };
const provider$ = createStubObservable<Cardano.Tip>(
cold('a|', mockTips),
cold('b|', mockTips),
cold('c|', mockTips)
);
const tracker$ = new TipTracker({
connectionStatus$,
logger,
maxPollInterval: Number.MAX_VALUE,
minPollInterval: pollInterval,
pollController$: poll$,
provider$,
store,
syncStatus: syncStatus as SyncStatus
});
expectObservable(tracker$, '^-----------!').toBe('a--b------c', mockTips);
});
});

it('syncStatus timeout while connection is down does not emit tip updates', () => {
createTestScheduler().run(({ cold, hot, expectObservable, expectSubscriptions }) => {
const syncStatus: Partial<SyncStatus> = { isSettled$: hot('10ms |') };
Expand All @@ -195,6 +225,7 @@ describe('TipTracker', () => {
logger,
maxPollInterval: 6,
minPollInterval: 0,
pollController$: of(true),
provider$,
store,
syncStatus: syncStatus as SyncStatus
Expand Down
Loading