Skip to content
Open
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
25 changes: 22 additions & 3 deletions src/frontend/src/lib/workers/auth.worker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AUTH_TIMER_INTERVAL } from '$lib/constants/app.constants';
import { AuthClientProvider } from '$lib/providers/auth-client.provider';
import type { PostMessageRequest } from '$lib/types/post-message';
import { nonNullish } from '@dfinity/utils';
import { IdbStorage, KEY_STORAGE_DELEGATION } from '@icp-sdk/auth/client';
import { DelegationChain, isDelegationValid } from '@icp-sdk/core/identity';

Expand All @@ -21,18 +22,36 @@ export const onAuthMessage = async ({

let timer: NodeJS.Timeout | undefined = undefined;

// Recursive setTimeout (not setInterval) so the idle check cannot overlap
// itself: the next tick is scheduled only after the previous onIdleSignOut
// resolves. See #2522 / oisy-wallet#9706 for the motivation.
const scheduleNext = (): void => {
timer = setTimeout(async () => {
await onIdleSignOut();

if (nonNullish(timer)) {
scheduleNext();
}
}, AUTH_TIMER_INTERVAL);
};

/**
* The timer is executed only if user has signed in
*/
export const startIdleTimer = () =>
(timer = setInterval(async () => await onIdleSignOut(), AUTH_TIMER_INTERVAL));
export const startIdleTimer = () => {
if (nonNullish(timer)) {
return;
}

scheduleNext();
};

export const stopIdleTimer = () => {
if (!timer) {
return;
}

clearInterval(timer);
clearTimeout(timer);
timer = undefined;
};

Expand Down
47 changes: 28 additions & 19 deletions src/frontend/src/lib/workers/cycles.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { CanisterInfo, CanisterSegment, CanisterSyncData, Segment } from '$
import type { PostMessageDataRequest, PostMessageRequest } from '$lib/types/post-message';
import { emitCanisters, emitSavedCanisters, loadIdentity } from '$lib/utils/worker.utils';
import { CanistersStore } from '$lib/workers/_stores/canisters.store';
import { isNullish } from '@dfinity/utils';
import { isNullish, nonNullish } from '@dfinity/utils';
import type { Identity } from '@icp-sdk/core/agent';
import { set } from 'idb-keyval';

Expand All @@ -38,33 +38,53 @@ export const onCyclesMessage = async ({ data: dataMsg }: MessageEvent<PostMessag

let timer: NodeJS.Timeout | undefined = undefined;

// Recursive setTimeout (not setInterval) so the canister sync cannot
// overlap itself. See #2522 / oisy-wallet#9706.
const scheduleNext = ({
identity,
segments
}: {
identity: Identity;
segments: CanisterSegment[];
}): void => {
timer = setTimeout(async () => {
await syncCanisters({ identity, segments });

if (nonNullish(timer)) {
scheduleNext({ identity, segments });
}
}, SYNC_CYCLES_TIMER_INTERVAL);
};

const startCyclesTimer = async ({ data: { segments } }: { data: PostMessageDataRequest }) => {
if (nonNullish(timer)) {
return;
}

const identity = await loadIdentity();

if (isNullish(identity)) {
// We do nothing if no identity
return;
}

const sync = async () => await syncCanisters({ identity, segments: segments ?? [] });
const effectiveSegments = segments ?? [];

// We sync the cycles now but also schedule the update afterwards
await sync();
await syncCanisters({ identity, segments: effectiveSegments });

timer = setInterval(sync, SYNC_CYCLES_TIMER_INTERVAL);
scheduleNext({ identity, segments: effectiveSegments });
};

const stopCyclesTimer = () => {
if (!timer) {
return;
}

clearInterval(timer);
clearTimeout(timer);
timer = undefined;
};

let syncing = false;

const syncCanisters = async ({
identity,
segments
Expand All @@ -77,23 +97,12 @@ const syncCanisters = async ({
return;
}

// We avoid to relaunch a sync while previous sync is not finished
if (syncing) {
return;
}

syncing = true;

await emitSavedCanisters({
canisterIds: segments.map(({ canisterId }) => canisterId),
customStore: cyclesIdbStore
});

try {
await syncIcStatusCanisters({ identity, segments });
} finally {
syncing = false;
}
await syncIcStatusCanisters({ identity, segments });
};

const syncIcStatusCanisters = async ({
Expand Down
35 changes: 19 additions & 16 deletions src/frontend/src/lib/workers/exchange.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { exchangeIdbStore } from '$lib/stores/app/idb.store';
import type { CanisterIdText } from '$lib/types/canister';
import type { ExchangePrice } from '$lib/types/exchange';
import type { PostMessageDataResponseExchange, PostMessageRequest } from '$lib/types/post-message';
import { isNullish } from '@dfinity/utils';
import { isNullish, nonNullish } from '@dfinity/utils';
import { del, entries, set } from 'idb-keyval';

export const onExchangeMessage = async ({ data: dataMsg }: MessageEvent<PostMessageRequest>) => {
Expand All @@ -22,39 +22,44 @@ export const onExchangeMessage = async ({ data: dataMsg }: MessageEvent<PostMess

let timer: NodeJS.Timeout | undefined = undefined;

// Recursive setTimeout (not setInterval) so the exchange sync cannot
// overlap itself. See #2522 / oisy-wallet#9706.
const scheduleNext = (): void => {
timer = setTimeout(async () => {
await syncExchange();

if (nonNullish(timer)) {
scheduleNext();
}
}, SYNC_TOKENS_TIMER_INTERVAL);
};

const startTimer = async () => {
const sync = async () => await syncExchange();
if (nonNullish(timer)) {
return;
}

// First we emit the value we already have in IDB
await emitSavedExchanges();

// We sync the cycles now but also schedule the update afterwards
await sync();
await syncExchange();

timer = setInterval(sync, SYNC_TOKENS_TIMER_INTERVAL);
scheduleNext();
};

const stopTimer = () => {
if (!timer) {
return;
}

clearInterval(timer);
clearTimeout(timer);
timer = undefined;
};

let syncing = false;

let retry = 0;

const syncExchange = async () => {
// We avoid to relaunch a sync while previous sync is not finished
if (syncing) {
return;
}

syncing = true;

try {
const icpExchange = await exchangeRateICPToUsd();

Expand All @@ -78,8 +83,6 @@ const syncExchange = async () => {
}

retry++;
} finally {
syncing = false;
}
};

Expand Down
37 changes: 20 additions & 17 deletions src/frontend/src/lib/workers/hosting.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SYNC_CUSTOM_DOMAIN_TIMER_INTERVAL } from '$lib/constants/app.constants'
import { getCustomDomainRegistration } from '$lib/rest/bn.v1.rest';
import type { CustomDomain, CustomDomainName, CustomDomainState } from '$lib/types/custom-domain';
import type { PostMessageDataRequest, PostMessageRequest } from '$lib/types/post-message';
import { isNullish } from '@dfinity/utils';
import { isNullish, nonNullish } from '@dfinity/utils';

export const onHostingMessage = async ({ data: dataMsg }: MessageEvent<PostMessageRequest>) => {
const { msg, data } = dataMsg;
Expand All @@ -23,34 +23,39 @@ const stopTimer = () => {
return;
}

clearInterval(timer);
clearTimeout(timer);
timer = undefined;
};

// Recursive setTimeout (not setInterval) so the registration sync cannot
// overlap itself. See #2522 / oisy-wallet#9706.
const scheduleNext = ({ customDomain }: { customDomain: CustomDomain }): void => {
timer = setTimeout(async () => {
await syncCustomDomainRegistration({ customDomain });

if (nonNullish(timer)) {
scheduleNext({ customDomain });
}
}, SYNC_CUSTOM_DOMAIN_TIMER_INTERVAL);
};

const startTimer = async ({ data: { customDomain } }: { data: PostMessageDataRequest }) => {
if (nonNullish(timer)) {
return;
}

if (isNullish(customDomain)) {
// No custom domain registration to sync
return;
}

const sync = async () => await syncCustomDomainRegistration({ customDomain });

// We sync the cycles now but also schedule the update afterwards
await sync();
await syncCustomDomainRegistration({ customDomain });

timer = setInterval(sync, SYNC_CUSTOM_DOMAIN_TIMER_INTERVAL);
scheduleNext({ customDomain });
};

let syncing = false;

const syncCustomDomainRegistration = async ({ customDomain }: { customDomain: CustomDomain }) => {
// We avoid to relaunch a sync while previous sync is not finished
if (syncing) {
return;
}

syncing = true;

try {
const sync = async (): Promise<CustomDomainState> => {
const [domainName] = customDomain;
Expand All @@ -72,8 +77,6 @@ const syncCustomDomainRegistration = async ({ customDomain }: { customDomain: Cu
// We sync until Available or Failed
stopTimer();
}

syncing = false;
};

const syncCustomDomainRegistrationV1 = async ({
Expand Down
35 changes: 19 additions & 16 deletions src/frontend/src/lib/workers/icp-cycles-rate.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
PostMessageDataResponseIcpToCyclesRate,
PostMessageRequest
} from '$lib/types/post-message';
import { isNullish } from '@dfinity/utils';
import { isNullish, nonNullish } from '@dfinity/utils';
import { del, get, set } from 'idb-keyval';

export const onIcpToCyclesRateMessage = async ({
Expand All @@ -24,35 +24,40 @@ export const onIcpToCyclesRateMessage = async ({

let timer: NodeJS.Timeout | undefined = undefined;

// Recursive setTimeout (not setInterval) so the rate sync cannot overlap
// itself. See #2522 / oisy-wallet#9706.
const scheduleNext = (): void => {
timer = setTimeout(async () => {
await syncRate();

if (nonNullish(timer)) {
scheduleNext();
}
}, SYNC_TOKENS_TIMER_INTERVAL);
};

const startTimer = async () => {
const sync = async () => await syncRate();
if (nonNullish(timer)) {
return;
}

// First we emit the value we already have in IDB
await emitSavedRate();

// We sync the cycles now but also schedule the update afterwards
await sync();
await syncRate();

timer = setInterval(sync, SYNC_TOKENS_TIMER_INTERVAL);
scheduleNext();
};

const stopTimer = () => {
clearInterval(timer);
clearTimeout(timer);
timer = undefined;
};

let syncing = false;

let retry = 0;

const syncRate = async () => {
// We avoid to relaunch a sync while previous sync is not finished
if (syncing) {
return;
}

syncing = true;

try {
const trillionRatio = await getIcpToCyclesConversionRate();

Expand All @@ -71,8 +76,6 @@ const syncRate = async () => {
}

retry++;
} finally {
syncing = false;
}
};

Expand Down
Loading