/* * Copyright (c) 2018 Jeffrey Walter * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package arlo import ( "context" "fmt" "sync" "time" "github.com/go-resty/resty/v2" ) type Arlo struct { user string pass string client *resty.Client Account Account Basestations Basestations Cameras Cameras rwmutex sync.RWMutex } func NewArlo() (arlo *Arlo) { c := resty.New(). SetHostURL(BaseUrl). SetTimeout(30 * time.Second) return &Arlo{ client: c, } } func (a *Arlo) Login(ctx context.Context, user string, pass string) error { var loginResponse LoginResponse _, err := a.client.R(). SetBody(map[string]string{ "email": user, "password": pass, }). SetResult(&loginResponse). // or SetResult(AuthSuccess{}). Post(LoginV2Uri) if err != nil { return fmt.Errorf("failed to login: %v", err) } if !loginResponse.Success { return fmt.Errorf("failed to login") } // Cache the auth token. a.client.SetHeader("Authorization", loginResponse.Data.Token) // Save the account info with the arlo struct. a.Account = loginResponse.Data // Get the devices, which also caches them on the arlo object. if _, err := a.GetDevices(ctx); err != nil { return fmt.Errorf("getting devices: %v", err) } return nil } func (a *Arlo) Logout() error { var response Status _, err := a.client.R(). SetResult(&response). Put(LogoutUri) if err != nil { return fmt.Errorf("logging out: %v", err) } if response.Success == false { return fmt.Errorf("logging out: %s", response.Reason) } return nil } func (a *Arlo) GetSession() (*Session, error) { var response SessionResponse _, err := a.client.R(). SetResult(&response). Get(SessionUri) if err != nil { return nil, fmt.Errorf("getting session: %v", err) } if response.Success == false { return nil, fmt.Errorf("getting session: %s", response.Reason) } return &response.Data, nil } func (a *Arlo) GetDevices(ctx context.Context) (*Devices, error) { var response DeviceResponse _, err := a.client.R(). SetResult(&response). Get(fmt.Sprintf(DevicesUri, time.Now().Format("20060102"))) if err != nil { return nil, fmt.Errorf("getting devices: %v", err) } if !response.Success { return nil, fmt.Errorf("failed to get devices") } if len(response.Data) == 0 { return nil, fmt.Errorf("no device found") } // Cache a pointer to the arlo object with each device. for i := range response.Data { response.Data[i].arlo = a } // Disconnect all of the basestations from the EventStream. for _, basestation := range a.Basestations { if err := basestation.Disconnect(); err != nil { return nil, fmt.Errorf("disconnecting device %s: %v", basestation.DeviceName, err) } } a.rwmutex.Lock() // Cache the devices as their respective types. a.Cameras = response.Data.GetCameras() a.Basestations = response.Data.GetBasestations() a.rwmutex.Unlock() // subscribe each basestation to the EventStream. for _, basestation := range a.Basestations { if err := basestation.Subscribe(ctx); err != nil { return nil, fmt.Errorf("subscribing device %s: %v", basestation.DeviceName, err) } } return &response.Data, nil } // GetProfile returns the user profile for the currently logged in user. func (a *Arlo) GetProfile() (*UserProfile, error) { var response UserProfileResponse _, err := a.client.R(). SetResult(&response). Get(ProfileUri) if err != nil { return nil, fmt.Errorf("getting user profile: %v", err) } if response.Success == false { return nil, fmt.Errorf("getting user profile: %s", response.Reason) } return &response.Data, nil } //// UpdateDisplayOrder sets the display order according to the order defined in the DeviceOrder given. //func (a *Arlo) UpdateDisplayOrder(d DeviceOrder) error { // resp, err := a.post(CameraOrderUri, "", d, nil) // return checkRequest(resp, err, "failed to display order") //} // //// UpdateProfile takes a first and last name, and updates the user profile with that information. //func (a *Arlo) UpdateProfile(firstName, lastName string) error { // body := map[string]string{"firstName": firstName, "lastName": lastName} // resp, err := a.put(ProfileUri, "", body, nil) // return checkRequest(resp, err, "failed to update profile") //} // //func (a *Arlo) UpdatePassword(pass string) error { // body := map[string]string{"currentPassword": a.pass, "newPassword": pass} // resp, err := a.post(UpdatePasswordUri, "", body, nil) // if err := checkRequest(resp, err, "failed to update password"); err != nil { // return err // } // // a.pass = pass // // return nil //} // //func (a *Arlo) UpdateFriends(f Friend) error { // resp, err := a.put(FriendsUri, "", f, nil) // return checkRequest(resp, err, "failed to update friends") //}