file.js 5.85 KB
'use strict';

const FileModel = require('../models/file');
const _ = require('lodash');
const shelljs = require('shelljs');
const decompress = require('decompress');
const decompressUnzip = require('decompress-unzip');
const moment = require('moment');
const path = require('path');
const fs = require('fs');
const rd = require('rd');
const ws = require('../../lib/ws');
const CDNCONFIG = require('../../config/cdn_config');
const qn = require('../../lib/qiniu')(CDNCONFIG.feature); // 活动上传

const FILE_SAVE_ROOT_PATH = './uploads'; // 上传到本地服务器的根目录
const SUPER_FILE_CHECK_PASS = 'yohowebtech.superfile'; // 存在此文件,直接上传到七牛
const BROADCAST_PATH = '/upload'; // ws 键

class FileApi {
    /**
     * 上传到服务器的文件处理
     * @param {文件} file
     * @param {路径} actPath
     * @param {用户} user
     */
    async upload(file, actPath, user) {
        let fileName = _.get(file, 'name');
        let fileNameWithoutType = _.split(fileName, '.')[0];
        let fileSavePath = path.join(FILE_SAVE_ROOT_PATH, fileName); // 文件保存到服务器的路径

        await new Promise((resolve, reject) => {
            let readable = fs.createReadStream(file.path);
            let writable = fs.createWriteStream(fileSavePath);

            readable.pipe(writable);
            readable.on('end', result => {
                resolve(result);
            });
        });

        ws.broadcast(BROADCAST_PATH, {
            state: '压缩包已经上传到服务器,开始解压...'
        });

        let fileDistPath = path.join(FILE_SAVE_ROOT_PATH, actPath); // 文件解压的路径

        shelljs.mkdir('-p', fileDistPath);

        // 解压
        await decompress(path.resolve(fileSavePath), path.resolve(fileDistPath), {
            plugins: [
                decompressUnzip()
            ]
        });

        ws.broadcast(BROADCAST_PATH, {
            state: '压缩包已经解压成功,开始校验文件...'
        });

        let fileList = rd.readSync(fileDistPath); // 读取待上传的文件列表
        let testRes = this._testFiles(fileList); // 文件校验

        if (testRes) {
            ws.broadcast(BROADCAST_PATH, {
                state: '校验文件通过,开始将文件上传到七牛...'
            });

            let fileModel = new FileModel();
            let insertRes = await fileModel.insert({ // 上传记录写库
                date: moment().format('YYYY-MM-DD HH:mm'),
                fileName: fileName,
                actPath: actPath,
                username: user.username,
                user_id: user._id
            });

            await this._uploadToQiniu(fileList, fileDistPath);

            ws.broadcast(BROADCAST_PATH, {
                state: '文件上传到七牛处理结束!'
            });
        } else {
            ws.broadcast(BROADCAST_PATH, {
                state: '校验文件失败,非法上传!'
            });
        }

        return true;
    }
    
    /**
     * 上传到七牛
     * @param {待上传的文件列表} fileList
     * @param {待上传的文件夹路径} fileDistPath 
     */
    async _uploadToQiniu(fileList, fileDistPath) {
        _.remove(fileList, perFilePath => {
            return !perFilePath || /__MACOSX/.test(perFilePath) || /.DS_Store/.test(perFilePath) || !fs.lstatSync(perFilePath).isFile();
        });

        let fileListPromises = _.map(fileList, filepath => {
            let fileKey = path.relative(FILE_SAVE_ROOT_PATH, filepath);

            return new Promise((resolve, reject) => {
                qn.uploadFile(filepath, {key:fileKey}, (err, result) => {
                    if (err) {
                        ws.broadcast(BROADCAST_PATH, {
                            state: `${fileKey} 上传到七牛过程中出现错误`
                        });
                        reject(err);
                    } else {
                        if (result && result.url) {
                            ws.broadcast(BROADCAST_PATH, {
                                state: `${fileKey} 上传到七牛成功`
                            });
                        } else {
                            ws.broadcast(BROADCAST_PATH, {
                                state: `${fileKey} 上传到七牛失败`
                            });
                        }
                        resolve(result);
                    }
                });
            });
        });

        return Promise.all(fileListPromises);
    }

    /**
     * 测试是否是可以上传的文件包
     * @param {待上传的文件列表} fileDistPath 
     */
    _testFiles(fileList) {
        let isSuperFile = false;
        let isExistedHyperesources = false;
        let isExistedHypeGenerated = false;

        _.forEach(fileList, file => {
            if (file.indexOf(SUPER_FILE_CHECK_PASS) > 0) {
                isSuperFile = true;
                return false;
            }

            if (/.hyperesources/.test(file)) {
                isExistedHyperesources = true;
            }

            if (/_hype_generated_script/.test(file)) {
                isExistedHypeGenerated = true;
            }

            if (isExistedHyperesources && isExistedHypeGenerated) {
                return false;
            }
        });

       return isSuperFile || (isExistedHyperesources && isExistedHypeGenerated);
    }

    /**
     * 获取上传记录
     */
    async getAllLogs(params) {
        let page = _.parseInt(params.page);
        let limit = 10;
        let skip = page > 0? limit * (page - 1) : 0;
        
        let result = await new FileModel().cfind({}).sort({
            date: -1
        }).skip(skip).limit(limit).exec();

        _.forEach(result, perLog => {
            perLog.link = _.get(CDNCONFIG, 'feature.origin') + '/' + perLog.actPath + '/index.html';
        });

        return result;
    }

}

module.exports = FileApi;