The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Rocket.Chat/packages/rocketchat-file/file.server.js

294 lines
6.9 KiB

8 years ago
import Grid from 'gridfs-stream';
import stream from 'stream';
import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import gm from 'gm';
import {exec} from 'child_process';
8 years ago
// Fix problem with usernames being converted to object id
Grid.prototype.tryParseObjectId = function() {
return false;
};
//TODO: REMOVE RocketChatFile from globals
RocketChatFile = {
gm,
enabled: undefined,
enable() {
RocketChatFile.enabled = true;
return RocketChat.settings.updateOptionsById('Accounts_AvatarResize', {
alert: undefined
});
},
disable() {
RocketChatFile.enabled = false;
return RocketChat.settings.updateOptionsById('Accounts_AvatarResize', {
alert: 'The_image_resize_will_not_work_because_we_can_not_detect_ImageMagick_or_GraphicsMagick_installed_in_your_server'
});
}
};
const detectGM = function() {
return exec('gm version', Meteor.bindEnvironment(function(error, stdout) {
if ((error == null) && stdout.indexOf('GraphicsMagick') > -1) {
RocketChatFile.enable();
RocketChat.Info.GraphicsMagick = {
enabled: true,
version: stdout
};
} else {
RocketChat.Info.GraphicsMagick = {
enabled: false
};
}
return exec('convert -version', Meteor.bindEnvironment(function(error, stdout) {
if ((error == null) && stdout.indexOf('ImageMagick') > -1) {
if (RocketChatFile.enabled !== true) {
8 years ago
// Enable GM to work with ImageMagick if no GraphicsMagick
RocketChatFile.gm = RocketChatFile.gm.subClass({
imageMagick: true
});
RocketChatFile.enable();
}
return RocketChat.Info.ImageMagick = {
enabled: true,
version: stdout
};
} else {
if (RocketChatFile.enabled !== true) {
RocketChatFile.disable();
}
return RocketChat.Info.ImageMagick = {
enabled: false
};
}
}));
}));
};
detectGM();
Meteor.methods({
'detectGM'() {
detectGM();
}
});
RocketChatFile.bufferToStream = function(buffer) {
const bufferStream = new stream.PassThrough();
bufferStream.end(buffer);
return bufferStream;
};
RocketChatFile.dataURIParse = function(dataURI) {
const imageData = dataURI.split(';base64,');
return {
image: imageData[1],
contentType: imageData[0].replace('data:', '')
};
};
RocketChatFile.addPassThrough = function(st, fn) {
const pass = new stream.PassThrough();
fn(pass, st);
return pass;
};
RocketChatFile.GridFS = class {
8 years ago
constructor(config = {}) {
const {name = 'file', transformWrite} = config;
this.name = name;
this.transformWrite = transformWrite;
const mongo = Package.mongo.MongoInternals.NpmModule;
const db = Package.mongo.MongoInternals.defaultRemoteCollectionDriver().mongo.db;
this.store = new Grid(db, mongo);
this.findOneSync = Meteor.wrapAsync(this.store.collection(this.name).findOne.bind(this.store.collection(this.name)));
this.removeSync = Meteor.wrapAsync(this.store.remove.bind(this.store));
this.countSync = Meteor.wrapAsync(this.store._col.count.bind(this.store._col));
this.getFileSync = Meteor.wrapAsync(this.getFile.bind(this));
}
findOne(fileName) {
return this.findOneSync({
_id: fileName
});
}
remove(fileName) {
return this.removeSync({
_id: fileName,
root: this.name
});
}
createWriteStream(fileName, contentType) {
const self = this;
let ws = this.store.createWriteStream({
_id: fileName,
filename: fileName,
mode: 'w',
root: this.name,
content_type: contentType
});
if (self.transformWrite != null) {
ws = RocketChatFile.addPassThrough(ws, function(rs, ws) {
const file = {
name: self.name,
fileName,
contentType
};
return self.transformWrite(file, rs, ws);
});
}
ws.on('close', function() {
return ws.emit('end');
});
return ws;
}
createReadStream(fileName) {
return this.store.createReadStream({
_id: fileName,
root: this.name
});
}
getFileWithReadStream(fileName) {
const file = this.findOne(fileName);
if (file == null) {
return null;
}
const rs = this.createReadStream(fileName);
return {
readStream: rs,
contentType: file.contentType,
length: file.length,
uploadDate: file.uploadDate
};
}
getFile(fileName, cb) {
const file = this.getFileWithReadStream(fileName);
if (!file) {
return cb();
}
const data = [];
file.readStream.on('data', Meteor.bindEnvironment(function(chunk) {
return data.push(chunk);
}));
return file.readStream.on('end', Meteor.bindEnvironment(function() {
return cb(null, {
buffer: Buffer.concat(data),
contentType: file.contentType,
length: file.length,
uploadDate: file.uploadDate
});
}));
}
deleteFile(fileName) {
const file = this.findOne(fileName);
if (file == null) {
8 years ago
return undefined;
}
return this.remove(fileName);
}
};
RocketChatFile.FileSystem = class {
8 years ago
constructor(config = {}) {
let {absolutePath = '~/uploads'} = config;
const {transformWrite} = config;
this.transformWrite = transformWrite;
if (absolutePath.split(path.sep)[0] === '~') {
const homepath = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
if (homepath != null) {
absolutePath = absolutePath.replace('~', homepath);
} else {
throw new Error('Unable to resolve "~" in path');
}
}
this.absolutePath = path.resolve(absolutePath);
mkdirp.sync(this.absolutePath);
this.statSync = Meteor.wrapAsync(fs.stat.bind(fs));
this.unlinkSync = Meteor.wrapAsync(fs.unlink.bind(fs));
this.getFileSync = Meteor.wrapAsync(this.getFile.bind(this));
}
createWriteStream(fileName, contentType) {
const self = this;
let ws = fs.createWriteStream(path.join(this.absolutePath, fileName));
if (self.transformWrite != null) {
ws = RocketChatFile.addPassThrough(ws, function(rs, ws) {
const file = {
fileName,
contentType
};
return self.transformWrite(file, rs, ws);
});
}
ws.on('close', function() {
return ws.emit('end');
});
return ws;
}
createReadStream(fileName) {
return fs.createReadStream(path.join(this.absolutePath, fileName));
}
stat(fileName) {
return this.statSync(path.join(this.absolutePath, fileName));
}
remove(fileName) {
return this.unlinkSync(path.join(this.absolutePath, fileName));
}
getFileWithReadStream(fileName) {
try {
const stat = this.stat(fileName);
const rs = this.createReadStream(fileName);
return {
readStream: rs,
8 years ago
// contentType: file.contentType
length: stat.size
};
} catch (error1) {
return null;
}
}
getFile(fileName, cb) {
const file = this.getFileWithReadStream(fileName);
if (!file) {
return cb();
}
const data = [];
file.readStream.on('data', Meteor.bindEnvironment(function(chunk) {
return data.push(chunk);
}));
return file.readStream.on('end', Meteor.bindEnvironment(function() {
return {
buffer: Buffer.concat(data)({
contentType: file.contentType,
length: file.length,
uploadDate: file.uploadDate
})
};
}));
}
deleteFile(fileName) {
try {
return this.remove(fileName);
} catch (error1) {
return null;
}
}
};