mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 12:11:35 +00:00
Create RoboPool
This commit is contained in:
parent
463608f9b2
commit
3edd9280a5
@ -14,6 +14,7 @@ import { coordinatorDefaultValues } from './Coordinator.model';
|
||||
import { updateExchangeInfo } from './Exchange.model';
|
||||
import eventToPublicOrder from '../utils/nostr';
|
||||
import { SubCloser } from 'nostr-tools/lib/types/pool';
|
||||
import RoboPool from '../services/RoboPool';
|
||||
|
||||
type FederationHooks = 'onFederationUpdate';
|
||||
|
||||
@ -60,11 +61,7 @@ export class Federation {
|
||||
if (tesnetHost) settings.network = 'testnet';
|
||||
this.connection = null;
|
||||
|
||||
const relays = [
|
||||
'ws://4t4jxmivv6uqej6xzx2jx3fxh75gtt65v3szjoqmc4ugdlhipzdat6yd.onion/nostr',
|
||||
// 'ws://ngdk7ocdzmz5kzsysa3om6du7ycj2evxp2f2olfkyq37htx3gllwp2yd.onion/nostr'
|
||||
];
|
||||
this.relayPool.trustedRelayURLs = new Set<string>(relays);
|
||||
this.roboPool = new RoboPool(settings, origin);
|
||||
}
|
||||
|
||||
public coordinators: Record<string, Coordinator>;
|
||||
@ -75,57 +72,42 @@ export class Federation {
|
||||
|
||||
public hooks: Record<FederationHooks, Array<() => void>>;
|
||||
|
||||
public relayPool: SimplePool = new SimplePool();
|
||||
public relaySubscriptions: SubCloser[] = [];
|
||||
public roboPool: RoboPool;
|
||||
|
||||
setConnection = (settings: Settings): void => {
|
||||
this.connection = settings.connection;
|
||||
|
||||
if (this.connection === 'nostr') {
|
||||
this.connectNostr(settings);
|
||||
this.roboPool.connect();
|
||||
this.loadBookNostr();
|
||||
} else {
|
||||
this.relayPool.close(Array.from(this.relayPool.trustedRelayURLs));
|
||||
this.roboPool.close();
|
||||
this.loadBook();
|
||||
}
|
||||
};
|
||||
|
||||
connectNostr = (settings: Settings): void => {
|
||||
loadBookNostr = (): void => {
|
||||
this.loading = true;
|
||||
this.book = {};
|
||||
|
||||
this.exchange.loadingCache = this.relayPool.trustedRelayURLs.size;
|
||||
this.exchange.loadingCache = this.roboPool.relays.length;
|
||||
|
||||
const authors = Object.values(defaultFederation)
|
||||
.map((f) => f.nostrHexPubkey)
|
||||
.filter((item) => item !== undefined);
|
||||
|
||||
const sub = this.relayPool.subscribeMany(
|
||||
Array.from(this.relayPool.trustedRelayURLs),
|
||||
[
|
||||
{
|
||||
authors,
|
||||
kinds: [38383],
|
||||
'#n': [settings.network],
|
||||
},
|
||||
],
|
||||
{
|
||||
onevent: (event) => {
|
||||
const { dTag, publicOrder } = eventToPublicOrder(event);
|
||||
if (publicOrder) {
|
||||
this.book[dTag] = publicOrder;
|
||||
} else {
|
||||
delete this.book[dTag];
|
||||
}
|
||||
},
|
||||
oneose: () => {
|
||||
this.exchange.loadingCache = this.exchange.loadingCache - 1;
|
||||
this.loading = this.exchange.loadingCache > 0 && this.exchange.loadingCoordinators > 0;
|
||||
this.updateExchange();
|
||||
this.triggerHook('onFederationUpdate');
|
||||
},
|
||||
this.roboPool.subscribeBook({
|
||||
onevent: (event) => {
|
||||
const { dTag, publicOrder } = eventToPublicOrder(event);
|
||||
if (publicOrder) {
|
||||
this.book[dTag] = publicOrder;
|
||||
} else {
|
||||
delete this.book[dTag];
|
||||
}
|
||||
},
|
||||
);
|
||||
this.relaySubscriptions.push(sub);
|
||||
oneose: () => {
|
||||
this.exchange.loadingCache = this.exchange.loadingCache - 1;
|
||||
this.loading = this.exchange.loadingCache > 0 && this.exchange.loadingCoordinators > 0;
|
||||
this.updateExchange();
|
||||
this.triggerHook('onFederationUpdate');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
addCoordinator = (
|
||||
|
101
frontend/src/services/RoboPool/index.ts
Normal file
101
frontend/src/services/RoboPool/index.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { Event } from 'nostr-tools';
|
||||
import { Settings } from '../../models';
|
||||
import defaultFederation from '../../../static/federation.json';
|
||||
import { Origins } from '../../models/Coordinator.model';
|
||||
|
||||
interface RoboPoolEvents {
|
||||
onevent: (event: Event) => void;
|
||||
oneose: () => void;
|
||||
}
|
||||
|
||||
class RoboPool {
|
||||
constructor(settings: Settings, origin: string) {
|
||||
this.network = settings.network ?? 'mainnet';
|
||||
this.relays = Object.values(defaultFederation)
|
||||
.map((coord) => {
|
||||
const url = coord[this.network][settings.selfhostedClient ? 'onion' : origin];
|
||||
|
||||
if (!url) return;
|
||||
|
||||
return `ws://${url.replace(/^https?:\/\//, '')}/nostr`;
|
||||
})
|
||||
.filter((item) => item !== undefined);
|
||||
}
|
||||
|
||||
public relays: string[];
|
||||
public network: string;
|
||||
|
||||
public webSockets: WebSocket[] = [];
|
||||
private messageHandlers: Array<(url: string, event: MessageEvent) => void> = [];
|
||||
|
||||
connect = () => {
|
||||
this.relays.forEach((url) => {
|
||||
if (this.webSockets.find((w: WebSocket) => w.url === url)) return;
|
||||
|
||||
let ws: WebSocket;
|
||||
|
||||
const connect = () => {
|
||||
ws = new WebSocket(url);
|
||||
|
||||
// Add event listeners for the WebSocket
|
||||
ws.onopen = () => {
|
||||
console.log(`Connected to ${url}`);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
this.messageHandlers.forEach((handler) => handler(url, event));
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error(`WebSocket error on ${url}:`, error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log(`Disconnected from ${url}. Attempting to reconnect...`);
|
||||
setTimeout(connect, 1000); // Reconnect after 1 second
|
||||
};
|
||||
};
|
||||
|
||||
connect();
|
||||
this.webSockets.push(ws);
|
||||
});
|
||||
};
|
||||
|
||||
close = () => {
|
||||
this.webSockets.forEach((ws) => ws.close());
|
||||
};
|
||||
|
||||
sendMessage = (message: string) => {
|
||||
const send = (index: number, message: string) => {
|
||||
const ws = this.webSockets[index];
|
||||
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(message);
|
||||
} else if (ws.readyState === WebSocket.CONNECTING) {
|
||||
setTimeout(send, 500, index, message);
|
||||
}
|
||||
};
|
||||
|
||||
this.webSockets.forEach((_ws, index) => send(index, message));
|
||||
};
|
||||
|
||||
subscribeBook = (events: RoboPoolEvents) => {
|
||||
const authors = Object.values(defaultFederation)
|
||||
.map((f) => f.nostrHexPubkey)
|
||||
.filter((item) => item !== undefined);
|
||||
|
||||
const request = ['REQ', 'subscribeBook', { authors, kinds: [38383], '#n': [this.network] }];
|
||||
|
||||
this.messageHandlers.push((_url: string, messageEvent: MessageEvent) => {
|
||||
const jsonMessage = JSON.parse(messageEvent.data);
|
||||
if (jsonMessage[0] === 'EVENT') {
|
||||
events.onevent(jsonMessage[2]);
|
||||
} else if (jsonMessage[0] === 'EOSE') {
|
||||
events.oneose();
|
||||
}
|
||||
});
|
||||
this.sendMessage(JSON.stringify(request));
|
||||
};
|
||||
}
|
||||
|
||||
export default RoboPool;
|
@ -32,7 +32,7 @@ class RoboGenerator {
|
||||
|
||||
setTimeout(() => {
|
||||
this.waitingForLibrary = false;
|
||||
}, 2500);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
public generate: (hash: string, size: 'small' | 'large') => Promise<string> = async (
|
||||
|
Loading…
Reference in New Issue
Block a user