UNPKG

dalao-proxy

Version:

An expandable HTTP proxy based on the plug-in system for frontend developers with request caching request mock and development!

133 lines (112 loc) 4.5 kB
const chalk = require('chalk'); const httpolyglot = require('@httptoolkit/httpolyglot'); const WebSocket = require('ws'); const http = require('http'); const URL = require('url').URL; const dalaoProxy = require('./core'); const { getIPv4Address, locationMatch, locationTransform } = require('../utils'); const register = require('../plugin').register; const { connections } = require('../runtime'); const { getCert } = require('../cert'); const networkIp = getIPv4Address(); // attach server to port function attachServerListener(program, server, config) { let { host, port, secure } = config; server.on('listening', function () { const protocal = `http${secure ? 's' : ''}://`; const localAddress = `${protocal}${host === '0.0.0.0' ? 'localhost' : host}:${port}`; const networkAddress = networkIp ? `${protocal}${networkIp}:${port}` : 'unavailable'; server.address = { local: new URL(localAddress), network: networkIp ? new URL(networkAddress) : null, }; config.port = port; console.log(chalk.green('\n> dalao has setup the Proxy for you 🚀\n')); console.log('> dalao is listening at: '); console.log(' - Local: ' + chalk.green(localAddress)); console.log(' - Network: ' + chalk.green(networkAddress)); console.log(chalk.grey(' You can enter `rs`,`restart`,`reload` to reload server anytime.')); console.log(); // trigger field `server` register._trigger('server', server, value => { program.context.server = value; }); }); server.on('error', function (err) { server.close(); if (/listen EACCES/.test(err.message)) { console.error(chalk.red(` Try listening port ${port} failed with code ${err.code}, please change anther port`)); // console.error(err); } else if (/EADDRINUSE/i.test(err.message)) { console.error(chalk.red(` Port ${port} is in use, please change anther port`)); // console.log(chalk.grey(` Port ${port} is in use, dalao is trying to change port to ${++port}`)); // server.listen(port, host); } else { console.error(err); } }); server.on('connection', function (connection) { connections.add(connection); connection.on('close', () => { connections.delete(connection); }); }); server.listen(port, host); } async function createProxyServer(program) { const { config, plugins } = program.context; // print route table console.log(program.context.output.routeTable.toString()); const proxyCallback = dalaoProxy.httpCallback(config, plugins); let server; if (config.secure) { const { cert, key } = await getCert(networkIp); const secureOpt = { key, cert }; // server = https.createServer(secureOpt, proxyCallback); server = httpolyglot.createServer(secureOpt, proxyCallback); } else { server = http.createServer(proxyCallback); } server.timeout = 2 * 60 * 1000; server.maxConnections = 1000; server.keepAliveTimeout = 10 * 1000; server.headersTimeout = 60 * 1000; // attach server to port attachServerListener(program, server, config); createWebSocketServer(program, server, config); return server; } function createWebSocketServer(program, server, config) { const { proxyTable } = config; const wss = new WebSocket.Server({ server }); wss.on('connection', (ws, request) => { const url = request.url; const locationMatcher = locationMatch(url, proxyTable); const proxyUrl = locationTransform(proxyTable[locationMatcher.matched], locationMatcher.matchResult); const wsReq = new WebSocket(proxyUrl); const incomingWs = WebSocket.createWebSocketStream(ws, { encoding: 'utf8', decodeStrings: false }); const duplex = WebSocket.createWebSocketStream(wsReq, { encoding: 'utf8', decodeStrings: false }); duplex.on('error', err => { console.error(err); wsReq.terminate(); ws.terminate(); }); incomingWs.pipe(duplex); duplex.pipe(incomingWs); ws.on('close', () => { wsReq.terminate(); }); wsReq.on('close', () => { ws.terminate(); }); }); } module.exports = { createProxyServer };