From 5458b107743fcb6fa52b9527f08f36342339753f Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 24 Jul 2018 01:58:11 +0900
Subject: [PATCH] wip

---
 .config/example.yml            | 16 ++++++++
 package.json                   |  2 +
 src/config/types.ts            |  8 ++++
 src/services/drive/add-file.ts | 68 ++++++++++++++++++----------------
 4 files changed, 63 insertions(+), 31 deletions(-)

diff --git a/.config/example.yml b/.config/example.yml
index 6c939a4f32..28a850182f 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -53,6 +53,22 @@ remoteDriveCapacityMb: 8
 #  Users cannot see remote images when they turn off "Show media from a remote server" setting.
 preventCache: false
 
+drive:
+  storage: 'db'
+
+  # OR
+
+  # storage: 'object-storage'
+  # service: 'minio'
+  # bucket:
+  # prefix:
+  # config:
+  #   endPoint:
+  #   port:
+  #   secure:
+  #   accessKey:
+  #   secretKey:
+
 #
 # Below settings are optional
 #
diff --git a/package.json b/package.json
index 845a6166b1..849ff7a62b 100644
--- a/package.json
+++ b/package.json
@@ -57,6 +57,7 @@
 		"@types/koa-views": "2.0.3",
 		"@types/koa__cors": "2.2.2",
 		"@types/kue": "0.11.9",
+		"@types/minio": "6.0.2",
 		"@types/mkdirp": "0.5.2",
 		"@types/mocha": "5.2.3",
 		"@types/mongodb": "3.1.2",
@@ -147,6 +148,7 @@
 		"kue": "0.11.6",
 		"loader-utils": "1.1.0",
 		"mecab-async": "0.1.2",
+		"minio": "6.0.0",
 		"mkdirp": "0.5.1",
 		"mocha": "5.2.0",
 		"moji": "0.5.1",
diff --git a/src/config/types.ts b/src/config/types.ts
index c26ff9db9a..b2e28f7306 100644
--- a/src/config/types.ts
+++ b/src/config/types.ts
@@ -49,6 +49,14 @@ export type Source = {
 	remoteDriveCapacityMb: number;
 	preventCacheRemoteFiles: boolean;
 
+	drive?: {
+		storage: string;
+		bucket: string;
+		prefix: string;
+		service?: string;
+		config?: any;
+	};
+
 	/**
 	 * ゴーストアカウントのID
 	 */
diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts
index f7c8922b58..a1b9686956 100644
--- a/src/services/drive/add-file.ts
+++ b/src/services/drive/add-file.ts
@@ -8,14 +8,14 @@ import * as _gm from 'gm';
 import * as debug from 'debug';
 import fileType = require('file-type');
 const prominence = require('prominence');
+import * as Minio from 'minio';
+import * as uuid from 'uuid';
 
 import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file';
 import DriveFolder from '../../models/drive-folder';
 import { pack } from '../../models/drive-file';
 import event, { publishDriveStream } from '../../stream';
 import { isLocalUser, IUser, IRemoteUser } from '../../models/user';
-import { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';
-import genThumbnail from '../../drive/gen-thumbnail';
 import delFile from './delete-file';
 import config from '../../config';
 
@@ -25,28 +25,43 @@ const gm = _gm.subClass({
 
 const log = debug('misskey:drive:add-file');
 
-const writeChunks = (name: string, readable: stream.Readable, type: string, metadata: any) =>
-	getDriveFileBucket()
-		.then(bucket => new Promise((resolve, reject) => {
+async function save(readable: stream.Readable, name: string, type: string, hash: string, size: number, metadata: any): Promise<IDriveFile> {
+	if (config.drive && config.drive.storage == 'object-storage') {
+		if (config.drive.service == 'minio') {
+
+			const minio = new Minio.Client(config.drive.config);
+			const id = uuid.v4();
+			const obj = `${config.drive.prefix}/${id}`;
+			await minio.putObject(config.drive.bucket, obj, readable);
+
+			Object.assign(metadata, {
+				obj: id,
+				url: `${ config.drive.config.secure ? 'https' : 'http' }://${ config.drive.config.endPoint }${ config.drive.config.port ? ':' + config.drive.config.port : '' }/${ config.drive.bucket }/${ obj }`
+			});
+
+			const file = await DriveFile.insert({
+				length: size,
+				uploadDate: new Date(),
+				md5: hash,
+				filename: name,
+				metadata: metadata,
+				contentType: type
+			});
+
+			return file;
+		}
+	} else {
+		// Get MongoDB GridFS bucket
+		const bucket = await getDriveFileBucket();
+
+		return new Promise<IDriveFile>((resolve, reject) => {
 			const writeStream = bucket.openUploadStream(name, { contentType: type, metadata });
 			writeStream.once('finish', resolve);
 			writeStream.on('error', reject);
 			readable.pipe(writeStream);
-		}));
-
-const writeThumbnailChunks = (name: string, readable: stream.Readable, originalId: mongodb.ObjectID) =>
-	getDriveFileThumbnailBucket()
-		.then(bucket => new Promise((resolve, reject) => {
-			const writeStream = bucket.openUploadStream(name, {
-				contentType: 'image/jpeg',
-				metadata: {
-					originalId
-				}
-			});
-			writeStream.once('finish', resolve);
-			writeStream.on('error', reject);
-			readable.pipe(writeStream);
-		}));
+		});
+	}
+}
 
 async function deleteOldFile(user: IRemoteUser) {
 	const oldFile = await DriveFile.findOne({
@@ -283,7 +298,7 @@ export default async function(
 			metadata: metadata,
 			contentType: mime
 		})
-		: await (writeChunks(detectedName, fs.createReadStream(path), mime, metadata) as Promise<IDriveFile>);
+		: await (save(fs.createReadStream(path), detectedName, mime, hash, size, metadata));
 
 	log(`drive file has been created ${driveFile._id}`);
 
@@ -293,16 +308,7 @@ export default async function(
 		publishDriveStream(user._id, 'file_created', packedFile);
 	});
 
-	if (!metaOnly) {
-		try {
-			const thumb = await genThumbnail(driveFile);
-			if (thumb) {
-				await writeThumbnailChunks(detectedName, thumb, driveFile._id);
-			}
-		} catch (e) {
-			// noop
-		}
-	}
+	// TODO: サムネイル生成
 
 	return driveFile;
 }