Skip to content

Instantly share code, notes, and snippets.

@ostronom
Last active March 18, 2022 05:29
Show Gist options
  • Save ostronom/84b709cef06077998509 to your computer and use it in GitHub Desktop.
Save ostronom/84b709cef06077998509 to your computer and use it in GitHub Desktop.
gogo
package main
import (
"log"
"net/http"
"encoding/xml"
"database/sql"
pq "github.com/lib/pq"
mapset "github.com/deckarep/golang-set"
)
type DayRate struct {
Date *string `xml:"time,attr"`
Rates []Rate `xml:"Cube"`
}
type Rate struct {
Currency *string `xml:"currency,attr"`
Rate *float32 `xml:"rate,attr"`
}
func (dr *DayRate) NormalizeByUSD() {
var usd_coeff float32 = 1
for _, rate := range dr.Rates {
// lookup USD
if *rate.Currency == "USD" {
usd_coeff = 1/ (*rate.Rate)
*rate.Rate = 1
*rate.Currency = "EUR"
break
}
}
for _, rate := range dr.Rates {
// renormalize everything
*rate.Rate = usd_coeff * (*rate.Rate)
}
}
func inserter(comm chan *DayRate, done chan bool) {
// TODO: insert only new rates
currencies := mapset.NewSet()
db, err := sql.Open("postgres", "postgres://mtt:pgpw@postgre.service.consul/mtt?sslmode=disable")
if err != nil { log.Fatal(err) }
defer db.Close()
rows, err := db.Query("select code from currencies_currency")
if err != nil { log.Fatal(err) }
defer rows.Close()
for rows.Next() {
var code string
err = rows.Scan(&code)
if err != nil { log.Fatal(err) }
currencies.Add(code)
}
if err = rows.Err(); err != nil { log.Fatal(err) }
tx, err := db.Begin()
if err != nil { log.Fatal(err) }
stmt, err := tx.Prepare(pq.CopyIn("currencies_currencyrate", "currency_id", "date", "rate"))
if err != nil { log.Fatal(err) }
for {
dr, more := <- comm
if !more { break }
dr.NormalizeByUSD()
for _, rate := range dr.Rates {
if currencies.Contains(*rate.Currency) {
_, err = stmt.Exec(*rate.Currency, *dr.Date, *rate.Rate)
if err != nil { log.Fatal(err, *dr.Date, *rate.Currency, *rate.Rate) }
}
}
}
err = stmt.Close()
if err != nil { log.Fatal(err) }
err = tx.Commit()
if err != nil { log.Fatal(err) }
done <- true
}
func parser(comm chan *DayRate) {
defer close(comm)
response, err := http.Get("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml")
if err != nil { log.Fatal(err) }
defer response.Body.Close()
decoder := xml.NewDecoder(response.Body)
var level = 0
for {
t, _ := decoder.Token()
if t == nil { break }
switch se := t.(type) {
case xml.StartElement:
if se.Name.Local == "Cube" {
if level == 1 {
var dr = new(DayRate)
decoder.DecodeElement(&dr, &se)
comm <- dr
} else { level += 1 }
}
case xml.EndElement:
if se.Name.Local == "Cube" { level -= 1 }
}
}
}
func main() {
comm := make(chan *DayRate, 10)
done := make(chan bool)
go inserter(comm, done)
go parser(comm)
<- done
}
@NaNamobile
Copy link

hi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment