summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/FileServerService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/FileServerService.ts')
-rw-r--r--packages/backend/src/server/FileServerService.ts99
1 files changed, 47 insertions, 52 deletions
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index dc073e34ac..088e780d69 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -2,10 +2,8 @@ import * as fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import { Inject, Injectable } from '@nestjs/common';
-import Koa from 'koa';
-import cors from '@koa/cors';
-import Router from '@koa/router';
-import send from 'koa-send';
+import { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
+import fastifyStatic from '@fastify/static';
import rename from 'rename';
import type { Config } from '@/config.js';
import type { DriveFilesRepository } from '@/models/index.js';
@@ -46,45 +44,44 @@ export class FileServerService {
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('server', 'gray', false);
+
+ this.createServer = this.createServer.bind(this);
}
- public commonReadableHandlerGenerator(ctx: Koa.Context) {
- return (e: Error): void => {
- this.logger.error(e);
- ctx.status = 500;
- ctx.set('Cache-Control', 'max-age=300');
+ public commonReadableHandlerGenerator(reply: FastifyReply) {
+ return (err: Error): void => {
+ this.logger.error(err);
+ reply.code(500);
+ reply.header('Cache-Control', 'max-age=300');
};
}
- public createServer() {
- const app = new Koa();
- app.use(cors());
- app.use(async (ctx, next) => {
- ctx.set('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\'');
- await next();
+ public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
+ fastify.addHook('onRequest', (request, reply, done) => {
+ reply.header('Content-Security-Policy', 'default-src \'none\'; img-src \'self\'; media-src \'self\'; style-src \'unsafe-inline\'');
+ done();
});
- // Init router
- const router = new Router();
+ fastify.register(fastifyStatic, {
+ root: _dirname,
+ serve: false,
+ });
- router.get('/app-default.jpg', ctx => {
+ fastify.get('/app-default.jpg', (request, reply) => {
const file = fs.createReadStream(`${_dirname}/assets/dummy.png`);
- ctx.body = file;
- ctx.set('Content-Type', 'image/jpeg');
- ctx.set('Cache-Control', 'max-age=31536000, immutable');
+ reply.header('Content-Type', 'image/jpeg');
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+ return reply.send(file);
});
- router.get('/:key', ctx => this.sendDriveFile(ctx));
- router.get('/:key/(.*)', ctx => this.sendDriveFile(ctx));
-
- // Register router
- app.use(router.routes());
+ fastify.get<{ Params: { key: string; } }>('/:key', async (request, reply) => await this.sendDriveFile(request, reply));
+ fastify.get<{ Params: { key: string; } }>('/:key/*', async (request, reply) => await this.sendDriveFile(request, reply));
- return app;
+ done();
}
- private async sendDriveFile(ctx: Koa.Context) {
- const key = ctx.params.key;
+ private async sendDriveFile(request: FastifyRequest<{ Params: { key: string; } }>, reply: FastifyReply) {
+ const key = request.params.key;
// Fetch drive file
const file = await this.driveFilesRepository.createQueryBuilder('file')
@@ -94,10 +91,9 @@ export class FileServerService {
.getOne();
if (file == null) {
- ctx.status = 404;
- ctx.set('Cache-Control', 'max-age=86400');
- await send(ctx as any, '/dummy.png', { root: assets });
- return;
+ reply.code(404);
+ reply.header('Cache-Control', 'max-age=86400');
+ return reply.sendFile('/dummy.png', assets);
}
const isThumbnail = file.thumbnailAccessKey === key;
@@ -135,18 +131,18 @@ export class FileServerService {
};
const image = await convertFile();
- ctx.body = image.data;
- ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
- ctx.set('Cache-Control', 'max-age=31536000, immutable');
+ reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+ return image.data;
} catch (err) {
this.logger.error(`${err}`);
if (err instanceof StatusError && err.isClientError) {
- ctx.status = err.statusCode;
- ctx.set('Cache-Control', 'max-age=86400');
+ reply.code(err.statusCode);
+ reply.header('Cache-Control', 'max-age=86400');
} else {
- ctx.status = 500;
- ctx.set('Cache-Control', 'max-age=300');
+ reply.code(500);
+ reply.header('Cache-Control', 'max-age=300');
}
} finally {
cleanup();
@@ -154,8 +150,8 @@ export class FileServerService {
return;
}
- ctx.status = 204;
- ctx.set('Cache-Control', 'max-age=86400');
+ reply.code(204);
+ reply.header('Cache-Control', 'max-age=86400');
return;
}
@@ -166,18 +162,17 @@ export class FileServerService {
extname: ext ? `.${ext}` : undefined,
}).toString();
- ctx.body = this.internalStorageService.read(key);
- ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : 'application/octet-stream');
- ctx.set('Cache-Control', 'max-age=31536000, immutable');
- ctx.set('Content-Disposition', contentDisposition('inline', filename));
+ reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : 'application/octet-stream');
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+ reply.header('Content-Disposition', contentDisposition('inline', filename));
+ return this.internalStorageService.read(key);
} else {
const readable = this.internalStorageService.read(file.accessKey!);
- readable.on('error', this.commonReadableHandlerGenerator(ctx));
- ctx.body = readable;
- ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.type) ? file.type : 'application/octet-stream');
- ctx.set('Cache-Control', 'max-age=31536000, immutable');
- ctx.set('Content-Disposition', contentDisposition('inline', file.name));
+ readable.on('error', this.commonReadableHandlerGenerator(reply));
+ reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.type) ? file.type : 'application/octet-stream');
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+ reply.header('Content-Disposition', contentDisposition('inline', file.name));
+ return readable;
}
}
}
-