Skip to content

Commit

Permalink
Added config, partial estacions API operations, basic skeleton for el…
Browse files Browse the repository at this point in the history
…asticsearch example
  • Loading branch information
oscaromeu committed Jan 10, 2021
1 parent 8f5ca7e commit 801543f
Show file tree
Hide file tree
Showing 13 changed files with 8,031 additions and 52 deletions.
112 changes: 112 additions & 0 deletions estacions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package meteocat

import (
"encoding/json"
"fmt"
"net/http"
"strings"
)

// Coordenades struct holds georeference information of the stations
type Coordenades struct {
Latitud float64 `json:"latitud"` // Latitude expressed in decimal degrees. WSG84 reference system
Longitud float64 `json:"Longitud"` // Longitude expressed in decimal degrees. WSG84 reference system
}

// Municipi struct holds information on which municipi is located the station.
type Municipi struct {
Codi string `json:"codi"` // INE code of the municipi
Nom string `json:"nom"` // Name of the municipi
}

// Comarca struct holds information on which Comarca is located the station.
type Comarca struct {
Codi int `json:"codi"` // Comarca identification code
Nom string `json:"nom"` // Name of the comarca
}

// Provincia struct holds information on which Provincia is located the station.
type Provincia struct {
Codi int `json:"codi"` // Provincia identification code
Nom string `json:"nom"` // Name of the provincia
}

// Xarxa struct holds information on which Xarxa is located the station. The xarxa field
// refers to the stations of the Network of Automatic Meteorological Stations (XEMA) of Catalonia
type Xarxa struct {
Codi int `json:"codi"` // Xarxa identification code
Nom string `json:"nom"` // Name of the Network
}

// Aggregation of fields and structs to unmarshal the responses
type MetadadesEstacions struct {
Codi string `json:"codi"` // Identification code for each automatic weather station (EMA)
Nom string `json:"nom"` // Name of the EMA
Tipus string `json:"tipus"` // Type of station typically automatic
Coordenades Coordenades `json:"coordenades"` // Georeference data of the station
Emplacament string `json:"emplacament"` // Descriptive name of where the station is located e.g Planters Gusi, ctra. antiga de València, km 14
Altitud float64 `json:"altitud"` // Altitude in meters of the station above the sea level.
Municipi Municipi `json:"municipi"` // Municipi
Comarca Comarca `json:"comarca"` // Comarca
Provincia Provincia `json:"provincia"` // Provincia
Xarxa Xarxa `json:"xarxa"` // Network tipically XEMA
Estats Estats `json:"estats"`
}

// Mesurades holds all the data representations to unmarshall the API responses
type Estacions struct {
MetadadesEstacions
Key string
CodiEstacio string // ?
CodiVariable string // ?
*Settings
}

// Returns a list of metadata from all stations. If settings are specified, filters by specified status and date
// The API resource is /estacions/metadades?estat={estat}&data={data} where the
// parameters `estat` and data optional.
// Request example: https://api.meteo.cat/xema/v1/estacions/metadades?estat=ope&data=2017-03-27Z
func (e *Estacions) StationsAll(p *Parameters) error {

dataOk := ValidData(p.Data)

if p.codiEstat != "" && dataOk == true {
p.codiEstat = strings.ToLower(p.codiEstat)

if ValidCodiEstat(p.codiEstat) {
sFlag = true
url = fmt.Sprintf(baseURL, fmt.Sprintf("/estacions/metadades?estat=%s&data=%s-%s-%sZ", p.codiEstat, p.Any, p.Mes, p.Dia))
} else {
return errEstacioUnavailable
}

} else {
url = fmt.Sprintf(baseURL, fmt.Sprintf("/estacions/metadades"))
}

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}

req.Header.Add("X-Api-Key", e.Key)

resp, err := e.client.Do(req)

if err != nil {
fmt.Println(err)
return err
}
defer resp.Body.Close()
if sFlag == true {
if err = json.NewDecoder(resp.Body).Decode(&e.MetadadesEstacions); err != nil {
return err
}
} else {
if err = json.NewDecoder(resp.Body).Decode(&e.MetadadesEstacions); err != nil {
return err
}
}
// print status line and headers
return nil
}
157 changes: 157 additions & 0 deletions examples/elasticsearch/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package main

import (
"fmt"
"github.com/kelseyhightower/envconfig"
"github.com/oscaromeu/meteocat"
"github.com/oscaromeu/meteocat/examples/elasticsearch/config"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)

// Entry point of the app

var (
log = logrus.New()
appdir = os.Getenv("PWD")
homeDir string
pidFile string
logDir = filepath.Join(appdir, "log")
confDir = filepath.Join(appdir, "config")
downloadDir = filepath.Join(appdir, "download")
dataDir = confDir
configFile = filepath.Join(confDir, "conf.yaml")
// MainConfig has all configuration
MainConfig config.Config
)

func writePIDFile() {
if pidFile == "" {
return
}

// Ensure the required directory structure exists.
err := os.MkdirAll(filepath.Dir(pidFile), 0700)
if err != nil {
log.Fatal(3, "Failed to verify pid directory", err)
}

// Retrieve the PID and write it.
pid := strconv.Itoa(os.Getpid())
if err := ioutil.WriteFile(pidFile, []byte(pid), 0644); err != nil {
log.Fatal(3, "Failed to write pidfile", err)
}
}

func init() {

customFormatter := new(logrus.TextFormatter)
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
log.Formatter = customFormatter
customFormatter.FullTimestamp = true

//log.SetOutput(os.Stdout)
v := viper.New()

// now load up config settings
if _, err := os.Stat(configFile); err == nil {
v.SetConfigFile(configFile)
confDir = filepath.Dir(configFile)
} else {
v.SetConfigName("conf")
v.SetConfigType("yaml")
v.AddConfigPath("../config")
v.AddConfigPath("../../config")
v.AddConfigPath(".")
}
err := v.ReadInConfig()
if err != nil {
log.Errorf("Fatal error config file: %s \n", err)
os.Exit(1)
}
err = v.Unmarshal(&MainConfig)
if err != nil {
log.Errorf("Fatal error config file: %s \n", err)
os.Exit(1)
}
log.Infof("CONFIG FROM FILE : %+v", &MainConfig)

//parse config with environtment vars

//envConf := &config.Config{}

err = envconfig.Process("M_", &MainConfig)
if err != nil {
log.Warnf("Some error happened when trying to read config from env: %s", err)
}
//log.Infof("CONFIG FROM ENV : %+v", envConf)

//mergo.MergeWithOverwrite(&agent.MainConfig, envConf)

log.Infof("CONFIG AFTER MERGE : %+v", &MainConfig)
// Setting defaults

cfg := &MainConfig

if cfg.General.LogMode != "file" {
//default if not set
log.Out = os.Stdout

} else {
if len(cfg.General.LogDir) > 0 {
logDir = cfg.General.LogDir
os.Mkdir(logDir, 0755)
//Log output
f, _ := os.OpenFile(logDir+"/es_meteocat.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
log.Out = f
}
}
if len(cfg.General.LogLevel) > 0 {
l, _ := logrus.ParseLevel(cfg.General.LogLevel)
log.Level = l
}

if len(cfg.General.HomeDir) > 0 {
homeDir = cfg.General.HomeDir
}

log.Debugf("MAINCONFIG LOAD %#+v", cfg)
fmt.Println("")

}

func main() {

// Load Logger settings for other packages. These packages will inherit the log config defined in main
config.SetLogger(log)

d, err := meteocat.NewMesurades(MainConfig.General.ApiKey)
if err != nil {
log.Fatalln(err)
}

if meteocat.CheckAPIKeyExists(d.Key) == false {
fmt.Println("ApiKey is not set. ")
}

data := meteocat.Data{
Any: "2021",
Mes: "01",
Dia: "06",
}
params, _ := meteocat.NewParameters(
meteocat.OptionCodiVariable("32"),
meteocat.OptionData(data),
)

// Call MeasurementByDay Method
d.MeasurementLast(params)

for _,v := range d.Measurements {
fmt.Println(v)
}
}
21 changes: 21 additions & 0 deletions examples/elasticsearch/config/conf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
general:
# log directory set the Directory path for each device individual log
# could be set also with M_LOGDIR env var,default $CWD/log
log_dir: "./log"
# logLevel set de main process log level
# valid values: panic,fatal,error,warn,info,debug
# could also be set with M_LOGLEVEL env var, default info if not set
log_level: "info"
# Log mode could be "file/console" default "console" ir not set
# could be set also with M_LOGMODE env var
log_mode: "console"
#home_dir:
temporal_path: "/tmp"
# could also be set M_ES_USERNAME env var
es_user: "Admin"
# could also be set M_ES_PASSWORD env var
es_password: "Admin"
# could also be set M_ES_SERVER env var
es_server: "localhost"
# could also be set with M_API_KEY
api_key: "api_key"
86 changes: 86 additions & 0 deletions examples/elasticsearch/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package config

import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"strings"
)

var (

//Log the Logger
log *logrus.Logger
)



// ReadEnv reads the environmental variable associated with a given key function paramater
func ReadEnv(key string) string {

v := viper.New()

// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
// E.g. In this case the prefix is "gs", the env registry will look for env
// variables that start with "GS_". To import a template to a zabbix instance we must set the
// following variables: ZABBIX_PASSWORD, ZABBIX_SERVER, ZABBIX_USERNAME
v.SetEnvPrefix("gs")
//v.SetDefault("LOG_DEBUG", false)

// Make sure that ENV.VAR => ENV_VAR
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

// Enable VIPER to read Environment Variables
v.AutomaticEnv()

// AllowEmptyEnv tells Viper to consider set,
// but empty environment variables as valid values instead of falling back.
v.AllowEmptyEnv(true)

// viper.Get() returns an empty interface{}
// to get the underlying type of the key,
// we have to do the type assertion, we know the underlying value is string
// if we type assert to other type it will throw an error
value, err := v.Get(key).(string)

if !err {
err := errors.Errorf("Failed to get the environmental variable %q", value)
log.Error(err)
}
return value
}

//// Load reads the config/config.yaml file
//func Load() (*Config, error) {
//
// v := viper.New()
// // Set the file name of the configurations file
// v.SetConfigName("conf")
//
// // Set the path to look for the configurations file
// v.AddConfigPath("../../config")
//
// // Enable VIPER to read Environment Variables
// v.AutomaticEnv()
//
// v.SetConfigType("yaml")
// //var configuration Configurations
//
// var conf Config
//
// if err := v.ReadInConfig(); err != nil {
// return nil, errors.Wrapf(err, "Error reading config file")
// }
//
// err := v.Unmarshal(&conf)
// if err != nil {
// return nil, errors.Wrapf(err, "Unable to decode into struct, %q", conf)
// }
// return &conf, err
//
//}

// SetLogger set the output log
func SetLogger(l *logrus.Logger) {
log = l
}
19 changes: 19 additions & 0 deletions examples/elasticsearch/config/mainconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package config

// GeneralConfig has miscellaneous configuration options
type GeneralConfig struct {
LogDir string `mapstructure:"log_dir" envconfig:"M_LOGDIR"`
LogLevel string `mapstructure:"log_level" envconfig:"M_LOGLEVEL"`
LogMode string `mapstructure:"log_mode" envconfig:"M_LOGMODE"`
HomeDir string `mapstructure:"home_dir" envconfig:"M_HOMEDIR"`
TemporalPath string `mapstructure:"temporal_path" envconfig:"M_TEMPORAL_PATH"`
ESUser string `mapstructure:"user" envconfig:"M_ES_USERNAME"`
ESPassword string `mapstructure:"password" envconfig:"M_ES_PASSWORD"`
ESServer string `mapstructure:"password" envconfig:"M_ES_SERVER"`
ApiKey string `mapstructure:"api_key" envconfig:"M_API_KEY"`
}


type Config struct {
General GeneralConfig `mapstructure:"general"`
}
Loading

0 comments on commit 801543f

Please sign in to comment.