cbrfWorker/internal/worker/worker.go
2023-06-22 11:26:42 +03:00

170 lines
3.5 KiB
Go

package worker
import (
"context"
"encoding/xml"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/danilsolovyov/croupierCbrf/internal/dal"
"github.com/themakers/hlog"
"golang.org/x/text/encoding/charmap"
)
type worker struct {
ctx context.Context
mc *dal.MongoConnection
logger hlog.Logger
}
func InitAndStart(ctx context.Context, mc *dal.MongoConnection, logger hlog.Logger) error {
w := worker{ctx, mc, logger}
return w.start()
}
func (w *worker) start() error {
go func() {
for {
quotes, err := getQuotes()
if err != nil {
w.logger.Emit(ErrorWorker{err})
continue
}
date, err := time.Parse("02.01.2006 Z07", quotes.Date+" +03")
fmt.Println(date)
if err != nil {
w.logger.Emit(ErrorWorker{err})
continue
}
// Проверяем существование котировки USD и дату последнего обновления по ЦБ РФ
usd, err := w.mc.GetQuote(w.ctx, "USD")
if err != nil {
w.logger.Emit(ErrorWorker{err})
continue
}
// Если не находит или дата обновилась, то вставляем новые значения
if usd == nil || !date.Equal(usd.Date) {
for _, item := range quotes.Quotes {
quote, err := respQuoteToDalQuote(date, &item)
if err != nil {
w.logger.Emit(ErrorWorker{err})
continue
}
err = w.mc.UpdateQuote(w.ctx, quote)
if err != nil {
w.logger.Emit(ErrorWorker{err})
continue
}
}
}
now := time.Now()
// Сверяем даты по дню - если не совпадают, то ставим таймер на 15 минут
nextTime := 15 * time.Minute
if date.Day() == now.In(time.FixedZone(date.Zone())).Day() {
next := date.AddDate(0, 0,
1).Add(time.Hour * 16) // Примерно в это время гарантированно обновляются котировки
nextTime = next.Sub(now)
}
select {
case <-w.ctx.Done():
return
case <-time.After(nextTime):
continue
}
}
}()
return nil
}
type RespDailyQuotes struct {
Date string `xml:"Date,attr"`
Name string `xml:"name,attr"`
Quotes []RespQuote `xml:"Valute"`
}
type RespQuote struct {
ID string `xml:"ID,attr"`
NumCode int `xml:"NumCode"`
CharCode string `xml:"CharCode"`
Nominal int `xml:"Nominal"`
Name string `xml:"Name"`
Value string `xml:"Value"`
}
func getQuotes() (*RespDailyQuotes, error) {
resp, err := http.Get("https://cbr.ru/scripts/XML_daily.asp")
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, errors.New(fmt.Sprintf("bad status: %v", resp.Status))
}
var result RespDailyQuotes
d := xml.NewDecoder(resp.Body)
d.CharsetReader = identReader
err = d.Decode(&result)
if err != nil {
return nil, err
}
return &result, nil
}
func identReader(encoding string, input io.Reader) (io.Reader, error) {
switch encoding {
case "windows-1251":
return charmap.Windows1251.NewDecoder().Reader(input), nil
}
return input, nil
}
func respQuoteToDalQuote(date time.Time, data *RespQuote) (*dal.Quote, error) {
strVal := strings.ReplaceAll(data.Value, ",", ".")
value, err := strconv.ParseFloat(strVal, 64)
if err != nil {
return nil, err
}
result := &dal.Quote{
ID: data.CharCode,
Date: date,
IDCb: data.ID,
NumCode: data.NumCode,
Nominal: data.Nominal,
Name: data.Name,
Value: value,
}
return result, nil
}