UNPKG

node-red-contrib-voice-assistant

Version:

一个小度-小爱-猫精音箱控制NODE-RED自定义设备的节点

207 lines (198 loc) 6.84 kB
const fs = require('fs'); const path = require('path'); const os = require('os'); const got = require('got'); const Zip = require('decompress-zip'); const uuid = require('uuid'); const ini = require('ini'); const { spawn } = require('child_process'); class FrpClient { constructor() { this.url = this.getCdnUrl(); this._ondownloadProgress = []; this.cacheUrl = path.join(__dirname, 'frpc.zip'); //frp路径 this.target = path.join(__dirname, 'frpc'); this.config = { common: { server_addr: '47.110.232.79', server_port: 7000, }, }; } getCdnUrl() { const arch = os.platform() + os.arch(); const cdn = 'https://hasskit.com/'; const cdnPath = 'public/frp/'; const cdnFiles = { linuxarm: cdn + cdnPath + 'linux-arm.zip', linuxarm64: cdn + cdnPath + 'linux-arm64.zip', linuxia32: cdn + cdnPath + 'linux-386.zip', linuxx64: cdn + cdnPath + 'linux-amd64.zip', }; const url = cdnFiles[arch]; if (!url) { console.error('frpc - platform ' + arch + ' is not supported.'); return; } return url; } download() { const downloadStream = got.stream(this.url + ''); const fileWriteStream = fs.createWriteStream(this.cacheUrl); return new Promise((resolve, reject) => { downloadStream .on('downloadProgress', (info) => { this._ondownloadProgress && this._ondownloadProgress(info.percent.toFixed(2) * 100); }) .on('error', (err) => { resolve(); }); fileWriteStream.on('finish', () => { resolve(true); console.log('下载完成'); }); downloadStream.pipe(fileWriteStream); }); } set onDownloadProgress(fn) { this._ondownloadProgress = fn; } removeFrp() { fs.unlinkSync(this.target); } //解包 extract() { return new Promise((resolve) => { new Zip(this.cacheUrl) .extract({ path: __dirname }) .once('error', error) .once('extract', () => { fs.chmodSync(this.target, 755); if (!fs.existsSync(this.target) || fs.statSync(this.target).size <= 0) { return error(new Error('corrupted file ' + this.target)); } console.log('frp - binary unpacked to ' + this.target); resolve(null); fs.unlinkSync(this.cacheUrl); }); function error(e) { console.error('ngrok - error unpacking binary', e); resolve(e); } }); } //frp运行 createSection(local_addr = '127.0.0.1', local_port = 0, remote_port = 0) { const section = (0, uuid.v4)().replace(/-/g, ''); this.config[section] = { type: 'tcp', local_ip: local_addr, local_port: local_port, remote_port: remote_port, }; return section; } createConfig() { fs.writeFileSync(path.join(__dirname, 'frpc.ini'), ini.stringify(this.config)); } handleData(data) { const obj = { code: 0, msg: data }; if (data.includes('service.go:104')) { obj.code = 104; obj.msg = 'frp连接失败'; } else if (data.includes('service.go:301')) { obj.code = 301; obj.msg = 'frp连接成功'; } else if (data.includes('control.go:178')) { obj.code = 178; obj.msg = '端口占用'; } else if (data.includes('control.go:180')) { obj.code = 180; obj.msg = '端口映射成功'; } return obj; } async setup(node) { node.options = [ { url: '127.0.0.1', port: 8123 }, { url: '127.0.0.1', port: 1880 }, ]; node.options.forEach((it) => { this.createSection(it.url, it.port, 10004); }); this.createConfig(); if (!fs.existsSync(this.target) || fs.statSync(this.target).size <= 0) { this.onDownloadProgress = function (msg) { node.status({ fill: 'green', shape: 'dot', text: '下载进度:' + msg + '%' }); }; if (!this.url) return; const status = await this.download(); if (!status) { node.status({ fill: 'red', shape: 'dot', text: '下载失败' }); this.removeFrp(); return; } const extract = await this.extract(); if (!extract) { console.log('解包成功'); return; } else { this.removeFrp(); } } } run(cb) { this.child = spawn(this.target, ['-c', path.join(__dirname, 'frpc.ini')]); this.child.on('error', function (err) { console.log('error', err); }); this.child.on('close', (code) => { console.log(code); this.emitClose && this.emitClose(); this.close(); }); this.child.stdout.on('data', (msg) => { const msgObj = this.handleData(msg.toString().trim()); cb && cb(msgObj); }); } start(cb) { try { this.run(cb); return true; } catch (_a) { console.log(_a); return false; } } close(done) { this.connect = false; try { spawn('kill', ['-9', child.pid.toString()]); if (done) { this.emitClose = done; done(); } } catch (_a) { done && done(); } } } module.exports = FrpClient; /* (async () => { const frpClient = new FrpClient(); if (!fs.existsSync(frpClient.target) || fs.statSync(frpClient.target).size <= 0) { frpClient.onDownloadProgress = function (msg) { console.log('下载进度:', msg, '%'); }; if (!frpClient.url) return; const status = await frpClient.download(); if (!status) return; const extract = await frpClient.extract(); if (!extract) console.log('解包成功'); } frpClient.createSection(undefined, 1880, 10004); frpClient.createConfig(); frpClient.start(); })(); */