samoke that connects to the newly created iniversa network

This commit is contained in:
sergeych committed 2026-07-30 18:42:27 +04:00
1 parent 391754bcc4
commit ab2cc9c1bf
8 files changed
+372 -63

No files matched your search

+96 -9
View File
@@ -2,14 +2,17 @@
import { readFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import { createConnection } from 'node:net';
import { basename, dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { Command } from 'commander';
const require = createRequire(import.meta.url);
const scriptDirectory = dirname(fileURLToPath(import.meta.url));
const topologyFile = resolve(scriptDirectory, 'indigo_demo_2025.json');
const topologyFile = resolve(scriptDirectory, 'universa.json');
const universaCoreDist = resolve(scriptDirectory, '../node_modules/universa-core/dist');
const networkTimeoutMs = 20000;
const endpointProbeTimeoutMs = 3000;
function withTimeout(promise, timeoutMs, message) {
let timeoutId;
@@ -50,14 +53,42 @@ async function withUniversaWasmLoader(callback) {
}
function loadUniversaCore() {
const window = globalThis.window;
globalThis.window = globalThis;
const windowDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'window');
const navigatorDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'navigator');
const localStorageDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'localStorage');
Object.defineProperty(globalThis, 'window', {
configurable: true,
value: globalThis
});
Object.defineProperty(globalThis, 'navigator', {
configurable: true,
value: {
hardwareConcurrency: 1,
languages: ['en-US']
}
});
Object.defineProperty(globalThis, 'localStorage', {
configurable: true,
value: {
getItem: () => null,
setItem: () => {},
removeItem: () => {},
clear: () => {}
}
});
try {
return require('universa-core');
} finally {
if (window === undefined) delete globalThis.window;
else globalThis.window = window;
if (windowDescriptor) Object.defineProperty(globalThis, 'window', windowDescriptor);
else delete globalThis.window;
if (navigatorDescriptor) Object.defineProperty(globalThis, 'navigator', navigatorDescriptor);
else delete globalThis.navigator;
if (localStorageDescriptor) Object.defineProperty(globalThis, 'localStorage', localStorageDescriptor);
else delete globalThis.localStorage;
}
}
@@ -70,18 +101,72 @@ function generatePrivateKey() {
async function loadTopology(Topology) {
return withUniversaWasmLoader(async () => {
const packedTopology = JSON.parse(readFileSync(topologyFile, 'utf8'));
const packedTopology = readTopology();
return Topology.load(packedTopology);
});
}
function readTopology() {
const parsedTopology = JSON.parse(readFileSync(topologyFile, 'utf8'));
const packedTopology = Array.isArray(parsedTopology)
? { list: parsedTopology, updated: Math.floor(Date.now() / 1000) }
: parsedTopology;
if (!Array.isArray(packedTopology.list)) {
throw new Error(`Topology file must contain a node array or an object with a list array: ${topologyFile}`);
}
return packedTopology;
}
async function probeEndpoint(url) {
return new Promise((resolveProbe) => {
const endpoint = new URL(url);
const port = endpoint.port || (endpoint.protocol === 'https:' ? 443 : 80);
const socket = createConnection({
host: endpoint.hostname,
port: Number(port),
timeout: endpointProbeTimeoutMs
});
function finish(ok, error = '') {
socket.destroy();
resolveProbe({ url, ok, error });
}
socket.once('connect', () => finish(true));
socket.once('timeout', () => finish(false, 'TCP connection timed out'));
socket.once('error', (error) => finish(false, error.message));
});
}
async function assertReachableTopology(directConnection) {
const topology = readTopology();
const urls = topology.list.flatMap((node) => (
directConnection ? node.direct_urls : node.domain_urls
) || []);
if (urls.length === 0) {
throw new Error(`Topology file does not contain ${directConnection ? 'direct_urls' : 'domain_urls'} entries: ${topologyFile}`);
}
const results = await Promise.all(urls.map(probeEndpoint));
if (results.some((result) => result.ok)) return;
const details = results
.map(({ url, error }) => ` ${url}/topology: ${error}`)
.join('\n');
throw new Error(`No reachable topology endpoints in ${topologyFile}:\n${details}`);
}
const program = new Command();
program
.name('u-js-sample')
.description('Example Node.js console script with universa-core functions.')
.option('--generate-key', 'generate a Universa private key and print its short address')
.option('--test-network', 'generate a key and connect to the Universa network from indigo_demo_2025.json')
.option('--test-network', `generate a key and connect to the Universa network from ${basename(topologyFile)}`)
.action(async (options) => {
if (options.generateKey || options.testNetwork) {
const privateKey = await generatePrivateKey();
@@ -90,10 +175,12 @@ program
if (options.testNetwork) {
const { Network, Topology } = loadUniversaCore();
const topology = await loadTopology(Topology);
const network = new Network(privateKey, { topology, directConnection: true });
const directConnection = true;
const network = new Network(privateKey, { topology, directConnection });
console.log(`Connecting with topology: ${topologyFile}`);
await withTimeout(network.connect(), 20000, 'Network connection timed out');
await assertReachableTopology(directConnection);
await withTimeout(network.connect(), networkTimeoutMs, 'Network connection timed out');
console.log(`Connected to ${network.size()} nodes`);
const response = await withTimeout(network.command('sping'), 10000, 'Network sping command timed out');
-49
View File
@@ -1,49 +0,0 @@
{
"list": [
{
"number": 1,
"domain_urls": [
"https://31.41.155.11"
],
"name": "node-01",
"direct_urls": [
"http://31.41.155.11:8080"
],
"key": "HggcAQABxAAB5IfycVepakIjOt3c5eyLFswYH8dokrmHTyRIgaCSz+EY+mm8hM2Cn1PJjyiJj4K1A8CPN9p9mj6z/yyGSH6pvW3HMGs6Az7KvhGbZJlsFP0tNy6A3YQEWP/XToSqtT3f0Ji/r2nYw2zEgnGvOBkkcyN/EEslnxTj1R3fZlaSHh9Uem6NFk62ZxSBj8hJkvfHbTB/XZ2z8wtpwcAJClylITbbCSg9RdXoD8ZwCJMaCWasxfdo5+sMYTcABYFErbw8ndeQ5aL3N2+XiFM8WO5wQnd3SNTYUQGucBkXO5zqmZjnreVOWIsQtKzjwH4WIi57kz+87V72TbDrX0jYMYsOSw=="
},
{
"number": 2,
"domain_urls": [
"https://37.9.5.102"
],
"name": "node-02",
"direct_urls": [
"http://37.9.5.102:8080"
],
"key": "HggcAQABxAAB3GST2bRm2SrwypfKZRplqDwLUvDF7DoRgVMZfzOHzYodHfIpNrRKZfJdr63UdpK6359G1TAAHm52UaLCaCqBZNuFDqE9s9fEe+2UoSzoMKGG0NtgFD2HdDhuNWw4LnqZiZ5lPlZuUKtxVCzhlI0SNweBKMn0oopjdOYfx7hkPHVB2TyADXPrcnxFHEpc6USjJgP3aHPgum4CxYD09KTF59t5W+B+rDpTd/ro3ENBSFi9xlt4qMrLx5KzIdm8IqcsEm+mTYS5mx0F4e6wlCiXElwGe1NdXNwb/A8S2JBSUKP2CfSKdJtB0D7GHFnMuF3+u29/pykBOvlUoUa4S5QxJQ=="
},
{
"number": 3,
"domain_urls": [
"https://37.9.4.133"
],
"name": "node-03",
"direct_urls": [
"http://37.9.4.133:8080"
],
"key": "HggcAQABxAABtTajk8wkzstB+mmj09fkP/a9IqX4tVuuXnd/fO6a3TAjNbulqtkvVyfhu2DeUdUFiYP9kc+YQmHsIe5T/xZgdecWAbHKT0Ok530nLju8dog+75j6aCqD+winCCb+s7dzAYNIsKS0QgBPPWyBUyDL+di17s2Z5U2mibV+sXQYfWU4Gy02WNuavC8QZ0gA7K3Ah6ohR/Yn37WpiWvS+kQOnZF/q/8LYRQgxdDrztzTgpouggwk/1VJ181fYcXq/54n+L5yV2M0GZy7B942ce07MV6EGmQJu4eoOQi8DN3Ee30WOuIIiEyiQLMJjva0uxvkXmlftsr8rGiLXB+kiMd2fQ=="
},
{
"number": 4,
"domain_urls": [
"https://37.9.4.137"
],
"name": "node-04",
"direct_urls": [
"http://37.9.4.137:8080"
],
"key": "HggcAQABxAABkGzNgQnnNh/aNR3zQujD/6mgcqqfZ3tl14DDLhXLunUhc8hkn3y+ViukIj1qbkPi6Ps5irDZ2TzVfepoVWqX+XkI8wUbXKpDN/zWYx9kW4/soA4C7KS6fS/NFsFflUyzDNQeQXmiQkPTNnn43sdSqYb6Zr3I7Wa6mEwIP7MakKo6SbJQ/gTdXPlKWnU1nGJISMowCfhawYQLZgI5URsgS3VV7Owb3Yo4IZ0YNDTceboY4ljYuc/R2LqJcGjcWfSweaHV2T64RY6yQt1W0h2KweK99cflJdh/QSCqBhRdSYYfgKDlmp2ZTvrrfj0bbz2mPBh5JG5RQe+O9MzT0Is4ew=="
}
],
"updated": 1742911675
}
+46
View File
@@ -0,0 +1,46 @@
[
{
"number": 1,
"domain_urls": [
"https://38.60.255.83"
],
"name": "node-01",
"direct_urls": [
"http://38.60.255.83:8080"
],
"key": "HggcAQABxAAB5IfycVepakIjOt3c5eyLFswYH8dokrmHTyRIgaCSz+EY+mm8hM2Cn1PJjyiJj4K1A8CPN9p9mj6z/yyGSH6pvW3HMGs6Az7KvhGbZJlsFP0tNy6A3YQEWP/XToSqtT3f0Ji/r2nYw2zEgnGvOBkkcyN/EEslnxTj1R3fZlaSHh9Uem6NFk62ZxSBj8hJkvfHbTB/XZ2z8wtpwcAJClylITbbCSg9RdXoD8ZwCJMaCWasxfdo5+sMYTcABYFErbw8ndeQ5aL3N2+XiFM8WO5wQnd3SNTYUQGucBkXO5zqmZjnreVOWIsQtKzjwH4WIi57kz+87V72TbDrX0jYMYsOSw=="
},
{
"number": 2,
"domain_urls": [
"https://38.60.238.117"
],
"name": "node-02",
"direct_urls": [
"http://38.60.238.117:8080"
],
"key": "HggcAQABxAAB3GST2bRm2SrwypfKZRplqDwLUvDF7DoRgVMZfzOHzYodHfIpNrRKZfJdr63UdpK6359G1TAAHm52UaLCaCqBZNuFDqE9s9fEe+2UoSzoMKGG0NtgFD2HdDhuNWw4LnqZiZ5lPlZuUKtxVCzhlI0SNweBKMn0oopjdOYfx7hkPHVB2TyADXPrcnxFHEpc6USjJgP3aHPgum4CxYD09KTF59t5W+B+rDpTd/ro3ENBSFi9xlt4qMrLx5KzIdm8IqcsEm+mTYS5mx0F4e6wlCiXElwGe1NdXNwb/A8S2JBSUKP2CfSKdJtB0D7GHFnMuF3+u29/pykBOvlUoUa4S5QxJQ=="
},
{
"number": 3,
"domain_urls": [
"https://130.94.0.186"
],
"name": "node-03",
"direct_urls": [
"http://130.94.0.186:8080"
],
"key": "HggcAQABxAABtTajk8wkzstB+mmj09fkP/a9IqX4tVuuXnd/fO6a3TAjNbulqtkvVyfhu2DeUdUFiYP9kc+YQmHsIe5T/xZgdecWAbHKT0Ok530nLju8dog+75j6aCqD+winCCb+s7dzAYNIsKS0QgBPPWyBUyDL+di17s2Z5U2mibV+sXQYfWU4Gy02WNuavC8QZ0gA7K3Ah6ohR/Yn37WpiWvS+kQOnZF/q/8LYRQgxdDrztzTgpouggwk/1VJ181fYcXq/54n+L5yV2M0GZy7B942ce07MV6EGmQJu4eoOQi8DN3Ee30WOuIIiEyiQLMJjva0uxvkXmlftsr8rGiLXB+kiMd2fQ=="
},
{
"number": 4,
"domain_urls": [
"https://38.60.208.39"
],
"name": "node-04",
"direct_urls": [
"http://38.60.208.39:8080"
],
"key": "HggcAQABxAABkGzNgQnnNh/aNR3zQujD/6mgcqqfZ3tl14DDLhXLunUhc8hkn3y+ViukIj1qbkPi6Ps5irDZ2TzVfepoVWqX+XkI8wUbXKpDN/zWYx9kW4/soA4C7KS6fS/NFsFflUyzDNQeQXmiQkPTNnn43sdSqYb6Zr3I7Wa6mEwIP7MakKo6SbJQ/gTdXPlKWnU1nGJISMowCfhawYQLZgI5URsgS3VV7Owb3Yo4IZ0YNDTceboY4ljYuc/R2LqJcGjcWfSweaHV2T64RY6yQt1W0h2KweK99cflJdh/QSCqBhRdSYYfgKDlmp2ZTvrrfj0bbz2mPBh5JG5RQe+O9MzT0Is4ew=="
}
]