From 6787bd464e5afc9fcf1fcd6d5c0cd2d65ac6fea2 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 19 Mar 2022 12:00:28 +0100 Subject: [PATCH] Bluelink: fix handling of stamps (#2936) --- vehicle/bluelink/identity.go | 23 ++++----- vehicle/bluelink/stamps.go | 96 ++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 64 deletions(-) diff --git a/vehicle/bluelink/identity.go b/vehicle/bluelink/identity.go index cee730879..4c145c98b 100644 --- a/vehicle/bluelink/identity.go +++ b/vehicle/bluelink/identity.go @@ -55,19 +55,15 @@ func NewIdentity(log *util.Logger, config Config) *Identity { config: config, } - // fetch updated stamps - updateStamps(log, config.CCSPApplicationID) - return v } -// Credits to https://openwb.de/forum/viewtopic.php?f=5&t=1215&start=10#p11877 - -func (v *Identity) stamp() string { - return Stamps.New(v.config.CCSPApplicationID) -} - func (v *Identity) getDeviceID() (string, error) { + stamp, err := Stamps[v.config.CCSPApplicationID].Get() + if err != nil { + return "", err + } + uniID, _ := uuid.NewUUID() data := map[string]interface{}{ "pushRegId": "1", @@ -79,7 +75,7 @@ func (v *Identity) getDeviceID() (string, error) { "ccsp-service-id": v.config.CCSPServiceID, "Content-type": "application/json;charset=UTF-8", "User-Agent": "okhttp/3.10.0", - "Stamp": v.stamp(), + "Stamp": stamp, } var resp struct { @@ -362,6 +358,11 @@ func (v *Identity) Login(user, password, language string) (err error) { // Request decorates requests with authorization headers func (v *Identity) Request(req *http.Request) error { + stamp, err := Stamps[v.config.CCSPApplicationID].Get() + if err != nil { + return err + } + token, err := v.Token() if err != nil { return err @@ -373,7 +374,7 @@ func (v *Identity) Request(req *http.Request) error { "ccsp-application-id": v.config.CCSPApplicationID, "offset": "1", "User-Agent": "okhttp/3.10.0", - "Stamp": v.stamp(), + "Stamp": stamp, } { req.Header.Set(k, v) } diff --git a/vehicle/bluelink/stamps.go b/vehicle/bluelink/stamps.go index b369d580f..fcf4e949b 100644 --- a/vehicle/bluelink/stamps.go +++ b/vehicle/bluelink/stamps.go @@ -15,72 +15,62 @@ const ( HyundaiAppID = "014d2225-8495-4735-812d-2616334fd15d" ) -// StampsRegistry collects stamps for a single brand -type StampsRegistry map[string]*StampCollection - -type StampCollection struct { - Stamps []string - Generated time.Time - Frequency float64 -} - -var Stamps = StampsRegistry{ - KiaAppID: nil, - HyundaiAppID: nil, +type stampCollection struct { + mu sync.Mutex + log *util.Logger + AppID, Brand string + Stamps []string + Generated time.Time + Frequency float64 + updated time.Time } var ( - mu sync.Mutex - updater map[string]struct{} = make(map[string]struct{}) - client = request.NewHelper(util.NewLogger("http")) - brands = map[string]string{ - KiaAppID: "kia", - HyundaiAppID: "hyundai", + + Stamps = map[string]*stampCollection{ + KiaAppID: {log: util.NewLogger("kia"), AppID: KiaAppID, Brand: "kia"}, + HyundaiAppID: {log: util.NewLogger("hyundai"), AppID: HyundaiAppID, Brand: "hyundai"}, } ) -func download(log *util.Logger, id, brand string) { - var res StampCollection - uri := fmt.Sprintf("https://raw.githubusercontent.com/neoPix/bluelinky-stamps/master/%s-%s.v2.json", brand, id) +// New creates a new stamp +func (c *stampCollection) Get() (string, error) { + c.mu.Lock() + defer c.mu.Unlock() - if err := client.GetJSON(uri, &res); err != nil { - log.ERROR.Println(err) - return + length := float64(len(c.Stamps)) + position := float64(time.Since(c.Generated).Milliseconds()) / c.Frequency + + // download + if position >= 0.9*length { + if time.Since(c.updated) > 15*time.Minute { + c.log.TRACE.Printf("retry stamps download, last attempt: %v", c.updated) + if err := c.download(); err != nil { + return "", err + } + } + + length = float64(len(c.Stamps)) + position = float64(time.Since(c.Generated).Milliseconds()) / c.Frequency } - mu.Lock() - Stamps[id] = &res - mu.Unlock() + if position >= length { + position = length - 1 + } + + return c.Stamps[int64(position+5*rand.Float64())], nil } // updateStamps updates stamps according to https://github.com/Hacksore/bluelinky/pull/144 -func updateStamps(log *util.Logger, id string) { - if _, ok := updater[id]; ok { - return +func (c *stampCollection) download() error { + c.updated = time.Now() + + uri := fmt.Sprintf("https://raw.githubusercontent.com/neoPix/bluelinky-stamps/master/%s-%s.v2.json", c.Brand, c.AppID) + + if err := client.GetJSON(uri, &c); err != nil { + return fmt.Errorf("failed to download stamps: %w", err) } - updater[id] = struct{}{} - download(log, id, brands[id]) - - go func() { - for range time.NewTicker(24 * time.Hour).C { - download(log, id, brands[id]) - } - }() -} - -// New creates a new stamp -func (s StampsRegistry) New(id string) string { - mu.Lock() - defer mu.Unlock() - - source := s[id] - if source == nil { - panic(id) - } - - position := float64(time.Since(source.Generated).Milliseconds()) / source.Frequency - - return source.Stamps[int64(position+5*rand.Float64())] + return nil }