hfs
Version:
HTTP File Server
95 lines (94 loc) • 3.84 kB
JavaScript
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.disconnectionsLog = exports.Connection = void 0;
exports.normalizeIp = normalizeIp;
exports.newConnection = newConnection;
exports.getConnections = getConnections;
exports.socket2connection = socket2connection;
exports.getConnection = getConnection;
exports.updateConnectionForCtx = updateConnectionForCtx;
exports.updateConnection = updateConnection;
exports.disconnect = disconnect;
const events_1 = __importDefault(require("./events"));
const geo_1 = require("./geo");
const lodash_1 = __importDefault(require("lodash"));
class Connection {
// the sockets we collect are the plain ones, as soon as the tcp layer is connected
constructor(socket) {
this.socket = socket;
this.started = new Date();
this.sent = 0; // socket-scoped, not request-scoped
this.got = 0;
all.push(this);
socket.on('close', () => {
all.splice(all.indexOf(this), 1);
events_1.default.emit('connectionClosed', this);
});
events_1.default.emit('connection', this);
}
get ip() {
var _a, _b;
return ((_a = this.ctx) === null || _a === void 0 ? void 0 : _a.ip) || ((_b = this._cachedIp) !== null && _b !== void 0 ? _b : (this._cachedIp = normalizeIp(this.socket.remoteAddress || '')));
}
get secure() {
return this.socket.server.cert > '';
}
}
exports.Connection = Connection;
function normalizeIp(ip) {
return ip.replace(/^::ffff:/, ''); // simplify ipv6-mapped addresses
}
const all = [];
function newConnection(socket) {
const ip = normalizeIp(socket.remoteAddress || '');
const res = events_1.default.emit('newSocket', { socket, ip });
const msg = (res === null || res === void 0 ? void 0 : res.isDefaultPrevented()) ? 'plugin (newSocket)' : res === null || res === void 0 ? void 0 : res.find(lodash_1.default.isString);
if (!msg)
return new Connection(socket);
disconnect(socket, msg);
}
function getConnections() {
return all;
}
function socket2connection(socket) {
return all.find(x => // socket exposed by Koa is TLSSocket which encapsulates simple Socket, and I've found no way to access it for simple comparison
x.socket.remotePort === socket.remotePort // but we can still match them because IP:PORT is key
&& x.socket.remoteAddress === socket.remoteAddress);
}
function getConnection(ctx) {
return ctx.state.connection;
}
function updateConnectionForCtx(ctx) {
const conn = getConnection(ctx);
if (conn)
updateConnection(conn, { ctx });
return conn;
}
function updateConnection(conn, change, changeState) {
const { ctx } = conn;
if (changeState && ctx) {
Object.assign(ctx.state, changeState);
Object.assign(change, { ctx });
}
Object.assign(conn, change);
events_1.default.emit('connectionUpdated', conn, change);
}
exports.disconnectionsLog = [];
function disconnect(what, debugLog = '') {
if ('socket' in what)
what = what.socket;
const ip = normalizeIp(what.remoteAddress || '');
if (debugLog)
console.debug("disconnection:", debugLog, ip);
(0, geo_1.ip2country)(ip).then(res => {
const rec = { ip, country: res || undefined, ts: new Date, msg: debugLog || undefined };
exports.disconnectionsLog.unshift(rec);
exports.disconnectionsLog.length = Math.min(1000, exports.disconnectionsLog.length);
events_1.default.emit('disconnection', rec);
});
return what.destroy();
}
;