From 3e9262e8435dc10bed8df6cefdf621aec7d911e3 Mon Sep 17 00:00:00 2001 From: Paul Lecuq Date: Wed, 5 Jun 2019 21:48:21 +0200 Subject: [PATCH] initial commit for fuelprices --- .gitignore | 2 + common.ini.sample | 12 ++++ fuelprices.go | 99 ++++++++++++++++++++++++++++++++ functions.go | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100644 .gitignore create mode 100644 common.ini.sample create mode 100644 fuelprices.go create mode 100644 functions.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c04312f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.ini +fuelprices diff --git a/common.ini.sample b/common.ini.sample new file mode 100644 index 0000000..151d4af --- /dev/null +++ b/common.ini.sample @@ -0,0 +1,12 @@ +[fuelprices] +remote_url=https://donnees.roulez-eco.fr/opendata/instantane +remote_filename=PrixCarburants_instantane.xml +xpath_base=.//pdv[@id='%s']/prix[@nom='%s'] +pos=50000007 +types=Gazole,SP95,SP98 +tmp_dir=/tmp/ +influx_host=nuc +influx_db=me +influx_port=8086 +influx_user=influx +influx_pass=blablabla diff --git a/fuelprices.go b/fuelprices.go new file mode 100644 index 0000000..f1715dd --- /dev/null +++ b/fuelprices.go @@ -0,0 +1,99 @@ +package main + +import ( + "archive/zip" + "fmt" + "log" + "time" + + client "github.com/influxdata/influxdb1-client/v2" +) + +// Srcfile source file +type Srcfile struct { + Filename string + Filepath string + Content []byte +} + +type Outfile struct { + Content []byte +} + +type FuelPricesConfig struct { + RemoteURL string + RemoteFilename string + XPathBase string + Pos []string + Types []string + TmpDir string + InfluxHost string + InfluxPort int + InfluxUser string + InfluxPass string + InfluxDB string +} + +type Price struct { + Id string + Fuel string + Amount float64 +} + +var szip Srcfile +var sxml Srcfile +var ofile Outfile +var err error +var zipfile *zip.Reader + +func main() { + + var fpc FuelPricesConfig + GetConfig("common.ini", &fpc) + + sxml.Filename = fpc.RemoteFilename + sxml.Filepath = fmt.Sprintf("%s/%s", fpc.TmpDir, sxml.Filename) + + httpClient, err := client.NewHTTPClient(client.HTTPConfig{ + Addr: fmt.Sprintf("http://%s:%d", fpc.InfluxHost, fpc.InfluxPort), + Username: fpc.InfluxUser, + Password: fpc.InfluxPass, + }) + + bp, err := client.NewBatchPoints(client.BatchPointsConfig{ + Database: fpc.InfluxDB, + }) + + err = DownloadFile(fpc.RemoteURL) + if err != nil { + log.Fatal("Unable to download file") + } + + err = ExtractZip() + if err != nil { + log.Fatal("Unable extract file") + } + + var prices *[]Price + var now = time.Now() + + GetPrices(&prices, fpc.Pos, fpc.Types, fpc.XPathBase) + + for _, p := range *prices { + + tags := map[string]string{"pdv": p.Id, "fuel": p.Fuel} + fields := map[string]interface{}{"value": p.Amount} + + point, _ := client.NewPoint( + "fuel_price", + tags, + fields, + now, + ) + + bp.AddPoint(point) + err = httpClient.Write(bp) + HandleError(err) + } + +} diff --git a/functions.go b/functions.go new file mode 100644 index 0000000..49d23c5 --- /dev/null +++ b/functions.go @@ -0,0 +1,143 @@ +package main + +import ( + "archive/zip" + "bytes" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strconv" + "strings" + + "github.com/antchfx/xmlquery" + "gopkg.in/ini.v1" +) + +func ParseArgs() error { + return nil +} + +func GetConfig(configfile string, fuelpricesconfig *FuelPricesConfig) error { + flag.Usage = Usage + flag.Parse() + + config, err := ini.Load(configfile) + HandleFatalError(err) + + var fpc FuelPricesConfig + + fuelpricesSection := config.Section("fuelprices") + fpc.RemoteURL = fuelpricesSection.Key("remote_url").String() + fpc.RemoteFilename = fuelpricesSection.Key("remote_filename").String() + fpc.XPathBase = fuelpricesSection.Key("xpath_base").String() + fpc.InfluxHost = fuelpricesSection.Key("influx_host").String() + fpc.InfluxPort, err = fuelpricesSection.Key("influx_port").Int() + HandleError(err) + fpc.InfluxUser = fuelpricesSection.Key("influx_user").String() + fpc.InfluxPass = fuelpricesSection.Key("influx_pass").String() + HandleError(err) + + fpc.InfluxDB = fuelpricesSection.Key("influx_db").String() + + fpc.Pos = strings.Split(fuelpricesSection.Key("pos").String(), ",") + fpc.Types = strings.Split(fuelpricesSection.Key("types").String(), ",") + + *fuelpricesconfig = fpc + + return err +} + +func DownloadFile(url string) error { + resp, err := http.Get(url) + if err != nil { + return err + } + + szip.Content, err = ioutil.ReadAll(resp.Body) + + if err != nil { + return err + } + + err = resp.Body.Close() + if err != nil { + return err + } + + return err +} + +func ExtractZip() error { + + zipfile, err = zip.NewReader(bytes.NewReader(szip.Content), int64(len(szip.Content))) + if err != nil { + log.Fatal("Unable to open zipfile") + } + + for _, f := range zipfile.File { + if f.Name == sxml.Filename { + rc, err := f.Open() + if err != nil { + return err + } + ofile.Content, err = ioutil.ReadAll(rc) + rc.Close() + } else { + log.Fatal("File not found") + } + } + return err +} + +func GetPrices(prices **[]Price, spos []string, stypes []string, sxpathbase string) error { + + var pr []Price + var xml *xmlquery.Node + f := bytes.NewReader(ofile.Content) + xml, err = xmlquery.Parse(f) + HandleError(err) + + for _, station := range spos { + for _, fuel := range stypes { + query := fmt.Sprintf(sxpathbase, station, fuel) + list := xmlquery.FindOne(xml, query) + + for _, i := range list.Attr { + if i.Name.Local == "valeur" { + var val float64 + if s, err := strconv.ParseFloat(i.Value, 64); err == nil { + val = s + } + pr = append(pr, Price{Id: station, Fuel: fuel, Amount: val}) + } + } + } + } + *prices = &pr + return err +} + +func HandleError(err error) error { + if err != nil { + return err + } + return nil +} + +// HandleFatalError fatal errors +func HandleFatalError(err error) { + if err != nil { + log.Fatal(err) + os.Exit(2) + } +} + +// Usage displays possible arguments +func Usage() { + fmt.Fprintf(os.Stderr, "Usage: fuelprices [configfile]\n") + flag.PrintDefaults() + os.Exit(1) +}