2018-09-19 07:07:32 +00:00
|
|
|
package arlo
|
2017-12-10 19:17:09 +00:00
|
|
|
|
|
|
|
import (
|
2020-05-27 08:49:40 +00:00
|
|
|
"context"
|
2018-12-11 23:48:51 +00:00
|
|
|
"fmt"
|
2018-09-22 14:15:22 +00:00
|
|
|
"sync"
|
2018-12-11 23:48:51 +00:00
|
|
|
"time"
|
2018-09-22 14:15:22 +00:00
|
|
|
|
2020-05-27 08:49:40 +00:00
|
|
|
"github.com/go-resty/resty/v2"
|
2017-12-10 19:17:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Arlo struct {
|
|
|
|
user string
|
|
|
|
pass string
|
2020-05-27 08:49:40 +00:00
|
|
|
client *resty.Client
|
2018-09-17 04:44:41 +00:00
|
|
|
Account Account
|
|
|
|
Basestations Basestations
|
|
|
|
Cameras Cameras
|
2018-09-22 14:15:22 +00:00
|
|
|
rwmutex sync.RWMutex
|
2017-12-10 19:17:09 +00:00
|
|
|
}
|
|
|
|
|
2020-05-27 08:49:40 +00:00
|
|
|
func NewArlo() (arlo *Arlo) {
|
2018-09-22 19:22:42 +00:00
|
|
|
|
2020-05-27 08:49:40 +00:00
|
|
|
c := resty.New().
|
|
|
|
SetHostURL(BaseUrl).
|
|
|
|
SetTimeout(30 * time.Second)
|
2018-09-19 19:12:06 +00:00
|
|
|
|
|
|
|
return &Arlo{
|
2017-12-10 19:17:09 +00:00
|
|
|
client: c,
|
|
|
|
}
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:35:02 +00:00
|
|
|
func (a *Arlo) get(url string, result interface{}) error {
|
|
|
|
var errorResponse ErrorResponse
|
|
|
|
resp, err := a.client.R().
|
|
|
|
SetResult(result).
|
|
|
|
SetError(&errorResponse).
|
|
|
|
Get(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if resp.IsError() {
|
|
|
|
return fmt.Errorf(errorResponse.Reason)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Arlo) post(url string, body interface{}, result interface{}, xcloudId string) error {
|
|
|
|
var errorResponse ErrorResponse
|
|
|
|
request := a.client.R().
|
|
|
|
SetBody(body).
|
|
|
|
SetResult(result).
|
|
|
|
SetError(&errorResponse)
|
|
|
|
if xcloudId != "" {
|
|
|
|
request.SetHeader("xcloudId", xcloudId)
|
|
|
|
}
|
|
|
|
resp, err := request.Post(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if resp.IsError() {
|
|
|
|
return fmt.Errorf(errorResponse.Reason)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Arlo) put(url string, result interface{}, xcloudId string) error {
|
|
|
|
var errorResponse ErrorResponse
|
|
|
|
request := a.client.R().
|
|
|
|
SetResult(result).
|
|
|
|
SetError(&errorResponse)
|
|
|
|
if xcloudId != "" {
|
|
|
|
request.SetHeader("xcloudId", xcloudId)
|
|
|
|
}
|
|
|
|
resp, err := request.Put(url)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if resp.IsError() {
|
|
|
|
return fmt.Errorf(errorResponse.Reason)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-27 08:49:40 +00:00
|
|
|
func (a *Arlo) Login(ctx context.Context, user string, pass string) error {
|
|
|
|
var loginResponse LoginResponse
|
2020-05-27 11:35:02 +00:00
|
|
|
err := a.post(LoginV2Uri, map[string]string{
|
|
|
|
"email": user,
|
|
|
|
"password": pass,
|
|
|
|
}, &loginResponse, "")
|
2018-09-22 19:22:42 +00:00
|
|
|
if err != nil {
|
2020-05-27 11:35:02 +00:00
|
|
|
return fmt.Errorf("posting login request: %v", err)
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2020-05-27 08:49:40 +00:00
|
|
|
if !loginResponse.Success {
|
2020-05-27 11:35:02 +00:00
|
|
|
return fmt.Errorf("no success but no error")
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2020-05-27 08:49:40 +00:00
|
|
|
a.client.SetHeader("Authorization", loginResponse.Data.Token)
|
|
|
|
a.Account = loginResponse.Data
|
|
|
|
if _, err := a.GetDevices(ctx); err != nil {
|
|
|
|
return fmt.Errorf("getting devices: %v", err)
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2020-05-27 08:49:40 +00:00
|
|
|
return nil
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Arlo) Logout() error {
|
|
|
|
|
2020-05-27 11:35:02 +00:00
|
|
|
var response BaseResponse
|
|
|
|
err := a.put(LogoutUri, &response, "")
|
2018-12-11 23:48:51 +00:00
|
|
|
if err != nil {
|
2020-05-27 11:35:02 +00:00
|
|
|
return err
|
2020-05-27 08:49:40 +00:00
|
|
|
}
|
2020-05-27 11:35:02 +00:00
|
|
|
if !response.Success {
|
|
|
|
return fmt.Errorf("no success but no error")
|
2018-12-11 23:48:51 +00:00
|
|
|
}
|
2020-05-27 08:49:40 +00:00
|
|
|
return nil
|
|
|
|
}
|
2018-12-11 23:48:51 +00:00
|
|
|
|
2020-05-27 08:49:40 +00:00
|
|
|
func (a *Arlo) GetSession() (*Session, error) {
|
2018-12-11 23:48:51 +00:00
|
|
|
var response SessionResponse
|
2020-05-27 11:35:02 +00:00
|
|
|
err := a.get(SessionUri, &response)
|
2020-05-27 08:49:40 +00:00
|
|
|
if err != nil {
|
2020-05-27 11:35:02 +00:00
|
|
|
return nil, err
|
2018-12-11 23:48:51 +00:00
|
|
|
}
|
2020-05-27 11:35:02 +00:00
|
|
|
if !response.Success {
|
|
|
|
return nil, fmt.Errorf("no success but no error")
|
2018-12-11 23:48:51 +00:00
|
|
|
}
|
|
|
|
return &response.Data, nil
|
|
|
|
}
|
|
|
|
|
2020-05-27 08:49:40 +00:00
|
|
|
func (a *Arlo) GetDevices(ctx context.Context) (*Devices, error) {
|
2018-12-11 23:48:51 +00:00
|
|
|
var response DeviceResponse
|
2020-05-27 11:35:02 +00:00
|
|
|
err := a.get(fmt.Sprintf(DevicesUri, time.Now().Format("20060102")), &response)
|
2020-05-27 08:49:40 +00:00
|
|
|
if err != nil {
|
2020-05-27 11:35:02 +00:00
|
|
|
return nil, err
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2018-12-11 23:48:51 +00:00
|
|
|
if !response.Success {
|
2020-05-27 11:35:02 +00:00
|
|
|
return nil, fmt.Errorf("no success but no error")
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2018-12-11 23:48:51 +00:00
|
|
|
if len(response.Data) == 0 {
|
2020-05-27 08:49:40 +00:00
|
|
|
return nil, fmt.Errorf("no device found")
|
2018-09-20 22:38:01 +00:00
|
|
|
}
|
|
|
|
|
2018-09-22 19:22:42 +00:00
|
|
|
// Cache a pointer to the arlo object with each device.
|
2018-12-11 23:48:51 +00:00
|
|
|
for i := range response.Data {
|
|
|
|
response.Data[i].arlo = a
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
|
|
|
|
2018-09-22 19:22:42 +00:00
|
|
|
// Disconnect all of the basestations from the EventStream.
|
2020-05-27 08:49:40 +00:00
|
|
|
for _, basestation := range a.Basestations {
|
|
|
|
if err := basestation.Disconnect(); err != nil {
|
|
|
|
return nil, fmt.Errorf("disconnecting device %s: %v", basestation.DeviceName, err)
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2018-09-19 21:35:05 +00:00
|
|
|
}
|
2018-09-19 19:12:06 +00:00
|
|
|
|
2018-09-22 14:15:22 +00:00
|
|
|
a.rwmutex.Lock()
|
2018-09-19 21:35:05 +00:00
|
|
|
// Cache the devices as their respective types.
|
2020-05-27 08:49:40 +00:00
|
|
|
a.Cameras = response.Data.GetCameras()
|
|
|
|
a.Basestations = response.Data.GetBasestations()
|
2018-09-22 14:15:22 +00:00
|
|
|
a.rwmutex.Unlock()
|
2018-09-19 21:35:05 +00:00
|
|
|
|
2018-09-22 14:15:22 +00:00
|
|
|
// subscribe each basestation to the EventStream.
|
2020-05-27 08:49:40 +00:00
|
|
|
for _, basestation := range a.Basestations {
|
|
|
|
if err := basestation.Subscribe(ctx); err != nil {
|
|
|
|
return nil, fmt.Errorf("subscribing device %s: %v", basestation.DeviceName, err)
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
|
|
|
}
|
2018-12-11 23:48:51 +00:00
|
|
|
return &response.Data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetProfile returns the user profile for the currently logged in user.
|
2020-05-27 08:49:40 +00:00
|
|
|
func (a *Arlo) GetProfile() (*UserProfile, error) {
|
2018-12-11 23:48:51 +00:00
|
|
|
var response UserProfileResponse
|
2020-05-27 11:35:02 +00:00
|
|
|
err := a.get(ProfileUri, &response)
|
2020-05-27 08:49:40 +00:00
|
|
|
if err != nil {
|
2020-05-27 11:35:02 +00:00
|
|
|
return nil, err
|
2018-12-11 23:48:51 +00:00
|
|
|
}
|
2020-05-27 11:35:02 +00:00
|
|
|
if !response.Success {
|
|
|
|
return nil, fmt.Errorf("no success but no error")
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|
2020-05-27 08:49:40 +00:00
|
|
|
return &response.Data, nil
|
2018-09-19 19:12:06 +00:00
|
|
|
}
|