Files
snort/packages/system/dist/NostrSystem.js
2023-06-08 12:45:23 +02:00

237 lines
9.4 KiB
JavaScript

"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _NostrSystem_instances, _NostrSystem_sockets, _NostrSystem_log, _NostrSystem_relayCache, _NostrSystem_cleanup;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NostrSystem = void 0;
const debug_1 = __importDefault(require("debug"));
const ExternalStore_1 = __importDefault(require("./ExternalStore"));
const Connection_1 = require("./Connection");
const Query_1 = require("./Query");
const Util_1 = require("./Util");
/**
* Manages nostr content retrieval system
*/
class NostrSystem extends ExternalStore_1.default {
constructor(relayCache) {
super();
_NostrSystem_instances.add(this);
/**
* All currently connected websockets
*/
_NostrSystem_sockets.set(this, new Map());
/**
* All active queries
*/
this.Queries = new Map();
_NostrSystem_log.set(this, (0, debug_1.default)("System"));
_NostrSystem_relayCache.set(this, void 0);
__classPrivateFieldSet(this, _NostrSystem_relayCache, relayCache, "f");
__classPrivateFieldGet(this, _NostrSystem_instances, "m", _NostrSystem_cleanup).call(this);
}
get Sockets() {
return [...__classPrivateFieldGet(this, _NostrSystem_sockets, "f").values()].map(a => a.snapshot());
}
/**
* Connect to a NOSTR relay if not already connected
*/
async ConnectToRelay(address, options) {
try {
const addr = (0, Util_1.unwrap)((0, Util_1.sanitizeRelayUrl)(address));
if (!__classPrivateFieldGet(this, _NostrSystem_sockets, "f").has(addr)) {
const c = new Connection_1.Connection(addr, options, this.HandleAuth?.bind(this));
__classPrivateFieldGet(this, _NostrSystem_sockets, "f").set(addr, c);
c.OnEvent = (s, e) => this.OnEvent(s, e);
c.OnEose = s => this.OnEndOfStoredEvents(c, s);
c.OnDisconnect = id => this.OnRelayDisconnect(id);
await c.Connect();
}
else {
// update settings if already connected
(0, Util_1.unwrap)(__classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(addr)).Settings = options;
}
}
catch (e) {
console.error(e);
}
}
OnRelayDisconnect(id) {
for (const [, q] of this.Queries) {
q.connectionLost(id);
}
}
OnEndOfStoredEvents(c, sub) {
for (const [, v] of this.Queries) {
v.eose(sub, c);
}
}
OnEvent(sub, ev) {
for (const [, v] of this.Queries) {
v.onEvent(sub, ev);
}
}
/**
*
* @param address Relay address URL
*/
async ConnectEphemeralRelay(address) {
try {
const addr = (0, Util_1.unwrap)((0, Util_1.sanitizeRelayUrl)(address));
if (!__classPrivateFieldGet(this, _NostrSystem_sockets, "f").has(addr)) {
const c = new Connection_1.Connection(addr, { read: true, write: false }, this.HandleAuth?.bind(this), true);
__classPrivateFieldGet(this, _NostrSystem_sockets, "f").set(addr, c);
c.OnEvent = (s, e) => this.OnEvent(s, e);
c.OnEose = s => this.OnEndOfStoredEvents(c, s);
c.OnDisconnect = id => this.OnRelayDisconnect(id);
await c.Connect();
return c;
}
}
catch (e) {
console.error(e);
}
}
/**
* Disconnect from a relay
*/
DisconnectRelay(address) {
const c = __classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(address);
if (c) {
__classPrivateFieldGet(this, _NostrSystem_sockets, "f").delete(address);
c.Close();
}
}
GetQuery(id) {
return this.Queries.get(id);
}
Query(type, req) {
const existing = this.Queries.get(req.id);
if (existing) {
const filters = !req.options?.skipDiff
? req.buildDiff(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f"), existing.filters)
: req.build(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f"));
if (filters.length === 0 && !!req.options?.skipDiff) {
return existing;
}
else {
for (const subQ of filters) {
this.SendQuery(existing, subQ).then(qta => qta.forEach(v => __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "New QT from diff %s %s %O from: %O", req.id, v.id, v.filters, existing.filters)));
}
this.notifyChange();
return existing;
}
}
else {
const store = new type();
const filters = req.build(__classPrivateFieldGet(this, _NostrSystem_relayCache, "f"));
const q = new Query_1.Query(req.id, store, req.options?.leaveOpen);
this.Queries.set(req.id, q);
for (const subQ of filters) {
this.SendQuery(q, subQ).then(qta => qta.forEach(v => __classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "New QT from diff %s %s %O", req.id, v.id, v.filters)));
}
this.notifyChange();
return q;
}
}
async SendQuery(q, qSend) {
if (qSend.relay) {
__classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "Sending query to %s %O", qSend.relay, qSend);
const s = __classPrivateFieldGet(this, _NostrSystem_sockets, "f").get(qSend.relay);
if (s) {
const qt = q.sendToRelay(s, qSend);
if (qt) {
return [qt];
}
}
else {
const nc = await this.ConnectEphemeralRelay(qSend.relay);
if (nc) {
const qt = q.sendToRelay(nc, qSend);
if (qt) {
return [qt];
}
}
else {
console.warn("Failed to connect to new relay for:", qSend.relay, q);
}
}
}
else {
const ret = [];
for (const [, s] of __classPrivateFieldGet(this, _NostrSystem_sockets, "f")) {
if (!s.Ephemeral) {
const qt = q.sendToRelay(s, qSend);
if (qt) {
ret.push(qt);
}
}
}
return ret;
}
return [];
}
/**
* Send events to writable relays
*/
BroadcastEvent(ev) {
for (const [, s] of __classPrivateFieldGet(this, _NostrSystem_sockets, "f")) {
s.SendEvent(ev);
}
}
/**
* Write an event to a relay then disconnect
*/
async WriteOnceToRelay(address, ev) {
return new Promise((resolve, reject) => {
const c = new Connection_1.Connection(address, { write: true, read: false }, this.HandleAuth, true);
const t = setTimeout(reject, 5000);
c.OnConnected = async () => {
clearTimeout(t);
await c.SendAsync(ev);
c.Close();
resolve();
};
c.Connect();
});
}
takeSnapshot() {
return {
queries: [...this.Queries.values()].map(a => {
return {
id: a.id,
filters: a.filters,
subFilters: [],
};
}),
};
}
}
exports.NostrSystem = NostrSystem;
_NostrSystem_sockets = new WeakMap(), _NostrSystem_log = new WeakMap(), _NostrSystem_relayCache = new WeakMap(), _NostrSystem_instances = new WeakSet(), _NostrSystem_cleanup = function _NostrSystem_cleanup() {
let changed = false;
for (const [k, v] of this.Queries) {
if (v.canRemove()) {
v.sendClose();
this.Queries.delete(k);
__classPrivateFieldGet(this, _NostrSystem_log, "f").call(this, "Deleted query %s", k);
changed = true;
}
}
if (changed) {
this.notifyChange();
}
setTimeout(() => __classPrivateFieldGet(this, _NostrSystem_instances, "m", _NostrSystem_cleanup).call(this), 1000);
};
//# sourceMappingURL=NostrSystem.js.map