| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- package currency
- import (
- "fmt"
- "strings"
- "sync"
- "time"
- )
- type currencyConverter struct {
- client client
- cache cache
- config Config
- mu sync.RWMutex
- }
- func NewConverter(config Config) (Converter, error) {
- if config.APIKey == "" {
- return nil, fmt.Errorf("API key is required")
- }
- if config.CacheTTL == 0 {
- config.CacheTTL = 24 * time.Hour
- }
- if config.APITimeout == 0 {
- config.APITimeout = 10 * time.Second
- }
- client := newExchangeRateClient(config.APIKey, config.APITimeout)
- cache := newMemoryCache(config.CacheTTL)
- return ¤cyConverter{
- client: client,
- cache: cache,
- config: config,
- }, nil
- }
- func (c *currencyConverter) Convert(amount float64, from, to string) (float64, error) {
- from = strings.ToUpper(strings.TrimSpace(from))
- to = strings.ToUpper(strings.TrimSpace(to))
- if from == to {
- return amount, nil
- }
- rate, err := c.GetRate(from, to)
- if err != nil {
- return 0, fmt.Errorf("failed to get exchange rate from %s to %s: %w", from, to, err)
- }
- return amount * rate, nil
- }
- func (c *currencyConverter) GetRate(from, to string) (float64, error) {
- from = strings.ToUpper(strings.TrimSpace(from))
- to = strings.ToUpper(strings.TrimSpace(to))
- if from == to {
- return 1.0, nil
- }
- cachedRates, found := c.cache.get(from)
- if found && cachedRates.rates != nil {
- if rate, exists := cachedRates.rates[to]; exists {
- return rate, nil
- }
- }
- rates, err := c.fetchAndCacheRates(from)
- if err != nil {
- return 0, err
- }
- rate, exists := rates[to]
- if !exists {
- return 0, fmt.Errorf("currency %s not supported or not found in exchange rates", to)
- }
- return rate, nil
- }
- func (c *currencyConverter) fetchAndCacheRates(baseCurrency string) (map[string]float64, error) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if cachedRates, found := c.cache.get(baseCurrency); found {
- return cachedRates.rates, nil
- }
- response, err := c.client.fetchRates(baseCurrency)
- if err != nil {
- return nil, fmt.Errorf("failed to fetch rates from API: %w", err)
- }
- cachedRates := &cachedRates{
- rates: response.ConversionRates,
- baseCode: response.BaseCode,
- fetchedAt: time.Now(),
- }
- c.cache.set(baseCurrency, cachedRates)
- return response.ConversionRates, nil
- }
|