From aa30feba85166158aa10580a6ccd24aad70882aa Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Sat, 2 May 2026 02:15:46 +0200 Subject: [PATCH] asdasd --- modules/mining-checker/src/Api/Router.php | 159 ++++++++++++++++++++-- 1 file changed, 151 insertions(+), 8 deletions(-) diff --git a/modules/mining-checker/src/Api/Router.php b/modules/mining-checker/src/Api/Router.php index 8a9c69b..be71016 100644 --- a/modules/mining-checker/src/Api/Router.php +++ b/modules/mining-checker/src/Api/Router.php @@ -33,6 +33,8 @@ final class Router private ?SeedImporter $seedImporter = null; private ?SchemaManager $schemaManager = null; private ?FxService $fx = null; + private ?array $fxRatesSettingsCache = null; + private ?array $currencyCatalogCache = null; private DebugTrace $debug; public function __construct(string $moduleBasePath) @@ -790,7 +792,11 @@ final class Router private function refreshCurrencies(): array { - return $this->fx()->refreshCurrencyCatalog(); + $result = $this->fx()->refreshCurrencyCatalog(); + $synced = $this->syncLocalCurrencyCatalogFromFxRates(true); + return $result + [ + 'local_catalog_synced' => count($synced), + ]; } private function probeCurrencies(): array @@ -1216,7 +1222,7 @@ final class Router 'fx_max_age_hours' => 3, 'module_theme_mode' => 'inherit', 'module_theme_accent' => 'teal', - 'preferred_currencies' => ['DOGE', 'USD', 'EUR'], + 'preferred_currencies' => $this->preferredCurrencies(), ]; if (!$this->isValidTimezone((string) ($base['display_timezone'] ?? ''))) { $base['display_timezone'] = 'Europe/Berlin'; @@ -1233,6 +1239,7 @@ final class Router $base['cost_plans'] = $this->costPlans($projectKey); $base['currencies'] = $this->currencies(); + $base['preferred_currencies'] = $this->preferredCurrencies($base['preferred_currencies'] ?? null); $base['payouts'] = $this->payouts($projectKey); $base['miner_offers'] = $this->minerOffers($projectKey); $base['purchased_miners'] = $this->purchasedMiners($projectKey); @@ -1265,6 +1272,7 @@ final class Router $this->assertCurrencyType($settings['crypto_currency'], true, 'crypto_currency'); $this->repository()->saveSettings($projectKey, $settings); + $this->syncFxRatesPreferredCurrencies($settings['preferred_currencies']); return $this->settings($projectKey); } @@ -1455,17 +1463,18 @@ final class Router $knownCodes = array_map( static fn (array $currency): string => strtoupper((string) ($currency['code'] ?? '')), - $this->repository()->listCurrencies() + $this->currencies() ); if (in_array($priceCurrency, $knownCodes, true)) { return; } - $this->repository()->ensureCurrencyCode($priceCurrency, $priceCurrency); + $matched = $this->currencyCatalogEntry($priceCurrency); + $this->repository()->ensureCurrencyCode($priceCurrency, $matched['name'] ?? $priceCurrency); try { - $this->fx()->refreshCurrencyCatalog(); + $this->refreshCurrencies(); } catch (\Throwable) { // Measurement save must not fail because the external currency sync is unavailable. } @@ -1557,7 +1566,8 @@ final class Router private function currencies(): array { - return $this->repository()->listCurrencies(); + $catalog = $this->syncLocalCurrencyCatalogFromFxRates(); + return $catalog !== [] ? $catalog : $this->repository()->listCurrencies(); } private function currencyAliases(): array @@ -1926,16 +1936,22 @@ final class Router return (string) $resolved['code']; } + $catalogEntry = $this->currencyCatalogEntry($currency); + if (is_array($catalogEntry)) { + $this->repository()->ensureCurrencyCode($currency, (string) ($catalogEntry['name'] ?? $currency)); + return $currency; + } + throw new ApiException( "Feld {$field} verweist auf keinen vorhandenen Waehrungsrecord.", 422, [ 'field' => $field, 'missing_currency' => $currency, - 'hint' => 'Lege zuerst die Waehrung an oder hinterlege einen Alias auf einen bestehenden Waehrungsrecord.', + 'hint' => 'Synchronisiere zuerst den Waehrungskatalog aus fx-rates oder hinterlege einen Alias auf einen bestehenden Waehrungsrecord.', 'available_currencies' => array_slice(array_map( static fn (array $item): string => (string) ($item['code'] ?? ''), - $this->repository()->listCurrencies() + $this->currencies() ), 0, 50), ] ); @@ -1951,6 +1967,7 @@ final class Router private function assertCurrencyType(string $code, bool $expectedCrypto, string $field): void { + $this->ensureLocalCurrencyRecord($code); $resolved = $this->repository()->resolveCurrencyCode($code); $currency = is_array($resolved) ? ($resolved['currency'] ?? null) : null; $isCrypto = !empty($currency['is_crypto']); @@ -2142,6 +2159,132 @@ final class Router return $result; } + private function fxRatesSettings(): array + { + if ($this->fxRatesSettingsCache !== null) { + return $this->fxRatesSettingsCache; + } + + if (!modules()->isEnabled('fx-rates') || !modules()->hasFunction('fx-rates', 'settings')) { + return $this->fxRatesSettingsCache = []; + } + + $settings = module_fn('fx-rates', 'settings'); + return $this->fxRatesSettingsCache = is_array($settings) ? $settings : []; + } + + private function preferredCurrencies(?array $fallback = null): array + { + $settings = $this->fxRatesSettings(); + $preferred = $settings['preferred_currencies'] ?? $fallback ?? ['DOGE', 'USD', 'EUR']; + $normalized = []; + foreach (is_array($preferred) ? $preferred : [] as $code) { + $normalizedCode = strtoupper(trim((string) $code)); + if ($normalizedCode !== '' && !in_array($normalizedCode, $normalized, true)) { + $normalized[] = $normalizedCode; + } + } + + return $normalized !== [] ? $normalized : ['DOGE', 'USD', 'EUR']; + } + + private function currencyCatalog(): array + { + if ($this->currencyCatalogCache !== null) { + return $this->currencyCatalogCache; + } + + $settings = $this->fxRatesSettings(); + $catalog = []; + foreach (is_array($settings['currency_catalog'] ?? null) ? $settings['currency_catalog'] : [] as $entry) { + if (!is_array($entry)) { + continue; + } + $code = strtoupper(trim((string) ($entry['code'] ?? ''))); + $name = trim((string) ($entry['name'] ?? '')); + if ($code === '') { + continue; + } + $catalog[] = [ + 'code' => $code, + 'name' => $name !== '' ? $name : $code, + 'symbol' => $code, + 'is_active' => 1, + 'is_crypto' => $this->isCryptoCurrencyCode($code) ? 1 : 0, + 'sort_order' => 1000, + ]; + } + + return $this->currencyCatalogCache = $catalog; + } + + private function currencyCatalogEntry(string $code): ?array + { + $normalizedCode = strtoupper(trim($code)); + if ($normalizedCode === '') { + return null; + } + + foreach ($this->currencyCatalog() as $entry) { + if ($normalizedCode === strtoupper((string) ($entry['code'] ?? ''))) { + return $entry; + } + } + + return null; + } + + private function syncLocalCurrencyCatalogFromFxRates(bool $forceRefresh = false): array + { + if ($forceRefresh) { + $this->fxRatesSettingsCache = null; + $this->currencyCatalogCache = null; + } + + $catalog = $this->currencyCatalog(); + if ($catalog === []) { + return []; + } + + $this->repository()->saveCurrencies($catalog); + return $this->repository()->listCurrencies(); + } + + private function syncFxRatesPreferredCurrencies(array $preferredCurrencies): void + { + if (!modules()->isEnabled('fx-rates') || !modules()->hasFunction('fx-rates', 'save_runtime_settings')) { + return; + } + + module_fn('fx-rates', 'save_runtime_settings', [ + 'preferred_currencies' => $preferredCurrencies, + ]); + $this->fxRatesSettingsCache = null; + } + + private function ensureLocalCurrencyRecord(string $code): void + { + $resolved = $this->repository()->resolveCurrencyCode($code); + if ($resolved !== null) { + return; + } + + $catalogEntry = $this->currencyCatalogEntry($code); + if ($catalogEntry !== null) { + $this->repository()->saveCurrency($catalogEntry); + return; + } + + $this->repository()->ensureCurrencyCode($code, $code); + } + + private function isCryptoCurrencyCode(string $code): bool + { + return in_array(strtoupper(trim($code)), [ + 'ADA', 'ARB', 'AVAX', 'BNB', 'BTC', 'DAI', 'DOGE', 'DOT', 'ETH', 'LINK', 'LTC', 'MATIC', 'SOL', 'TRX', 'USDC', 'USDT', 'XRP', 'XMR' + ], true); + } + private function resolveMeasurementFxFetchId(string $projectKey, array $payload, bool $allowRefresh, ?float $maxAgeHoursOverride = null): ?int { $measuredAt = trim((string) ($payload['measured_at'] ?? ''));