@@ -13,6 +13,7 @@ import (
1313 "path/filepath"
1414 "sort"
1515 "strconv"
16+ "strings"
1617 "time"
1718)
1819
2930
3031func main () {
3132 conf := NewConfiguration ()
33+ zones := ""
3234
33- flag .StringVar (& conf . Zone , "zone " , conf . Zone , "Price Area like DK1 " )
35+ flag .StringVar (& zones , "zones " , zones , "Comma-separated list of price areas to keep " )
3436 flag .StringVar (& conf .Output , "output" , conf .Output , "Directory to place output into" )
3537 flag .StringVar (& conf .Endpoint , "endpoint" , conf .Endpoint , "Endpoint to fetch from" )
3638 flag .Int64Var (& conf .V2Date , "v2date" , conf .V2Date , "Date when day-a-head prices take effect" )
@@ -40,6 +42,11 @@ func main() {
4042 flag .IntVar (& conf .SleepInterval , "sleep-interval" , conf .SleepInterval , "Milliseconds to sleep when API is throttling" )
4143
4244 flag .Parse ()
45+
46+ if zones != "" {
47+ conf .Zones = strings .Split (zones , "," )
48+ }
49+
4350 err := conf .Validate ()
4451 if err != nil {
4552 log .Fatal (err )
@@ -62,31 +69,52 @@ func run(c Configuration) error {
6269
6370func runConfigurations (cs []Configuration ) error {
6471 for _ , c := range cs {
65- records , err := fetchRecords (c .Endpoint , c .Zone , c . From , c .End , c .Limit , c .SleepInterval , c .apiVersion )
72+ records , err := fetchRecords (c .Endpoint , c .From , c .End , c .Limit , c .SleepInterval , c .apiVersion )
6673 if err != nil {
6774 return err
6875 }
6976
70- err = saveRecords (c . Zone , records , c .Output , c .apiVersion )
77+ err = saveRecords (records , c . Zones , c .Output , c .apiVersion )
7178 if err != nil {
7279 return err
7380 }
7481 }
7582 return nil
7683}
7784
78- func saveRecords (zone string , records []Record , output string , version ApiVersion ) error {
85+ func saveRecords (records []Record , zones []string , output string , version ApiVersion ) error {
86+ byZone := make (map [string ][]Record )
87+ for _ , r := range records {
88+ byZone [r .Zone ] = append (byZone [r .Zone ], r )
89+ }
90+
91+ zoneSet := make (map [string ]bool )
92+ for _ , z := range zones {
93+ zoneSet [z ] = true
94+ }
95+
7996 outputs := make (map [string ][]Record )
8097
81- switch version {
82- case ApiV2 :
83- for file , value := range produceOutputs (records , filepath .Join (output , "v2" ), 15 * time .Minute , filepath .Join (zone , "index.json" )) {
84- outputs [file ] = append (outputs [file ], value ... )
98+ for zone , zoneRecords := range byZone {
99+ if ! zoneSet [zone ] {
100+ continue
85101 }
86- fallthrough
87- case ApiV1 :
88- for file , value := range produceOutputs (records , output , 1 * time .Hour , fmt .Sprintf ("%s.json" , zone )) {
89- outputs [file ] = append (outputs [file ], value ... )
102+
103+ stripped := make ([]Record , len (zoneRecords ))
104+ for i , r := range zoneRecords {
105+ stripped [i ] = Record {Euro : r .Euro , Timestamp : r .Timestamp }
106+ }
107+
108+ switch version {
109+ case ApiV2 :
110+ for file , value := range produceOutputs (stripped , filepath .Join (output , "v2" ), 15 * time .Minute , filepath .Join (zone , "index.json" )) {
111+ outputs [file ] = append (outputs [file ], value ... )
112+ }
113+ fallthrough
114+ case ApiV1 :
115+ for file , value := range produceOutputs (stripped , output , 1 * time .Hour , fmt .Sprintf ("%s.json" , zone )) {
116+ outputs [file ] = append (outputs [file ], value ... )
117+ }
90118 }
91119 }
92120
@@ -205,21 +233,21 @@ func updateOutput(file string, records []Record) ([]Record, error) {
205233 return updated , nil
206234}
207235
208- func fetchRecords (endpoint string , zone string , from int64 , end int64 , limit int , sleep int , version ApiVersion ) ([]Record , error ) {
236+ func fetchRecords (endpoint string , from int64 , end int64 , limit int , sleep int , version ApiVersion ) ([]Record , error ) {
209237 var (
210- data = make (map [int64 ]Record )
238+ data = make (map [recordKey ]Record )
211239 records = make ([]Record , 0 )
212240 req string
213241 bytes []byte
214242 err error
215243 items []Record
216244 item Record
217245 size int
218- key int64
246+ key recordKey
219247 )
220248
221249 for from < end {
222- req , err = buildRequest (endpoint , zone , from , end , limit , version )
250+ req , err = buildRequest (endpoint , from , end , limit , version )
223251 if err != nil {
224252 return records , err
225253 }
@@ -236,16 +264,16 @@ func fetchRecords(endpoint string, zone string, from int64, end int64, limit int
236264
237265 size = len (data )
238266 for _ , item = range items {
239- data [item .Timestamp ] = item
267+ data [recordKey { timestamp : item .Timestamp , zone : item . Zone } ] = item
240268 }
241269
242270 if len (data ) == size {
243271 break
244272 }
245273
246274 for key = range data {
247- if key > from {
248- from = key
275+ if key . timestamp > from {
276+ from = key . timestamp
249277 }
250278 }
251279
@@ -261,7 +289,7 @@ func fetchRecords(endpoint string, zone string, from int64, end int64, limit int
261289 return records , nil
262290}
263291
264- func buildRequest (endpoint string , zone string , from int64 , end int64 , limit int , version ApiVersion ) (string , error ) {
292+ func buildRequest (endpoint string , from int64 , end int64 , limit int , version ApiVersion ) (string , error ) {
265293 var (
266294 params = url.Values {}
267295 uri * url.URL
@@ -285,7 +313,6 @@ func buildRequest(endpoint string, zone string, from int64, end int64, limit int
285313 }
286314
287315 params .Add ("end" , time .Unix (end , 0 ).Format ("2006-01-02T15:04" ))
288- params .Add ("filter" , fmt .Sprintf (`{"PriceArea":"%s"}` , zone ))
289316 params .Add ("limit" , strconv .Itoa (limit ))
290317 params .Add ("start" , time .Unix (from , 0 ).Format ("2006-01-02T15:04" ))
291318 params .Add ("timezone" , "UTC" )
@@ -360,7 +387,7 @@ func parseBodyV1(body []byte) ([]Record, error) {
360387 if err != nil {
361388 return records , errors .Join (errConvert , err )
362389 }
363- records = append (records , Record {Euro : item .Euro , Timestamp : stamp .Unix ()})
390+ records = append (records , Record {Euro : item .Euro , Timestamp : stamp .Unix (), Zone : item . Zone })
364391 }
365392
366393 return records , nil
@@ -384,7 +411,7 @@ func parseBodyV2(body []byte) ([]Record, error) {
384411 if err != nil {
385412 return records , errors .Join (errConvert , err )
386413 }
387- records = append (records , Record {Euro : item .Euro , Timestamp : stamp .Unix ()})
414+ records = append (records , Record {Euro : item .Euro , Timestamp : stamp .Unix (), Zone : item . Zone })
388415 }
389416
390417 return records , nil
@@ -398,10 +425,11 @@ const (
398425)
399426
400427type Configuration struct {
401- Zone , Output , Endpoint string
402- From , End , V2Date int64
403- Limit , SleepInterval int
404- apiVersion ApiVersion
428+ Output , Endpoint string
429+ Zones []string
430+ From , End , V2Date int64
431+ Limit , SleepInterval int
432+ apiVersion ApiVersion
405433}
406434
407435func NewConfiguration () Configuration {
@@ -414,7 +442,7 @@ func NewConfiguration() Configuration {
414442}
415443
416444func (f * Configuration ) Validate () error {
417- if len (f .Zone ) == 0 || len (f .Output ) == 0 || f .From == 0 || f .End == 0 {
445+ if len (f .Zones ) == 0 || len (f .Output ) == 0 || f .From == 0 || f .End == 0 {
418446 return fmt .Errorf ("missing flag, provided flags: %s" , os .Args [1 :])
419447 }
420448
@@ -455,9 +483,15 @@ func (c *Configuration) Partitions() ([]Configuration, error) {
455483 return parts , nil
456484}
457485
486+ type recordKey struct {
487+ timestamp int64
488+ zone string
489+ }
490+
458491type Record struct {
459492 Euro float32 `json:"euro"`
460493 Timestamp int64 `json:"timestamp"`
494+ Zone string `json:"zone,omitempty"`
461495}
462496
463497type SpotRecords struct {
@@ -467,6 +501,7 @@ type SpotRecords struct {
467501type SpotRecord struct {
468502 Euro float32 `json:"SpotPriceEUR"`
469503 Timestamp string `json:"HourUTC"`
504+ Zone string `json:"PriceArea"`
470505}
471506
472507type DayAHeadRecords struct {
@@ -476,4 +511,5 @@ type DayAHeadRecords struct {
476511type DayAHeadRecord struct {
477512 Euro float32 `json:"DayAheadPriceEUR"`
478513 Timestamp string `json:"TimeUTC"`
514+ Zone string `json:"PriceArea"`
479515}
0 commit comments