490 lines
19 KiB
V
490 lines
19 KiB
V
module gridproxy
|
|
|
|
// client library for threefold gridproxy API.
|
|
import json
|
|
import math
|
|
import incubaid.herolib.mycelium.grid3.gridproxy.model { Bill, Contract, ContractFilter, ContractIterator, Farm, FarmFilter, FarmIterator, GridStat, Node, NodeFilter, NodeIterator, NodeStats, Node_, StatFilter, Twin, TwinFilter, TwinIterator }
|
|
import incubaid.herolib.ui.console
|
|
|
|
/*
|
|
all errors returned by the gridproxy API or the client are wrapped in a standard `Error` object with two fields.
|
|
{
|
|
msg string
|
|
code int // could be API call error code or client error code
|
|
}
|
|
|
|
`code` is an error code that can be used to identify the error.
|
|
in API call errors, `code` represents the HTTP status code. (100..599)
|
|
|
|
Client errors codes are represented by numbers in the range of 1..99
|
|
currently, the following client error codes are used:
|
|
id not found error code: 4
|
|
json parsing error code: 10
|
|
http client error code: 11
|
|
invalid response from server (e.g. empty response) error code: 24
|
|
*/
|
|
// clinet error codes
|
|
const err_not_found = 4
|
|
const err_json_parse = 10
|
|
const err_http_client = 11
|
|
const err_invalid_resp = 24
|
|
const err_grid_client = 30
|
|
|
|
// get_node_by_id fetchs specific node information by node id.
|
|
//
|
|
// * `node_id` (u64): node id.
|
|
//
|
|
// returns: `Node` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_node_by_id(node_id u64) !Node {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
|
|
res := http_client.send(prefix: 'nodes/', id: '${node_id}') or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
node := json.decode(Node, res.data) or {
|
|
return error_with_code('error to get jsonstr for node data, json decode: node id: ${node_id}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return node
|
|
}
|
|
|
|
// get_node_stats_by_id fetchs specific node statistics by node id.
|
|
//
|
|
// * `node_id` (u64): node id.
|
|
//
|
|
// returns: `Node_stats` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_node_stats_by_id(node_id u64) !NodeStats {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
|
|
res := http_client.send(prefix: 'nodes/', id: '${node_id}/statistics') or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
node_stats := json.decode(NodeStats, res.data) or {
|
|
return error_with_code('error to get jsonstr for node data, json decode: node id: ${node_id}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return node_stats
|
|
}
|
|
|
|
// get_gateway_by_id fetchs specific gateway information by node id.
|
|
//
|
|
// * `node_id` (u64): node id.
|
|
//
|
|
// returns: `Node` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_gateway_by_id(node_id u64) !Node {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
|
|
res := http_client.send(prefix: 'gateways/', id: '${node_id}') or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
node := json.decode(Node, res.data) or {
|
|
return error_with_code('error to get jsonstr for gateway data, json decode: gateway id: ${node_id}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return node
|
|
}
|
|
|
|
// get_nodes fetchs nodes information and public configurations with pagination.
|
|
//
|
|
// * `available_for` (u64): Available for twin id. [optional].
|
|
// * `certification_type` (string): Certificate type NotCertified, Silver or Gold. [optional].
|
|
// * `city_contains` (string): Node partial city filter. [optional].
|
|
// * `city` (string): Node city filter. [optional].
|
|
// * `country_contains` (string): Node partial country filter. [optional].
|
|
// * `country` (string): Node country filter. [optional].
|
|
// * `dedicated` (bool): Set to true to get the dedicated nodes only. [optional].
|
|
// * `domain` (string): Set to true to filter nodes with domain. [optional].
|
|
// * `farm_ids` ([]u64): List of farm ids. [optional].
|
|
// * `farm_name_contains` (string): Get nodes for specific farm. [optional].
|
|
// * `farm_name` (string): Get nodes for specific farm. [optional].
|
|
// * `free_hru` (u64): Min free reservable hru in bytes. [optional].
|
|
// * `free_ips` (u64): Min number of free ips in the farm of the node. [optional].
|
|
// * `free_mru` (u64): Min free reservable mru in bytes. [optional].
|
|
// * `free_sru` (u64): Min free reservable sru in bytes. [optional].
|
|
// * `gpu_available` (bool): Filter nodes that have available GPU. [optional].
|
|
// * `gpu_device_id` (string): Filter nodes based on GPU device ID. [optional].
|
|
// * `gpu_device_name` (string): Filter nodes based on GPU device partial name. [optional].
|
|
// * `gpu_vendor_id` (string): Filter nodes based on GPU vendor ID. [optional].
|
|
// * `gpu_vendor_name` (string): Filter nodes based on GPU vendor partial name. [optional].
|
|
// * `has_gpu`: Filter nodes on whether they have GPU support or not. [optional].
|
|
// * `ipv4` (string): Set to true to filter nodes with ipv4. [optional].
|
|
// * `ipv6` (string): Set to true to filter nodes with ipv6. [optional].
|
|
// * `node_id` (u64): Node id. [optional].
|
|
// * `page` (u64): Page number. [optional].
|
|
// * `rentable` (bool): Set to true to filter the available nodes for renting. [optional].
|
|
// * `rented_by` (u64): Rented by twin id. [optional].
|
|
// * `ret_count` (bool): Set nodes' count on headers based on filter. [optional].
|
|
// * `size` (u64): Max result per page. [optional].
|
|
// * `status` (string): Node status filter, set to 'up' to get online nodes only. [optional].
|
|
// * `total_cru` (u64): Min total cru in bytes. [optional].
|
|
// * `total_hru` (u64): Min total hru in bytes. [optional].
|
|
// * `total_mru` (u64): Min total mru in bytes. [optional].
|
|
// * `total_sru` (u64): Min total sru in bytes. [optional].
|
|
// * `twin_id` (u64): Twin id. [optional].
|
|
//
|
|
// returns: `[]Node` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_nodes(params NodeFilter) ![]Node {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
params_map := params.to_map()
|
|
res := http_client.send(prefix: 'nodes/', params: params_map) or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
nodes_ := json.decode([]Node_, res.data) or {
|
|
return error_with_code('error to get jsonstr for node list data, json decode: node filter: ${params_map}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
nodes := nodes_.map(it.with_nested_capacity())
|
|
return nodes
|
|
}
|
|
|
|
// get_gateways fetchs gateways information and public configurations and domains with pagination.
|
|
//
|
|
// * `available_for` (u64): Available for twin id. [optional].
|
|
// * `certification_type` (string): Certificate type NotCertified, Silver or Gold. [optional].
|
|
// * `city_contains` (string): Node partial city filter. [optional].
|
|
// * `city` (string): Node city filter. [optional].
|
|
// * `country_contains` (string): Node partial country filter. [optional].
|
|
// * `country` (string): Node country filter. [optional].
|
|
// * `dedicated` (bool): Set to true to get the dedicated nodes only. [optional].
|
|
// * `domain` (bool): Set to true to filter nodes with domain. [optional].
|
|
// * `farm_ids` ([]u64): List of farm ids. [optional].
|
|
// * `farm_name_contains` (string): Get nodes for specific farm. [optional].
|
|
// * `farm_name` (string): Get nodes for specific farm. [optional].
|
|
// * `free_hru` (u64): Min free reservable hru in bytes. [optional].
|
|
// * `free_ips` (u64): Min number of free ips in the farm of the node. [optional].
|
|
// * `free_mru` (u64): Min free reservable mru in bytes. [optional].
|
|
// * `free_sru` (u64): Min free reservable sru in bytes. [optional].
|
|
// * `gpu_available` (bool): Filter nodes that have available GPU. [optional].
|
|
// * `gpu_device_id` (string): Filter nodes based on GPU device ID. [optional].
|
|
// * `gpu_device_name` (string): Filter nodes based on GPU device partial name. [optional].
|
|
// * `gpu_vendor_id` (string): Filter nodes based on GPU vendor ID. [optional].
|
|
// * `gpu_vendor_name` (string): Filter nodes based on GPU vendor partial name. [optional].
|
|
// * `has_gpu`: Filter nodes on whether they have GPU support or not. [optional].
|
|
// * `ipv4` (string): Set to true to filter nodes with ipv4. [optional].
|
|
// * `ipv6` (string): Set to true to filter nodes with ipv6. [optional].
|
|
// * `node_id` (u64): Node id. [optional].
|
|
// * `page` (u64): Page number. [optional].
|
|
// * `rentable` (bool): Set to true to filter the available nodes for renting. [optional].
|
|
// * `rented_by` (u64): Rented by twin id. [optional].
|
|
// * `ret_count` (bool): Set nodes' count on headers based on filter. [optional].
|
|
// * `size` (u64): Max result per page. [optional].
|
|
// * `status` (string): Node status filter, set to 'up' to get online nodes only. [optional].
|
|
// * `total_cru` (u64): Min total cru in bytes. [optional].
|
|
// * `total_hru` (u64): Min total hru in bytes. [optional].
|
|
// * `total_mru` (u64): Min total mru in bytes. [optional].
|
|
// * `total_sru` (u64): Min total sru in bytes. [optional].
|
|
// * `twin_id` (u64): Twin id. [optional].
|
|
//
|
|
// returns: `[]Node` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_gateways(params NodeFilter) ![]Node {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
params_map := params.to_map()
|
|
res := http_client.send(prefix: 'gateways/', params: params_map) or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
nodes_ := json.decode([]Node_, res.data) or {
|
|
return error_with_code('error to get jsonstr for gateways list data, json decode: gateway filter: ${params_map}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
nodes := nodes_.map(it.with_nested_capacity())
|
|
return nodes
|
|
}
|
|
|
|
// get_stats fetchs stats about the grid.
|
|
//
|
|
// * `status` (string): Node status filter, set to 'up' to get online nodes only.. [optional].
|
|
//
|
|
// returns: `GridStat` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_stats(filter StatFilter) !GridStat {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
mut params_map := map[string]string{}
|
|
params_map['status'] = match filter.status {
|
|
.all { '' }
|
|
.online { 'up' }
|
|
}
|
|
|
|
res := http_client.send(prefix: 'stats/', params: params_map) or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
stats := json.decode(GridStat, res.data) or {
|
|
return error_with_code('error to get jsonstr for grid stats data, json decode: stats filter: ${params_map}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return stats
|
|
}
|
|
|
|
// get_twins fetchs twins information with pagaination.
|
|
//
|
|
// * `account_id` (string): Account address. [optional].
|
|
// * `page` (u64): Page number. [optional].
|
|
// * `public_key` (string): twin public key used for e2e encryption. [optional].
|
|
// * `relay` (string): relay domain name. [optional].
|
|
// * `ret_count` (bool): Set farms' count on headers based on filter. [optional].
|
|
// * `size` (u64): Max result per page. [optional].
|
|
// * `twin_id` (u64): Twin id. [optional].
|
|
//
|
|
// returns: `[]Twin` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_twins(params TwinFilter) ![]Twin {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
params_map := params.to_map()
|
|
res := http_client.send(prefix: 'twins/', params: params_map) or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
twins := json.decode([]Twin, res.data) or {
|
|
return error_with_code('error to get jsonstr for twin list data, json decode: twin filter: ${params_map}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return twins
|
|
}
|
|
|
|
// get_contracts fetchs contracts information with pagination.
|
|
//
|
|
// * `contract_id` (u64): Contract id. [optional].
|
|
// * `contract_type` (string): [optional].
|
|
// * `deployment_data` (string): Contract deployment data in case of 'node' contracts. [optional].
|
|
// * `deployment_hash` (string): Contract deployment hash in case of 'node' contracts. [optional].
|
|
// * `name` (string): Contract name in case of 'name' contracts. [optional].
|
|
// * `node_id` (u64): Node id which contract is deployed on in case of ('rent' or 'node' contracts). [optional].
|
|
// * `number_of_public_ips` (u64): Min number of public ips in the 'node' contract. [optional].
|
|
// * `page` (u64): Page number. [optional].
|
|
// * `randomize` (bool): [optional].
|
|
// * `ret_count` (bool): Set farms' count on headers based on filter. [optional].
|
|
// * `size` (u64): Max result per page. [optional].
|
|
// * `state` (string): Contract state 'Created', or 'Deleted'. [optional].
|
|
// * `twin_id` (u64): Twin id. [optional].
|
|
// * `type` (string): Contract type 'node', 'name', or 'rent'. [optional].
|
|
//
|
|
// * returns: `[]Contract` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_contracts(params ContractFilter) ![]Contract {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
params_map := params.to_map()
|
|
res := http_client.send(prefix: 'contracts/', params: params_map) or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
contracts := json.decode([]Contract, res.data) or {
|
|
return error_with_code('error to get jsonstr for contract list data, json decode: contract filter: ${params_map}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return contracts
|
|
}
|
|
|
|
pub fn (mut c GridProxyClient) get_contract_bill(contract_id u64) ![]Bill {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
|
|
res := http_client.send(prefix: 'contracts/', id: '${contract_id}/bills') or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
console.print_debug(res.data)
|
|
bills := json.decode([]Bill, res.data) or {
|
|
return error_with_code('error to get jsonstr for billing data, json decode: contract_id id: ${contract_id}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return bills
|
|
}
|
|
|
|
pub fn (mut c GridProxyClient) get_contract_hourly_bill(contract_id u64) !f64 {
|
|
bills := c.get_contract_bill(contract_id)!
|
|
if bills.len == 0 {
|
|
return f64(0)
|
|
}
|
|
mut duration := u64(0)
|
|
if bills.len >= 2 {
|
|
duration = (bills[0].timestamp - bills[1].timestamp) / 3600 // one hour
|
|
} else if bills.len == 1 {
|
|
contracts := c.get_contracts(contract_id: contract_id)!
|
|
if contracts.len > 0 {
|
|
duration = (bills[0].timestamp - contracts[0].created_at) / 3600
|
|
}
|
|
}
|
|
if duration > 0 {
|
|
return bills[0].amount_billed / duration / math.pow(10, 7)
|
|
}
|
|
return f64(0)
|
|
}
|
|
|
|
// get_farms fetchs farms information and public ips.
|
|
//
|
|
// * `certification_type` (string): Certificate type DIY or Certified. [optional].
|
|
// * `country` (string): Farm country. [optional].
|
|
// * `dedicated` (bool): Farm is dedicated. [optional].
|
|
// * `farm_id` (u64): Farm id. [optional].
|
|
// * `free_ips` (u64): Min number of free ips in the farm. [optional].
|
|
// * `name_contains` (string): Farm name contains. [optional].
|
|
// * `name` (string): Farm name. [optional].
|
|
// * `node_available_for` (u64): Twin ID of user for whom there is at least one node that is available to be deployed to in the farm. [optional].
|
|
// * `node_certified` (bool): True for farms who have at least one certified node. [optional].
|
|
// * `node_free_hru` (u64): Min free reservable hru for at least a single node that belongs to the farm, in bytes. [optional].
|
|
// * `node_free_mru` (u64): Min free reservable mru for at least a single node that belongs to the farm, in bytes. [optional].
|
|
// * `node_free_sru` (u64): Min free reservable sru for at least a single node that belongs to the farm, in bytes. [optional].
|
|
// * `node_has_gpu` (bool): True for farms who have at least one node with a GPU
|
|
// * `node_rented_by` (u64): Twin ID of user who has at least one rented node in the farm
|
|
// * `node_status` (string): Node status for at least a single node that belongs to the farm
|
|
// * `page` (u64): Page number. [optional].
|
|
// * `pricing_policy_id` (u64): Pricing policy id. [optional].
|
|
// * `randomize` (bool): [optional].
|
|
// * `ret_count` (bool): Set farms' count on headers based on filter. [optional].
|
|
// * `size` (u64): Max result per page. [optional].
|
|
// * `stellar_address` (string): Farm stellar_address. [optional].
|
|
// * `total_ips` (u64): Min number of total ips in the farm. [optional].
|
|
// * `twin_id` (u64): Twin id associated with the farm. [optional].
|
|
// * `version` (u64): Farm version. [optional].
|
|
//
|
|
// returns: `[]Farm` or `Error`.
|
|
pub fn (mut c GridProxyClient) get_farms(params FarmFilter) ![]Farm {
|
|
// needed to allow to use threads
|
|
mut http_client := c.http_client
|
|
params_map := params.to_map()
|
|
res := http_client.send(prefix: 'farms/', params: params_map) or {
|
|
return error_with_code('http client error: ${err.msg()}', err_http_client)
|
|
}
|
|
|
|
if !res.is_ok() {
|
|
return error_with_code(res.data, res.code)
|
|
}
|
|
|
|
if res.data == '' {
|
|
return error_with_code('empty response', err_invalid_resp)
|
|
}
|
|
|
|
farms := json.decode([]Farm, res.data) or {
|
|
return error_with_code('error to get jsonstr for farm list data, json decode: farm filter: ${params_map}, data: ${res.data}',
|
|
err_json_parse)
|
|
}
|
|
return farms
|
|
}
|
|
|
|
// is_pingable checks if API server is reachable and responding.
|
|
//
|
|
// returns: bool, `true` if API server is reachable and responding, `false` otherwise
|
|
pub fn (mut c GridProxyClient) is_pingable() !bool {
|
|
mut http_client := c.http_client
|
|
res := http_client.send(prefix: 'ping/') or { return false }
|
|
if !res.is_ok() {
|
|
return false
|
|
}
|
|
health_map := json.decode(map[string]string, res.data) or { return false }
|
|
|
|
if health_map['ping'] != 'pong' {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Iterators have the next() method, which returns the next page of the objects.
|
|
// to be used in a loop to get all available results, or to lazely traverse pages till a specific condition is met.
|
|
|
|
// get_nodes_iterator creates an iterator through node pages with custom filter
|
|
fn (mut c GridProxyClient) get_nodes_iterator(filter NodeFilter) NodeIterator {
|
|
return NodeIterator{filter, c.get_nodes}
|
|
}
|
|
|
|
// get_gateways_iterator creates an iterator through gateway pages with custom filter
|
|
fn (mut c GridProxyClient) get_gateways_iterator(filter NodeFilter) NodeIterator {
|
|
return NodeIterator{filter, c.get_gateways}
|
|
}
|
|
|
|
// get_farms_iterator creates an iterator through farms pages with custom filter
|
|
fn (mut c GridProxyClient) get_farms_iterator(filter FarmFilter) FarmIterator {
|
|
return FarmIterator{filter, c.get_farms}
|
|
}
|
|
|
|
// get_twins_iterator creates an iterator through twin pages with custom filter
|
|
fn (mut c GridProxyClient) get_twins_iterator(filter TwinFilter) TwinIterator {
|
|
return TwinIterator{filter, c.get_twins}
|
|
}
|
|
|
|
// get_contracts_iterator creates an iterator through contracts pages with custom filter
|
|
fn (mut c GridProxyClient) get_contracts_iterator(filter ContractFilter) ContractIterator {
|
|
return ContractIterator{filter, c.get_contracts}
|
|
}
|