feat(cmds): listing availabilities

This commit is contained in:
Adam Uhlíř 2025-06-11 09:23:20 +02:00
parent 6fde43fc06
commit 35b0247a0f
No known key found for this signature in database
GPG Key ID: 1D17A9E81F76155B
5 changed files with 528 additions and 98 deletions

444
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,8 @@
"dockerode": "^4", "dockerode": "^4",
"node-fetch": "^3", "node-fetch": "^3",
"ora": "^8", "ora": "^8",
"semver": "^7" "semver": "^7",
"tty-table": "^4.2.3"
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1", "@eslint/compat": "^1",
@ -42,7 +43,7 @@
"engines": { "engines": {
"node": ">=20.0.0", "node": ">=20.0.0",
"npm": ">=6.0.0", "npm": ">=6.0.0",
"codex": "0.2.1", "codex": "0.2.3",
"supportedCodex": ">0.2.0" "supportedCodex": ">0.2.0"
}, },
"files": [ "files": [

View File

@ -0,0 +1,62 @@
import { Flags } from '@oclif/core'
import { Header } from 'tty-table'
import Table from 'tty-table'
import { BaseCommand } from '../../../base.js'
import { ContainerType } from '../../../utils/docker.js'
import { getClientForContainer } from '../../../utils/api.js'
import { formatBytes, formatId, formatTokenAmount } from '../../../utils/format.js'
export default class LsAvailability extends BaseCommand<typeof LsAvailability> {
static override description = 'Lists all availabilities'
static override examples = [
'<%= config.bin %> <%= command.id %>',
'<%= config.bin %> <%= command.id %> -n client',
'<%= config.bin %> <%= command.id %> --node host1'
]
static override flags = {
node: Flags.string({
char: 'n',
default: ContainerType.HOST,
description: 'Node to run the command on',
options: Object.values(ContainerType).filter((value) => value !== ContainerType.BLOCKCHAIN),
})
}
public async run (): Promise<void> {
const { flags } = await this.parse(LsAvailability)
const header: Header[] = [
{value: 'Availability ID'},
{value: 'Total Size'},
{value: 'Free Size'},
{value: 'Total Collateral'},
{value: 'Total Remaining Collateral'},
{value: 'Min Price Per Byte Per Second'},
]
const apiClient = getClientForContainer((flags.node as ContainerType))
const availabilitiesResult = await apiClient.marketplace.availabilities()
if (availabilitiesResult.error) {
throw availabilitiesResult.data
}
const rows = availabilitiesResult.data.map((availability) => {
return [
formatId(availability.id),
formatBytes(availability.totalSize),
formatBytes(availability.freeSize || 0),
formatTokenAmount(availability.totalCollateral),
formatTokenAmount(availability.totalRemainingCollateral),
formatTokenAmount(availability.minPricePerBytePerSecond),
]
})
// eslint-disable-next-line new-cap
console.log(Table(header, rows).render())
}
}

33
src/utils/api.ts Normal file
View File

@ -0,0 +1,33 @@
import { Codex } from '@codex-storage/sdk-js'
import { ContainerType } from './docker.js'
export function getClientForContainer (node: ContainerType): Codex {
switch (node) {
case ContainerType.CLIENT: {
return new Codex('http://localhost:8080')
}
case ContainerType.HOST: {
return new Codex('http://localhost:8081')
}
case ContainerType.HOST_2: {
return new Codex('http://localhost:8082')
}
case ContainerType.HOST_3: {
return new Codex('http://localhost:8083')
}
case ContainerType.HOST_4: {
return new Codex('http://localhost:8084')
}
default: {
throw new Error('Unsupported node type!')
}
}
}

82
src/utils/format.ts Normal file
View File

@ -0,0 +1,82 @@
/**
* Converts a number of bytes into a human-readable string with units.
* @param bytes - The number of bytes to convert.
* @param decimals - Number of decimal places to include (default is 2).
* @returns The formatted string in a human-readable format.
*/
export function formatBytes (bytes: number, decimals = 2): string {
if (bytes === 0) return '0 Bytes'
const k = 1024 // Bytes in a Kilobyte
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
const formattedValue = Number.parseFloat((bytes / k**i).toFixed(decimals))
return `${formattedValue} ${sizes[i]}`
}
/**
* Formats a long hash by taking a specified number of characters
* from the start and end of the hash.
* @param hash - The long hash to format.
* @param chars - The number of characters to take from both the start and end (default: 1).
* @param separator - The string to place between the start and end characters (default: "...").
* @returns The formatted hash string.
*/
export function formatId (
hash: string,
chars = 3,
separator = '...'
): string {
if (!hash || hash.length <= chars * 2) {
return hash // Return the hash as is if it's too short to format
}
const start = hash.slice(0, chars) // Extract the starting characters
const end = hash.slice(-chars) // Extract the ending characters
return `${start}${separator}${end}`
}
/**
* Formats token amounts by automatically determining the most appropriate unit
* (`TST`, `gTSTWei`, or `TSTWei`) for human readability, using `bigint` for precision.
* @param amount - The token amount in `wei` (as a string, number, or bigint).
* @returns The formatted token amount string.
*/
export function formatTokenAmount(amount: bigint | number | string): string {
const decimals = 10n ** 18n; // 10^18 for TST
const gWeiFactor = 10n ** 9n; // 10^9 for gTSTWei
let numericAmount: bigint;
// Convert input to bigint
if (typeof amount === "string") {
numericAmount = BigInt(amount);
} else if (typeof amount === "number") {
numericAmount = BigInt(Math.floor(amount)); // Convert to an integer first
} else {
numericAmount = amount;
}
// If the amount is greater than or equal to 1 TST (10^18 wei), format in TST
if (numericAmount >= decimals) {
const wholeUnits = (numericAmount * 100n) / decimals; // Multiply by 100 to handle decimals
return (
`${Number(wholeUnits / 100n).toLocaleString()}` +
`.${String(wholeUnits % 100n).padStart(2, "0")} TST`
);
}
// If the amount is greater than or equal to 1 gTSTWei (10^9 wei), format in gTSTWei
if (numericAmount >= gWeiFactor) {
const wholeUnits = (numericAmount * 100n) / gWeiFactor; // Multiply by 100 to handle decimals
return (
`${Number(wholeUnits / 100n).toLocaleString()}` +
`.${String(wholeUnits % 100n).padStart(2, "0")} gTSTWei`
);
}
// Otherwise, format as TSTWei (smallest unit)
return `${numericAmount.toLocaleString()} TSTWei`;
}