mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-20 17:54:30 +08:00
code refactor
This commit is contained in:
+3
-100
@@ -1,20 +1,10 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/exchangerates"
|
"github.com/mayswind/ezbookkeeping/pkg/exchangerates"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/log"
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExchangeRatesApi represents exchange rate api
|
// ExchangeRatesApi represents exchange rate api
|
||||||
@@ -39,98 +29,11 @@ func (a *ExchangeRatesApi) LatestExchangeRateHandler(c *core.WebContext) (any, *
|
|||||||
return nil, errs.ErrInvalidExchangeRatesDataSource
|
return nil, errs.ErrInvalidExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.GetCurrentUid()
|
exchangeRateResponse, err := dataSource.GetLatestExchangeRates(c, c.GetCurrentUid(), a.container.Current)
|
||||||
|
|
||||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
|
||||||
utils.SetProxyUrl(transport, a.CurrentConfig().ExchangeRatesProxy)
|
|
||||||
|
|
||||||
if a.CurrentConfig().ExchangeRatesSkipTLSVerify {
|
|
||||||
transport.TLSClientConfig = &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: transport,
|
|
||||||
Timeout: time.Duration(a.CurrentConfig().ExchangeRatesRequestTimeout) * time.Millisecond,
|
|
||||||
}
|
|
||||||
|
|
||||||
requests, err := dataSource.BuildRequests()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(c, "[exchange_rates.LatestExchangeRateHandler] failed to build requests for user \"uid:%d\", because %s", uid, err.Error())
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
return nil, errs.ErrFailedToRequestRemoteApi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exchangeRateResps := make([]*models.LatestExchangeRateResponse, 0, len(requests))
|
return exchangeRateResponse, nil
|
||||||
|
|
||||||
for i := 0; i < len(requests); i++ {
|
|
||||||
req := requests[i]
|
|
||||||
|
|
||||||
if len(req.Header.Values("User-Agent")) < 1 {
|
|
||||||
req.Header.Set("User-Agent", fmt.Sprintf("ezBookkeeping/%s", settings.Version))
|
|
||||||
} else if req.Header.Get("User-Agent") == "" {
|
|
||||||
req.Header.Del("User-Agent")
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf(c, "[exchange_rates.LatestExchangeRateHandler] failed to request latest exchange rate data for user \"uid:%d\", because %s", uid, err.Error())
|
|
||||||
return nil, errs.ErrFailedToRequestRemoteApi
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
log.Errorf(c, "[exchange_rates.LatestExchangeRateHandler] failed to get latest exchange rate data response for user \"uid:%d\", because response code is not 200", uid)
|
|
||||||
return nil, errs.ErrFailedToRequestRemoteApi
|
|
||||||
}
|
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
|
||||||
|
|
||||||
log.Debugf(c, "[exchange_rates.LatestExchangeRateHandler] response#%d is %s", i, body)
|
|
||||||
|
|
||||||
exchangeRateResp, err := dataSource.Parse(c, body)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf(c, "[exchange_rates.LatestExchangeRateHandler] failed to parse response for user \"uid:%d\", because %s", uid, err.Error())
|
|
||||||
return nil, errs.Or(err, errs.ErrFailedToRequestRemoteApi)
|
|
||||||
}
|
|
||||||
|
|
||||||
exchangeRateResps = append(exchangeRateResps, exchangeRateResp)
|
|
||||||
}
|
|
||||||
|
|
||||||
lastExchangeRateResponse := exchangeRateResps[len(exchangeRateResps)-1]
|
|
||||||
allExchangeRatesMap := make(map[string]string)
|
|
||||||
|
|
||||||
for i := 0; i < len(exchangeRateResps); i++ {
|
|
||||||
exchangeRateResp := exchangeRateResps[i]
|
|
||||||
|
|
||||||
for j := 0; j < len(exchangeRateResp.ExchangeRates); j++ {
|
|
||||||
exchangeRate := exchangeRateResp.ExchangeRates[j]
|
|
||||||
allExchangeRatesMap[exchangeRate.Currency] = exchangeRate.Rate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allExchangeRatesMap[lastExchangeRateResponse.BaseCurrency] = "1"
|
|
||||||
allExchangeRates := make(models.LatestExchangeRateSlice, 0, len(allExchangeRatesMap))
|
|
||||||
|
|
||||||
for currency, rate := range allExchangeRatesMap {
|
|
||||||
allExchangeRates = append(allExchangeRates, &models.LatestExchangeRate{
|
|
||||||
Currency: currency,
|
|
||||||
Rate: rate,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(allExchangeRates)
|
|
||||||
|
|
||||||
finalExchangeRateResponse := &models.LatestExchangeRateResponse{
|
|
||||||
DataSource: lastExchangeRateResponse.DataSource,
|
|
||||||
ReferenceUrl: lastExchangeRateResponse.ReferenceUrl,
|
|
||||||
UpdateTime: lastExchangeRateResponse.UpdateTime,
|
|
||||||
BaseCurrency: lastExchangeRateResponse.BaseCurrency,
|
|
||||||
ExchangeRates: allExchangeRates,
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalExchangeRateResponse, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const bankOfCanadaDataUpdateDateTimezone = "America/Toronto"
|
|||||||
|
|
||||||
// BankOfCanadaDataSource defines the structure of exchange rates data source of bank of Canada
|
// BankOfCanadaDataSource defines the structure of exchange rates data source of bank of Canada
|
||||||
type BankOfCanadaDataSource struct {
|
type BankOfCanadaDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// BankOfCanadaExchangeRateData represents the whole data from bank of Canada
|
// BankOfCanadaExchangeRateData represents the whole data from bank of Canada
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const bankOfIsraelDataUpdateDateFormat = "2006-01-02T15:04:05.9999999Z"
|
|||||||
|
|
||||||
// BankOfIsraelDataSource defines the structure of exchange rates data source of bank of Israel
|
// BankOfIsraelDataSource defines the structure of exchange rates data source of bank of Israel
|
||||||
type BankOfIsraelDataSource struct {
|
type BankOfIsraelDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// BankOfIsraelExchangeRateData represents the whole data from bank of Israel
|
// BankOfIsraelExchangeRateData represents the whole data from bank of Israel
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const bankOfRussiaUpdateDateTimezone = "Europe/Moscow"
|
|||||||
|
|
||||||
// BankOfRussiaDataSource defines the structure of exchange rates data source of bank of Russia
|
// BankOfRussiaDataSource defines the structure of exchange rates data source of bank of Russia
|
||||||
type BankOfRussiaDataSource struct {
|
type BankOfRussiaDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// BankOfRussiaExchangeRateData represents the whole data from bank of Russia
|
// BankOfRussiaExchangeRateData represents the whole data from bank of Russia
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const centralBankOfHungaryUpdateDateTimezone = "Europe/Budapest"
|
|||||||
|
|
||||||
// CentralBankOfHungaryDataSource defines the structure of exchange rates data source of central bank of Hungary
|
// CentralBankOfHungaryDataSource defines the structure of exchange rates data source of central bank of Hungary
|
||||||
type CentralBankOfHungaryDataSource struct {
|
type CentralBankOfHungaryDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// CentralBankOfHungaryExchangeRateServiceResponse represents the response data of exchange rate service for central bank of Hungary
|
// CentralBankOfHungaryExchangeRateServiceResponse represents the response data of exchange rate service for central bank of Hungary
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ var centralBankOfMyanmarSpecialCurrencyUnits = map[string]int32{
|
|||||||
|
|
||||||
// CentralBankOfMyanmarDataSource defines the structure of exchange rates data source of central bank of Myanmar
|
// CentralBankOfMyanmarDataSource defines the structure of exchange rates data source of central bank of Myanmar
|
||||||
type CentralBankOfMyanmarDataSource struct {
|
type CentralBankOfMyanmarDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// CentralBankOfMyanmarExchangeRate represents the exchange rate data from central bank of Myanmar
|
// CentralBankOfMyanmarExchangeRate represents the exchange rate data from central bank of Myanmar
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const centralBankOfUzbekistanUpdateDateTimezone = "Asia/Samarkand"
|
|||||||
|
|
||||||
// CentralBankOfUzbekistanDataSource defines the structure of exchange rates data source of the central bank of the Republic of Uzbekistan
|
// CentralBankOfUzbekistanDataSource defines the structure of exchange rates data source of the central bank of the Republic of Uzbekistan
|
||||||
type CentralBankOfUzbekistanDataSource struct {
|
type CentralBankOfUzbekistanDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// CentralBankOfUzbekistanExchangeRates represents the exchange rates data from the central bank of the Republic of Uzbekistan
|
// CentralBankOfUzbekistanExchangeRates represents the exchange rates data from the central bank of the Republic of Uzbekistan
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const czechNationalBankDataUpdateDateTimezone = "Europe/Prague"
|
|||||||
|
|
||||||
// CzechNationalBankDataSource defines the structure of exchange rates data source of Czech National Bank
|
// CzechNationalBankDataSource defines the structure of exchange rates data source of Czech National Bank
|
||||||
type CzechNationalBankDataSource struct {
|
type CzechNationalBankDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildRequests returns the Czech National Bank exchange rates http requests
|
// BuildRequests returns the Czech National Bank exchange rates http requests
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const danmarksNationalbankDataUpdateDateTimezone = "Europe/Copenhagen"
|
|||||||
|
|
||||||
// DanmarksNationalbankDataSource defines the structure of exchange rates data source of Danmarks Nationalbank
|
// DanmarksNationalbankDataSource defines the structure of exchange rates data source of Danmarks Nationalbank
|
||||||
type DanmarksNationalbankDataSource struct {
|
type DanmarksNationalbankDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// DanmarksNationalbankExchangeRateData represents the whole data from Danmarks Nationalbank
|
// DanmarksNationalbankExchangeRateData represents the whole data from Danmarks Nationalbank
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const euroCentralBankDataUpdateDateTimezone = "Europe/Berlin"
|
|||||||
|
|
||||||
// EuroCentralBankDataSource defines the structure of exchange rates data source of euro central bank
|
// EuroCentralBankDataSource defines the structure of exchange rates data source of euro central bank
|
||||||
type EuroCentralBankDataSource struct {
|
type EuroCentralBankDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// EuroCentralBankExchangeRateData represents the whole data from euro central bank
|
// EuroCentralBankExchangeRateData represents the whole data from euro central bank
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
package exchangerates
|
package exchangerates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExchangeRatesDataSource defines the structure of exchange rates data source
|
// ExchangeRatesDataSource defines the structure of exchange rates data source
|
||||||
type ExchangeRatesDataSource interface {
|
type ExchangeRatesDataSource interface {
|
||||||
// BuildRequests returns the http requests
|
// GetLatestExchangeRates returns the common response entities
|
||||||
BuildRequests() ([]*http.Request, error)
|
GetLatestExchangeRates(c core.Context, uid int64, currentConfig *settings.Config) (*models.LatestExchangeRateResponse, error)
|
||||||
|
|
||||||
// Parse returns the common response entity according to the data source raw response
|
|
||||||
Parse(c core.Context, content []byte) (*models.LatestExchangeRateResponse, error)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,55 +18,55 @@ var (
|
|||||||
// InitializeExchangeRatesDataSource initializes the current exchange rates data source according to the config
|
// InitializeExchangeRatesDataSource initializes the current exchange rates data source according to the config
|
||||||
func InitializeExchangeRatesDataSource(config *settings.Config) error {
|
func InitializeExchangeRatesDataSource(config *settings.Config) error {
|
||||||
if config.ExchangeRatesDataSource == settings.ReserveBankOfAustraliaDataSource {
|
if config.ExchangeRatesDataSource == settings.ReserveBankOfAustraliaDataSource {
|
||||||
Container.Current = &ReserveBankOfAustraliaDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&ReserveBankOfAustraliaDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.BankOfCanadaDataSource {
|
} else if config.ExchangeRatesDataSource == settings.BankOfCanadaDataSource {
|
||||||
Container.Current = &BankOfCanadaDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&BankOfCanadaDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.CzechNationalBankDataSource {
|
} else if config.ExchangeRatesDataSource == settings.CzechNationalBankDataSource {
|
||||||
Container.Current = &CzechNationalBankDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&CzechNationalBankDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.DanmarksNationalbankDataSource {
|
} else if config.ExchangeRatesDataSource == settings.DanmarksNationalbankDataSource {
|
||||||
Container.Current = &DanmarksNationalbankDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&DanmarksNationalbankDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.EuroCentralBankDataSource {
|
} else if config.ExchangeRatesDataSource == settings.EuroCentralBankDataSource {
|
||||||
Container.Current = &EuroCentralBankDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&EuroCentralBankDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.NationalBankOfGeorgiaDataSource {
|
} else if config.ExchangeRatesDataSource == settings.NationalBankOfGeorgiaDataSource {
|
||||||
Container.Current = &NationalBankOfGeorgiaDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&NationalBankOfGeorgiaDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.CentralBankOfHungaryDataSource {
|
} else if config.ExchangeRatesDataSource == settings.CentralBankOfHungaryDataSource {
|
||||||
Container.Current = &CentralBankOfHungaryDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&CentralBankOfHungaryDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.BankOfIsraelDataSource {
|
} else if config.ExchangeRatesDataSource == settings.BankOfIsraelDataSource {
|
||||||
Container.Current = &BankOfIsraelDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&BankOfIsraelDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.CentralBankOfMyanmarDataSource {
|
} else if config.ExchangeRatesDataSource == settings.CentralBankOfMyanmarDataSource {
|
||||||
Container.Current = &CentralBankOfMyanmarDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&CentralBankOfMyanmarDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.NorgesBankDataSource {
|
} else if config.ExchangeRatesDataSource == settings.NorgesBankDataSource {
|
||||||
Container.Current = &NorgesBankDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&NorgesBankDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.NationalBankOfPolandDataSource {
|
} else if config.ExchangeRatesDataSource == settings.NationalBankOfPolandDataSource {
|
||||||
Container.Current = &NationalBankOfPolandDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&NationalBankOfPolandDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.NationalBankOfRomaniaDataSource {
|
} else if config.ExchangeRatesDataSource == settings.NationalBankOfRomaniaDataSource {
|
||||||
Container.Current = &NationalBankOfRomaniaDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&NationalBankOfRomaniaDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.BankOfRussiaDataSource {
|
} else if config.ExchangeRatesDataSource == settings.BankOfRussiaDataSource {
|
||||||
Container.Current = &BankOfRussiaDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&BankOfRussiaDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.SwissNationalBankDataSource {
|
} else if config.ExchangeRatesDataSource == settings.SwissNationalBankDataSource {
|
||||||
Container.Current = &SwissNationalBankDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&SwissNationalBankDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.NationalBankOfUkraineDataSource {
|
} else if config.ExchangeRatesDataSource == settings.NationalBankOfUkraineDataSource {
|
||||||
Container.Current = &NationalBankOfUkraineDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&NationalBankOfUkraineDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.CentralBankOfUzbekistanDataSource {
|
} else if config.ExchangeRatesDataSource == settings.CentralBankOfUzbekistanDataSource {
|
||||||
Container.Current = &CentralBankOfUzbekistanDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&CentralBankOfUzbekistanDataSource{})
|
||||||
return nil
|
return nil
|
||||||
} else if config.ExchangeRatesDataSource == settings.InternationalMonetaryFundDataSource {
|
} else if config.ExchangeRatesDataSource == settings.InternationalMonetaryFundDataSource {
|
||||||
Container.Current = &InternationalMonetaryFundDataSource{}
|
Container.Current = newCommonHttpExchangeRatesDataSource(&InternationalMonetaryFundDataSource{})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package exchangerates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/log"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HttpExchangeRatesDataSource defines the structure of http exchange rates data source
|
||||||
|
type HttpExchangeRatesDataSource interface {
|
||||||
|
// BuildRequests returns the http requests
|
||||||
|
BuildRequests() ([]*http.Request, error)
|
||||||
|
|
||||||
|
// Parse returns the common response entity according to the data source raw response
|
||||||
|
Parse(c core.Context, content []byte) (*models.LatestExchangeRateResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommonHttpExchangeRatesDataSource defines the structure of common http exchange rates data source
|
||||||
|
type CommonHttpExchangeRatesDataSource struct {
|
||||||
|
ExchangeRatesDataSource
|
||||||
|
dataSource HttpExchangeRatesDataSource
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *CommonHttpExchangeRatesDataSource) GetLatestExchangeRates(c core.Context, uid int64, currentConfig *settings.Config) (*models.LatestExchangeRateResponse, error) {
|
||||||
|
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
utils.SetProxyUrl(transport, currentConfig.ExchangeRatesProxy)
|
||||||
|
|
||||||
|
if currentConfig.ExchangeRatesSkipTLSVerify {
|
||||||
|
transport.TLSClientConfig = &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
Timeout: time.Duration(currentConfig.ExchangeRatesRequestTimeout) * time.Millisecond,
|
||||||
|
}
|
||||||
|
|
||||||
|
requests, err := e.dataSource.BuildRequests()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(c, "[http_exchange_rates_datasource.GetLatestExchangeRates] failed to build requests for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.ErrFailedToRequestRemoteApi
|
||||||
|
}
|
||||||
|
|
||||||
|
exchangeRateResps := make([]*models.LatestExchangeRateResponse, 0, len(requests))
|
||||||
|
|
||||||
|
for i := 0; i < len(requests); i++ {
|
||||||
|
req := requests[i]
|
||||||
|
|
||||||
|
if len(req.Header.Values("User-Agent")) < 1 {
|
||||||
|
req.Header.Set("User-Agent", fmt.Sprintf("ezBookkeeping/%s", settings.Version))
|
||||||
|
} else if req.Header.Get("User-Agent") == "" {
|
||||||
|
req.Header.Del("User-Agent")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(c, "[http_exchange_rates_datasource.GetLatestExchangeRates] failed to request latest exchange rate data for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.ErrFailedToRequestRemoteApi
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
log.Errorf(c, "[http_exchange_rates_datasource.GetLatestExchangeRates] failed to get latest exchange rate data response for user \"uid:%d\", because response code is not 200", uid)
|
||||||
|
return nil, errs.ErrFailedToRequestRemoteApi
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
log.Debugf(c, "[http_exchange_rates_datasource.GetLatestExchangeRates] response#%d is %s", i, body)
|
||||||
|
|
||||||
|
exchangeRateResp, err := e.dataSource.Parse(c, body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(c, "[http_exchange_rates_datasource.GetLatestExchangeRates] failed to parse response for user \"uid:%d\", because %s", uid, err.Error())
|
||||||
|
return nil, errs.Or(err, errs.ErrFailedToRequestRemoteApi)
|
||||||
|
}
|
||||||
|
|
||||||
|
exchangeRateResps = append(exchangeRateResps, exchangeRateResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastExchangeRateResponse := exchangeRateResps[len(exchangeRateResps)-1]
|
||||||
|
allExchangeRatesMap := make(map[string]string)
|
||||||
|
|
||||||
|
for i := 0; i < len(exchangeRateResps); i++ {
|
||||||
|
exchangeRateResp := exchangeRateResps[i]
|
||||||
|
|
||||||
|
for j := 0; j < len(exchangeRateResp.ExchangeRates); j++ {
|
||||||
|
exchangeRate := exchangeRateResp.ExchangeRates[j]
|
||||||
|
allExchangeRatesMap[exchangeRate.Currency] = exchangeRate.Rate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allExchangeRatesMap[lastExchangeRateResponse.BaseCurrency] = "1"
|
||||||
|
allExchangeRates := make(models.LatestExchangeRateSlice, 0, len(allExchangeRatesMap))
|
||||||
|
|
||||||
|
for currency, rate := range allExchangeRatesMap {
|
||||||
|
allExchangeRates = append(allExchangeRates, &models.LatestExchangeRate{
|
||||||
|
Currency: currency,
|
||||||
|
Rate: rate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(allExchangeRates)
|
||||||
|
|
||||||
|
finalExchangeRateResponse := &models.LatestExchangeRateResponse{
|
||||||
|
DataSource: lastExchangeRateResponse.DataSource,
|
||||||
|
ReferenceUrl: lastExchangeRateResponse.ReferenceUrl,
|
||||||
|
UpdateTime: lastExchangeRateResponse.UpdateTime,
|
||||||
|
BaseCurrency: lastExchangeRateResponse.BaseCurrency,
|
||||||
|
ExchangeRates: allExchangeRates,
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalExchangeRateResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCommonHttpExchangeRatesDataSource(dataSource HttpExchangeRatesDataSource) *CommonHttpExchangeRatesDataSource {
|
||||||
|
return &CommonHttpExchangeRatesDataSource{
|
||||||
|
dataSource: dataSource,
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-17
@@ -1,4 +1,4 @@
|
|||||||
package api
|
package exchangerates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/exchangerates"
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
"github.com/mayswind/ezbookkeeping/pkg/settings"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||||
@@ -318,27 +317,19 @@ func executeLatestExchangeRateHandler(t *testing.T, dataSourceType string) *mode
|
|||||||
ExchangeRatesSkipTLSVerify: true,
|
ExchangeRatesSkipTLSVerify: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsContainer := &settings.ConfigContainer{
|
err := InitializeExchangeRatesDataSource(config)
|
||||||
Current: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := exchangerates.InitializeExchangeRatesDataSource(config)
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
exchangeRatesApi := &ExchangeRatesApi{
|
dataSource := Container.Current
|
||||||
ApiUsingConfig: ApiUsingConfig{
|
assert.NotNil(t, dataSource)
|
||||||
container: settingsContainer,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ginContext, _ := gin.CreateTestContext(httptest.NewRecorder())
|
ginContext, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||||
|
context := &core.WebContext{
|
||||||
response, err := exchangeRatesApi.LatestExchangeRateHandler(&core.WebContext{
|
|
||||||
Context: ginContext,
|
Context: ginContext,
|
||||||
})
|
}
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
exchangeRateResponse := response.(*models.LatestExchangeRateResponse)
|
exchangeRateResponse, err := dataSource.GetLatestExchangeRates(context, context.GetCurrentUid(), config)
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, exchangeRateResponse)
|
assert.NotNil(t, exchangeRateResponse)
|
||||||
|
|
||||||
return exchangeRateResponse
|
return exchangeRateResponse
|
||||||
@@ -27,7 +27,7 @@ var internationalMonetaryFundCurrencyNameCodeMap map[string]string
|
|||||||
|
|
||||||
// InternationalMonetaryFundDataSource defines the structure of exchange rates data source of international monetary fund
|
// InternationalMonetaryFundDataSource defines the structure of exchange rates data source of international monetary fund
|
||||||
type InternationalMonetaryFundDataSource struct {
|
type InternationalMonetaryFundDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const nationalBankOfGeorgiaUpdateDateFormat = "2006-01-02T15:04:05.999Z"
|
|||||||
|
|
||||||
// NationalBankOfGeorgiaDataSource defines the structure of exchange rates data source of national bank of Georgia
|
// NationalBankOfGeorgiaDataSource defines the structure of exchange rates data source of national bank of Georgia
|
||||||
type NationalBankOfGeorgiaDataSource struct {
|
type NationalBankOfGeorgiaDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NationalBankOfGeorgiaExchangeRates represents the exchange rates data from national bank of Georgia
|
// NationalBankOfGeorgiaExchangeRates represents the exchange rates data from national bank of Georgia
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const nationalBankOfPolandDataUpdateDateTimezone = "Europe/Warsaw"
|
|||||||
|
|
||||||
// NationalBankOfPolandDataSource defines the structure of exchange rates data source of National Bank of Poland
|
// NationalBankOfPolandDataSource defines the structure of exchange rates data source of National Bank of Poland
|
||||||
type NationalBankOfPolandDataSource struct {
|
type NationalBankOfPolandDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NationalBankOfPolandExchangeRateData represents the whole data from National Bank of Poland
|
// NationalBankOfPolandExchangeRateData represents the whole data from National Bank of Poland
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const nationalBankOfRomaniaUpdateDateTimezone = "Europe/Bucharest"
|
|||||||
|
|
||||||
// NationalBankOfRomaniaDataSource defines the structure of exchange rates data source of national bank of Romania
|
// NationalBankOfRomaniaDataSource defines the structure of exchange rates data source of national bank of Romania
|
||||||
type NationalBankOfRomaniaDataSource struct {
|
type NationalBankOfRomaniaDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NationalBankOfRomaniaExchangeRateData represents the whole data from national bank of Romania
|
// NationalBankOfRomaniaExchangeRateData represents the whole data from national bank of Romania
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const nationalBankOfUkraineUpdateDateFormat = "02.01.2006"
|
|||||||
|
|
||||||
// NationalBankOfUkraineDataSource defines the structure of exchange rates data source of National Bank of Ukraine
|
// NationalBankOfUkraineDataSource defines the structure of exchange rates data source of National Bank of Ukraine
|
||||||
type NationalBankOfUkraineDataSource struct {
|
type NationalBankOfUkraineDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NationalBankOfUkraineExchangeRates represents the exchange rates data from National Bank of Ukraine
|
// NationalBankOfUkraineExchangeRates represents the exchange rates data from National Bank of Ukraine
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const norgesBankUpdateDateTimezone = "Europe/Oslo"
|
|||||||
|
|
||||||
// NorgesBankDataSource defines the structure of exchange rates data source of Norges Bank
|
// NorgesBankDataSource defines the structure of exchange rates data source of Norges Bank
|
||||||
type NorgesBankDataSource struct {
|
type NorgesBankDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NorgesBankExchangeRateData represents the whole data from Norges Bank
|
// NorgesBankExchangeRateData represents the whole data from Norges Bank
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const reserveBankOfAustraliaDataUpdateDateFormat = "2006-01-02T15:04:05Z07:00"
|
|||||||
|
|
||||||
// ReserveBankOfAustraliaDataSource defines the structure of exchange rates data source of the reserve bank of Australia
|
// ReserveBankOfAustraliaDataSource defines the structure of exchange rates data source of the reserve bank of Australia
|
||||||
type ReserveBankOfAustraliaDataSource struct {
|
type ReserveBankOfAustraliaDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReserveBankOfAustraliaData represents the whole data from the reserve bank of Australia
|
// ReserveBankOfAustraliaData represents the whole data from the reserve bank of Australia
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const swissNationalBankExchangeRatePeriodDateFormat = "2006-01-02"
|
|||||||
|
|
||||||
// SwissNationalBankDataSource defines the structure of exchange rates data source of the reserve Swiss National Bank
|
// SwissNationalBankDataSource defines the structure of exchange rates data source of the reserve Swiss National Bank
|
||||||
type SwissNationalBankDataSource struct {
|
type SwissNationalBankDataSource struct {
|
||||||
ExchangeRatesDataSource
|
HttpExchangeRatesDataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// SwissNationalBankData represents the whole data from the reserve Swiss National Bank
|
// SwissNationalBankData represents the whole data from the reserve Swiss National Bank
|
||||||
|
|||||||
Reference in New Issue
Block a user