chore: remove dead code (#11451)
This commit is contained in:
parent
0e30e819e6
commit
7fa3d252c9
18 changed files with 6 additions and 699 deletions
|
|
@ -10,10 +10,6 @@ const (
|
|||
|
||||
type UsageChoice string
|
||||
|
||||
func (u UsageChoice) String() string {
|
||||
return string(u)
|
||||
}
|
||||
|
||||
type DeviceCategory string
|
||||
|
||||
func (c DeviceCategory) String() string {
|
||||
|
|
|
|||
|
|
@ -4,27 +4,6 @@ import "github.com/evcc-io/evcc/cmd/detect/tasks"
|
|||
|
||||
type Criteria map[string]interface{}
|
||||
|
||||
func filter(list []tasks.Result, criteria []Criteria) (match []tasks.Result) {
|
||||
for _, res := range list {
|
||||
for _, criterium := range criteria {
|
||||
ok := true
|
||||
|
||||
for matchKey, matchVal := range criterium {
|
||||
if foundVal, found := res.Attributes[matchKey]; !found || foundVal != matchVal {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ok {
|
||||
match = append(match, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return match
|
||||
}
|
||||
|
||||
type TypeSummary struct {
|
||||
Results []tasks.Result
|
||||
Found, Unique bool
|
||||
|
|
@ -33,66 +12,3 @@ type TypeSummary struct {
|
|||
type Summary struct {
|
||||
Charger, Grid, PV, Charge, Battery, Meter TypeSummary
|
||||
}
|
||||
|
||||
func summarize(res []tasks.Result) TypeSummary {
|
||||
return TypeSummary{
|
||||
Results: res,
|
||||
Found: len(res) > 0,
|
||||
Unique: len(res) == 1,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
tid = "task.id"
|
||||
smaHttp = "details.http"
|
||||
)
|
||||
|
||||
func Consolidate(res []tasks.Result) Summary {
|
||||
grid := filter(res, []Criteria{
|
||||
{tid: taskOpenwb},
|
||||
{tid: taskSMA, smaHttp: false},
|
||||
{tid: taskE3DC},
|
||||
{tid: taskSonnen},
|
||||
})
|
||||
|
||||
pv := filter(res, []Criteria{
|
||||
{tid: taskOpenwb},
|
||||
{tid: taskInverter},
|
||||
})
|
||||
|
||||
battery := filter(res, []Criteria{
|
||||
{tid: taskOpenwb},
|
||||
{tid: taskE3DC},
|
||||
{tid: taskSonnen},
|
||||
{tid: taskBattery},
|
||||
})
|
||||
|
||||
charger := filter(res, []Criteria{
|
||||
{tid: taskOpenwb},
|
||||
{tid: taskWallbe},
|
||||
{tid: taskPhoenixEMEth},
|
||||
{tid: taskPhoenixEVEth},
|
||||
{tid: taskEVSEWifi},
|
||||
{tid: taskGoE},
|
||||
{tid: taskKEBA},
|
||||
})
|
||||
|
||||
charge := filter(res, []Criteria{
|
||||
{tid: taskOpenwb},
|
||||
{tid: taskKEBA},
|
||||
})
|
||||
|
||||
meter := filter(res, []Criteria{
|
||||
{tid: taskSMA, smaHttp: true},
|
||||
{tid: taskMeter},
|
||||
})
|
||||
|
||||
return Summary{
|
||||
Grid: summarize(grid),
|
||||
PV: summarize(pv),
|
||||
Battery: summarize(battery),
|
||||
Charger: summarize(charger),
|
||||
Charge: summarize(charge),
|
||||
Meter: summarize(meter),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,6 @@ type Planner struct {
|
|||
tariff api.Tariff
|
||||
}
|
||||
|
||||
// WithClock sets a mockable clock
|
||||
func WithClock(clock clock.Clock) func(t *Planner) {
|
||||
return func(t *Planner) {
|
||||
t.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a price planner
|
||||
func New(log *util.Logger, tariff api.Tariff, opt ...func(t *Planner)) *Planner {
|
||||
p := &Planner{
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
package settings
|
||||
|
||||
import "github.com/evcc-io/evcc/api/store"
|
||||
|
||||
type storer struct {
|
||||
key string
|
||||
}
|
||||
|
||||
var _ store.Store = (*storer)(nil)
|
||||
|
||||
func NewStore(key string) store.Store {
|
||||
return &storer{key: key}
|
||||
}
|
||||
|
||||
func (s *storer) Load(res any) error {
|
||||
return Json(s.key, &res)
|
||||
}
|
||||
|
||||
func (s *storer) Save(val any) error {
|
||||
return SetJson(s.key, val)
|
||||
}
|
||||
|
|
@ -20,22 +20,6 @@ type route struct {
|
|||
HandlerFunc http.HandlerFunc
|
||||
}
|
||||
|
||||
// routeLogger traces matched routes including their executing time
|
||||
//
|
||||
//lint:ignore U1000 if needed
|
||||
func routeLogger(inner http.Handler) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
inner.ServeHTTP(w, r)
|
||||
log.TRACE.Printf(
|
||||
"%s\t%s\t%s",
|
||||
r.Method,
|
||||
r.RequestURI,
|
||||
time.Since(start),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPd wraps an http.Server and adds the root router
|
||||
type HTTPd struct {
|
||||
*http.Server
|
||||
|
|
|
|||
|
|
@ -32,50 +32,3 @@ func Query(query *gojq.Query, input []byte) (interface{}, error) {
|
|||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Float64 converts interface to float64
|
||||
func Float64(v interface{}) (float64, error) {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
return float64(v), nil
|
||||
case float64:
|
||||
return v, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unexpected float type: %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Int64 converts interface to int64
|
||||
func Int64(v interface{}) (int64, error) {
|
||||
switch v := v.(type) {
|
||||
case int:
|
||||
return int64(v), nil
|
||||
case float64:
|
||||
if float64(int64(v)) == v {
|
||||
return int64(v), nil
|
||||
}
|
||||
return 0, fmt.Errorf("unexpected int64: %v", v)
|
||||
default:
|
||||
return 0, fmt.Errorf("unexpected int64 type: %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
// String converts interface to string
|
||||
func String(v interface{}) (string, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return v, nil
|
||||
default:
|
||||
return "", fmt.Errorf("unexpected string type: %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Bool converts interface to bool
|
||||
func Bool(v interface{}) (bool, error) {
|
||||
switch v := v.(type) {
|
||||
case bool:
|
||||
return v, nil
|
||||
default:
|
||||
return false, fmt.Errorf("unexpected bool type: %T", v)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,17 +46,3 @@ func Init() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Localize(lc *Config) string {
|
||||
msg, _, err := Localizer.LocalizeWithTag(lc)
|
||||
if err != nil {
|
||||
msg = lc.MessageID
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func LocalizeID(id string) string {
|
||||
return Localize(&Config{
|
||||
MessageID: id,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,10 @@ import (
|
|||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RTUFloat64ToFloat64(b []byte) float64 {
|
||||
bits := binary.BigEndian.Uint64(b)
|
||||
return math.Float64frombits(bits)
|
||||
}
|
||||
|
||||
// decodeMask converts a bit mask in decimal or hex format to uint64
|
||||
func decodeMask(mask string) (uint64, error) {
|
||||
mask = strings.ToLower(mask)
|
||||
|
|
|
|||
|
|
@ -64,44 +64,6 @@ func (l *Deduplicator) Pipe(in <-chan util.Param) <-chan util.Param {
|
|||
return out
|
||||
}
|
||||
|
||||
// Limiter allows filtering of channel data by given criteria
|
||||
type Limiter struct {
|
||||
clock clock.Clock
|
||||
interval time.Duration
|
||||
cache map[string]cacheItem
|
||||
}
|
||||
|
||||
// NewLimiter creates limiter
|
||||
func NewLimiter(interval time.Duration) Piper {
|
||||
l := &Limiter{
|
||||
clock: clock.New(),
|
||||
interval: interval,
|
||||
cache: make(map[string]cacheItem),
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *Limiter) pipe(in <-chan util.Param, out chan<- util.Param) {
|
||||
for p := range in {
|
||||
key := p.UniqueID()
|
||||
item, cached := l.cache[key]
|
||||
|
||||
// forward if not cached or expired
|
||||
if !cached || l.clock.Since(item.updated) >= l.interval {
|
||||
l.cache[key] = cacheItem{updated: l.clock.Now(), val: p.Val}
|
||||
out <- p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pipe creates a new filtered output channel for given input channel
|
||||
func (l *Limiter) Pipe(in <-chan util.Param) <-chan util.Param {
|
||||
out := make(chan util.Param)
|
||||
go l.pipe(in, out)
|
||||
return out
|
||||
}
|
||||
|
||||
// Dropper allows filtering of channel data by given criteria
|
||||
type Dropper struct {
|
||||
filter []string
|
||||
|
|
|
|||
|
|
@ -9,49 +9,6 @@ import (
|
|||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
func TestLimiter(t *testing.T) {
|
||||
l := NewLimiter(time.Hour).(*Limiter)
|
||||
clck := clock.NewMock()
|
||||
l.clock = clck
|
||||
|
||||
in := make(chan util.Param)
|
||||
out := l.Pipe(in)
|
||||
|
||||
p := util.Param{Key: "k", Val: 1}
|
||||
in <- p
|
||||
|
||||
if o := <-out; o.Key != p.Key || o.Val != p.Val {
|
||||
t.Errorf("unexpected param %v", o)
|
||||
}
|
||||
|
||||
p.Val = 2
|
||||
in <- p
|
||||
|
||||
runtime.Gosched()
|
||||
select {
|
||||
case o := <-out:
|
||||
t.Errorf("unexpected param %v", o)
|
||||
case <-time.After(time.Millisecond):
|
||||
}
|
||||
|
||||
clck.Add(2 * l.interval)
|
||||
p.Val = 3
|
||||
in <- p
|
||||
|
||||
if o := <-out; o.Key != p.Key || o.Val != p.Val {
|
||||
t.Errorf("unexpected param %v", o)
|
||||
}
|
||||
|
||||
// allow nils
|
||||
clck.Add(2 * l.interval)
|
||||
p.Val = nil
|
||||
in <- p
|
||||
|
||||
if o := <-out; o.Key != p.Key || o.Val != p.Val {
|
||||
t.Errorf("unexpected param %v", o)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeduplicator(t *testing.T) {
|
||||
l := NewDeduplicator(time.Hour, "filtered").(*Deduplicator)
|
||||
clck := clock.NewMock()
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@ type StatusError struct {
|
|||
resp *http.Response
|
||||
}
|
||||
|
||||
// NewStatusError create new StatusError for given response
|
||||
func NewStatusError(resp *http.Response) StatusError {
|
||||
return StatusError{resp: resp}
|
||||
}
|
||||
|
||||
func (e StatusError) Error() string {
|
||||
return fmt.Sprintf("unexpected status: %d (%s)", e.resp.StatusCode, http.StatusText(e.resp.StatusCode))
|
||||
}
|
||||
|
|
|
|||
6
vehicle/bluelink/params.go
Normal file
6
vehicle/bluelink/params.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package bluelink
|
||||
|
||||
const (
|
||||
KiaAppID = "a2b8469b-30a3-4361-8e13-6fceea8fbe74"
|
||||
HyundaiAppID = "014d2225-8495-4735-812d-2616334fd15d"
|
||||
)
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
package bluelink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
)
|
||||
|
||||
const (
|
||||
KiaAppID = "a2b8469b-30a3-4361-8e13-6fceea8fbe74"
|
||||
HyundaiAppID = "014d2225-8495-4735-812d-2616334fd15d"
|
||||
)
|
||||
|
||||
type stampCollection struct {
|
||||
mu sync.Mutex
|
||||
log *util.Logger
|
||||
AppID, Brand string
|
||||
Stamps []string
|
||||
Generated time.Time
|
||||
Frequency int
|
||||
updated time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
client = request.NewHelper(util.NewLogger("http"))
|
||||
|
||||
Stamps = map[string]*stampCollection{
|
||||
KiaAppID: {log: util.NewLogger("kia"), AppID: KiaAppID, Brand: "kia"},
|
||||
HyundaiAppID: {log: util.NewLogger("hyundai"), AppID: HyundaiAppID, Brand: "hyundai"},
|
||||
}
|
||||
)
|
||||
|
||||
// New creates a new stamp
|
||||
func (c *stampCollection) Get() (string, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
var position int
|
||||
if c.Frequency > 0 {
|
||||
position = int(time.Since(c.Generated).Milliseconds()) / c.Frequency
|
||||
}
|
||||
|
||||
// download
|
||||
if position >= len(c.Stamps)*9/10 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
position = int(time.Since(c.Generated).Milliseconds()) / c.Frequency
|
||||
}
|
||||
|
||||
if len(c.Stamps) == 0 {
|
||||
return "", errors.New("no stamps available")
|
||||
}
|
||||
|
||||
if position >= len(c.Stamps) {
|
||||
position = len(c.Stamps) - 1
|
||||
}
|
||||
|
||||
return c.Stamps[position], nil
|
||||
}
|
||||
|
||||
// updateStamps updates stamps according to https://github.com/Hacksore/bluelinky/pull/144
|
||||
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)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package ford
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -72,51 +71,3 @@ func (v *API) Vehicles() ([]string, error) {
|
|||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Status performs a /status request
|
||||
func (v *API) Status(vin string) (StatusResponse, error) {
|
||||
uri := fmt.Sprintf("%s/api/vehicles/v5/%s/status", ApiURI, vin)
|
||||
|
||||
var res StatusResponse
|
||||
err := v.GetJSON(uri, &res)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// RefreshResult retrieves a refresh result using /statusrefresh
|
||||
func (v *API) RefreshResult(vin, refreshId string) (StatusResponse, error) {
|
||||
var res StatusResponse
|
||||
|
||||
uri := fmt.Sprintf("%s/api/vehicles/v5/%s/statusrefresh/%s", ApiURI, vin, refreshId)
|
||||
err := v.GetJSON(uri, &res)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// RefreshRequest requests status refresh tracked by commandId
|
||||
func (v *API) RefreshRequest(vin string) (string, error) {
|
||||
var resp struct {
|
||||
CommandId string
|
||||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/api/vehicles/v5/%s/status", ApiURI, vin)
|
||||
req, err := http.NewRequest(http.MethodPut, uri, nil)
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, &resp)
|
||||
}
|
||||
|
||||
if err == nil && resp.CommandId == "" {
|
||||
err = errors.New("refresh failed")
|
||||
}
|
||||
|
||||
return resp.CommandId, err
|
||||
}
|
||||
|
||||
// WakeUp performs a wakeup request
|
||||
func (v *API) WakeUp(vin string) error {
|
||||
uri := fmt.Sprintf("%s/api/dashboard/v1/users/vehicles?wakeupVin=%s", TokenURI, vin)
|
||||
|
||||
_, err := v.GetBody(uri)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
package ford
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type VehiclesResponse struct {
|
||||
UserVehicles struct {
|
||||
VehicleDetails []struct {
|
||||
|
|
@ -12,60 +7,3 @@ type VehiclesResponse struct {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StatusResponse is the response to the vehicle status request
|
||||
type StatusResponse struct {
|
||||
VehicleStatus struct {
|
||||
BatteryFillLevel struct {
|
||||
Value float64
|
||||
Timestamp Timestamp
|
||||
}
|
||||
ElVehDTE struct {
|
||||
Value float64
|
||||
Timestamp Timestamp
|
||||
}
|
||||
ChargingStatus struct {
|
||||
Value string
|
||||
Timestamp Timestamp
|
||||
}
|
||||
ChargeEndTime struct {
|
||||
Value Timestamp
|
||||
Timestamp Timestamp
|
||||
}
|
||||
PlugStatus struct {
|
||||
Value int
|
||||
Timestamp Timestamp
|
||||
}
|
||||
Odometer struct {
|
||||
Value float64
|
||||
Timestamp Timestamp
|
||||
}
|
||||
Gps struct {
|
||||
Latitude float64 `json:",string"`
|
||||
Longitude float64 `json:",string"`
|
||||
GpsState string
|
||||
Timestamp Timestamp
|
||||
}
|
||||
LastRefresh Timestamp
|
||||
}
|
||||
Status int
|
||||
}
|
||||
|
||||
const TimeFormat = "01-02-2006 15:04:05" // time format used by Ford API, time is in UTC
|
||||
|
||||
// Timestamp implements JSON unmarshal
|
||||
type Timestamp struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes string timestamp into time.Time
|
||||
func (ct *Timestamp) UnmarshalJSON(data []byte) error {
|
||||
s := strings.Trim(string(data), "\"")
|
||||
|
||||
t, err := time.Parse(TimeFormat, s)
|
||||
if err == nil {
|
||||
ct.Time = t
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,177 +0,0 @@
|
|||
package connected
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/evcc-io/evcc/provider"
|
||||
"github.com/evcc-io/evcc/server/auth"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type IdentityOptions func(c *Identity) error
|
||||
|
||||
// // WithToken provides an oauth2.Token to the client for auth.
|
||||
// func WithToken(t *oauth2.Token) IdentityOptions {
|
||||
// return func(v *Identity) error {
|
||||
// v.ReuseTokenSource.Apply(t)
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
|
||||
type Identity struct {
|
||||
log *util.Logger
|
||||
*request.Helper
|
||||
*ReuseTokenSource
|
||||
oc *oauth2.Config
|
||||
baseURL string
|
||||
authC chan<- bool
|
||||
}
|
||||
|
||||
// TODO SessionSecret from config/persistence
|
||||
func NewIdentity(log *util.Logger, id, secret string, options ...IdentityOptions) (*Identity, error) {
|
||||
// provider, err := oidc.NewProvider(context.Background(), "https://id.mercedes-benz.com")
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("failed to initialize OIDC provider: %s", err)
|
||||
// }
|
||||
|
||||
oc := &oauth2.Config{
|
||||
ClientID: id,
|
||||
ClientSecret: secret,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: "https://volvoid.eu.volvocars.com/as/authorization.oauth2",
|
||||
TokenURL: "https://volvoid.eu.volvocars.com/as/token.oauth2",
|
||||
},
|
||||
Scopes: []string{oidc.ScopeOpenID, "conve:fuel_status", "conve:odometer_status", "conve:environment"},
|
||||
}
|
||||
|
||||
v := &Identity{
|
||||
log: log,
|
||||
Helper: request.NewHelper(log),
|
||||
oc: oc,
|
||||
}
|
||||
|
||||
ts := &ReuseTokenSource{
|
||||
oc: oc,
|
||||
cb: v.invalidToken,
|
||||
}
|
||||
ts.Apply(nil)
|
||||
|
||||
v.ReuseTokenSource = ts
|
||||
|
||||
// for _, o := range options {
|
||||
// if err == nil {
|
||||
// err = o(v)
|
||||
// }
|
||||
// }
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (v *Identity) Login(user, password string) error {
|
||||
oc := v.ReuseTokenSource.oc
|
||||
data := url.Values{
|
||||
"username": {user},
|
||||
"password": {password},
|
||||
"access_token_manager_id": {"JWTh4Yf0b"},
|
||||
"grant_type": {"password"},
|
||||
"scope": oc.Scopes,
|
||||
}
|
||||
|
||||
req, err := request.New(http.MethodPost, oc.Endpoint.AuthURL, strings.NewReader(data.Encode()), map[string]string{
|
||||
"Content-Type": request.FormContent,
|
||||
"Authorization": "Basic aDRZZjBiOlU4WWtTYlZsNnh3c2c1WVFxWmZyZ1ZtSWFEcGhPc3kxUENhVXNpY1F0bzNUUjVrd2FKc2U0QVpkZ2ZJZmNMeXc=",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var res string
|
||||
err = v.DoJSON(req, &res)
|
||||
|
||||
os.Exit(1)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// invalidToken is the callback for the token source when token expires
|
||||
func (v *Identity) invalidToken() {
|
||||
if v.authC != nil {
|
||||
v.authC <- false
|
||||
}
|
||||
}
|
||||
|
||||
// var _ api.ProviderLogin = (*Identity)(nil)
|
||||
|
||||
func (v *Identity) SetCallbackParams(baseURL, redirectURL string, authC chan<- bool) {
|
||||
v.baseURL = baseURL
|
||||
v.oc.RedirectURL = redirectURL
|
||||
v.authC = authC
|
||||
}
|
||||
|
||||
func (v *Identity) LoginHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
state := auth.Register(v.callbackHandler)
|
||||
|
||||
fmt.Println(v.oc.AuthCodeURL(state))
|
||||
|
||||
b, _ := json.Marshal(struct {
|
||||
LoginUri string `json:"loginUri"`
|
||||
}{
|
||||
LoginUri: v.oc.AuthCodeURL(state), //, oauth2.AccessTypeOffline), // oauth2.SetAuthURLParam("prompt", "login consent"),
|
||||
})
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Identity) LogoutHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v.ReuseTokenSource.Apply(nil)
|
||||
v.authC <- false
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Identity) callbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
v.log.TRACE.Println("callback request retrieved")
|
||||
|
||||
data, err := url.ParseQuery(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
fmt.Fprintln(w, "invalid response:", data)
|
||||
return
|
||||
}
|
||||
|
||||
codes, ok := data["code"]
|
||||
if !ok || len(codes) != 1 {
|
||||
fmt.Fprintln(w, "invalid response:", data)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := v.oc.Exchange(context.Background(), codes[0])
|
||||
if err != nil {
|
||||
fmt.Fprintln(w, "token error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
if token.Valid() {
|
||||
v.log.TRACE.Println("sending login update...")
|
||||
v.ReuseTokenSource.Apply(token)
|
||||
v.authC <- true
|
||||
|
||||
provider.ResetCached()
|
||||
}
|
||||
|
||||
http.Redirect(w, r, v.baseURL, http.StatusFound)
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package connected
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type ReuseTokenSource struct {
|
||||
mu sync.Mutex
|
||||
oc *oauth2.Config
|
||||
ts oauth2.TokenSource
|
||||
cb func()
|
||||
}
|
||||
|
||||
func (ts *ReuseTokenSource) Token() (*oauth2.Token, error) {
|
||||
ts.mu.Lock()
|
||||
defer ts.mu.Unlock()
|
||||
|
||||
t, err := ts.ts.Token()
|
||||
if err != nil || !t.Valid() {
|
||||
// invalid token callback
|
||||
ts.cb()
|
||||
}
|
||||
|
||||
return t, err
|
||||
}
|
||||
|
||||
func (ts *ReuseTokenSource) Apply(t *oauth2.Token) {
|
||||
ts.mu.Lock()
|
||||
ts.ts = ts.oc.TokenSource(context.Background(), t)
|
||||
ts.mu.Unlock()
|
||||
}
|
||||
|
|
@ -41,17 +41,6 @@ func NewAPI(log *util.Logger, ts oauth2.TokenSource, brand, country string) *API
|
|||
return v
|
||||
}
|
||||
|
||||
// Vehicles implements the /vehicles response
|
||||
func (v *API) Vehicles() ([]string, error) {
|
||||
var res VehiclesResponse
|
||||
uri := fmt.Sprintf("%s/usermanagement/users/v1/%s/%s/vehicles", v.baseURI, v.brand, v.country)
|
||||
err := v.GetJSON(uri, &res)
|
||||
if err != nil && res.Error != nil {
|
||||
err = res.Error.Error()
|
||||
}
|
||||
return res.UserVehicles.Vehicle, err
|
||||
}
|
||||
|
||||
// HomeRegion updates the home region for the given vehicle
|
||||
func (v *API) HomeRegion(vin string) error {
|
||||
var res HomeRegion
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue