synor/sdk/c/src/economics/economics.c
Gulshan Yadav 6607223c9e feat(sdk): complete Phase 4 SDKs for all remaining languages
Add Economics, Governance, and Mining SDKs for:
- Java: Full SDK with CompletableFuture async operations
- Kotlin: Coroutine-based SDK with suspend functions
- Swift: Modern Swift SDK with async/await
- Flutter/Dart: Complete Dart SDK with Future-based API
- C: Header files and implementations with opaque handles
- C++: Modern C++17 with std::future and PIMPL pattern
- C#: Records, async/await Tasks, and IDisposable
- Ruby: Struct-based types with Faraday HTTP client

Also includes minor Dart lint fixes (const exceptions).
2026-01-28 08:33:20 +05:30

424 lines
13 KiB
C

/**
* @file economics.c
* @brief Synor Economics SDK implementation
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "synor/economics.h"
/* Forward declarations from common.c */
typedef struct synor_http_client synor_http_client_t;
synor_http_client_t* synor_http_client_create(
const char* api_key, const char* endpoint,
uint32_t timeout_ms, uint32_t retries, bool debug);
void synor_http_client_destroy(synor_http_client_t* client);
int synor_http_get(synor_http_client_t* client, const char* path,
char** response, size_t* response_size);
int synor_http_post(synor_http_client_t* client, const char* path,
const char* body, char** response, size_t* response_size);
char* synor_strdup(const char* s);
char* synor_url_encode(const char* s);
/* Internal economics structure */
struct synor_economics {
synor_http_client_t* http;
bool closed;
bool debug;
};
static const char* service_type_to_string(synor_service_type_t type) {
switch (type) {
case SYNOR_SERVICE_COMPUTE: return "compute";
case SYNOR_SERVICE_STORAGE: return "storage";
case SYNOR_SERVICE_DATABASE: return "database";
case SYNOR_SERVICE_HOSTING: return "hosting";
case SYNOR_SERVICE_RPC: return "rpc";
case SYNOR_SERVICE_BRIDGE: return "bridge";
default: return "unknown";
}
}
static const char* billing_period_to_string(synor_billing_period_t period) {
switch (period) {
case SYNOR_BILLING_HOURLY: return "hourly";
case SYNOR_BILLING_DAILY: return "daily";
case SYNOR_BILLING_WEEKLY: return "weekly";
case SYNOR_BILLING_MONTHLY: return "monthly";
default: return "monthly";
}
}
synor_economics_t* synor_economics_create(const synor_economics_config_t* config) {
if (!config || !config->api_key) {
return NULL;
}
synor_economics_t* economics = calloc(1, sizeof(synor_economics_t));
if (!economics) return NULL;
const char* endpoint = config->endpoint ?
config->endpoint : "https://economics.synor.io/v1";
uint32_t timeout = config->timeout_ms > 0 ? config->timeout_ms : 30000;
uint32_t retries = config->retries > 0 ? config->retries : 3;
economics->http = synor_http_client_create(
config->api_key, endpoint, timeout, retries, config->debug);
if (!economics->http) {
free(economics);
return NULL;
}
economics->closed = false;
economics->debug = config->debug;
return economics;
}
void synor_economics_destroy(synor_economics_t* economics) {
if (!economics) return;
economics->closed = true;
synor_http_client_destroy(economics->http);
free(economics);
}
bool synor_economics_is_closed(synor_economics_t* economics) {
return economics ? economics->closed : true;
}
bool synor_economics_health_check(synor_economics_t* economics) {
if (!economics || economics->closed) return false;
char* response = NULL;
size_t response_size = 0;
if (synor_http_get(economics->http, "/health", &response, &response_size) != 0) {
return false;
}
bool healthy = response && strstr(response, "\"healthy\"") != NULL;
free(response);
return healthy;
}
/* ==================== Pricing Operations ==================== */
synor_economics_error_t synor_economics_get_pricing(synor_economics_t* economics,
synor_service_type_t* service, synor_service_pricing_list_t* result) {
if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
(void)service; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_price(synor_economics_t* economics,
synor_service_type_t service, const synor_usage_metrics_t* usage,
synor_price_result_t* result) {
if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
if (!usage || !result) return SYNOR_ECONOMICS_ERROR_UNKNOWN;
char body[1024];
snprintf(body, sizeof(body),
"{\"service\":\"%s\",\"computeUnits\":%.2f,\"storageBytes\":%.2f,\"bandwidthBytes\":%.2f,\"durationSeconds\":%lld,\"requests\":%d}",
service_type_to_string(service),
usage->compute_units, usage->storage_bytes, usage->bandwidth_bytes,
(long long)usage->duration_seconds, usage->requests);
char* response = NULL;
size_t response_size = 0;
int err = synor_http_post(economics->http, "/pricing/calculate", body, &response, &response_size);
if (err != 0) {
free(response);
return SYNOR_ECONOMICS_ERROR_HTTP;
}
/* TODO: Parse JSON response */
free(response);
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_estimate_cost(synor_economics_t* economics,
const synor_usage_plan_t* plan, synor_cost_estimate_t* result) {
(void)economics; (void)plan; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
void synor_service_pricing_free(synor_service_pricing_t* pricing) {
if (!pricing) return;
free(pricing->unit);
free(pricing->price_per_unit);
free(pricing->currency);
}
void synor_service_pricing_list_free(synor_service_pricing_list_t* list) {
if (!list) return;
for (size_t i = 0; i < list->count; i++) {
synor_service_pricing_free(&list->prices[i]);
}
free(list->prices);
list->prices = NULL;
list->count = 0;
}
void synor_price_result_free(synor_price_result_t* result) {
if (!result) return;
free(result->amount);
free(result->currency);
}
void synor_cost_estimate_free(synor_cost_estimate_t* estimate) {
if (!estimate) return;
free(estimate->total);
free(estimate->currency);
for (size_t i = 0; i < estimate->breakdown_count; i++) {
free(estimate->breakdown[i].amount);
}
free(estimate->breakdown);
free(estimate->discount_applied);
}
/* ==================== Billing Operations ==================== */
synor_economics_error_t synor_economics_get_usage(synor_economics_t* economics,
synor_billing_period_t* period, synor_usage_t* result) {
if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
char path[256];
if (period) {
snprintf(path, sizeof(path), "/billing/usage?period=%s", billing_period_to_string(*period));
} else {
snprintf(path, sizeof(path), "/billing/usage");
}
char* response = NULL;
size_t response_size = 0;
int err = synor_http_get(economics->http, path, &response, &response_size);
if (err != 0) {
free(response);
return SYNOR_ECONOMICS_ERROR_HTTP;
}
/* TODO: Parse JSON response */
(void)result;
free(response);
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_invoices(synor_economics_t* economics,
synor_invoice_list_t* result) {
(void)economics; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_invoice(synor_economics_t* economics,
const char* invoice_id, synor_invoice_t* result) {
(void)economics; (void)invoice_id; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_balance(synor_economics_t* economics,
synor_account_balance_t* result) {
(void)economics; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
void synor_usage_free(synor_usage_t* usage) {
if (!usage) return;
for (size_t i = 0; i < usage->items_count; i++) {
free(usage->items[i].cost);
}
free(usage->items);
free(usage->total_cost);
free(usage->currency);
}
void synor_invoice_free(synor_invoice_t* invoice) {
if (!invoice) return;
free(invoice->id);
for (size_t i = 0; i < invoice->lines_count; i++) {
free(invoice->lines[i].service);
free(invoice->lines[i].description);
free(invoice->lines[i].unit_price);
free(invoice->lines[i].amount);
}
free(invoice->lines);
free(invoice->subtotal);
free(invoice->discount);
free(invoice->tax);
free(invoice->total);
free(invoice->currency);
free(invoice->pdf_url);
}
void synor_invoice_list_free(synor_invoice_list_t* list) {
if (!list) return;
for (size_t i = 0; i < list->count; i++) {
synor_invoice_free(&list->invoices[i]);
}
free(list->invoices);
list->invoices = NULL;
list->count = 0;
}
void synor_account_balance_free(synor_account_balance_t* balance) {
if (!balance) return;
free(balance->available);
free(balance->pending);
free(balance->staked);
free(balance->total);
free(balance->currency);
}
/* ==================== Staking Operations ==================== */
synor_economics_error_t synor_economics_stake(synor_economics_t* economics,
const char* amount, int32_t duration_days, synor_stake_receipt_t* result) {
if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
if (!amount || !result) return SYNOR_ECONOMICS_ERROR_UNKNOWN;
char body[256];
snprintf(body, sizeof(body), "{\"amount\":\"%s\",\"durationDays\":%d}", amount, duration_days);
char* response = NULL;
size_t response_size = 0;
int err = synor_http_post(economics->http, "/staking/stake", body, &response, &response_size);
if (err != 0) {
free(response);
return SYNOR_ECONOMICS_ERROR_HTTP;
}
/* TODO: Parse JSON response */
free(response);
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_unstake(synor_economics_t* economics,
const char* stake_id, synor_unstake_receipt_t* result) {
(void)economics; (void)stake_id; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_stakes(synor_economics_t* economics,
synor_stake_list_t* result) {
(void)economics; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_stake(synor_economics_t* economics,
const char* stake_id, synor_stake_t* result) {
(void)economics; (void)stake_id; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_staking_rewards(synor_economics_t* economics,
synor_staking_rewards_t* result) {
(void)economics; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_claim_rewards(synor_economics_t* economics,
synor_stake_receipt_t* result) {
(void)economics; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
void synor_stake_free(synor_stake_t* stake) {
if (!stake) return;
free(stake->id);
free(stake->amount);
free(stake->rewards_earned);
}
void synor_stake_list_free(synor_stake_list_t* list) {
if (!list) return;
for (size_t i = 0; i < list->count; i++) {
synor_stake_free(&list->stakes[i]);
}
free(list->stakes);
list->stakes = NULL;
list->count = 0;
}
void synor_stake_receipt_free(synor_stake_receipt_t* receipt) {
if (!receipt) return;
free(receipt->id);
free(receipt->amount);
free(receipt->tx_hash);
}
void synor_unstake_receipt_free(synor_unstake_receipt_t* receipt) {
if (!receipt) return;
free(receipt->id);
free(receipt->amount);
free(receipt->tx_hash);
}
void synor_staking_rewards_free(synor_staking_rewards_t* rewards) {
if (!rewards) return;
free(rewards->pending);
free(rewards->claimed);
free(rewards->total);
}
/* ==================== Discount Operations ==================== */
synor_economics_error_t synor_economics_apply_discount(synor_economics_t* economics,
const char* code, synor_discount_result_t* result) {
if (!economics || economics->closed) return SYNOR_ECONOMICS_ERROR_CLIENT_CLOSED;
if (!code || !result) return SYNOR_ECONOMICS_ERROR_UNKNOWN;
char body[256];
snprintf(body, sizeof(body), "{\"code\":\"%s\"}", code);
char* response = NULL;
size_t response_size = 0;
int err = synor_http_post(economics->http, "/discounts/apply", body, &response, &response_size);
if (err != 0) {
free(response);
return SYNOR_ECONOMICS_ERROR_HTTP;
}
/* TODO: Parse JSON response */
free(response);
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_remove_discount(synor_economics_t* economics,
const char* code) {
(void)economics; (void)code;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
synor_economics_error_t synor_economics_get_discounts(synor_economics_t* economics,
synor_discount_list_t* result) {
(void)economics; (void)result;
return SYNOR_ECONOMICS_ERROR_UNKNOWN;
}
void synor_discount_free(synor_discount_t* discount) {
if (!discount) return;
free(discount->code);
free(discount->value);
free(discount->description);
free(discount->applicable_services);
}
void synor_discount_list_free(synor_discount_list_t* list) {
if (!list) return;
for (size_t i = 0; i < list->count; i++) {
synor_discount_free(&list->discounts[i]);
}
free(list->discounts);
list->discounts = NULL;
list->count = 0;
}
void synor_discount_result_free(synor_discount_result_t* result) {
if (!result) return;
synor_discount_free(&result->discount);
free(result->savings_estimate);
}