summaryrefslogtreecommitdiff
path: root/src/server/file/send-drive-file.ts
blob: e04400317f27643f1363d560441c349de69e853e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import * as fs from 'fs';

import * as Koa from 'koa';
import * as send from 'koa-send';
import * as mongodb from 'mongodb';
import DriveFile, { getDriveFileBucket } from '../../models/drive-file';
import DriveFileThumbnail, { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';

const assets = `${__dirname}/../../server/file/assets/`;

const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => {
	console.error(e);
	ctx.status = 500;
};

export default async function(ctx: Koa.Context) {
	// Validate id
	if (!mongodb.ObjectID.isValid(ctx.params.id)) {
		ctx.throw(400, 'incorrect id');
		return;
	}

	const fileId = new mongodb.ObjectID(ctx.params.id);

	// Fetch drive file
	const file = await DriveFile.findOne({ _id: fileId });

	if (file == null) {
		ctx.status = 404;
		await send(ctx, '/dummy.png', { root: assets });
		return;
	}

	if (file.metadata.deletedAt) {
		ctx.status = 410;
		await send(ctx, '/tombstone.png', { root: assets });
		return;
	}

	if (file.metadata.isMetaOnly) {
		ctx.status = 204;
		return;
	}

	const sendRaw = async () => {
		const bucket = await getDriveFileBucket();
		const readable = bucket.openDownloadStream(fileId);
		readable.on('error', commonReadableHandlerGenerator(ctx));
		ctx.set('Content-Type', file.contentType);
		ctx.body = readable;
	};

	if ('thumbnail' in ctx.query) {
		// 画像以外
		if (!file.contentType.startsWith('image/')) {
			const readable = fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
			ctx.set('Content-Type', 'image/png');
			ctx.body = readable;
		} else if (file.contentType == 'image/gif') {
			// GIF
			await sendRaw();
		} else {
			const thumb = await DriveFileThumbnail.findOne({ 'metadata.originalId': fileId });
			if (thumb != null) {
				ctx.set('Content-Type', 'image/jpeg');
				const bucket = await getDriveFileThumbnailBucket();
				ctx.body = bucket.openDownloadStream(thumb._id);
			} else {
				await sendRaw();
			}
		}
	} else {
		if ('download' in ctx.query) {
			ctx.set('Content-Disposition', 'attachment');
		}

		await sendRaw();
	}
}