dosubot[bot] commented on issue #29902:
URL: https://github.com/apache/superset/issues/29902#issuecomment-2277357852
<!-- Greeting -->
Hey @da201501245! 👋 I'm here to help you with any bugs, questions, or
contributions. Let's squash those bugs together!
<!-- Answer -->
To address the issue where the `fetchGuestToken` function is not called
after the internet connection is restored, you can implement a mechanism to
detect when the internet connection is back online and then refresh the guest
token. Here is an improved implementation that ensures the `fetchGuestToken`
function is called to refresh the guest token after the internet connection is
restored:
```ts
import jwt_decode from "jwt-decode";
const REFRESH_TIMING_BUFFER_MS = 5000; // refresh guest token early to avoid
failed superset requests
const MIN_REFRESH_WAIT_MS = 10000; // avoid blasting requests as fast as the
cpu can handle
const DEFAULT_TOKEN_EXP_MS = 300000; // (5 min) used only when parsing guest
token exp fails
function getGuestTokenRefreshTiming(currentGuestToken: string) {
const parsedJwt = jwt_decode<Record<string, any>>(currentGuestToken);
const exp = new Date(/[^0-9\.]/g.test(parsedJwt.exp) ? parsedJwt.exp :
parseFloat(parsedJwt.exp) * 1000);
const isValidDate = exp.toString() !== 'Invalid Date';
const ttl = isValidDate ? Math.max(MIN_REFRESH_WAIT_MS, exp.getTime() -
Date.now()) : DEFAULT_TOKEN_EXP_MS;
return ttl - REFRESH_TIMING_BUFFER_MS;
}
function setupGuestTokenRefresh(fetchGuestToken: () => Promise<string>,
ourPort: any) {
async function refreshGuestToken() {
const newGuestToken = await fetchGuestToken();
ourPort.emit('guestToken', { guestToken: newGuestToken });
setTimeout(refreshGuestToken, getGuestTokenRefreshTiming(newGuestToken));
}
function handleOnline() {
refreshGuestToken();
}
// Check if the browser is online when the script runs
if (navigator.onLine) {
refreshGuestToken();
}
// Add an event listener to detect when the internet connection is restored
window.addEventListener('online', handleOnline);
// Optionally, you can add an event listener to handle when the internet
connection is lost
window.addEventListener('offline', () => {
console.log('Internet connection lost');
});
// Initial token refresh setup
fetchGuestToken().then(initialToken => {
ourPort.emit('guestToken', { guestToken: initialToken });
setTimeout(refreshGuestToken, getGuestTokenRefreshTiming(initialToken));
});
}
// Example usage within the embedDashboard function
export async function embedDashboard({
id,
supersetDomain,
mountPoint,
fetchGuestToken,
dashboardUiConfig,
debug = false,
iframeTitle = "Embedded Dashboard",
}: EmbedDashboardParams): Promise<EmbeddedDashboard> {
function log(...info: unknown[]) {
if (debug) {
console.debug(`[superset-embedded-sdk][dashboard ${id}]`, ...info);
}
}
log('embedding');
if (supersetDomain.endsWith("/")) {
supersetDomain = supersetDomain.slice(0, -1);
}
function calculateConfig() {
let configNumber = 0;
if (dashboardUiConfig) {
if (dashboardUiConfig.hideTitle) {
configNumber += 1;
}
if (dashboardUiConfig.hideTab) {
configNumber += 2;
}
if (dashboardUiConfig.hideChartControls) {
configNumber += 8;
}
}
return configNumber;
}
async function mountIframe(): Promise<Switchboard> {
return new Promise(resolve => {
const iframe = document.createElement('iframe');
const dashboardConfigUrlParams = dashboardUiConfig ? { uiConfig:
`${calculateConfig()}` } : undefined;
const filterConfig = dashboardUiConfig?.filters || {};
const filterConfigKeys = Object.keys(filterConfig);
const filterConfigUrlParams = Object.fromEntries(filterConfigKeys.map(
key => [DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY[key],
filterConfig[key]]
));
// Allow url query parameters from dashboardUiConfig.urlParams to
override the ones from filterConfig
const urlParams = { ...dashboardConfigUrlParams,
...filterConfigUrlParams, ...dashboardUiConfig?.urlParams };
const urlParamsString = Object.keys(urlParams).length ? '?' + new
URLSearchParams(urlParams).toString() : '';
// set up the iframe's sandbox configuration
iframe.sandbox.add("allow-same-origin"); // needed for postMessage to
work
iframe.sandbox.add("allow-scripts"); // obviously the iframe needs
scripts
iframe.sandbox.add("allow-presentation"); // for fullscreen charts
iframe.sandbox.add("allow-downloads"); // for downloading charts as
image
iframe.sandbox.add("allow-forms"); // for forms to submit
iframe.sandbox.add("allow-popups"); // for exporting charts as csv
// add the event listener before setting src, to be 100% sure that we
capture the load event
iframe.addEventListener('load', () => {
const commsChannel = new MessageChannel();
const ourPort = commsChannel.port1;
const theirPort = commsChannel.port2;
iframe.contentWindow!.postMessage(
{ type: IFRAME_COMMS_MESSAGE_TYPE, handshake: "port transfer" },
supersetDomain,
[theirPort],
);
log('sent message channel to the iframe');
resolve(new Switchboard({ port: ourPort, name:
'superset-embedded-sdk', debug }));
});
iframe.src = `${supersetDomain}/embedded/${id}${urlParamsString}`;
iframe.title = iframeTitle;
mountPoint.replaceChildren(iframe);
log('placed the iframe');
});
}
const [guestToken, ourPort]: [string, Switchboard] = await Promise.all([
fetchGuestToken(),
mountIframe(),
]);
ourPort.emit('guestToken', { guestToken });
log('sent guest token');
setupGuestTokenRefresh(fetchGuestToken, ourPort);
function unmount() {
log('unmounting');
mountPoint.replaceChildren();
}
const getScrollSize = () => ourPort.get<Size>('getScrollSize');
const getDashboardPermalink = (anchor: string) =>
ourPort.get<string>('getDashboardPermalink', { anchor });
const getActiveTabs = () => ourPort.get<string[]>('getActiveTabs');
return {
getScrollSize,
unmount,
getDashboardPermalink,
getActiveTabs,
};
}
```
This code sets up an event listener for the `online` event, which is
triggered when the browser regains internet connectivity. When this event is
detected, the `refreshGuestToken` function is called to refresh the guest
token. The `getGuestTokenRefreshTiming` function is used to determine the
optimal timing for refreshing the guest token, ensuring it is refreshed early
enough to avoid failed requests. The `setupGuestTokenRefresh` function is
integrated into the `embedDashboard` function to handle the initial token setup
and subsequent refreshes
<sup>[[1]](https://github.com/apache/superset/blob/master/superset-embedded-sdk/src/guestTokenRefresh.test.ts)</sup><sup>[[2]](https://github.com/apache/superset/blob/master/superset-embedded-sdk/src/guestTokenRefresh.ts)</sup><sup>[[3]](https://github.com/apache/superset/blob/master/superset-embedded-sdk/src/index.ts)</sup>.
<!-- Dosu Comment Footer -->
*To continue talking to [Dosu](https://dosu.dev), mention @dosu.*
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]