Skip to content

Commit 9bad2df

Browse files
committed
refactor!: rename 'coldObservableProvider' util to 'poll'
this util is not Provider-aware it resides in 'util-rxjs' package, which does not depend on 'core' follow-up commit will add a new Provider-aware util that knows about retryable ProviderErrors BREAKING CHANGE: rename poll props 'provider' to 'sample'
1 parent 350fbb0 commit 9bad2df

File tree

13 files changed

+109
-108
lines changed

13 files changed

+109
-108
lines changed

packages/tx-construction/src/tx-builder/TxBuilder.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ import {
3939
validateValidityInterval
4040
} from './utils';
4141
import { SelectionSkeleton } from '@cardano-sdk/input-selection';
42-
import { coldObservableProvider } from '@cardano-sdk/util-rxjs';
4342
import { contextLogger, deepEquals } from '@cardano-sdk/util';
4443
import { createOutputValidator } from '../output-validation';
4544
import { initializeTx } from './initializeTx';
4645
import { lastValueFrom } from 'rxjs';
46+
import { poll } from '@cardano-sdk/util-rxjs';
4747
import omit from 'lodash/omit.js';
4848
import uniq from 'lodash/uniq.js';
4949

@@ -499,12 +499,12 @@ export class GenericTxBuilder implements TxBuilder {
499499
allRewardAccounts = uniq([...knownAddresses, ...newAddresses]).map(({ rewardAccount }) => rewardAccount);
500500
}
501501

502-
const rewardAccounts$ = coldObservableProvider({
502+
const rewardAccounts$ = poll({
503503
logger: contextLogger(this.#logger, 'getOrCreateRewardAccounts'),
504504
pollUntil: (rewardAccounts) =>
505505
allRewardAccounts.every((newAccount) => rewardAccounts.some((acct) => acct.address === newAccount)),
506-
provider: this.#dependencies.txBuilderProviders.rewardAccounts,
507-
retryBackoffConfig: { initialInterval: 10, maxInterval: 100, maxRetries: 10 }
506+
retryBackoffConfig: { initialInterval: 10, maxInterval: 100, maxRetries: 10 },
507+
sample: this.#dependencies.txBuilderProviders.rewardAccounts
508508
});
509509

510510
try {

packages/util-rxjs/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ export * from './passthrough';
55
export * from './finalizeWithLatest';
66
export * from './concatAndCombineLatest';
77
export * from './shareRetryBackoff';
8-
export * from './coldObservableProvider';
8+
export * from './poll';
99
export * from './types';

packages/util-rxjs/src/coldObservableProvider.ts renamed to packages/util-rxjs/src/poll.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import {
1818
} from 'rxjs';
1919
import { RetryBackoffConfig, retryBackoff } from 'backoff-rxjs';
2020

21-
export interface ColdObservableProviderProps<T> {
22-
provider: () => Promise<T>;
21+
export interface PollProps<T> {
22+
sample: () => Promise<T>;
2323
retryBackoffConfig: RetryBackoffConfig;
2424
onFatalError?: (value: unknown) => void;
2525
trigger$?: Observable<unknown>;
@@ -30,8 +30,8 @@ export interface ColdObservableProviderProps<T> {
3030
logger: Logger;
3131
}
3232

33-
export const coldObservableProvider = <T>({
34-
provider,
33+
export const poll = <T>({
34+
sample,
3535
retryBackoffConfig,
3636
onFatalError,
3737
trigger$ = of(true),
@@ -40,15 +40,15 @@ export const coldObservableProvider = <T>({
4040
cancel$ = NEVER,
4141
pollUntil = () => true,
4242
logger
43-
}: ColdObservableProviderProps<T>) =>
43+
}: PollProps<T>) =>
4444
new Observable<T>((subscriber) => {
4545
const cancelOnFatalError$ = new Subject<boolean>();
4646
const internalCancel$ = merge(cancel$, cancelOnFatalError$);
4747
const sub = trigger$
4848
.pipe(
4949
combinator(() =>
5050
defer(() =>
51-
from(provider()).pipe(
51+
from(sample()).pipe(
5252
mergeMap((v) =>
5353
pollUntil(v)
5454
? of(v)

packages/util-rxjs/test/coldObservableProvider.test.ts renamed to packages/util-rxjs/test/poll.test.ts

+45-45
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,84 @@ import { BehaviorSubject, EmptyError, Subject, firstValueFrom, lastValueFrom, ta
22
import { InvalidStringError } from '@cardano-sdk/util';
33
import { RetryBackoffConfig, retryBackoff } from 'backoff-rxjs';
44
import { TestLogger, createLogger } from '@cardano-sdk/util-dev';
5-
import { coldObservableProvider } from '../src';
5+
import { poll } from '../src';
66

77
// There might be a more elegant way to mock with original implementation (spy)
88
jest.mock('backoff-rxjs', () => ({
99
retryBackoff: jest.fn().mockImplementation((...args) => jest.requireActual('backoff-rxjs').retryBackoff(...args))
1010
}));
1111

12-
describe('coldObservableProvider', () => {
12+
describe('poll', () => {
1313
let logger: TestLogger;
1414
const testErrorStr = 'Test error';
1515

1616
beforeEach(() => {
1717
logger = createLogger({ record: true });
1818
});
1919

20-
it('returns an observable that calls underlying provider on each subscription and uses retryBackoff', async () => {
21-
const underlyingProvider = jest.fn().mockResolvedValue(true);
20+
it('returns an observable that calls sample on each subscription and uses retryBackoff', async () => {
21+
const sample = jest.fn().mockResolvedValue(true);
2222
const backoffConfig: RetryBackoffConfig = { initialInterval: 1 };
23-
const provider$ = coldObservableProvider({
23+
const values$ = poll({
2424
logger,
25-
provider: underlyingProvider,
26-
retryBackoffConfig: backoffConfig
25+
retryBackoffConfig: backoffConfig,
26+
sample
2727
});
28-
expect(await firstValueFrom(provider$)).toBe(true);
29-
expect(await firstValueFrom(provider$)).toBe(true);
30-
expect(underlyingProvider).toBeCalledTimes(2);
28+
expect(await firstValueFrom(values$)).toBe(true);
29+
expect(await firstValueFrom(values$)).toBe(true);
30+
expect(sample).toBeCalledTimes(2);
3131
expect(retryBackoff).toBeCalledTimes(2);
3232
});
3333

34-
it('provider is unsubscribed on cancel emit', async () => {
35-
const fakeProviderSubject = new Subject();
36-
const underlyingProvider = () => firstValueFrom(fakeProviderSubject);
34+
it('completes on cancel emit', async () => {
35+
const fakeSampleSubject = new Subject();
36+
const sample = () => firstValueFrom(fakeSampleSubject);
3737
const backoffConfig: RetryBackoffConfig = { initialInterval: 1 };
3838
const cancel$ = new BehaviorSubject<boolean>(true);
39-
const provider$ = coldObservableProvider({
39+
const values$ = poll({
4040
cancel$,
4141
logger,
42-
provider: underlyingProvider,
43-
retryBackoffConfig: backoffConfig
42+
retryBackoffConfig: backoffConfig,
43+
sample
4444
});
4545

4646
try {
47-
await firstValueFrom(provider$);
47+
await firstValueFrom(values$);
4848
} catch (error) {
4949
expect(error).toBeInstanceOf(EmptyError);
5050
}
5151
expect.assertions(1);
5252
});
5353

54-
it('retries using retryBackoff, when underlying provider rejects', async () => {
55-
const underlyingProvider = jest.fn().mockRejectedValueOnce(false).mockResolvedValue(true);
54+
it('retries using retryBackoff, when sample rejects', async () => {
55+
const sample = jest.fn().mockRejectedValueOnce(false).mockResolvedValue(true);
5656
const retryBackoffConfig: RetryBackoffConfig = { initialInterval: 1 };
57-
const provider$ = coldObservableProvider({ logger, provider: underlyingProvider, retryBackoffConfig });
58-
const resolvedValue = await firstValueFrom(provider$);
59-
expect(underlyingProvider).toBeCalledTimes(2);
57+
const values$ = poll({ logger, retryBackoffConfig, sample });
58+
const resolvedValue = await firstValueFrom(values$);
59+
expect(sample).toBeCalledTimes(2);
6060
expect(resolvedValue).toBeTruthy();
6161
});
6262

63-
it('does not retry, when underlying provider rejects with InvalidStringError', async () => {
63+
it('does not retry, when sample rejects with InvalidStringError', async () => {
6464
const testValue = { test: 'value' };
6565
const testError = new InvalidStringError('Test invalid string error');
66-
const underlyingProvider = jest
66+
const sample = jest
6767
.fn()
6868
.mockRejectedValueOnce(new Error(testErrorStr))
6969
.mockResolvedValueOnce(testValue)
7070
.mockRejectedValueOnce(testError)
7171
.mockResolvedValueOnce(testValue);
7272
const onFatalError = jest.fn();
7373
const retryBackoffConfig: RetryBackoffConfig = { initialInterval: 1, shouldRetry: () => true };
74-
const provider$ = coldObservableProvider({
74+
const values$ = poll({
7575
logger,
7676
onFatalError,
77-
provider: underlyingProvider,
78-
retryBackoffConfig
77+
retryBackoffConfig,
78+
sample
7979
});
80-
await expect(firstValueFrom(provider$)).resolves.toBe(testValue);
81-
await expect(firstValueFrom(provider$)).rejects.toThrow(EmptyError);
82-
expect(underlyingProvider).toBeCalledTimes(3);
80+
await expect(firstValueFrom(values$)).resolves.toBe(testValue);
81+
await expect(firstValueFrom(values$)).rejects.toThrow(EmptyError);
82+
expect(sample).toBeCalledTimes(3);
8383
expect(onFatalError).toBeCalledWith(testError);
8484
expect(logger.messages).toStrictEqual([
8585
{ level: 'error', message: [new Error(testErrorStr)] },
@@ -89,45 +89,45 @@ describe('coldObservableProvider', () => {
8989
]);
9090
});
9191

92-
it('polls the provider until the pollUntil condition is satisfied', async () => {
93-
const underlyingProvider = jest
92+
it('polls sample until the pollUntil condition is satisfied', async () => {
93+
const sample = jest
9494
.fn()
9595
.mockResolvedValueOnce('a')
9696
.mockResolvedValueOnce('b')
9797
.mockResolvedValueOnce('c')
9898
.mockResolvedValue('Never reached');
9999
const backoffConfig: RetryBackoffConfig = { initialInterval: 1 };
100100

101-
const provider$ = coldObservableProvider({
101+
const values$ = poll({
102102
logger,
103103
pollUntil: (v) => v === 'c',
104-
provider: underlyingProvider,
105-
retryBackoffConfig: backoffConfig
104+
retryBackoffConfig: backoffConfig,
105+
sample
106106
});
107107

108-
const providerValues: unknown[] = [];
109-
await lastValueFrom(provider$.pipe(tap((v) => providerValues.push(v))));
110-
expect(providerValues).toEqual(['a', 'b', 'c']);
111-
expect(underlyingProvider).toBeCalledTimes(3);
108+
const sampleValues: unknown[] = [];
109+
await lastValueFrom(values$.pipe(tap((v) => sampleValues.push(v))));
110+
expect(sampleValues).toEqual(['a', 'b', 'c']);
111+
expect(sample).toBeCalledTimes(3);
112112
});
113113

114114
it('stops retrying after maxRetries attempts and handles the error in catchError', async () => {
115115
const testError = new Error(testErrorStr);
116-
const underlyingProvider = jest.fn().mockRejectedValue(testError);
116+
const sample = jest.fn().mockRejectedValue(testError);
117117
const maxRetries = 3;
118118
const retryBackoffConfig: RetryBackoffConfig = { initialInterval: 1, maxRetries };
119119
const onFatalError = jest.fn();
120120

121-
const provider$ = coldObservableProvider({
121+
const values$ = poll({
122122
logger,
123123
onFatalError,
124-
provider: underlyingProvider,
125-
retryBackoffConfig
124+
retryBackoffConfig,
125+
sample
126126
});
127127

128-
await expect(firstValueFrom(provider$)).rejects.toThrow(testError);
128+
await expect(firstValueFrom(values$)).rejects.toThrow(testError);
129129

130-
expect(underlyingProvider).toBeCalledTimes(maxRetries + 1);
130+
expect(sample).toBeCalledTimes(maxRetries + 1);
131131
expect(onFatalError).toBeCalledWith(expect.any(Error));
132132
expect(logger.messages).toStrictEqual([
133133
{ level: 'error', message: [testError] },

packages/wallet/src/Wallets/BaseWallet.ts

+17-17
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ import {
7171
TxSubmitProvider,
7272
UtxoProvider
7373
} from '@cardano-sdk/core';
74-
import { BehaviorObservable, TrackerSubject, coldObservableProvider } from '@cardano-sdk/util-rxjs';
74+
import { BehaviorObservable, TrackerSubject, poll } from '@cardano-sdk/util-rxjs';
7575
import {
7676
BehaviorSubject,
7777
EMPTY,
@@ -369,15 +369,15 @@ export class BaseWallet implements ObservableWallet {
369369

370370
if (isBip32PublicCredentialsManager(this.#publicCredentialsManager)) {
371371
this.#addressTracker = createAddressTracker({
372-
addressDiscovery$: coldObservableProvider({
372+
addressDiscovery$: poll({
373373
cancel$,
374374
logger: contextLogger(this.#logger, 'addressDiscovery$'),
375375
onFatalError,
376-
provider: () => {
376+
retryBackoffConfig,
377+
sample: () => {
377378
const credManager = this.#publicCredentialsManager as Bip32PublicCredentialsManager;
378379
return credManager.addressDiscovery.discover(credManager.bip32Account);
379-
},
380-
retryBackoffConfig
380+
}
381381
}).pipe(
382382
take(1),
383383
catchError((error) => {
@@ -403,12 +403,12 @@ export class BaseWallet implements ObservableWallet {
403403
logger: contextLogger(this.#logger, 'tip$'),
404404
maxPollInterval: maxInterval,
405405
minPollInterval: pollInterval,
406-
provider$: coldObservableProvider({
406+
provider$: poll({
407407
cancel$,
408408
logger: contextLogger(this.#logger, 'tip$'),
409409
onFatalError,
410-
provider: this.networkInfoProvider.ledgerTip,
411-
retryBackoffConfig
410+
retryBackoffConfig,
411+
sample: this.networkInfoProvider.ledgerTip
412412
}),
413413
store: stores.tip,
414414
syncStatus: this.syncStatus
@@ -426,13 +426,13 @@ export class BaseWallet implements ObservableWallet {
426426
// Era summaries
427427
const eraSummariesTrigger = new BehaviorSubject<void>(void 0);
428428
this.eraSummaries$ = new PersistentDocumentTrackerSubject(
429-
coldObservableProvider({
429+
poll({
430430
cancel$,
431431
equals: deepEquals,
432432
logger: contextLogger(this.#logger, 'eraSummaries$'),
433433
onFatalError,
434-
provider: this.networkInfoProvider.eraSummaries,
435434
retryBackoffConfig,
435+
sample: this.networkInfoProvider.eraSummaries,
436436
trigger$: eraSummariesTrigger.pipe(tap(() => 'Trigger request era summaries'))
437437
}),
438438
stores.eraSummaries
@@ -450,25 +450,25 @@ export class BaseWallet implements ObservableWallet {
450450
tap((epoch) => this.#logger.debug(`Current epoch is ${epoch}`))
451451
);
452452
this.protocolParameters$ = new PersistentDocumentTrackerSubject(
453-
coldObservableProvider({
453+
poll({
454454
cancel$,
455455
equals: isEqual,
456456
logger: contextLogger(this.#logger, 'protocolParameters$'),
457457
onFatalError,
458-
provider: this.networkInfoProvider.protocolParameters,
459458
retryBackoffConfig,
459+
sample: this.networkInfoProvider.protocolParameters,
460460
trigger$: epoch$
461461
}),
462462
stores.protocolParameters
463463
);
464464
this.genesisParameters$ = new PersistentDocumentTrackerSubject(
465-
coldObservableProvider({
465+
poll({
466466
cancel$,
467467
equals: isEqual,
468468
logger: contextLogger(this.#logger, 'genesisParameters$'),
469469
onFatalError,
470-
provider: this.networkInfoProvider.genesisParameters,
471470
retryBackoffConfig,
471+
sample: this.networkInfoProvider.genesisParameters,
472472
trigger$: epoch$
473473
}),
474474
stores.genesisParameters
@@ -602,13 +602,13 @@ export class BaseWallet implements ObservableWallet {
602602
this.handles$ = this.handleProvider
603603
? this.initializeHandles(
604604
new PersistentDocumentTrackerSubject(
605-
coldObservableProvider({
605+
poll({
606606
cancel$,
607607
equals: isEqual,
608608
logger: contextLogger(this.#logger, 'handles$'),
609609
onFatalError,
610-
provider: () => this.handleProvider.getPolicyIds(),
611-
retryBackoffConfig
610+
retryBackoffConfig,
611+
sample: () => this.handleProvider.getPolicyIds()
612612
}),
613613
stores.policyIds
614614
)

packages/wallet/src/services/AssetsTracker.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from 'rxjs';
2121
import { RetryBackoffConfig } from 'backoff-rxjs';
2222
import { TrackedAssetProvider } from './ProviderTracker';
23-
import { coldObservableProvider, concatAndCombineLatest } from '@cardano-sdk/util-rxjs';
23+
import { concatAndCombineLatest, poll } from '@cardano-sdk/util-rxjs';
2424
import { deepEquals, isNotNil } from '@cardano-sdk/util';
2525
import { newTransactions$ } from './TransactionsTracker';
2626
import chunk from 'lodash/chunk.js';
@@ -139,13 +139,13 @@ export const createAssetService =
139139
(assetIds: Cardano.AssetId[]) =>
140140
concatAndCombineLatest(
141141
chunk(assetIds, ASSET_INFO_FETCH_CHUNK_SIZE).map((assetIdsChunk) =>
142-
coldObservableProvider({
142+
poll({
143143
logger,
144144
onFatalError,
145145
pollUntil: isEveryAssetInfoComplete,
146-
provider: () =>
147-
getAssetsWithCache(assetIdsChunk, assetCache$, totalBalance$, assetProvider, maxAssetInfoCacheAge),
148146
retryBackoffConfig,
147+
sample: () =>
148+
getAssetsWithCache(assetIdsChunk, assetCache$, totalBalance$, assetProvider, maxAssetInfoCacheAge),
149149
trigger$: of(true) // fetch only once
150150
})
151151
)

0 commit comments

Comments
 (0)