in source/nodejs/adaptivecards/src/adaptive-applet.ts [521:715]
private async internalSendActivityRequestAsync(request: ActivityRequest) {
if (!this.channelAdapter) {
throw new Error("internalSendActivityRequestAsync: channelAdapter is not set.");
}
const overlay = this.createProgressOverlay(request);
if (overlay !== undefined) {
this.renderedElement.appendChild(overlay);
}
let done = false;
while (!done) {
let response: ActivityResponse | undefined = undefined;
if (request.attemptNumber === 1) {
logEvent(
Enums.LogLevel.Info,
"Sending activity request to channel (attempt " + request.attemptNumber + ")"
);
} else {
logEvent(
Enums.LogLevel.Info,
"Re-sending activity request to channel (attempt " + request.attemptNumber + ")"
);
}
try {
response = await this.channelAdapter.sendRequestAsync(request);
} catch (error) {
logEvent(Enums.LogLevel.Error, "Activity request failed: " + error);
this.removeProgressOverlay(request);
done = true;
}
if (response) {
if (response instanceof SuccessResponse) {
this.removeProgressOverlay(request);
if (response.rawContent === undefined) {
throw new Error(
"internalSendActivityRequestAsync: Action.Execute result is undefined"
);
}
let parsedContent = response.rawContent;
try {
parsedContent = JSON.parse(response.rawContent);
} catch {
// Leave parseContent as is
}
if (typeof parsedContent === "string") {
logEvent(
Enums.LogLevel.Info,
"The activity request returned a string after " +
request.attemptNumber +
" attempt(s)."
);
this.activityRequestSucceeded(response, parsedContent);
} else if (
typeof parsedContent === "object" &&
parsedContent["type"] === "AdaptiveCard"
) {
logEvent(
Enums.LogLevel.Info,
"The activity request returned an Adaptive Card after " +
request.attemptNumber +
" attempt(s)."
);
this.internalSetCard(parsedContent, request.consecutiveRefreshes);
this.activityRequestSucceeded(response, this.card);
} else {
throw new Error(
"internalSendActivityRequestAsync: Action.Execute result is of unsupported type (" +
typeof response.rawContent +
")"
);
}
done = true;
} else if (response instanceof ErrorResponse) {
const retryIn: number = this.activityRequestFailed(response);
if (
retryIn >= 0 &&
request.attemptNumber < GlobalSettings.applets.maximumRetryAttempts
) {
logEvent(
Enums.LogLevel.Warning,
`Activity request failed: ${response.error.message}. Retrying in ${retryIn}ms`
);
request.attemptNumber++;
await new Promise<void>((resolve, _reject) => {
window.setTimeout(() => {
resolve();
}, retryIn);
});
} else {
logEvent(
Enums.LogLevel.Error,
`Activity request failed: ${response.error.message}. Giving up after ${request.attemptNumber} attempt(s)`
);
this.removeProgressOverlay(request);
done = true;
}
} else if (response instanceof LoginRequestResponse) {
logEvent(
Enums.LogLevel.Info,
"The activity request returned a LoginRequestResponse after " +
request.attemptNumber +
" attempt(s)."
);
if (request.attemptNumber <= GlobalSettings.applets.maximumRetryAttempts) {
let attemptOAuth = true;
if (response.tokenExchangeResource && this.onSSOTokenNeeded) {
// Attempt to use SSO. The host will return true if it can handle SSO, in which case
// we bypass OAuth
attemptOAuth = !this.onSSOTokenNeeded(
this,
request,
response.tokenExchangeResource
);
}
if (attemptOAuth) {
// Attempt to use OAuth
this.removeProgressOverlay(request);
if (response.signinButton === undefined) {
throw new Error(
"internalSendActivityRequestAsync: the login request doesn't contain a valid signin URL."
);
}
logEvent(
Enums.LogLevel.Info,
"Login required at " + response.signinButton.value
);
if (this.onShowSigninPrompt) {
// Bypass the built-in auth prompt if the host app handles it
this.onShowSigninPrompt(this, request, response.signinButton);
} else {
this.showAuthCodeInputDialog(request);
const left =
window.screenX +
(window.outerWidth - GlobalSettings.applets.authPromptWidth) /
2;
const top =
window.screenY +
(window.outerHeight - GlobalSettings.applets.authPromptHeight) /
2;
window.open(
response.signinButton.value,
response.signinButton.title
? response.signinButton.title
: "Sign in",
`width=${GlobalSettings.applets.authPromptWidth},height=${GlobalSettings.applets.authPromptHeight},left=${left},top=${top}`
);
}
}
} else {
logEvent(
Enums.LogLevel.Error,
"Authentication failed. Giving up after " +
request.attemptNumber +
" attempt(s)"
);
alert(Strings.magicCodeInputCard.authenticationFailed());
}
// Exit the loop. After a LoginRequestResponse, the host app is responsible for retrying the request
break;
} else {
throw new Error("Unhandled response type: " + JSON.stringify(response));
}
}
}
}