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
5 changes: 5 additions & 0 deletions packages/widgets-core/src/datasource/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export default async function executeApiDatasource (config: ApiDatasourceConfig,
throw new HttpRequestError(response, await response.json());
}

if (!ctx.httpResponses) {
ctx.httpResponses = [];
}
ctx.httpResponses.push(response);

const data = await response.json();

return jp.query(data, config.parser.extract);
Expand Down
4 changes: 4 additions & 0 deletions packages/widgets-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export interface WidgetBaseContext<P extends Record<string, any> = Record<string
parameters: P;

getTimeParams (): { zone: string, period: string };

// For collect response info to calculate cache
// See: https://github.com/pingcap/ossinsight-next/issues/47
httpResponses?: Response[];
}

export interface LinkedDataContext {
Expand Down
12 changes: 10 additions & 2 deletions web/app/widgets/[vendor]/[name]/thumbnail.png/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { computeExpired } from '@/app/widgets/[vendor]/[name]/thumbnail.png/utils';
import config from '@/site.config';
import { apiEvent, autoParams, serverSendGaMeasurementEvent } from '@/utils/ga';
import { resolveImageSizeConfig } from '@/utils/siteConfig';
Expand Down Expand Up @@ -56,7 +57,11 @@ export async function GET (request: NextRequest, { params: { vendor, name: param
...autoParams('widget_param_', parameters),
}, request)]);

const data = await datasource(createWidgetBaseContext('server', parameters));
const ctx = createWidgetBaseContext('server', parameters);
const data = await datasource(ctx);
const expires = computeExpired(ctx)
// If no expires header exists in request context, set the cache to 3 minutes
?? new Date(Date.now() + 1000 * 60 * 3);

const colorScheme = request.nextUrl.searchParams.get('color_scheme') ?? 'dark';

Expand Down Expand Up @@ -121,9 +126,12 @@ export async function GET (request: NextRequest, { params: { vendor, name: param
return new NextResponse(canvas.toBuffer('image/png'), {
headers: {
'Content-Type': 'image/png',
...(expires && {
'Expires': expires.toUTCString(),
'Cache-Control': 'public',
}),
},
});
}

export const dynamic = 'force-dynamic';
export const fetchCache = 'force-cache';
30 changes: 30 additions & 0 deletions web/app/widgets/[vendor]/[name]/thumbnail.png/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { WidgetBaseContext } from '@ossinsight/widgets-types';

const DAYS = 1000 * 60 * 60 * 24;

/**
* Get `Expires` fields from all responses. If any response was empty, returns null.
* @param ctx
* @param maxDays set the max expires days.
*/
export function computeExpired (ctx: WidgetBaseContext, maxDays = 1) {
if (ctx.httpResponses?.length === 0) {
return null;
}

return ctx.httpResponses?.reduce((date: Date | null, response) => {
const e = response.headers.get('Expires');
if (e) {
const newDate = new Date(e);
if (date) {
if (newDate < date) {
return newDate;
} else {
return date;
}
}
return null;
}
return null;
}, new Date(Date.now() + maxDays * DAYS));
}