[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] branch master updated: anastasis-core: async provide
From: |
gnunet |
Subject: |
[taler-wallet-core] branch master updated: anastasis-core: async provider synchronization |
Date: |
Fri, 15 Apr 2022 12:56:19 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository wallet-core.
The following commit(s) were added to refs/heads/master by this push:
new d1b4cc99 anastasis-core: async provider synchronization
d1b4cc99 is described below
commit d1b4cc994bd287af5c8a3114eab70ee01f92b4ec
Author: Florian Dold <florian@dold.me>
AuthorDate: Fri Apr 15 12:56:16 2022 +0200
anastasis-core: async provider synchronization
---
packages/anastasis-core/src/index.ts | 71 +++++++++++++++++-----
packages/anastasis-core/src/reducer-types.ts | 8 ++-
.../src/hooks/use-anastasis-reducer.ts | 39 ++++++++++++
.../src/pages/home/ContinentSelectionScreen.tsx | 1 -
.../taler-wallet-core/src/operations/reserves.ts | 1 -
5 files changed, 101 insertions(+), 19 deletions(-)
diff --git a/packages/anastasis-core/src/index.ts
b/packages/anastasis-core/src/index.ts
index 5dd560a2..9db15264 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -94,6 +94,7 @@ import {
PolicyMetaInfo,
ChallengeInfo,
AggregatedPolicyMetaInfo,
+ AuthenticationProviderStatusMap,
} from "./reducer-types.js";
import fetchPonyfill from "fetch-ponyfill";
import {
@@ -329,15 +330,9 @@ async function backupEnterUserAttributes(
args: ActionArgsEnterUserAttributes,
): Promise<ReducerStateBackup> {
const attributes = args.identity_attributes;
- const providerUrls = Object.keys(state.authentication_providers ?? {});
- const newProviders = state.authentication_providers ?? {};
- for (const url of providerUrls) {
- newProviders[url] = await getProviderInfo(url);
- }
const newState = {
...state,
backup_state: BackupStates.AuthenticationsEditing,
- authentication_providers: newProviders,
identity_attributes: attributes,
};
return newState;
@@ -733,15 +728,23 @@ async function uploadSecret(
async function downloadPolicy(
state: ReducerStateRecovery,
): Promise<ReducerStateRecovery | ReducerStateError> {
+ logger.info("downloading policy");
let foundRecoveryInfo: RecoveryInternalData | undefined = undefined;
let recoveryDoc: RecoveryDocument | undefined = undefined;
const userAttributes = state.identity_attributes!;
if (!state.selected_version) {
throw Error("invalid state");
}
+ // FIXME: Do this concurrently/asynchronously so that one slow provider
doens't block us.
for (const prov of state.selected_version.providers) {
- const pi = state.authentication_providers?.[prov.url];
+ let pi = state.authentication_providers?.[prov.url];
if (!pi || pi.status !== "ok") {
+ // FIXME: this one blocks!
+ logger.info(`fetching provider info for ${prov.url}`);
+ pi = await getProviderInfo(prov.url);
+ }
+ logger.info(`new provider status is ${pi.status}`);
+ if (pi.status !== "ok") {
continue;
}
const userId = await userIdentifierDerive(userAttributes,
pi.provider_salt);
@@ -750,6 +753,9 @@ async function downloadPolicy(
reqUrl.searchParams.set("version", `${prov.version}`);
const resp = await fetch(reqUrl.href);
if (resp.status !== 200) {
+ logger.info(
+ `Could not download policy from provider ${prov.url}, status
${resp.status}`,
+ );
continue;
}
const body = await resp.arrayBuffer();
@@ -1058,16 +1064,10 @@ async function recoveryEnterUserAttributes(
args: ActionArgsEnterUserAttributes,
): Promise<ReducerStateRecovery | ReducerStateError> {
// FIXME: validate attributes
- const providerUrls = Object.keys(state.authentication_providers ?? {});
- const newProviders = state.authentication_providers ?? {};
- for (const url of providerUrls) {
- newProviders[url] = await getProviderInfo(url);
- }
const st: ReducerStateRecovery = {
...state,
recovery_state: RecoveryStates.SecretSelecting,
identity_attributes: args.identity_attributes,
- authentication_providers: newProviders,
};
return st;
}
@@ -1514,7 +1514,7 @@ async function nextFromChallengeSelecting(
};
}
-async function syncProviders(
+async function syncAllProvidersTransition(
state: ReducerStateRecovery,
args: void,
): Promise<ReducerStateRecovery | ReducerStateError> {
@@ -1722,7 +1722,7 @@ const recoveryTransitions: Record<
),
...transition("poll", codecForAny(), pollChallenges),
...transition("next", codecForAny(), nextFromChallengeSelecting),
- ...transition("sync_providers", codecForAny(), syncProviders),
+ ...transition("sync_providers", codecForAny(), syncAllProvidersTransition),
},
[RecoveryStates.ChallengeSolving]: {
...transitionRecoveryJump("back", RecoveryStates.ChallengeSelecting),
@@ -1746,6 +1746,7 @@ export async function discoverPolicies(
const providerUrls = Object.keys(state.authentication_providers || {});
// FIXME: Do we need to re-contact providers here / check if they're
disabled?
+ // FIXME: Do this concurrently and take the first. Otherwise, one provider
might block for a long time.
for (const providerUrl of providerUrls) {
const providerInfo = await getProviderInfo(providerUrl);
@@ -1839,3 +1840,43 @@ export async function reduceAction(
throw e;
}
}
+
+/**
+ * Update provider status of providers that we still need to contact.
+ *
+ * Returns updates as soon as new information about at least one provider
+ * is found.
+ *
+ * Returns an empty object if provider information is complete.
+ *
+ * FIXME: Also pass a cancelation token.
+ */
+export async function completeProviderStatus(
+ providerMap: AuthenticationProviderStatusMap,
+): Promise<AuthenticationProviderStatusMap> {
+ const updateTasks: Promise<[string, AuthenticationProviderStatus]>[] = [];
+ for (const [provUrl, pi] of Object.entries(providerMap)) {
+ switch (pi.status) {
+ case "ok":
+ case "error":
+ case "disabled":
+ default:
+ continue;
+ case "not-contacted":
+ updateTasks.push(
+ (async () => {
+ return [provUrl, await getProviderInfo(provUrl)];
+ })(),
+ );
+ }
+ }
+
+ if (updateTasks.length === 0) {
+ return {};
+ }
+
+ const [firstUrl, firstStatus] = await Promise.race(updateTasks);
+ return {
+ [firstUrl]: firstStatus,
+ };
+}
diff --git a/packages/anastasis-core/src/reducer-types.ts
b/packages/anastasis-core/src/reducer-types.ts
index a0af2f86..2e03a6ec 100644
--- a/packages/anastasis-core/src/reducer-types.ts
+++ b/packages/anastasis-core/src/reducer-types.ts
@@ -186,6 +186,10 @@ export interface RecoveryInformation {
}[][];
}
+export interface AuthenticationProviderStatusMap {
+ [url: string]: AuthenticationProviderStatus;
+}
+
export interface ReducerStateRecovery {
reducer_type: "recovery";
@@ -231,7 +235,7 @@ export interface ReducerStateRecovery {
value: string;
};
- authentication_providers?: { [url: string]: AuthenticationProviderStatus };
+ authentication_providers?: AuthenticationProviderStatusMap;
}
/**
@@ -342,7 +346,7 @@ export interface ReducerStateBackupUserAttributesCollecting
selected_country: string;
currencies: string[];
required_attributes: UserAttributeSpec[];
- authentication_providers: { [url: string]: AuthenticationProviderStatus };
+ authentication_providers: AuthenticationProviderStatusMap;
}
export interface ActionArgsEnterUserAttributes {
diff --git a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
index 434e5fb0..1b77db38 100644
--- a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
+++ b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
@@ -21,6 +21,7 @@ import { TalerErrorCode } from "@gnu-taler/taler-util";
import {
AggregatedPolicyMetaInfo,
BackupStates,
+ completeProviderStatus,
discoverPolicies,
DiscoveryCursor,
getBackupStartState,
@@ -206,6 +207,44 @@ export function useAnastasisReducer(): AnastasisReducerApi
{
console.log(e);
}
setAnastasisStateInternal(newState);
+
+ const tryUpdateProviders = () => {
+ const reducerState = newState.reducerState;
+ if (
+ reducerState?.reducer_type !== "backup" &&
+ reducerState?.reducer_type !== "recovery"
+ ) {
+ return;
+ }
+ const provMap = reducerState.authentication_providers;
+ if (!provMap) {
+ return;
+ }
+ const doUpdate = async () => {
+ const updates = await completeProviderStatus(provMap);
+ if (Object.keys(updates).length === 0) {
+ return;
+ }
+ console.log("got provider updates", updates);
+ const rs2 = reducerState;
+ if (rs2.reducer_type !== "backup" && rs2.reducer_type !== "recovery") {
+ return;
+ }
+ setAnastasisState({
+ ...anastasisState,
+ reducerState: {
+ ...rs2,
+ authentication_providers: {
+ ...rs2.authentication_providers,
+ ...updates,
+ },
+ },
+ });
+ };
+ doUpdate().catch((e) => console.log(e));
+ };
+
+ tryUpdateProviders();
};
async function doTransition(action: string, args: any): Promise<void> {
diff --git
a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
index 2a480de4..e5dbcd8f 100644
--- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx
@@ -37,7 +37,6 @@ export function ContinentSelectionScreen(): VNode {
if (!theCountry) return;
reducer.transition("select_country", {
country_code: countryCode,
- currencies: [theCountry.currency],
});
};
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts
b/packages/taler-wallet-core/src/operations/reserves.ts
index 8d891213..ff09d1a5 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -61,7 +61,6 @@ import {
getRetryDuration,
resetRetryInfo,
RetryInfo,
- updateRetryInfoTimeout,
} from "../util/retries.js";
import {
getExchangeDetails,
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-wallet-core] branch master updated: anastasis-core: async provider synchronization,
gnunet <=