file.js 5.23 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 qn = require('../../lib/qiniu');

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

class FileApi {

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

        let readable = fs.createReadStream(file.path);
        let writable = fs.createWriteStream(fileSavePath);

        readable.pipe(writable);

        readable.on('end', async() => {
            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 upToQiniuResult = await this._uploadToQiniu(fileList, fileDistPath);
                let fileModel = new FileModel();
                let insertRes = await fileModel.insert({ // 上传记录写库
                    date: moment().format('YYYY-MM-DD HH:mm'),
                    fileName: fileName,
                    actPath: actPath,
                    username: '' // TODO
                });

                ws.broadcast(BROADCAST_PATH, {
                    state: '文件已经全部上传到七牛'
                });
            } else {
                ws.broadcast(BROADCAST_PATH, {
                    state: '校验文件失败,非法上传!'
                });
            }
        });
    }
    
    /**
     * 上传到七牛
     * @param {待上传的文件列表} fileList
     * @param {待上传的文件夹路径} fileDistPath 
     */
    async _uploadToQiniu(fileList, fileDistPath) {
        let hasError = false;

        fileList = _.map(fileList, perFilePath => {
            return  fileDistPath + _.split(perFilePath, fileDistPath)[1];
        }); // 处理待上传的文件列表

        _.remove(fileList, perFilePath => {
            return !perFilePath || /__MACOSX/.test(perFilePath) || !fs.lstatSync(perFilePath).isFile();
        });

        for(let i = 0; i < fileList.length; i++) {
            let result = await qn.uploadFileAsync(fileList[i], {
                key: path.join(QINIU_PREFIX, fileList[i])
            });

            if (result && result.url) {
                ws.broadcast(BROADCAST_PATH, {
                    state: `${fileList[i]} 已经上传到七牛`
                });
            } else {
                ws.broadcast(BROADCAST_PATH, {
                    state: `${fileList[i]} 上传到七牛出错`
                });
            }
        }
    }

    /**
     * 测试是否是可以上传的文件包
     * @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();

        return result;
    }

}

module.exports = FileApi;