diff --git a/packages/gridproxy_client/src/modules/client.ts b/packages/gridproxy_client/src/modules/client.ts index 3a5324fa53..d6649e5b8f 100644 --- a/packages/gridproxy_client/src/modules/client.ts +++ b/packages/gridproxy_client/src/modules/client.ts @@ -28,9 +28,9 @@ export default class GridProxyClient { this.contracts = new ContractsClient(this.__uri); this.farms = new FarmsClient(this.__uri); this.gateways = new GatewaysClient(this.__uri); - this.nodes = new NodesClient(this.__uri, this.farms); - this.stats = new StatsClient(this.__uri); this.twins = new TwinsClient(this.__uri); + this.nodes = new NodesClient(this.__uri, this.farms, this.twins); + this.stats = new StatsClient(this.__uri); } public contracts: ContractsClient; diff --git a/packages/gridproxy_client/src/modules/gateways.ts b/packages/gridproxy_client/src/modules/gateways.ts index 3e940d06fa..dcd8356768 100644 --- a/packages/gridproxy_client/src/modules/gateways.ts +++ b/packages/gridproxy_client/src/modules/gateways.ts @@ -1,7 +1,8 @@ import { CertificationType, GatewayBuilder, GatewaysQuery, NodeStatus } from "../builders/public_api"; import { assertId, resolvePaginator } from "../utils"; import { AbstractClient } from "./abstract_client"; -import { Farm } from "./farms"; +import type { Farm } from "./farms"; +import type { Twin } from "./twins"; export interface Resources { cru: number; @@ -27,6 +28,16 @@ export interface PublicIps { free: number; } +export interface NodeStats { + system: Resources & { ipv4u: number }; + total: Resources & { ipv4u: number }; + used: Resources & { ipv4u: number }; + users: { + deployments: number; + workloads: number; + }; +} + export interface GridNode { id: string; nodeId: number; @@ -50,6 +61,8 @@ export interface GridNode { rentedByTwinId: number; farm: Farm; publicIps: PublicIps; + twin: Twin; + stats: NodeStats; } export class GatewaysClient extends AbstractClient { diff --git a/packages/gridproxy_client/src/modules/nodes.ts b/packages/gridproxy_client/src/modules/nodes.ts index e8d3124055..f273fecd35 100644 --- a/packages/gridproxy_client/src/modules/nodes.ts +++ b/packages/gridproxy_client/src/modules/nodes.ts @@ -1,18 +1,21 @@ -import type { Pagination } from "../builders/abstract_builder"; import { NodesBuilder, type NodesQuery } from "../builders/nodes"; import { resolvePaginator } from "../utils"; import { AbstractClient } from "./abstract_client"; import type { Farm, FarmsClient } from "./farms"; -import type { GridNode, PublicIps } from "./gateways"; +import type { GridNode, NodeStats, PublicIps } from "./gateways"; +import type { Twin, TwinsClient } from "./twins"; export interface NodesExtractOptions { loadFarm?: boolean; + loadTwin?: boolean; + loadStats?: boolean; } export class NodesClient extends AbstractClient { public farms: Map; + public twins: Map; - constructor(uri: string, private readonly __farmsClient: FarmsClient) { + constructor(uri: string, private readonly __farmsClient: FarmsClient, private readonly __twinsClient: TwinsClient) { super({ uri, Builder: NodesBuilder, @@ -20,49 +23,73 @@ export class NodesClient extends AbstractClient { this.farms = new Map(); this.setFarm = this.setFarm.bind(this); + + this.twins = new Map(); + this.setTwin = this.setTwin.bind(this); } public async list(queries: Partial = {}, extraOptions: NodesExtractOptions = {}) { const res = await this.builder(queries).build("/nodes"); const nodes = await resolvePaginator(res); + if (extraOptions.loadFarm) { await this.loadFarms(nodes.data.map(n => n.farmId)); nodes.data = nodes.data.map(this.setFarm); } + + if (extraOptions.loadTwin) { + await this.loadTwins(nodes.data.map(n => n.twinId)); + nodes.data = nodes.data.map(this.setTwin); + } + + if (extraOptions.loadStats) { + const nodesStats = await Promise.all(nodes.data.map(n => this.statsById(n.nodeId))); + nodes.data = nodes.data.map((n, index) => { + n.stats = nodesStats[index]; + return n; + }); + } + return nodes; } public async byId(nodeId: number, extraOptions: NodesExtractOptions = {}): Promise { const res = await this.builder({}).build(`/nodes/${nodeId}`); - const node = await res.json(); + let node: GridNode = await res.json(); + + const capacity = Reflect.get(node, "capacity"); + if (capacity) { + node.total_resources = Reflect.get(capacity, "total_resources"); + node.used_resources = Reflect.get(capacity, "used_resources"); + } + if (extraOptions.loadFarm && node) { await this.loadFarms([node.farmId]); - return this.setFarm(node); + node = this.setFarm(node); } + + if (extraOptions.loadTwin) { + await this.loadTwins([node.twinId]); + node = this.setTwin(node); + } + + if (extraOptions.loadStats) { + node.stats = await this.statsById(node.nodeId); + } + return node; } - public async listAll(queries: Partial = {}) { - const { count } = await this.list({ - ...queries, - size: 50, - page: 1, - retCount: true, - }); - const promises: Promise>[] = []; - const pages = Math.ceil(count! / 50); - for (let i = 0; i < pages; i++) { - promises.push(this.list({ ...queries, size: 50, page: i + 1 })); - } - const nodes = await Promise.all(promises); - return nodes.map(node => node.data).flat(1); + public async statsById(nodeId: number): Promise { + const res = await this.builder({}).build(`/nodes/${nodeId}/statistics`); + return res.json(); } private async loadFarms(farmIds: number[]): Promise { farmIds = farmIds.filter(id => !this.farms.has(id)); const ids = Array.from(new Set(farmIds)); if (!ids.length) return; - const farms = await Promise.all(ids.map(id => this.__farmsClient.list({ farmId: id }))); + const farms = await Promise.all(ids.map(farmId => this.__farmsClient.list({ farmId }))); for (const { data } of farms) { const [farm] = data; this.farms = this.farms.set(farm.farmId, farm); @@ -87,4 +114,23 @@ export class NodesClient extends AbstractClient { free, }; } + + private async loadTwins(twinIds: number[]): Promise { + twinIds = twinIds.filter(id => !this.twins.has(id)); + const ids = Array.from(new Set(twinIds)); + if (!ids.length) return; + const twins = await Promise.all(ids.map(twinId => this.__twinsClient.list({ twinId }))); + for (const { data } of twins) { + const [twin] = data; + this.twins = this.twins.set(twin.twinId, twin); + } + } + + private setTwin(node: GridNode): GridNode { + const twin = this.twins.get(node.twinId); + if (twin) { + node.twin = twin; + } + return node; + } } diff --git a/packages/gridproxy_client/src/modules/twins.ts b/packages/gridproxy_client/src/modules/twins.ts index 0799c3ed99..0d61c8466d 100644 --- a/packages/gridproxy_client/src/modules/twins.ts +++ b/packages/gridproxy_client/src/modules/twins.ts @@ -5,7 +5,8 @@ import { AbstractClient } from "./abstract_client"; export interface Twin { twinId: number; accountId: string; - ip: string; + relay: string; + publicKey: string; } export class TwinsClient extends AbstractClient {