91 lines
2.8 KiB
JavaScript
91 lines
2.8 KiB
JavaScript
import debug from 'debug';
|
|
import { EventEmitter } from 'events';
|
|
import http from 'http';
|
|
import pump from 'pump';
|
|
export class Client extends EventEmitter {
|
|
id;
|
|
agent;
|
|
graceTimeout;
|
|
log;
|
|
constructor(options) {
|
|
super();
|
|
this.agent = options.agent;
|
|
this.id = options.id;
|
|
this.log = debug(`lt:Client[${this.id}]`);
|
|
this.graceTimeout = setTimeout(() => {
|
|
this.close();
|
|
}, 1000);
|
|
this.graceTimeout.unref();
|
|
this.agent.on('online', () => {
|
|
this.log('client online %s', this.id);
|
|
clearTimeout(this.graceTimeout);
|
|
});
|
|
this.agent.on('offline', () => {
|
|
this.log('client offline %s', this.id);
|
|
clearTimeout(this.graceTimeout);
|
|
this.graceTimeout = setTimeout(() => {
|
|
this.close();
|
|
}, 1000);
|
|
this.graceTimeout.unref();
|
|
});
|
|
this.agent.once('error', () => {
|
|
this.close();
|
|
});
|
|
}
|
|
close() {
|
|
clearTimeout(this.graceTimeout);
|
|
this.agent.destroy();
|
|
this.emit('close');
|
|
}
|
|
handleRequest(req, res) {
|
|
this.log('> %s', req.url);
|
|
const opt = {
|
|
agent: this.agent,
|
|
headers: req.headers,
|
|
method: req.method,
|
|
path: req.url,
|
|
};
|
|
const clientReq = http.request(opt, (clientRes) => {
|
|
this.log('< %s', req.url);
|
|
res.writeHead(clientRes.statusCode, clientRes.headers);
|
|
pump(clientRes, res);
|
|
});
|
|
clientReq.once('error', () => {
|
|
// TODO: if headers not sent - respond with gateway unavailable
|
|
});
|
|
pump(req, clientReq);
|
|
}
|
|
handleUpgrade(req, socket) {
|
|
this.log('> [up] %s', req.url);
|
|
socket.once('error', (err) => {
|
|
if (err.code === 'ECONNRESET' || err.code === 'ETIMEDOUT')
|
|
return;
|
|
console.error(err);
|
|
});
|
|
this.agent.createConnection({}, (err, conn) => {
|
|
this.log('< [up] %s', req.url);
|
|
if (err || !conn) {
|
|
socket.end();
|
|
return;
|
|
}
|
|
if (!socket.readable || !socket.writable) {
|
|
conn.destroy();
|
|
socket.end();
|
|
return;
|
|
}
|
|
const arr = [`${req.method} ${req.url} HTTP/${req.httpVersion}`];
|
|
for (let i = 0; i < req.rawHeaders.length - 1; i += 2) {
|
|
arr.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);
|
|
}
|
|
arr.push('');
|
|
arr.push('');
|
|
pump(conn, socket);
|
|
pump(socket, conn);
|
|
conn.write(arr.join('\r\n'));
|
|
});
|
|
}
|
|
stats() {
|
|
return this.agent.stats();
|
|
}
|
|
}
|
|
//# sourceMappingURL=Client.js.map
|