import { stat, mkdir, createWriteStream, createReadStream, unlink } from 'fs';
import { parse as pathParser, extname, join as pathJoin } from 'path';
import { request, get } from 'http';
import { logger } from '@helper/helper';
/**
* uploadUrl = `http://${address}:${port}/xnode/file/ul?access_token=${token}`;
downloadUrl = `http://${address}:${port}/xnode/file/dl?access_token=${token}$media_id=`;
*/
async function createDownloadDir(dir) {
const opts = process.platform == 'win32' ? { recursive: true } : {};
return new Promise((resolve, reject) => {
mkdir(dir, opts, err => {
return err ? reject(err) : resolve(dir);
})
});
}
async function getFileStats(filePath) {
return new Promise((resolve, reject) => {
stat(filePath, (err, stats) => {
return err ? reject(err) : resolve(stats);
})
});
}
class FileManager {
constructor() {
this._downloadDir = process.cwd() + '/download';
}
init(opts = {}) {
opts = Object.assign({
port: 8099
}, opts);
this._opts = opts;
this._downloadDir = opts.downloadDir || process.cwd() + '/download';
this._uploadUrl = `http://${opts.address}:${opts.port}/xnode/file/ul?access_token=${opts.token}`;
this._downloadUrl = `http://${opts.address}:${opts.port}/xnode/file/dl?access_token=${opts.token}&media_id=`;
//this._createDownloadDir(this._downloadDir);
return this;
}
/**
* 上传文件
* @param {String} filePath 文件路径 E:\\Project\\cccs\\cccc\\public\\static\\imgs\\app.png
* @param {Function} onProgress
*/
async upload(filePath, onProgress) {
const fd = pathParser(filePath);
const fileName = fd.base;
const stats = await getFileStats(filePath);
const cb = onProgress && typeof onProgress == 'function' ? onProgress : null;
let totalLength = stats.size;
const opts = {
method: 'POST',
headers: {
'Content-disposition': `attachment; filename="${fileName}"`,
'Content-type': 'application/octet-stream', // 二进制数据流
'Content-length': totalLength,
'Connection': 'keep-alive',
'Transfer-Encoding': 'chunked', // 分片传输
}
};
return new Promise((resolve, reject) => {
let chunkLength = 0;
let totalProgress = 0;
let currProgress = 0;
let req = request(this._uploadUrl.replace('8099', '8099'), opts, res => {
let data = [];
res.on('data', chunk => {
data.push(chunk);
}).on('end', () => {
req = null;
data = data.join();
return resolve(JSON.parse(data));
});
});
req.on('socket', socket => {
socket.on('connect', () => {
let rs = createReadStream(filePath);
rs.on('data', chunk => {
chunkLength += chunk.length;
currProgress = (chunkLength / totalLength * 100) | 0;
if (currProgress != totalProgress) {
totalProgress = currProgress;
totalProgress % 5 == 0 && cb && cb(totalProgress);
}
}).on('end', () => {
rs.close();
rs = null;
req.end();
});
rs.pipe(req);
});
})
req.on('timeout', () => {
return reject('timeout');
}).on('error', err => {
return reject(err);
});
});
}
/**
* 下载文件
* @param {String} fileId 文件ID
* @param {Function} onProgress
*/
async download(fileId, onProgress) {
const dir = await createDownloadDir(this._downloadDir);
const cb = onProgress && typeof onProgress == 'function' ? onProgress : null;
return new Promise((resolve, reject) => {
const url = this._downloadUrl + fileId;
let req = request(url, res => {
console.log(res)
//content-disposition: "attachment; filename="IMG_20200610_143528.jpg""
const totalLength = res.headers['content-length'];
const fileName = res.headers['content-disposition'].split('=')[1].replace(/"/g, '');
const extName = extname(fileName);
const dest = pathJoin(dir, `${fileId}${extName}`);
let out = createWriteStream(dest);
if (res.statusCode != 200) {
}
let chunkLength = 0;
let totalProgress = 0;
let currProgress = 0;
res.on('data', chunk => {
chunkLength += chunk.length;
currProgress = (chunkLength / totalLength * 100) | 0;
if (currProgress != totalProgress) {
totalProgress = currProgress;
totalProgress % 5 == 0 && cb && cb(totalProgress);
}
}).on('end', () => {
});
out.on('finish', () => {
req = null;
out.close();
out = null;
resolve({
attachName: fileName,
attachPath: dest,
attachSize: totalLength
});
}).on('error', err => {
unlink(dest, err => { });
reject(err);
});
res.pipe(out);
});
req.on('timeout', () => {
return reject('timeout');
}).on('error', err => {
return reject('error');
});
req.end();
});
}
}
export default new FileManager();
function fetchProgress(url, opts = {}, onProgress) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(opts.method || 'get', url);
for (let key in opts.headers || {}) {
xhr.setRequestHeader(key, opts.headers[key]);
}
xhr.onload = e => resolve(e.target.responseText);
xhr.onerror = reject;
if (xhr.upload && onProgress) {
xhr.upload.onprogress = onProgress; //上传
}
if ('onprogerss' in xhr && onProgress) {
xhr.onprogress = onProgress; //下载
}
xhr.send(opts.body);
});
}