diff options
Diffstat (limited to 'src/server/file')
| -rw-r--r-- | src/server/file/assets/cache-expired.png | bin | 0 -> 15025 bytes | |||
| -rw-r--r-- | src/server/file/assets/tombstone.png | bin | 0 -> 6387 bytes | |||
| -rw-r--r-- | src/server/file/index.ts | 7 | ||||
| -rw-r--r-- | src/server/file/pour.ts | 88 | ||||
| -rw-r--r-- | src/server/file/send-drive-file.ts | 60 |
5 files changed, 58 insertions, 97 deletions
diff --git a/src/server/file/assets/cache-expired.png b/src/server/file/assets/cache-expired.png Binary files differnew file mode 100644 index 0000000000..ea681af0a0 --- /dev/null +++ b/src/server/file/assets/cache-expired.png diff --git a/src/server/file/assets/tombstone.png b/src/server/file/assets/tombstone.png Binary files differnew file mode 100644 index 0000000000..86224e3182 --- /dev/null +++ b/src/server/file/assets/tombstone.png diff --git a/src/server/file/index.ts b/src/server/file/index.ts index 29056c63e7..973528da33 100644 --- a/src/server/file/index.ts +++ b/src/server/file/index.ts @@ -6,7 +6,6 @@ import * as fs from 'fs'; import * as Koa from 'koa'; import * as cors from '@koa/cors'; import * as Router from 'koa-router'; -import pour from './pour'; import sendDriveFile from './send-drive-file'; // Init app @@ -24,12 +23,14 @@ const router = new Router(); router.get('/default-avatar.jpg', ctx => { const file = fs.createReadStream(`${__dirname}/assets/avatar.jpg`); - pour(file, 'image/jpeg', ctx); + ctx.set('Content-Type', 'image/jpeg'); + ctx.body = file; }); router.get('/app-default.jpg', ctx => { const file = fs.createReadStream(`${__dirname}/assets/dummy.png`); - pour(file, 'image/png', ctx); + ctx.set('Content-Type', 'image/jpeg'); + ctx.body = file; }); router.get('/:id', sendDriveFile); diff --git a/src/server/file/pour.ts b/src/server/file/pour.ts deleted file mode 100644 index 0fd0ad0e60..0000000000 --- a/src/server/file/pour.ts +++ /dev/null @@ -1,88 +0,0 @@ -import * as fs from 'fs'; -import * as stream from 'stream'; -import * as Koa from 'koa'; -import * as Gm from 'gm'; - -const gm = Gm.subClass({ - imageMagick: true -}); - -interface ISend { - contentType: string; - stream: stream.Readable; -} - -function thumbnail(data: stream.Readable, type: string, resize: number): ISend { - const readable: stream.Readable = (() => { - // 動画であれば - if (/^video\/.*$/.test(type)) { - // TODO - // 使わないことになったストリームはしっかり取り壊す - data.destroy(); - return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`); - // 画像であれば - // Note: SVGはapplication/xml - } else if (/^image\/.*$/.test(type) || type == 'application/xml') { - // 0フレーム目を送る - try { - return gm(data).selectFrame(0).stream(); - // だめだったら - } catch (e) { - // 使わないことになったストリームはしっかり取り壊す - data.destroy(); - return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`); - } - // 動画か画像以外 - } else { - data.destroy(); - return fs.createReadStream(`${__dirname}/assets/not-an-image.png`); - } - })(); - - let g = gm(readable); - - if (resize) { - g = g.resize(resize, resize); - } - - const stream = g - .compress('jpeg') - .quality(80) - .interlace('line') - .stream(); - - return { - contentType: 'image/jpeg', - stream - }; -} - -const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => { - console.error(e); - ctx.status = 500; -}; - -export default function(readable: stream.Readable, type: string, ctx: Koa.Context): void { - readable.on('error', commonReadableHandlerGenerator(ctx)); - - const data = ((): ISend => { - if (ctx.query.thumbnail !== undefined) { - return thumbnail(readable, type, ctx.query.size); - } - return { - contentType: type, - stream: readable - }; - })(); - - if (readable !== data.stream) { - data.stream.on('error', commonReadableHandlerGenerator(ctx)); - } - - if (ctx.query.download !== undefined) { - ctx.set('Content-Disposition', 'attachment'); - } - - ctx.set('Content-Type', data.contentType); - ctx.body = data.stream; -} diff --git a/src/server/file/send-drive-file.ts b/src/server/file/send-drive-file.ts index e6ee19ff1d..d613a3aa5f 100644 --- a/src/server/file/send-drive-file.ts +++ b/src/server/file/send-drive-file.ts @@ -1,8 +1,17 @@ +import * as fs from 'fs'; + import * as Koa from 'koa'; import * as send from 'koa-send'; import * as mongodb from 'mongodb'; -import DriveFile, { getGridFSBucket } from '../../models/drive-file'; -import pour from './pour'; +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 @@ -18,13 +27,52 @@ export default async function(ctx: Koa.Context) { if (file == null) { ctx.status = 404; - await send(ctx, `${__dirname}/assets/dummy.png`); + await send(ctx, '/dummy.png', { root: assets }); return; } - const bucket = await getGridFSBucket(); + if (file.metadata.deletedAt) { + ctx.status = 410; + if (file.metadata.isExpired) { + await send(ctx, '/cache-expired.png', { root: assets }); + } else { + await send(ctx, '/tombstone.png', { root: assets }); + } + 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; + }; - const readable = bucket.openDownloadStream(fileId); + 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'); + } - pour(readable, file.contentType, ctx); + await sendRaw(); + } } |