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 }