UNPKG

@themost/web

Version:

MOST Web Framework 2.0 - Web Server Module

504 lines (477 loc) 15.2 kB
/** * @license * MOST Web Framework 2.0 Codename Blueshift * Copyright (c) 2017, THEMOST LP All rights reserved * * Use of this source code is governed by an BSD-3-Clause license that can be * found in the LICENSE file at https://themost.io/license */ /// var path = require('path'); var fs = require('fs'); var _ = require('lodash'); var FileNotFoundError = require('@themost/common/errors').FileNotFoundError; var Base26Number = require('@themost/common/utils').Base26Number; var RandomUtils = require('@themost/common/utils').RandomUtils; var TraceUtils = require('@themost/common/utils').TraceUtils; var LangUtils = require('@themost/common/utils').LangUtils; /** * @abstract * @classdesc An abstract class that describes a file storage. * @class * @constructor * @property {string} root - Gets or sets a string that represents the physical root path of this file storage * @property {string} virtualPath - Gets or sets a string that represents the virtual path of this file storage */ function FileStorage() { // } /** * @param {HttpContext} context * @param {string} src * @param {*} attrs * @param {Function} callback */ FileStorage.prototype.copyFrom = function(context, src, attrs, callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} item * @param {string} dest * @param {Function} callback */ FileStorage.prototype.copyTo = function(context, item, dest, callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} item * @param {Function} callback */ FileStorage.prototype.resolvePhysicalPath = function(context, item, callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} item * @param {Function} callback */ FileStorage.prototype.resolveUrl = function(context, item, callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} item * @param {Function} callback */ FileStorage.prototype.createReadStream = function(context, item, callback) { callback = callback || function() {}; callback(); }; /** * @param {Function} callback */ FileStorage.prototype.init = function(callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} query * @param {Function} callback */ FileStorage.prototype.find = function(context, query, callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} query * @param {Function} callback */ FileStorage.prototype.findOne = function(context, query, callback) { callback = callback || function() {}; callback(); }; /** * @param {HttpContext} context * @param {*} item * @param {function(Error=,*=)} callback */ FileStorage.prototype.remove = function(context, item, callback) { callback = callback || function() {}; callback(); }; /** * @classdesc AttachmentFileSystemStorage class describes a file storage for attachments' management on local file system. * @class * @constructor * @augments FileStorage * @param {string} physicalPath The root directory of this storage */ function AttachmentFileSystemStorage(physicalPath) { this.root = physicalPath; this.virtualPath = null; this.ensure = function(callback) { var self = this; callback = callback || function() {}; if (self._initialized) { callback(); return; } if (_.isNil(self.root)) { callback(new Error('The file system storage root directory cannot be empty at this context.')); } else { //check directory existence fs.exists(self.root, function(exists) { if (exists) { self._initialized = true; callback(); } else { fs.mkdir(self.root,function(err) { if (err) { TraceUtils.error(err); callback(new Error('An error occured while trying to initialize file system storage.')); } else { self._initialized = true; callback(); } }); } }); } }; } LangUtils.inherits(AttachmentFileSystemStorage, FileStorage); /** * @param {HttpContext} context * @param {*} item * @param {function} callback */ AttachmentFileSystemStorage.prototype.save = function(context, item, callback) { var self = this; self.ensure(function(err) { if (err) { callback(err); } else { if (_.isNil(item)) { callback(); return; } var attachments = context.model('Attachment'); if (_.isNil(attachments)) { callback(new Error('Attachment model cannot be found.')); } //file default version item.version = item.version || 1; //file status (false) not published item.published = item.published || false; if (typeof item.alternateName === 'undefined' || item.alternateName === null) { item.alternateName = RandomUtils.randomChars(12); } //set url item.url = path.join(self.virtualPath, item.alternateName); //save attachment attachments.save(item, function(err) { callback(err); }); } }); }; /** * @param {HttpContext} context * @param {*} query * @param {Function} callback */ AttachmentFileSystemStorage.prototype.findOne = function(context, query, callback) { var self = this; self.ensure(function(err) { if (err) { callback(err); } else { if (_.isNil(query)) { callback(); return; } var attachments = context.model('Attachment'); if (_.isNil(attachments)) { callback(new Error('Attachment model cannot be found.')); } attachments.find(query).first(callback); } }); }; /** * * @param {HttpContext} context * @param {*} item * @param {Function} callback */ AttachmentFileSystemStorage.prototype.resolvePhysicalPath = function(context, item, callback) { var id = item.id, self = this, file_id; if (id) { file_id = Base26Number.toBase26(id); callback(null, path.join(self.root, file_id.substr(0,1), file_id)); } else { self.findOne(context, item, function(err, result) { if (err) { callback(err); } else { if (_.isNil(result)) { callback(new Error('Item cannot be found')); } else { file_id = Base26Number.toBase26(result.id); callback(null, path.join(self.root, file_id.substr(0,1), file_id)); } } }); } }; /** * * @param {HttpContext} context * @param {*} item * @param {function(Error=,string=)} callback */ AttachmentFileSystemStorage.prototype.resolveUrl = function(context, item, callback) { var alternateName = item.alternateName, self = this; if (alternateName) { callback(null, path.join(self.virtualPath, alternateName)); } else { self.findOne(context, item, function(err, result) { if (err) { callback(err); } else { if (_.isNil(result)) { callback(new Error('Item cannot be found')); } else { callback(null, path.join(self.virtualPath, item.alternateName)); } } }); } }; /** * @param {HttpContext} context * @param {*} item * @param {Function} callback */ AttachmentFileSystemStorage.prototype.createReadStream = function(context, item, callback) { var self = this, filePath; self.findOne(context, item, function(err, result) { if (err) { callback(err); } else { if (_.isNil(result)) { callback(new Error('Item cannot be found')); } else { //get file id var file_id = Base26Number.toBase26(result.id); //create file path filePath = path.join(self.root, file_id.substr(0,1), file_id); //check file fs.exists(filePath, function(exists) { if (!exists) { callback(new FileNotFoundError()); } else { callback(null, fs.createReadStream(filePath)); } }); } } }); }; /** * @param {HttpContext} context * @param {*} query * @param {Function} callback */ AttachmentFileSystemStorage.prototype.exists = function(context, query, callback) { callback = callback || function() {}; this.findOne(context, query, function(err, result) { if (err) { TraceUtils.error(err); callback(false); } else { callback(!_.isNil(result)); } }); }; /** * @param {HttpContext} context * @param {*} query * @param {function(Error=,*=)} callback */ AttachmentFileSystemStorage.prototype.find = function(context, query, callback) { var self = this; self.ensure(function(err) { if (err) { callback(err); } else { if (_.isNil(query)) { callback(); } else { var attachments = context.model('Attachment'); if (_.isNil(attachments)) { callback(new Error('Attachment model cannot be found.')); } attachments.find(query).all(callback) } } }); }; /** * @param {function(Error=)} callback */ AttachmentFileSystemStorage.prototype.init = function(callback) { this.ensure(callback); }; /** * @param {HttpContext} context * @param {string} src * @param {*} attrs * @param {Function} callback */ AttachmentFileSystemStorage.prototype.copyFrom = function(context, src, attrs, callback) { var self = this; callback = callback || function() {}; self.ensure(function(err) { if (err) { callback(err); } else { var filename = path.basename(src); attrs = attrs || {}; //set file composition name attrs.name = attrs.name || filename; //check source file fs.exists(src, function(exists) { if (!exists) { callback(new Error('The source file cannot be found')); } else { //save attributes //insert item attributes self.save(context, attrs, function(err) { if (err) { callback(err); } else { //file operation (save to folder) var file = Base26Number.toBase26(attrs.id); fs.exists(path.join(self.root, file.substr(0,1)), function(exists) { if (exists) { copyFile(src,path.join(self.root, file.substr(0,1), file), function(err) { callback(err); }); } else { fs.mkdir(path.join(self.root, file.substr(0,1)), function(err) { if (err) { callback(err); } else { copyFile(src,path.join(self.root, file.substr(0,1), file), function(err) { callback(err); }); } }); } }); } }); } }); } }); }; /** * @param {HttpContext} context * @param {string|*} item * @param {string} dest * @param {Function} callback */ AttachmentFileSystemStorage.prototype.copyTo = function(context, item, dest, callback) { var self = this; callback = callback || function() {}; self.ensure(function(err) { if (err) { callback(err); } else { if (_.isNil(item)) { callback(new Error('The source item cannot be empty at this context')); self.findOne(context, item, function(err, result) { if (err) { callback(err); } else { if (_.isNil(result)) { callback(new Error('The source item cannot be found.')); } else { var file = Base26Number.toBase26(result.id), src = path.join(self.root, file.substr(0,1), file); fs.exists(src, function(exists) { if (!exists) { callback(new Error('The source file cannot be found.')); } else { var destFile = path.join(dest, result.name); copyFile(src, destFile, function(err) { callback(err, destFile); }); } }); } } }); } } }); }; /** * @param {string} src * @param {string} dest * @param {Function} callback * @private */ function copyFile(src, dest, callback) { //create read stream var source = fs.createReadStream(src); //create write stream var finalDest = fs.createWriteStream(dest); //copy file source.pipe(finalDest); source.on('end', function() { callback(); }); source.on('error', function(err) { callback(err); }); } if (typeof exports !== 'undefined') { module.exports.FileStorage = FileStorage; module.exports.AttachmentFileSystemStorage = AttachmentFileSystemStorage; }