fix: image cache revalidation (#2071)

Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
This commit is contained in:
Anshuman Pandey
2024-02-14 16:02:44 +05:30
committed by GitHub
parent e6fe027e57
commit c85ae57697
2 changed files with 23 additions and 24 deletions

View File

@@ -2,12 +2,11 @@ import { responses } from "@/app/lib/api/response";
import { notFound } from "next/navigation";
import path from "path";
import { UPLOADS_DIR } from "@formbricks/lib/constants";
import { env } from "@formbricks/lib/env.mjs";
import { IS_S3_CONFIGURED, UPLOADS_DIR } from "@formbricks/lib/constants";
import { getLocalFile, getS3File } from "@formbricks/lib/storage/service";
const getFile = async (environmentId: string, accessType: string, fileName: string) => {
if (!env.S3_ACCESS_KEY || !env.S3_SECRET_KEY || !env.S3_REGION || !env.S3_BUCKET_NAME) {
if (!IS_S3_CONFIGURED) {
try {
const { fileBuffer, metaData } = await getLocalFile(
path.join(UPLOADS_DIR, environmentId, accessType, fileName)

View File

@@ -8,6 +8,7 @@ import {
import { PresignedPostOptions, createPresignedPost } from "@aws-sdk/s3-presigned-post";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { randomUUID } from "crypto";
import { add, isAfter, parseISO } from "date-fns";
import { access, mkdir, readFile, rmdir, unlink, writeFile } from "fs/promises";
import { lookup } from "mime-types";
import { unstable_cache } from "next/cache";
@@ -99,6 +100,7 @@ const getS3SignedUrl = async (fileKey: string): Promise<string> => {
export const getS3File = async (fileKey: string): Promise<string> => {
const signedUrl = await getS3SignedUrl(fileKey);
const signedUrlObject = new URL(signedUrl);
// The logic below is to check if the signed url has expired.
// We do this by parsing the X-Amz-Date and Expires query parameters from the signed url
@@ -106,37 +108,35 @@ export const getS3File = async (fileKey: string): Promise<string> => {
// If it is, we generate a new signed url and return that instead.
// We do this because the time-based revalidation for the signed url is not working as expected. (mayve a bug in next.js caching?)
const amzDate = signedUrl.match(/X-Amz-Date=(.*?)&/)?.[1];
const amzExpires = signedUrl.match(/X-Amz-Expires=(.*?)&/)?.[1];
const amzDate = signedUrlObject.searchParams.get("X-Amz-Date");
const amzExpires = signedUrlObject.searchParams.get("X-Amz-Expires");
if (amzDate && amzExpires) {
// Parse the X-Amz-Date and calculate the expiration date
const expiryDate = new Date(
Date.UTC(
parseInt(amzDate.slice(0, 4), 10), // year
parseInt(amzDate.slice(4, 6), 10) - 1, // month (0-indexed)
parseInt(amzDate.slice(6, 8), 10), // day
parseInt(amzDate.slice(9, 11), 10), // hour
parseInt(amzDate.slice(11, 13), 10), // minute
parseInt(amzDate.slice(13, 15), 10) // second
)
);
const expiresAfterSeconds = parseInt(amzExpires, 10);
const currentDate = new Date();
const expiryDateSeconds = expiryDate.getSeconds();
const expiresSeconds = parseInt(amzExpires, 10);
// Get the UTC components
const yearUTC = currentDate.getUTCFullYear();
const monthUTC = (currentDate.getUTCMonth() + 1).toString().padStart(2, "0");
const dayUTC = currentDate.getUTCDate().toString().padStart(2, "0");
const hoursUTC = currentDate.getUTCHours().toString().padStart(2, "0");
const minutesUTC = currentDate.getUTCMinutes().toString().padStart(2, "0");
const secondsUTC = currentDate.getUTCSeconds().toString().padStart(2, "0");
expiryDate.setSeconds(expiryDateSeconds + expiresSeconds);
// Construct the date-time string in UTC format
const currentDateTimeUTC = `${yearUTC}${monthUTC}${dayUTC}T${hoursUTC}${minutesUTC}${secondsUTC}Z`;
// Get the current UTC time
const now = new Date();
const amzSigningDate = parseISO(amzDate);
const amzExpiryDate = add(amzSigningDate, { seconds: expiresAfterSeconds });
const currentDateISO = parseISO(currentDateTimeUTC);
// Check if the current time is past the expiration time
const isExpired = now > expiryDate;
const isExpired = isAfter(currentDateISO, amzExpiryDate);
if (isExpired) {
// generate a new signed url
storageCache.revalidate({ fileKey });
return await getS3SignedUrl(fileKey);
const signedUrlAfterRefetch = await getS3SignedUrl(fileKey);
return signedUrlAfterRefetch;
}
}