cc-1.0.x-dev/modules/cc_cex/src/Controller/PrivateApiController.php
modules/cc_cex/src/Controller/PrivateApiController.php
<?php
namespace Drupal\cc_cex\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\cc_cex\Service\CcxtService;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Url;
use Drupal\Core\Cache\Cache;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Controller for private API operations.
*/
class PrivateApiController extends ControllerBase {
/**
* The CCXT service.
*
* @var \Drupal\cc_cex\Service\CcxtService
*/
protected $ccxtService;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Constructs a new PrivateApiController object.
*
* @param \Drupal\cc_cex\Service\CcxtService $ccxt_service
* The CCXT service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
*/
public function __construct(CcxtService $ccxt_service, ConfigFactoryInterface $config_factory) {
$this->ccxtService = $ccxt_service;
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('cc_cex.ccxt_service'),
$container->get('config.factory')
);
}
/**
* Display balances from enabled exchanges.
*/
public function balances() {
$build = [
'#cache' => [
'contexts' => ['user'],
'tags' => ['config:cc.settings', 'cc:balances'],
'max-age' => Cache::PERMANENT,
],
];
$config = $this->configFactory->get('cc.settings');
$enabled_exchanges = $config->get('enabled_exchanges') ?? '';
$enabled_exchanges = !empty($enabled_exchanges) ? array_map('trim', explode(',', $enabled_exchanges)) : [];
if (empty($enabled_exchanges)) {
$build['empty'] = [
'#markup' => '<p>' . $this->t('Please <a href="@settings">configure your exchange settings</a> first.', [
'@settings' => '/admin/config/services/cc_cex-exchange',
]) . '</p>',
];
return $build;
}
$build['actions'] = [
'#type' => 'container',
'#attributes' => ['class' => ['cc-actions']],
'refresh' => [
'#type' => 'link',
'#title' => $this->t('Refresh Balances'),
'#url' => Url::fromRoute('cc_cex.refresh_balances'),
'#attributes' => [
'class' => ['button', 'button--primary'],
],
],
];
$rows = [];
foreach ($enabled_exchanges as $exchange_id) {
try {
$balance = $this->ccxtService->getBalances($exchange_id);
$exchange_balances = $this->filterNonZeroBalances($balance);
foreach ($exchange_balances as $currency => $amounts) {
$rows[] = [
'exchange' => $exchange_id,
'currency' => $currency,
'free' => $amounts['free'],
'used' => $amounts['used'],
'total' => $amounts['total'],
];
}
}
catch (\Exception $e) {
\Drupal::logger('cc')->error('Error fetching balance for @exchange: @error', [
'@exchange' => $exchange_id,
'@error' => $exchange_id . ' ' . $e->getMessage(),
]);
}
}
if (empty($rows)) {
$build['empty'] = [
'#markup' => '<p>' . $this->t('No balances found.') . '</p>',
];
return $build;
}
$header = [
'exchange' => $this->t('Exchange'),
'currency' => $this->t('Currency'),
'free' => $this->t('Available'),
'used' => $this->t('In Orders'),
'total' => $this->t('Total'),
];
$build['table'] = [
'#type' => 'table',
'#header' => $header,
'#attributes' => ['class' => ['cc-balances-table']],
'#rows' => array_map(function($row) {
return [
'exchange' => ['data' => ['#markup' => $row['exchange']]],
'currency' => ['data' => ['#markup' => $row['currency']]],
'free' => ['data' => ['#markup' => number_format($row['free'], 8)]],
'used' => ['data' => ['#markup' => number_format($row['used'], 8)]],
'total' => ['data' => ['#markup' => number_format($row['total'], 8)]],
];
}, $rows),
];
return $build;
}
/**
* Refresh balances and invalidate cache.
*/
public function refreshBalances() {
// Invalidate the balances cache tag
Cache::invalidateTags(['cc:balances', 'config:cc.settings']);
$this->messenger()->addStatus($this->t('Balances refreshed.'));
return new RedirectResponse(Url::fromRoute('cc_cex.balances')->toString());
}
/**
* Filter out zero balances and format the response.
*
* @param array $balance
* The balance.
*
* @return array
* The non-zero balances.
*/
private function filterNonZeroBalances($balance) {
$non_zero_balances = [];
// Return empty array if balance is not valid
if (!is_array($balance) || !isset($balance['total']) || !is_array($balance['total'])) {
return $non_zero_balances;
}
foreach ($balance['total'] as $currency => $amount) {
if ($amount > 0) {
$non_zero_balances[$currency] = [
'free' => $balance['free'][$currency] ?? 0,
'used' => $balance['used'][$currency] ?? 0,
'total' => $amount,
];
}
}
return $non_zero_balances;
}
}
