(WIP) Arlo client written in Go.
This commit is contained in:
parent
50bc5bf56e
commit
2589b868a7
18
account.go
Normal file
18
account.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package arloclient
|
||||||
|
|
||||||
|
// Account is the account data.
|
||||||
|
type Account struct {
|
||||||
|
UserId string `json:"userId"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
PaymentId string `json:"paymentId"`
|
||||||
|
Authenticated uint32 `json:"authenticated"`
|
||||||
|
AccountStatus string `json:"accountStatus"`
|
||||||
|
SerialNumber string `json:"serialNumber"`
|
||||||
|
CountryCode string `json:"countryCode"`
|
||||||
|
TocUpdate bool `json:"tocUpdate"`
|
||||||
|
PolicyUpdate bool `json:"policyUpdate"`
|
||||||
|
ValidEmail bool `json:"validEmail"`
|
||||||
|
Arlo bool `json:"arlo"`
|
||||||
|
DateCreated float64 `json:"dateCreated"`
|
||||||
|
}
|
286
arloclient.go
286
arloclient.go
@ -1,12 +1,11 @@
|
|||||||
package arloclient
|
package arloclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jeffreydwalter/arloclient/internal/request"
|
"github.com/jeffreydwalter/arloclient/internal/request"
|
||||||
|
"github.com/jeffreydwalter/arloclient/internal/util"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,10 +13,11 @@ type Arlo struct {
|
|||||||
user string
|
user string
|
||||||
pass string
|
pass string
|
||||||
client *request.Client
|
client *request.Client
|
||||||
account Account
|
Account *Account
|
||||||
|
Devices *Devices
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArlo(user string, pass string) (*Arlo, error) {
|
func newArlo(user string, pass string) *Arlo {
|
||||||
|
|
||||||
c, _ := request.NewClient(BaseUrl)
|
c, _ := request.NewClient(BaseUrl)
|
||||||
arlo := &Arlo{
|
arlo := &Arlo{
|
||||||
@ -26,190 +26,240 @@ func NewArlo(user string, pass string) (*Arlo, error) {
|
|||||||
client: c,
|
client: c,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := arlo.Login(); err != nil {
|
return arlo
|
||||||
return nil, errors.WithMessage(err, "failed to create arlo object")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return arlo, nil
|
func Login(user string, pass string) (*Arlo, error) {
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Arlo) Login() (*Account, error) {
|
a := newArlo(user, pass)
|
||||||
|
|
||||||
|
body := map[string]string{"email": a.user, "password": a.pass}
|
||||||
|
resp, err := a.client.Post(LoginUri, body, nil)
|
||||||
|
|
||||||
resp, err := a.client.Post(LoginUri, Credentials{Email: a.user, Password: a.pass}, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to login")
|
return nil, errors.WithMessage(err, "login request failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
var loginResponse LoginResponse
|
var loginResponse LoginResponse
|
||||||
if err := mapstructure.Decode(resp.Data, &loginResponse); err != nil {
|
if err := util.Decode(resp.ParsedBody, &loginResponse); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to create loginresponse object")
|
return nil, err
|
||||||
}
|
|
||||||
|
|
||||||
if !loginResponse.Success {
|
|
||||||
return nil, errors.New("request was unsuccessful")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if loginResponse.Success {
|
||||||
// Cache the auth token.
|
// Cache the auth token.
|
||||||
a.client.BaseHttpHeader.Add("Authorization", loginResponse.Data.Token)
|
a.client.BaseHttpHeader.Add("Authorization", loginResponse.Data.Token)
|
||||||
|
|
||||||
// Save the account info with the Arlo struct.
|
// Save the account info with the Arlo struct.
|
||||||
a.account = loginResponse.Data
|
a.Account = &loginResponse.Data
|
||||||
|
|
||||||
return &loginResponse.Data, nil
|
if deviceResponse, err := a.GetDevices(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
if !deviceResponse.Success {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
a.Devices = &deviceResponse.Data
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("failed to login")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Arlo) Logout() (*request.Response, error) {
|
return a, nil
|
||||||
|
|
||||||
return a.client.Put(LogoutUri, nil, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Arlo) GetDevices() (*Devices, error) {
|
func (a *Arlo) Logout() (*Status, error) {
|
||||||
|
|
||||||
|
resp, err := a.client.Put(LogoutUri, nil, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "logout request failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
var status Status
|
||||||
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Arlo) GetDevices() (*DeviceResponse, error) {
|
||||||
|
|
||||||
resp, err := a.client.Get(DevicesUri, nil)
|
resp, err := a.client.Get(DevicesUri, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to get devices")
|
return nil, errors.WithMessage(err, "get devices request failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
var deviceResponse DeviceResponse
|
var deviceResponse DeviceResponse
|
||||||
if err := mapstructure.Decode(resp.Data, &deviceResponse); err != nil {
|
if err := util.Decode(resp.ParsedBody, &deviceResponse); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to create deviceresponse object")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !deviceResponse.Success {
|
return &deviceResponse, nil
|
||||||
return nil, errors.New("request was unsuccessful")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &deviceResponse.Data, nil
|
func (a *Arlo) GetLibraryMetaData(fromDate, toDate time.Time) (*LibraryMetaDataResponse, error) {
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Arlo) GetLibraryMetaData(fromDate, toDate time.Time) (*LibraryMetaData, error) {
|
body := map[string]string{"dateFrom": fromDate.Format("20060102"), "dateTo": toDate.Format("20060102")}
|
||||||
|
resp, err := a.client.Post(LibraryMetadataUri, body, nil)
|
||||||
resp, err := a.client.Post(LibraryMetadataUri, Duration{fromDate.Format("20060102"), toDate.Format("20060102")}, nil)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to get library metadata")
|
return nil, errors.WithMessage(err, "failed to get library metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("GETLIBRARYMETADATA: %v", resp.Data)
|
|
||||||
|
|
||||||
var libraryMetaDataResponse LibraryMetaDataResponse
|
var libraryMetaDataResponse LibraryMetaDataResponse
|
||||||
if err := mapstructure.Decode(resp.Data, &libraryMetaDataResponse); err != nil {
|
if err := util.Decode(resp.ParsedBody, &libraryMetaDataResponse); err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to create librarymetadataresponse object")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !libraryMetaDataResponse.Success {
|
return &libraryMetaDataResponse, nil
|
||||||
return nil, errors.New("request was unsuccessful")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &libraryMetaDataResponse.Data, nil
|
func (a *Arlo) GetLibrary(fromDate, toDate time.Time) (*LibraryResponse, error) {
|
||||||
|
|
||||||
|
body := map[string]string{"dateFrom": fromDate.Format("20060102"), "dateTo": toDate.Format("20060102")}
|
||||||
|
resp, err := a.client.Post(LibraryUri, body, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to get library")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Arlo) UpdateProfile(firstName, lastName string) (*UserProfile, error) {
|
var libraryResponse LibraryResponse
|
||||||
|
if err := util.Decode(resp.ParsedBody, &libraryResponse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := a.client.Put(UserProfileUri, FullName{firstName, lastName}, nil)
|
return &libraryResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Arlo) UpdateDeviceName(d Device, name string) (*Status, error) {
|
||||||
|
|
||||||
|
body := map[string]string{"deviceId": d.DeviceId, "deviceName": name, "parentId": d.ParentId}
|
||||||
|
resp, err := a.client.Put(DeviceRenameUri, body, nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to update device name")
|
||||||
|
}
|
||||||
|
|
||||||
|
var status Status
|
||||||
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var userProfileResponse UserProfileResponse
|
return &status, nil
|
||||||
if err := mapstructure.Decode(resp.Data, &userProfileResponse); err != nil {
|
|
||||||
return nil, err
|
return nil, errors.New("Device not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !userProfileResponse.Success {
|
// UpdateProfile takes a first and last name, and updates the user profile with that information.
|
||||||
return nil, err
|
func (a *Arlo) UpdateProfile(firstName, lastName string) (*Status, error) {
|
||||||
}
|
|
||||||
|
|
||||||
return &userProfileResponse.Data, nil
|
body := map[string]string{"firstName": firstName, "lastName": lastName}
|
||||||
}
|
resp, err := a.client.Put(UserProfileUri, body, nil)
|
||||||
|
|
||||||
func (a *Arlo) UpdatePassword(password string) error {
|
|
||||||
|
|
||||||
_, err := a.client.Post(UserChangePasswordUri, PasswordPair{a.pass, password}, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to update profile")
|
||||||
|
}
|
||||||
|
|
||||||
|
var status Status
|
||||||
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Arlo) UpdatePassword(password string) (*Status, error) {
|
||||||
|
|
||||||
|
body := map[string]string{"currentPassword": a.pass, "newPassword": password}
|
||||||
|
resp, err := a.client.Post(UserChangePasswordUri, body, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to update password")
|
||||||
|
}
|
||||||
|
|
||||||
|
var status Status
|
||||||
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Success {
|
||||||
a.pass = password
|
a.pass = password
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
|
return &status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
##
|
This is an example of the json you would pass in the body to UpdateFriends():
|
||||||
# This is an example of the json you would pass in the body to UpdateFriends():
|
{
|
||||||
#{
|
"firstName":"Some",
|
||||||
# "firstName":"Some",
|
"lastName":"Body",
|
||||||
# "lastName":"Body",
|
"devices":{
|
||||||
# "devices":{
|
"XXXXXXXXXXXXX":"Camera 1",
|
||||||
# "XXXXXXXXXXXXX":"Camera 1",
|
"XXXXXXXXXXXXX":"Camera 2 ",
|
||||||
# "XXXXXXXXXXXXX":"Camera 2 ",
|
"XXXXXXXXXXXXX":"Camera 3"
|
||||||
# "XXXXXXXXXXXXX":"Camera 3"
|
},
|
||||||
# },
|
"lastModified":1463977440911,
|
||||||
# "lastModified":1463977440911,
|
"adminUser":true,
|
||||||
# "adminUser":true,
|
"email":"user@example.com",
|
||||||
# "email":"user@example.com",
|
"id":"XXX-XXXXXXX"
|
||||||
# "id":"XXX-XXXXXXX"
|
}
|
||||||
#}
|
*/
|
||||||
##
|
func (a *Arlo) UpdateFriends(f Friend) (*Status, error) {
|
||||||
func (a *Arlo) UpdateFriends(body):
|
|
||||||
return a.client.Put('https://arlo.netgear.com/hmsweb/users/friends', body)
|
|
||||||
|
|
||||||
func (a *Arlo) UpdateDeviceName(device, name):
|
resp, err := a.client.Put(UserFriendsUri, f, nil)
|
||||||
return a.client.Put('https://arlo.netgear.com/hmsweb/users/devices/renameDevice', {'deviceId':device.get('deviceId'), 'deviceName':name, 'parentId':device.get('parentId')})
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to update friends")
|
||||||
|
}
|
||||||
|
|
||||||
##
|
var status Status
|
||||||
# This is an example of the json you would pass in the body to UpdateDisplayOrder() of your devices in the UI.
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
#
|
return nil, err
|
||||||
# XXXXXXXXXXXXX is the device id of each camera. You can get this from GetDevices().
|
}
|
||||||
#{
|
|
||||||
# "devices":{
|
|
||||||
# "XXXXXXXXXXXXX":1,
|
|
||||||
# "XXXXXXXXXXXXX":2,
|
|
||||||
# "XXXXXXXXXXXXX":3
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
##
|
|
||||||
func (a *Arlo) UpdateDisplayOrder(body):
|
|
||||||
return a.client.Post('https://arlo.netgear.com/hmsweb/users/devices/displayOrder', body)
|
|
||||||
|
|
||||||
##
|
return &status, nil
|
||||||
# This call returns the following:
|
}
|
||||||
# presignedContentUrl is a link to the actual video in Amazon AWS.
|
|
||||||
# presignedThumbnailUrl is a link to the thumbnail .jpg of the actual video in Amazon AWS.
|
|
||||||
#
|
|
||||||
#[
|
|
||||||
# {
|
|
||||||
# "mediaDurationSecond": 30,
|
|
||||||
# "contentType": "video/mp4",
|
|
||||||
# "name": "XXXXXXXXXXXXX",
|
|
||||||
# "presignedContentUrl": "https://arlos3-prod-z2.s3.amazonaws.com/XXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXXX/XXX-XXXXXXX/XXXXXXXXXXXXX/recordings/XXXXXXXXXXXXX.mp4?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&Expires=1472968703&Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
|
||||||
# "lastModified": 1472881430181,
|
|
||||||
# "localCreatedDate": XXXXXXXXXXXXX,
|
|
||||||
# "presignedThumbnailUrl": "https://arlos3-prod-z2.s3.amazonaws.com/XXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXXX/XXX-XXXXXXX/XXXXXXXXXXXXX/recordings/XXXXXXXXXXXXX_thumb.jpg?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&Expires=1472968703&Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
|
||||||
# "reason": "motionRecord",
|
|
||||||
# "deviceId": "XXXXXXXXXXXXX",
|
|
||||||
# "createdBy": "XXXXXXXXXXXXX",
|
|
||||||
# "createdDate": "20160903",
|
|
||||||
# "timeZone": "America/Chicago",
|
|
||||||
# "ownerId": "XXX-XXXXXXX",
|
|
||||||
# "utcCreatedDate": XXXXXXXXXXXXX,
|
|
||||||
# "currentState": "new",
|
|
||||||
# "mediaDuration": "00:00:30"
|
|
||||||
# }
|
|
||||||
#]
|
|
||||||
##
|
|
||||||
func (a *Arlo) GetLibrary(from_date, to_date):
|
|
||||||
return a.client.Post('https://arlo.netgear.com/hmsweb/users/library', {'dateFrom':from_date, 'dateTo':to_date})
|
|
||||||
|
|
||||||
|
func (a *Arlo) UpdateDisplayOrder(d DeviceOrder) (*Status, error) {
|
||||||
|
|
||||||
|
resp, err := a.client.Post(DeviceDisplayOrderUri, d, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to update display order")
|
||||||
|
}
|
||||||
|
|
||||||
|
var status Status
|
||||||
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
##
|
##
|
||||||
# Delete a single video recording from Arlo.
|
# Delete a single video recording from Arlo.
|
||||||
#
|
#
|
||||||
# All of the date info and device id you need to pass into this method are given in the results of the GetLibrary() call.
|
# All of the date info and device id you need to pass into this method are given in the results of the GetLibrary() call.
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
func (a *Arlo) DeleteRecording(camera, created_date, utc_created_date):
|
*/
|
||||||
return a.client.Post('https://arlo.netgear.com/hmsweb/users/library/recycle', {'data':[{'createdDate':created_date,'utcCreatedDate':utc_created_date,'deviceId':camera.get('deviceId')}]})
|
func (a *Arlo) DeleteRecording(r *Recording) (*Status, error) {
|
||||||
|
|
||||||
|
body := map[string]map[string]interface{}{"data": {"createdDate": r.CreatedDate, "utcCreatedDate": r.UtcCreatedDate, "deviceId": r.DeviceId}}
|
||||||
|
resp, err := a.client.Post(LibraryRecycleUri, body, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "failed to delete recording")
|
||||||
|
}
|
||||||
|
|
||||||
|
var status Status
|
||||||
|
if err := util.Decode(resp.ParsedBody, &status); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
##
|
##
|
||||||
# Delete a batch of video recordings from Arlo.
|
# Delete a batch of video recordings from Arlo.
|
||||||
#
|
#
|
||||||
|
70
devices.go
Normal file
70
devices.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package arloclient
|
||||||
|
|
||||||
|
// Device is the device data.
|
||||||
|
type Device struct {
|
||||||
|
DeviceType string `json:"deviceType"`
|
||||||
|
XCloudId string `json:"xCloudId"`
|
||||||
|
DisplayOrder uint8 `json:"displayOrder"`
|
||||||
|
State string `json:"state"`
|
||||||
|
ModelId string `json:"modelId"`
|
||||||
|
InterfaceVersion string `json:"interfaceVersion"`
|
||||||
|
ParentId string `json:"parentId"`
|
||||||
|
UserId string `json:"userId"`
|
||||||
|
DeviceName string `json:"deviceName"`
|
||||||
|
FirmwareVersion string `json:"firmwareVersion"`
|
||||||
|
MediaObjectCount uint8 `json:"mediaObjectCount"`
|
||||||
|
DateCreated float64 `json:"dateCreated"`
|
||||||
|
Owner Owner `json:"owner"`
|
||||||
|
Properties Properties `json:"properties"`
|
||||||
|
UniqueId string `json:"uniqueId"`
|
||||||
|
LastModified float64 `json:"lastModified"`
|
||||||
|
UserRole string `json:"userRole"`
|
||||||
|
InterfaceSchemaVer string `json:"interfaceSchemaVer"`
|
||||||
|
DeviceId string `json:"deviceId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Devices is an array of Device objects.
|
||||||
|
type Devices []Device
|
||||||
|
|
||||||
|
// DeviceOrder is a hash of # XXXXXXXXXXXXX is the device id of each camera. You can get this from GetDevices().
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"devices":{
|
||||||
|
"XXXXXXXXXXXXX":1,
|
||||||
|
"XXXXXXXXXXXXX":2,
|
||||||
|
"XXXXXXXXXXXXX":3
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
type DeviceOrder struct {
|
||||||
|
Devices map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *Devices) Find(deviceId string) *Device {
|
||||||
|
for _, d := range *ds {
|
||||||
|
if d.DeviceId == deviceId {
|
||||||
|
return &d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *Devices) BaseStations() *Devices {
|
||||||
|
var basestations Devices
|
||||||
|
for _, d := range *ds {
|
||||||
|
if d.DeviceType == "basestation" {
|
||||||
|
basestations = append(basestations, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &basestations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *Devices) Cameras() *Devices {
|
||||||
|
var cameras Devices
|
||||||
|
for _, d := range *ds {
|
||||||
|
if d.DeviceType != "basestation" {
|
||||||
|
cameras = append(cameras, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &cameras
|
||||||
|
}
|
@ -25,7 +25,7 @@ type Request struct {
|
|||||||
}
|
}
|
||||||
type Response struct {
|
type Response struct {
|
||||||
http.Response
|
http.Response
|
||||||
Data interface{}
|
ParsedBody interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(baseurl string) (*Client, error) {
|
func NewClient(baseurl string) (*Client, error) {
|
||||||
@ -88,27 +88,6 @@ func GetContentType(ct string) (string, error) {
|
|||||||
return mediaType, nil
|
return mediaType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (resp *Response) Parse(schema interface{}) (interface{}, error){
|
|
||||||
mediatype, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
log.Printf("CONTENT TYPE %s\n", mediatype)
|
|
||||||
|
|
||||||
switch mediatype {
|
|
||||||
case "application/json":
|
|
||||||
log.Println("DECODING JSON: %s", json.Valid(resp.Data))
|
|
||||||
if err := json.Unmarshal(resp.Data, schema); err != nil {
|
|
||||||
log.Println("GOT AN ERROR")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return schema, nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (c *Client) newRequest(method string, uri string, body interface{}, header http.Header) (*Request, error) {
|
func (c *Client) newRequest(method string, uri string, body interface{}, header http.Header) (*Request, error) {
|
||||||
|
|
||||||
var buf io.ReadWriter
|
var buf io.ReadWriter
|
||||||
@ -147,22 +126,22 @@ func (c *Client) newRequest(method string, uri string, body interface{}, header
|
|||||||
|
|
||||||
func (c *Client) newResponse(resp *http.Response) (*Response, error) {
|
func (c *Client) newResponse(resp *http.Response) (*Response, error) {
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Printf("DATA: %v", string(data))
|
// log.Printf("DATA: %v", string(data))
|
||||||
|
|
||||||
var d interface{}
|
|
||||||
mediaType, err := GetContentType(resp.Header.Get("Content-Type"))
|
mediaType, err := GetContentType(resp.Header.Get("Content-Type"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed to create response object")
|
return nil, errors.WithMessage(err, "failed to create response object")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pb interface{}
|
||||||
switch mediaType {
|
switch mediaType {
|
||||||
case "application/json":
|
case "application/json":
|
||||||
err = json.Unmarshal([]byte(data), &d)
|
err = json.Unmarshal([]byte(body), &pb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to create response object")
|
return nil, errors.Wrap(err, "failed to create response object")
|
||||||
}
|
}
|
||||||
@ -170,7 +149,7 @@ func (c *Client) newResponse(resp *http.Response) (*Response, error) {
|
|||||||
|
|
||||||
return &Response{
|
return &Response{
|
||||||
Response: *resp,
|
Response: *resp,
|
||||||
Data: d,
|
ParsedBody: pb,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
internal/util/util.go
Normal file
43
internal/util/util.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrettyPrint(data interface{}) string {
|
||||||
|
j, err := json.MarshalIndent(data, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprint("error:", err)
|
||||||
|
}
|
||||||
|
return fmt.Sprint(string(j))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
type Timestamp time.Time
|
||||||
|
|
||||||
|
func (t *Timestamp) MarshalJSON() ([]byte, error) {
|
||||||
|
ts := time.Time(*t).Unix()
|
||||||
|
stamp := fmt.Sprint(ts)
|
||||||
|
return []byte(stamp), nil
|
||||||
|
}
|
||||||
|
func (t *Timestamp) UnmarshalJSON(b []byte) error {
|
||||||
|
ts, err := strconv.Atoi(string(b))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = Timestamp(time.Unix(int64(ts), 0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func Decode(b interface{}, s interface{}) error {
|
||||||
|
if err := mapstructure.Decode(b, s); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to create "+reflect.TypeOf(s).String()+" object")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
31
library.go
Normal file
31
library.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package arloclient
|
||||||
|
|
||||||
|
// LibraryMetaData is the library meta data.
|
||||||
|
type LibraryMetaData struct {
|
||||||
|
DateTo string `json:"dateTo"`
|
||||||
|
DateFrom string `json:"dateFrom"`
|
||||||
|
Meta map[string]map[string]Favorite `json:"meta"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// presignedContentUrl is a link to the actual video in Amazon AWS.
|
||||||
|
// presignedThumbnailUrl is a link to the thumbnail .jpg of the actual video in Amazon AWS.
|
||||||
|
type Recording struct {
|
||||||
|
MediaDurationSecond int `json:"mediaDurationSecond"`
|
||||||
|
ContentType string `json:"contentType"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
PresignedContentUrl string `json:"presignedContentUrl"`
|
||||||
|
LastModified int64 `json:"lastModified"`
|
||||||
|
LocalCreatedDate int64 `json:"localCreatedDate"`
|
||||||
|
PresignedThumbnailUrl string `json:"presignedThumbnailUrl"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
DeviceId string `json:"deviceId"`
|
||||||
|
CreatedBy string `json:"createdBy"`
|
||||||
|
CreatedDate string `json:"createdDate"`
|
||||||
|
TimeZone string `json:"timeZone"`
|
||||||
|
OwnerId string `json:"ownerId"`
|
||||||
|
UtcCreatedDate int64 `json:"utcCreatedDate"`
|
||||||
|
CurrentState string `json:"currentState"`
|
||||||
|
MediaDuration string `json:"mediaDuration"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Library []Recording
|
29
responses.go
Normal file
29
responses.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package arloclient
|
||||||
|
|
||||||
|
// UpdateResponse is an intermediate struct used when parsing data from the UpdateProfile() call.
|
||||||
|
type Status struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginResponse is an intermediate struct used when parsing data from the Login() call.
|
||||||
|
type LoginResponse struct {
|
||||||
|
Data Account
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceResponse is an intermediate struct used when parsing data from the GetDevices() call.
|
||||||
|
type DeviceResponse struct {
|
||||||
|
Data Devices
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LibraryMetaDataResponse is an intermediate struct used when parsing data from the GetLibraryMetaData() call.
|
||||||
|
type LibraryMetaDataResponse struct {
|
||||||
|
Data LibraryMetaData
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LibraryResponse struct {
|
||||||
|
Data Library
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
87
types.go
87
types.go
@ -1,5 +1,6 @@
|
|||||||
package arloclient
|
package arloclient
|
||||||
|
|
||||||
|
/*
|
||||||
// Credentials is the login credential data.
|
// Credentials is the login credential data.
|
||||||
type Credentials struct {
|
type Credentials struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
@ -23,23 +24,7 @@ type FullName struct {
|
|||||||
FirstName string `json:"firstName"`
|
FirstName string `json:"firstName"`
|
||||||
LastName string `json:"lastName"`
|
LastName string `json:"lastName"`
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Account is the account data.
|
|
||||||
type Account struct {
|
|
||||||
UserId string `json:"userId"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Token string `json:"token"`
|
|
||||||
PaymentId string `json:"paymentId"`
|
|
||||||
Authenticated uint32 `json:"authenticated"`
|
|
||||||
AccountStatus string `json:"accountStatus"`
|
|
||||||
SerialNumber string `json:"serialNumber"`
|
|
||||||
CountryCode string `json:"countryCode"`
|
|
||||||
TocUpdate bool `json:"tocUpdate"`
|
|
||||||
PolicyUpdate bool `json:"policyUpdate"`
|
|
||||||
ValidEmail bool `json:"validEmail"`
|
|
||||||
Arlo bool `json:"arlo"`
|
|
||||||
DateCreated uint64 `json:"dateCreated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Owner is the owner of a Device data.
|
// Owner is the owner of a Device data.
|
||||||
type Owner struct {
|
type Owner struct {
|
||||||
@ -55,61 +40,17 @@ type Properties struct {
|
|||||||
HwVersion string `json:"hwVersion"`
|
HwVersion string `json:"hwVersion"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device is the device data.
|
type Favorite struct {
|
||||||
type Device struct {
|
NonFavorite uint8 `json:"nonFavorite"`
|
||||||
DeviceType string `json:"deviceType"`
|
Favorite uint8 `json:"Favorite"`
|
||||||
XCloudId string `json:"xCloudId"`
|
}
|
||||||
DisplayOrder uint8 `json:"displayOrder"`
|
|
||||||
State string `json:"state"`
|
type Friend struct {
|
||||||
ModelId string `json:"modelId"`
|
FirstName string `json:"firstName"`
|
||||||
InterfaceVersion string `json:"interfaceVersion"`
|
LastName string `json:"lastName"`
|
||||||
UserId string `json:"userId"`
|
Devices DeviceOrder `json:"devices"`
|
||||||
DeviceName string `json:"deviceName"`
|
|
||||||
FirmwareVersion string `json:"firmwareVersion"`
|
|
||||||
MediaObjectCount uint8 `json:"mediaObjectCount"`
|
|
||||||
DateCreated uint64 `json:"dateCreated"`
|
|
||||||
Owner Owner `json:"owner"`
|
|
||||||
Properties Properties `json:"properties"`
|
|
||||||
UniqueId string `json:"uniqueId"`
|
|
||||||
LastModified float64 `json:"lastModified"`
|
LastModified float64 `json:"lastModified"`
|
||||||
UserRole string `json:"userRole"`
|
AdminUser bool `json:"adminUser"`
|
||||||
InterfaceSchemaVer string `json:"interfaceSchemaVer"`
|
Email string `json:"email"`
|
||||||
DeviceId string `json:"deviceId"`
|
Id string `json:"id"`
|
||||||
}
|
|
||||||
|
|
||||||
// Devices is an array of Device objects.
|
|
||||||
type Devices []Device
|
|
||||||
|
|
||||||
// LibraryMetaData is the library meta data.
|
|
||||||
type LibraryMetaData struct {
|
|
||||||
// TODO: Fill this out.
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserProfile is the user profile data.
|
|
||||||
type UserProfile struct {
|
|
||||||
// TODO: Fill this out.
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoginResponse is an intermediate struct used when parsing data from the Login() call.
|
|
||||||
type LoginResponse struct {
|
|
||||||
Data Account
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeviceResponse is an intermediate struct used when parsing data from the GetDevices() call.
|
|
||||||
type DeviceResponse struct {
|
|
||||||
Data Devices
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LibraryMetaDataResponse is an intermediate struct used when parsing data from the GetLibraryMetaData() call.
|
|
||||||
type LibraryMetaDataResponse struct {
|
|
||||||
Data LibraryMetaData
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserProfile is an intermediate struct used when parsing data from the UpdateProfile() call.
|
|
||||||
type UserProfileResponse struct {
|
|
||||||
Data UserProfile
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user