hfs
Version:
HTTP File Server
116 lines (115 loc) • 5.11 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 });
const lodash_1 = __importDefault(require("lodash"));
const connections_1 = require("./connections");
const misc_1 = require("./misc");
const throttler_1 = require("./throttler");
const auth_1 = require("./auth");
const SendList_1 = require("./SendList");
const persistence_1 = require("./persistence");
exports.default = {
async disconnect({ ip, port, allButLocalhost }) {
const match = allButLocalhost ? ((x) => !(0, misc_1.isLocalHost)(x.ip))
: lodash_1.default.matches({ ip, port });
const found = (0, connections_1.getConnections)().filter(c => match(getConnAddress(c)));
for (const c of found)
(0, connections_1.disconnect)(c.socket, "manual disconnection");
return { result: found.length };
},
get_connections({}, ctx) {
const list = new SendList_1.SendListReadable({
diff: true,
addAtStart: (0, connections_1.getConnections)().map(c => !ignore(c) && serializeConnection(c)).filter(Boolean),
});
list.props({ you: ctx.ip });
return list.events(ctx, {
connection(conn) {
if (ignore(conn))
return;
list.add(serializeConnection(conn));
},
connectionClosed(conn) {
if (ignore(conn))
return;
list.remove(getConnAddress(conn));
},
connectionUpdated(conn, change) {
if (conn.socket.closed || ignore(conn) || ignore(change) || lodash_1.default.isEmpty(change))
return;
if (change.ctx) {
Object.assign(change, fromCtx(change.ctx));
change.ctx = undefined;
}
list.update(getConnAddress(conn), change);
},
});
function serializeConnection(conn) {
var _a;
const { socket, started, secure } = conn;
return {
...getConnAddress(conn),
v: (((_a = socket.remoteFamily) === null || _a === void 0 ? void 0 : _a.endsWith('6')) ? 6 : 4),
got: socket.bytesRead,
sent: socket.bytesWritten,
country: conn.country,
started,
secure: (secure || undefined), // undefined will save some space once json-ed
...fromCtx(conn.ctx),
};
}
function fromCtx(ctx) {
if (!ctx)
return;
const s = ctx.state; // short alias
return {
user: (0, auth_1.getCurrentUsername)(ctx),
agent: (0, misc_1.shortenAgent)(ctx.get('user-agent')),
archive: s.archive,
...s.browsing ? { op: 'browsing', path: decodeURIComponent(s.browsing) }
: s.uploadPath ? { op: 'upload', path: decodeURIComponent(s.uploadPath) }
: {
op: !s.considerAsGui && (ctx.state.archive || ctx.state.vfsNode) ? 'download' : undefined,
path: (0, misc_1.try_)(() => decodeURIComponent(ctx.originalUrl), () => ctx.originalUrl),
},
opProgress: lodash_1.default.isNumber(s.opProgress) ? lodash_1.default.round(s.opProgress, 3) : undefined,
opTotal: s.opTotal,
opOffset: s.opOffset,
};
}
},
async *get_connection_stats() {
while (1) {
const filtered = (0, connections_1.getConnections)().filter(x => !ignore(x));
yield {
outSpeed: throttler_1.totalOutSpeed,
inSpeed: throttler_1.totalInSpeed,
sent_got: [throttler_1.totalSent.get(), throttler_1.totalGot.get(), totalGotSentResetTime.get()],
connections: filtered.length,
ips: lodash_1.default.uniqBy(filtered, x => x.ip).length,
};
await (0, misc_1.wait)(1000);
}
},
async clear_persistent({ k }) {
(0, misc_1.apiAssertTypes)({ string_array: { k } });
totalGotSentResetTime.set(new Date);
for (const x of (0, misc_1.wantArray)(k))
void persistence_1.storedMap.del(x);
},
};
function ignore(conn) {
return false; //conn.socket && isLocalHost(conn)
}
function getConnAddress(conn) {
return {
ip: conn.ip,
port: conn.socket.remotePort,
};
}
const totalGotSentResetTime = persistence_1.storedMap.singleSync('totalGotSentResetTime', new Date(0));
totalGotSentResetTime.ready().then(() => // because default value is not stored, and we need to init this value
totalGotSentResetTime.set(was => was.getTime() ? was : new Date));
;