Skip to content

Commit

Permalink
Revert "Merge pull request #88 from hackerspace-ntnu/bun-s3-client"
Browse files Browse the repository at this point in the history
This reverts commit e40315d, reversing
changes made to e918311.
  • Loading branch information
michaelbrusegard committed Jan 23, 2025
1 parent 8fd70dd commit f925fea
Show file tree
Hide file tree
Showing 8 changed files with 355 additions and 45 deletions.
1 change: 1 addition & 0 deletions .github/workflows/deploy-script.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ jobs:
sleep 5
wait
docker compose run --rm app bun run db:migrate
docker compose run --rm app bun run s3:buckets
docker compose up -d app
267 changes: 234 additions & 33 deletions bun.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ RUN addgroup --system --gid 1002 nodejs && \
# Set the correct permission for prerender cache
RUN mkdir .next && chown nextjs:nodejs .next

# Copy necessary files for build
# Copy necessary files for migrations and S3 setup
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
# Copy necessary files for migrations
COPY --from=builder --chown=nextjs:nodejs /app/src/server/db/migrations ./src/server/db/migrations
COPY --from=builder --chown=nextjs:nodejs /app/drizzle.config.ts ./
COPY --from=builder --chown=nextjs:nodejs /app/src/server ./src/server
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./
Expand Down
14 changes: 14 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { env } from '@/env';
import type { NextConfig } from 'next';
import nextIntl from 'next-intl/plugin';

Expand All @@ -8,6 +9,19 @@ const config: NextConfig = {
images: {
formats: ['image/avif', 'image/webp'],
},
async rewrites() {
return {
beforeFiles: [
{
source: '/s3/:path*',
destination: `http://${env.S3_HOST}:${env.S3_PORT}/:path*`,
basePath: false,
},
],
afterFiles: [],
fallback: [],
};
},
};

export default withNextIntl(config);
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
"s3:start": "docker compose -f compose.local.yml up s3 -d",
"s3:stop": "docker compose -f compose.local.yml down s3",
"s3:delete": "bun -e \"require('fs').rmSync('data/s3', { recursive: true, force: true })\"",
"s3:logs": "docker compose -f compose.local.yml logs -f s3"
"s3:logs": "docker compose -f compose.local.yml logs -f s3",
"s3:buckets": "bun run src/server/s3/buckets.ts"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.679.0",
"@oslojs/crypto": "^1.0.1",
"@oslojs/encoding": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.1",
Expand Down
4 changes: 2 additions & 2 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const env = createEnv({
S3_PORT: z.string(),
S3_USER: z.string(),
S3_PASSWORD: z.string(),
S3_NAME: z.string(),
S3_BUCKETS: z.string(),
FEIDE_CLIENT_ID: z.string().optional(),
FEIDE_CLIENT_SECRET: z.string().optional(),
FEIDE_AUTHORIZATION_ENDPOINT: z.string().optional(),
Expand Down Expand Up @@ -53,7 +53,7 @@ export const env = createEnv({
S3_PORT: process.env.S3_PORT,
S3_USER: process.env.S3_USER,
S3_PASSWORD: process.env.S3_PASSWORD,
S3_NAME: process.env.S3_NAME,
S3_BUCKETS: process.env.S3_BUCKETS,
FEIDE_CLIENT_ID: process.env.FEIDE_CLIENT_ID,
FEIDE_CLIENT_SECRET: process.env.FEIDE_CLIENT_SECRET,
FEIDE_AUTHORIZATION_ENDPOINT: process.env.FEIDE_AUTHORIZATION_ENDPOINT,
Expand Down
89 changes: 89 additions & 0 deletions src/server/s3/buckets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { env } from '@/env';
import { s3 } from '@/server/s3';
import {
CreateBucketCommand,
HeadBucketCommand,
PutBucketPolicyCommand,
S3ServiceException,
} from '@aws-sdk/client-s3';

type BucketConfig = {
name: string;
isPublic?: boolean;
};

type BucketKeys = 'images';

type BucketsConfig = {
[K in BucketKeys]: BucketConfig;
};

const bucketNames = env.S3_BUCKETS.split(',');

const buckets: BucketsConfig = {
images: {
name: bucketNames[0] as string,
isPublic: true,
},
};

const getBucketConfigs = () => Object.values(buckets);

async function setupBucket(bucketConfig: { name: string; isPublic?: boolean }) {
const { name, isPublic } = bucketConfig;

try {
await s3.send(new HeadBucketCommand({ Bucket: name })).catch(async () => {
await s3.send(
new CreateBucketCommand({
Bucket: name,
...(isPublic && { ACL: 'public-read' }),
}),
);
});

if (isPublic) {
await s3.send(
new PutBucketPolicyCommand({
Bucket: name,
Policy: JSON.stringify({
Version: '2012-10-17',
Statement: [
{
Sid: 'PublicReadGetObject',
Effect: 'Allow',
Principal: '*',
Action: 's3:GetObject',
Resource: `arn:aws:s3:::${name}/*`,
},
],
}),
}),
);
}

console.log(`✅ Bucket ${name} configured successfully`);
} catch (error) {
if (error instanceof S3ServiceException) {
console.error(`❌ Error configuring bucket ${name}:`, error.message);
} else {
console.error(`❌ Unexpected error configuring bucket ${name}:`, error);
}
}
}

export async function main() {
console.log('🔄 Configuring S3 buckets...');
const bucketConfigs = getBucketConfigs();

await Promise.all(
bucketConfigs.filter(Boolean).map((config) => setupBucket(config)),
);

console.log('✅ All buckets configured successfully');
}

await main();
process.exit(0);

export { buckets, getBucketConfigs, setupBucket };
17 changes: 10 additions & 7 deletions src/server/s3/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { env } from '@/env';
import { S3Client } from 'bun';
import { S3Client } from '@aws-sdk/client-s3';

const endpoint = `http://${env.S3_HOST}:${env.S3_PORT}`;

Expand All @@ -11,15 +11,18 @@ const globalForS3 = globalThis as unknown as {
const s3 =
globalForS3.s3 ??
new S3Client({
accessKeyId: env.S3_USER,
secretAccessKey: env.S3_PASSWORD,
endpoint,
bucket: env.S3_NAME,
credentials: {
accessKeyId: env.S3_USER,
secretAccessKey: env.S3_PASSWORD,
},
endpoint: endpoint,
forcePathStyle: true,
region: 'auto', // Required but not used with self-hosted storage
});

if (env.NODE_ENV !== 'production') globalForS3.s3 = s3;

Bun.s3 = s3;
const buckets = env.S3_BUCKETS.split(',');
const imageBucket = buckets[0];

export { s3, endpoint };
export { s3, endpoint, imageBucket };

0 comments on commit f925fea

Please sign in to comment.