258 lines
7.6 KiB
JavaScript
258 lines
7.6 KiB
JavaScript
/**
|
|
* HTTP后端数据发送处理函数
|
|
* 更新: 2016/05/07
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const fs = require('fs'),
|
|
iconv = require('iconv-lite'),
|
|
through = require('through'),
|
|
superagent = require('superagent'),
|
|
superagentProxy = require('superagent-proxy');
|
|
|
|
let logger;
|
|
// 请求UA
|
|
const USER_AGENT = 'antSword/v2.0';
|
|
|
|
// 请求超时
|
|
const REQ_TIMEOUT = 10000;
|
|
|
|
// 代理配置
|
|
const APROXY_CONF = {
|
|
mode: 'noproxy',
|
|
uri: ''
|
|
}
|
|
|
|
class Request {
|
|
|
|
constructor(electron) {
|
|
logger = new electron.Logger('Request');
|
|
const ipcMain = electron.ipcMain;
|
|
|
|
ipcMain.on('aproxy', this.onAproxy.bind(this));
|
|
ipcMain.on('aproxytest', this.onAproxyTest.bind(this));
|
|
ipcMain.on('request', this.onRequest.bind(this));
|
|
ipcMain.on('download', this.onDownlaod.bind(this));
|
|
}
|
|
|
|
|
|
/**
|
|
* 加载代理配置
|
|
* @param {Object} event ipcMain事件
|
|
* @param {Object} opts 代理配置
|
|
* @return {[type]} [description]
|
|
*/
|
|
onAproxy(event, opts) {
|
|
logger.debug(
|
|
'aProxy::Set Proxy Mode -',
|
|
APROXY_CONF['mode'] === 'manualproxy' ? APROXY_CONF['uri'] : 'noproxy'
|
|
);
|
|
|
|
APROXY_CONF['mode'] = opts['aproxymode'];
|
|
APROXY_CONF['uri'] = opts['aproxyuri'];
|
|
|
|
if (APROXY_CONF['mode'] === 'noproxy') {
|
|
return superagent.Request.prototype.proxy = function() { return this };
|
|
}
|
|
superagentProxy(superagent);
|
|
}
|
|
|
|
/**
|
|
* 监听代理连接测试
|
|
* @param {Object} event ipcMain事件
|
|
* @param {Object} opts 测试配置
|
|
* @return {[type]} [description]
|
|
*/
|
|
onAproxyTest(event, opts) {
|
|
logger.debug('aProxy::Test Proxy -', opts['aproxyuri'], '- Connect to ', opts['url']);
|
|
superagentProxy(superagent);
|
|
superagent
|
|
.get(opts['url'])
|
|
.set('User-Agent', USER_AGENT)
|
|
.proxy(opts['aproxyuri'])
|
|
.timeout(REQ_TIMEOUT)
|
|
.end((err, ret) => {
|
|
if (err) {
|
|
logger.fatal("aProxy::Test Error", err);
|
|
return event.sender.send('aproxytest-error-' + opts['hash'], err);
|
|
}else{
|
|
logger.info("aProxy::Test Success");
|
|
return event.sender.send('aproxytest-success-' + opts['hash'], ret);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* 监听HTTP请求
|
|
* @param {Object} event ipcMain事件对象
|
|
* @param {Object} opts 请求配置
|
|
* @return {[type]} [description]
|
|
*/
|
|
onRequest(event, opts) {
|
|
logger.debug('onRequest::opts', opts);
|
|
|
|
const _request = superagent.post(opts['url']);
|
|
// 设置headers
|
|
_request.set('User-Agent', USER_AGENT);
|
|
// 自定义headers
|
|
for (let _ in opts.headers) {
|
|
_request.set(_, opts.headers[_]);
|
|
}
|
|
// 自定义body
|
|
const _postData = Object.assign({}, opts.body, opts.data);
|
|
_request
|
|
.proxy(APROXY_CONF['uri'])
|
|
.type('form')
|
|
// 超时
|
|
.timeout(opts.timeout || REQ_TIMEOUT)
|
|
// 忽略HTTPS
|
|
.ignoreHTTPS(opts['ignoreHTTPS'])
|
|
.send(_postData)
|
|
.parse((res, callback) => {
|
|
this.parse(opts['tag_s'], opts['tag_e'], (chunk) => {
|
|
event.sender.send('request-chunk-' + opts['hash'], chunk);
|
|
}, res, callback);
|
|
})
|
|
.end((err, ret) => {
|
|
if (err) {
|
|
return event.sender.send('request-error-' + opts['hash'], err);
|
|
};
|
|
let buff = ret.body;
|
|
// 解码
|
|
let text = iconv.decode(buff, opts['encode']);
|
|
// 回调数据
|
|
event.sender.send('request-' + opts['hash'], {
|
|
text: text,
|
|
buff: buff
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 监听下载请求
|
|
* @param {Object} event ipcMain事件对象
|
|
* @param {Object} opts 下载配置
|
|
* @return {[type]} [description]
|
|
*/
|
|
onDownlaod(event, opts) {
|
|
logger.debug('onDownlaod', opts);
|
|
|
|
// 创建文件流
|
|
const rs = fs.createWriteStream(opts['path']);
|
|
|
|
let indexStart = -1;
|
|
let indexEnd = -1;
|
|
let tempData = [];
|
|
|
|
const _request = superagent.post(opts['url']);
|
|
// 设置headers
|
|
_request.set('User-Agent', USER_AGENT);
|
|
// 自定义headers
|
|
for (let _ in opts.headers) {
|
|
_request.set(_, opts.headers[_]);
|
|
}
|
|
// 自定义body
|
|
const _postData = Object.assign({}, opts.body, opts.data);
|
|
_request
|
|
.proxy(APROXY_CONF['uri'])
|
|
.type('form')
|
|
// 设置超时会导致文件过大时写入出错
|
|
// .timeout(timeout)
|
|
// 忽略HTTPS
|
|
.ignoreHTTPS(opts['ignoreHTTPS'])
|
|
.send(_postData)
|
|
.pipe(through(
|
|
(chunk) => {
|
|
// 判断数据流中是否包含后截断符?长度++
|
|
let temp = chunk.indexOf(opts['tag_e']);
|
|
if (temp !== -1) {
|
|
indexEnd = Buffer.concat(tempData).length + temp;
|
|
};
|
|
tempData.push(chunk);
|
|
event.sender.send('download-progress-' + opts['hash'], chunk.length);
|
|
},
|
|
() => {
|
|
let tempDataBuffer = Buffer.concat(tempData);
|
|
|
|
indexStart = tempDataBuffer.indexOf(opts['tag_s']) || 0;
|
|
// 截取最后的数据
|
|
let finalData = new Buffer(tempDataBuffer.slice(
|
|
indexStart + opts['tag_s'].length,
|
|
indexEnd
|
|
), 'binary');
|
|
// 写入文件流&&关闭
|
|
rs.write(finalData);
|
|
rs.close();
|
|
event.sender.send('download-' + opts['hash'], finalData.length);
|
|
// 删除内存数据
|
|
finalData = tempDataBuffer = tempData = null;
|
|
}
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 二进制数据流解析
|
|
* @param {String} tag_s 数据截断符号(前)
|
|
* @param {String} tag_e 数据截断符号(后)
|
|
* @param {Function} chunkCallBack 数据流回调函数
|
|
* @param {Object} res Superagent::res对象
|
|
* @param {Function} callback 数据获取完毕回调事件
|
|
* @return {[type]} [description]
|
|
*/
|
|
parse(tag_s, tag_e, chunkCallBack, res, callback) {
|
|
// 数据转换二进制处理
|
|
res.setEncoding('binary');
|
|
res.data = '';
|
|
// 2. 把分隔符转换为16进制
|
|
const tagHexS = new Buffer(tag_s).toString('hex');
|
|
const tagHexE = new Buffer(tag_e).toString('hex');
|
|
|
|
let foundTagS = false;
|
|
let foundTagE = false;
|
|
res.on('data', (chunk) => {
|
|
|
|
// 这样吧,我们尝试一种新的数据截取算法:
|
|
// 1. 把数据流转换为16进制
|
|
let chunkHex = new Buffer(chunk).toString('hex');
|
|
// 3. 根据分隔符进行判断截断数据流
|
|
let temp = '';
|
|
// 如果包含前后截断,则截取中间
|
|
if (chunkHex.indexOf(tagHexS) >= 0 && chunkHex.lastIndexOf(tagHexE) >= 0) {
|
|
let index_s = chunkHex.indexOf(tagHexS);
|
|
let index_e = chunkHex.lastIndexOf(tagHexE);
|
|
temp = chunkHex.substr(index_s + tagHexS.length, index_e - index_s - tagHexE.length);
|
|
foundTagS = foundTagE = true;
|
|
}
|
|
// 如果只包含前截断,则截取后边
|
|
else if (chunkHex.indexOf(tagHexS) >= 0 && chunkHex.lastIndexOf(tagHexE) === -1) {
|
|
temp = chunkHex.split(tagHexS)[1];
|
|
foundTagS = true;
|
|
}
|
|
// 如果只包含后截断,则截取前边
|
|
else if (chunkHex.indexOf(tagHexS) === -1 && chunkHex.lastIndexOf(tagHexE) >= 0) {
|
|
temp = chunkHex.split(tagHexE)[0];
|
|
foundTagE = true;
|
|
}
|
|
// 如果有没有,那就是中途迷路的数据啦 ^.^
|
|
else if (foundTagS && !foundTagE) {
|
|
temp = chunkHex;
|
|
}
|
|
// 4. 十六进制还原为二进制
|
|
let finalData = new Buffer(temp, 'hex');
|
|
// 5. 返回还原好的数据
|
|
chunkCallBack(finalData);
|
|
|
|
res.data += finalData;
|
|
});
|
|
res.on('end', () => {
|
|
logger.info(`end.size=${res.data.length}`, res.data);
|
|
callback(null, new Buffer(res.data, 'binary'));
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = Request;
|