More cleanup. Added copyright notice.
This commit is contained in:
parent
8213d70258
commit
648de10f10
6
Gopkg.lock
generated
6
Gopkg.lock
generated
@ -2,12 +2,12 @@
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca"
|
||||
branch = "master"
|
||||
digest = "1:4a28080faacdaabfe54a78ba0bfb41468744cbcda6af15748b917ca725d3749c"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
revision = "c059e472caf75dbe73903f6521a20abac245b17f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
51
arlo.go
51
arlo.go
@ -1,6 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/jeffreydwalter/arlo-golang/internal/request"
|
||||
@ -20,13 +37,14 @@ type Arlo struct {
|
||||
|
||||
func newArlo(user string, pass string) (arlo *Arlo) {
|
||||
|
||||
c, _ := request.NewClient(BaseUrl)
|
||||
|
||||
// Add important headers.
|
||||
c.BaseHttpHeader.Add("DNT", "1")
|
||||
c.BaseHttpHeader.Add("schemaVersion", "1")
|
||||
c.BaseHttpHeader.Add("Host", "arlo.netgear.com")
|
||||
c.BaseHttpHeader.Add("Referer", "https://arlo.netgear.com/")
|
||||
baseHeaders := make(http.Header)
|
||||
baseHeaders.Add("DNT", "1")
|
||||
baseHeaders.Add("schemaVersion", "1")
|
||||
baseHeaders.Add("Host", "arlo.netgear.com")
|
||||
baseHeaders.Add("Referer", "https://arlo.netgear.com/")
|
||||
|
||||
c, _ := request.NewClient(BaseUrl, baseHeaders)
|
||||
|
||||
return &Arlo{
|
||||
user: user,
|
||||
@ -40,8 +58,8 @@ func Login(user string, pass string) (arlo *Arlo, err error) {
|
||||
|
||||
body := map[string]string{"email": arlo.user, "password": arlo.pass}
|
||||
resp, err := arlo.post(LoginUri, "", body, nil)
|
||||
if err := checkHttpRequest(resp, err, "login request failed"); err != nil {
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "failed to login")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@ -52,7 +70,7 @@ func Login(user string, pass string) (arlo *Arlo, err error) {
|
||||
|
||||
if loginResponse.Success {
|
||||
// Cache the auth token.
|
||||
arlo.client.BaseHttpHeader.Add("Authorization", loginResponse.Data.Token)
|
||||
arlo.client.AddHeader("Authorization", loginResponse.Data.Token)
|
||||
|
||||
// Save the account info with the arlo struct.
|
||||
arlo.Account = loginResponse.Data
|
||||
@ -75,10 +93,10 @@ func (a *Arlo) Logout() error {
|
||||
|
||||
// GetDevices returns an array of all devices.
|
||||
// When you call Login, this method is called and all devices are cached in the arlo object.
|
||||
func (a *Arlo) GetDevices() (devices Devices, err error) {
|
||||
func (a *Arlo) GetDevices() (devices *Devices, err error) {
|
||||
resp, err := a.get(DevicesUri, "", nil)
|
||||
if err := checkHttpRequest(resp, err, "failed to get devices"); err != nil {
|
||||
return nil, err
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, "failed to get devices")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@ -95,11 +113,12 @@ func (a *Arlo) GetDevices() (devices Devices, err error) {
|
||||
return nil, errors.New("no devices found")
|
||||
}
|
||||
|
||||
// Cache a pointer to the arlo object with each device.
|
||||
for i := range deviceResponse.Data {
|
||||
deviceResponse.Data[i].arlo = a
|
||||
}
|
||||
|
||||
// disconnect all of the basestations from the EventStream.
|
||||
// Disconnect all of the basestations from the EventStream.
|
||||
for i := range a.Basestations {
|
||||
if err := a.Basestations[i].Disconnect(); err != nil {
|
||||
return nil, errors.WithMessage(err, "failed to get devices")
|
||||
@ -108,8 +127,8 @@ func (a *Arlo) GetDevices() (devices Devices, err error) {
|
||||
|
||||
a.rwmutex.Lock()
|
||||
// Cache the devices as their respective types.
|
||||
a.Cameras = deviceResponse.Data.GetCameras()
|
||||
a.Basestations = deviceResponse.Data.GetBasestations()
|
||||
a.Cameras = *deviceResponse.Data.GetCameras()
|
||||
a.Basestations = *deviceResponse.Data.GetBasestations()
|
||||
a.rwmutex.Unlock()
|
||||
|
||||
// subscribe each basestation to the EventStream.
|
||||
@ -119,7 +138,7 @@ func (a *Arlo) GetDevices() (devices Devices, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
return deviceResponse.Data, nil
|
||||
return &deviceResponse.Data, nil
|
||||
}
|
||||
|
||||
// UpdateDisplayOrder sets the display order according to the order defined in the DeviceOrder given.
|
||||
|
16
arlo_test.go
16
arlo_test.go
@ -1 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
16
arlobaby.go
16
arlobaby.go
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
@ -17,7 +33,7 @@ type Basestation struct {
|
||||
eventStream *eventStream
|
||||
}
|
||||
|
||||
// Basestations is an array of Basestation objects.
|
||||
// Basestations is a slice of Basestation objects.
|
||||
type Basestations []Basestation
|
||||
|
||||
// Find returns a basestation with the device id passed in.
|
||||
|
173
camera.go
173
camera.go
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
@ -11,7 +27,7 @@ import (
|
||||
// This type is here just for semantics. Some methods explicitly require a device of a certain type.
|
||||
type Camera Device
|
||||
|
||||
// Cameras is an array of Camera objects.
|
||||
// Cameras is a slice of Camera objects.
|
||||
type Cameras []Camera
|
||||
|
||||
// Find returns a camera with the device id passed in.
|
||||
@ -103,83 +119,6 @@ func (c *Camera) SetBrightness(brightness int) (response *EventStreamResponse, e
|
||||
return b.makeEventStreamRequest(payload, msg)
|
||||
}
|
||||
|
||||
// StartStream returns a json object containing the rtmps url to the requested video stream.
|
||||
// You will need the to install a library to handle streaming of this protocol: https://pypi.python.org/pypi/python-librtmp
|
||||
//
|
||||
// The request to /users/devices/startStream returns:
|
||||
// NOTE: { "url":"rtsp://vzwow09-z2-prod.vz.netgear.com:80/vzmodulelive?egressToken=b1b4b675_ac03_4182_9844_043e02a44f71&userAgent=web&cameraId=48B4597VD8FF5_1473010750131" }
|
||||
func (c *Camera) StartStream() (response *StreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
PublishResponse: true,
|
||||
Properties: map[string]string{
|
||||
"activityState": "startUserStream",
|
||||
"cameraId": c.DeviceId,
|
||||
},
|
||||
TransId: genTransId(),
|
||||
From: fmt.Sprintf("%s_%s", c.UserId, TransIdPrefix),
|
||||
To: c.ParentId,
|
||||
}
|
||||
|
||||
msg := "failed to start stream"
|
||||
|
||||
resp, err := c.arlo.post(DeviceStartStreamUri, c.XCloudId, payload, nil)
|
||||
if err := checkHttpRequest(resp, err, msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err := resp.Decode(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !response.Success {
|
||||
return nil, errors.WithMessage(errors.New("status was false"), msg)
|
||||
}
|
||||
|
||||
response.Data.Url = strings.Replace(response.Data.Url, "rtsp://", "rtsps://", 1)
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// TakeSnapshot causes the camera to record a snapshot.
|
||||
func (c *Camera) TakeSnapshot() (response *StreamResponse, err error) {
|
||||
msg := "failed to take snapshot"
|
||||
|
||||
response, err = c.StartStream()
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
body := map[string]string{"deviceId": c.DeviceId, "parentId": c.ParentId, "xcloudId": c.XCloudId, "olsonTimeZone": c.Properties.OlsonTimeZone}
|
||||
resp, err := c.arlo.post(DeviceTakeSnapshotUri, c.XCloudId, body, nil)
|
||||
if err := checkRequest(resp, err, "failed to update device name"); err != nil {
|
||||
return nil, errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// StartRecording causes the camera to start recording and returns a url that you must start reading from using ffmpeg
|
||||
// or something similar.
|
||||
func (c *Camera) StartRecording() (response *StreamResponse, err error) {
|
||||
msg := "failed to start recording"
|
||||
|
||||
response, err = c.StartStream()
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
body := map[string]string{"deviceId": c.DeviceId, "parentId": c.ParentId, "xcloudId": c.XCloudId, "olsonTimeZone": c.Properties.OlsonTimeZone}
|
||||
resp, err := c.arlo.post(DeviceStartRecordUri, c.XCloudId, body, nil)
|
||||
if err := checkRequest(resp, err, "failed to update device name"); err != nil {
|
||||
return nil, errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *Camera) EnableMotionAlerts(sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
@ -321,3 +260,81 @@ func (c *Camera) SetAlertNotificationMethods(action string, email, push bool) (r
|
||||
}
|
||||
return b.makeEventStreamRequest(payload, msg)
|
||||
}
|
||||
|
||||
// StartStream returns a json object containing the rtmps url to the requested video stream.
|
||||
// You will need the to install a library to handle streaming of this protocol: https://pypi.python.org/pypi/python-librtmp
|
||||
//
|
||||
// The request to /users/devices/startStream returns:
|
||||
// NOTE: { "url":"rtsp://vzwow09-z2-prod.vz.netgear.com:80/vzmodulelive?egressToken=b1b4b675_ac03_4182_9844_043e02a44f71&userAgent=web&cameraId=48B4597VD8FF5_1473010750131" }
|
||||
func (c *Camera) StartStream() (url string, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
PublishResponse: true,
|
||||
Properties: map[string]string{
|
||||
"activityState": "startUserStream",
|
||||
"cameraId": c.DeviceId,
|
||||
},
|
||||
TransId: genTransId(),
|
||||
From: fmt.Sprintf("%s_%s", c.UserId, TransIdPrefix),
|
||||
To: c.ParentId,
|
||||
}
|
||||
|
||||
msg := "failed to start stream"
|
||||
|
||||
resp, err := c.arlo.post(DeviceStartStreamUri, c.XCloudId, payload, nil)
|
||||
if err != nil {
|
||||
return "", errors.WithMessage(err, msg)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
response := new(StreamResponse)
|
||||
if err := resp.Decode(response); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !response.Success {
|
||||
return "", errors.WithMessage(errors.New("status was false"), msg)
|
||||
}
|
||||
|
||||
response.URL = strings.Replace(response.URL, "rtsp://", "rtsps://", 1)
|
||||
|
||||
return response.URL, nil
|
||||
}
|
||||
|
||||
// TakeSnapshot causes the camera to record a snapshot.
|
||||
func (c *Camera) TakeSnapshot() (url string, err error) {
|
||||
msg := "failed to take snapshot"
|
||||
|
||||
url, err = c.StartStream()
|
||||
if err != nil {
|
||||
return "", errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
body := map[string]string{"deviceId": c.DeviceId, "parentId": c.ParentId, "xcloudId": c.XCloudId, "olsonTimeZone": c.Properties.OlsonTimeZone}
|
||||
resp, err := c.arlo.post(DeviceTakeSnapshotUri, c.XCloudId, body, nil)
|
||||
if err := checkRequest(resp, err, "failed to update device name"); err != nil {
|
||||
return "", errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// StartRecording causes the camera to start recording and returns a url that you must start reading from using ffmpeg
|
||||
// or something similar.
|
||||
func (c *Camera) StartRecording() (url string, err error) {
|
||||
msg := "failed to start recording"
|
||||
|
||||
url, err = c.StartStream()
|
||||
if err != nil {
|
||||
return "", errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
body := map[string]string{"deviceId": c.DeviceId, "parentId": c.ParentId, "xcloudId": c.XCloudId, "olsonTimeZone": c.Properties.OlsonTimeZone}
|
||||
resp, err := c.arlo.post(DeviceStartRecordUri, c.XCloudId, body, nil)
|
||||
if err := checkRequest(resp, err, "failed to update device name"); err != nil {
|
||||
return "", errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
return url, nil
|
||||
}
|
||||
|
20
const.go
20
const.go
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
const (
|
||||
@ -7,7 +23,6 @@ const (
|
||||
SubscribeUri = "/client/subscribe?token=%s"
|
||||
UnsubscribeUri = "/client/unsubscribe"
|
||||
NotifyUri = "/users/devices/notify/%s"
|
||||
ResetUri = "/users/library/reset"
|
||||
ServiceLevelUri = "/users/serviceLevel"
|
||||
OffersUri = "/users/payment/offers"
|
||||
UserProfileUri = "/users/profile"
|
||||
@ -18,8 +33,9 @@ const (
|
||||
UserLocationsUri = "/users/locations"
|
||||
UserLocationUri = "/users/locations/%s"
|
||||
LibraryUri = "/users/library"
|
||||
LibraryRecycleUri = "/users/library/recycle"
|
||||
LibraryMetadataUri = "/users/library/metadata"
|
||||
LibraryRecycleUri = "/users/library/recycle"
|
||||
LibraryResetUri = "/users/library/reset"
|
||||
DevicesUri = "/users/devices"
|
||||
DeviceRenameUri = "/users/devices/renameDevice"
|
||||
DeviceDisplayOrderUri = "/users/devices/displayOrder"
|
||||
|
34
devices.go
34
devices.go
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
// A Device is the device data, this can be a camera, basestation, arloq, etc.
|
||||
@ -42,7 +58,7 @@ type Device struct {
|
||||
XCloudId string `json:"xCloudId"`
|
||||
}
|
||||
|
||||
// Devices is an array of Device objects.
|
||||
// Devices is a slice of Device objects.
|
||||
type Devices []Device
|
||||
|
||||
// A DeviceOrder holds a map of device ids and a numeric index. The numeric index is the device order.
|
||||
@ -70,9 +86,9 @@ func (ds *Devices) Find(deviceId string) *Device {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ds *Devices) FindCameras(basestationId string) Cameras {
|
||||
func (ds Devices) FindCameras(basestationId string) Cameras {
|
||||
cs := new(Cameras)
|
||||
for _, d := range *ds {
|
||||
for _, d := range ds {
|
||||
if d.ParentId == basestationId {
|
||||
*cs = append(*cs, Camera(d))
|
||||
}
|
||||
@ -93,11 +109,11 @@ func (d Device) IsCamera() bool {
|
||||
// I did this because some device types, like arloq, don't have a basestation.
|
||||
// So, when interacting with them you must treat them like a basestation and a camera.
|
||||
// Cameras also includes devices of this type, so you can get the same data there or cast.
|
||||
func (ds Devices) GetBasestations() Basestations {
|
||||
var basestations Basestations
|
||||
func (ds Devices) GetBasestations() *Basestations {
|
||||
basestations := new(Basestations)
|
||||
for _, d := range ds {
|
||||
if d.IsBasestation() || !d.IsCamera() {
|
||||
basestations = append(basestations, Basestation{Device: d})
|
||||
*basestations = append(*basestations, Basestation{Device: d})
|
||||
}
|
||||
}
|
||||
return basestations
|
||||
@ -107,11 +123,11 @@ func (ds Devices) GetBasestations() Basestations {
|
||||
// I did this because some device types, like arloq, don't have a basestation.
|
||||
// So, when interacting with them you must treat them like a basestation and a camera.
|
||||
// Basestations also includes devices of this type, so you can get the same data there or cast.
|
||||
func (ds Devices) GetCameras() Cameras {
|
||||
var cameras Cameras
|
||||
func (ds Devices) GetCameras() *Cameras {
|
||||
cameras := new(Cameras)
|
||||
for _, d := range ds {
|
||||
if d.IsCamera() || !d.IsBasestation() {
|
||||
cameras = append(cameras, Camera(d))
|
||||
*cameras = append(*cameras, Camera(d))
|
||||
}
|
||||
}
|
||||
return cameras
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
@ -74,7 +90,7 @@ func (e *eventStream) listen() (connected chan bool) {
|
||||
/*
|
||||
fmt.Println("Got event message.")
|
||||
fmt.Printf("EVENT: %s\n", event.Event)
|
||||
fmt.Printf("DATA: %s\n", event.Data)
|
||||
fmt.Printf("DATA: %s\n", event.URL)
|
||||
*/
|
||||
|
||||
if event.Data != nil {
|
||||
|
@ -1,12 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 request
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@ -14,12 +32,13 @@ import (
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
BaseURL *url.URL
|
||||
BaseHttpHeader *http.Header
|
||||
HttpClient *http.Client
|
||||
BaseURL *url.URL
|
||||
BaseHeaders *http.Header
|
||||
HttpClient *http.Client
|
||||
rwmutex sync.RWMutex
|
||||
}
|
||||
|
||||
func NewClient(baseurl string) (*Client, error) {
|
||||
func NewClient(baseURL string, baseHeaders http.Header) (*Client, error) {
|
||||
var err error
|
||||
var jar *cookiejar.Jar
|
||||
|
||||
@ -30,7 +49,7 @@ func NewClient(baseurl string) (*Client, error) {
|
||||
}
|
||||
|
||||
var u *url.URL
|
||||
if u, err = url.Parse(baseurl); err != nil {
|
||||
if u, err = url.Parse(baseURL); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create client object")
|
||||
}
|
||||
|
||||
@ -40,12 +59,18 @@ func NewClient(baseurl string) (*Client, error) {
|
||||
header.Set("Accept", "application/json")
|
||||
|
||||
return &Client{
|
||||
BaseURL: u,
|
||||
BaseHttpHeader: &header,
|
||||
HttpClient: &http.Client{Jar: jar},
|
||||
BaseURL: u,
|
||||
BaseHeaders: &header,
|
||||
HttpClient: &http.Client{Jar: jar},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) AddHeader(key, value string) {
|
||||
c.rwmutex.Lock()
|
||||
c.BaseHeaders.Set(key, value)
|
||||
c.rwmutex.Unlock()
|
||||
}
|
||||
|
||||
func (c *Client) Get(uri string, header http.Header) (*Response, error) {
|
||||
req, err := c.newRequest("GET", uri, nil, header)
|
||||
if err != nil {
|
||||
@ -80,7 +105,7 @@ func (c *Client) newRequest(method string, uri string, body interface{}, header
|
||||
return nil, errors.Wrap(err, "failed to create request object")
|
||||
}
|
||||
}
|
||||
// log.Printf("\n\nBODY (%s): %s\n\n", uri, buf)
|
||||
log.Printf("\n\nBODY (%s): %s\n\n", uri, buf)
|
||||
|
||||
u := c.BaseURL.String() + uri
|
||||
req, err := http.NewRequest(method, u, buf)
|
||||
@ -88,7 +113,11 @@ func (c *Client) newRequest(method string, uri string, body interface{}, header
|
||||
return nil, errors.Wrap(err, "failed to create request object")
|
||||
}
|
||||
|
||||
for k, v := range *c.BaseHttpHeader {
|
||||
c.rwmutex.RLock()
|
||||
baseHeaders := *c.BaseHeaders
|
||||
c.rwmutex.RUnlock()
|
||||
|
||||
for k, v := range baseHeaders {
|
||||
for _, h := range v {
|
||||
//log.Printf("Adding header (%s): (%s - %s)\n\n", u, k, h)
|
||||
req.Header.Set(k, h)
|
||||
@ -116,8 +145,8 @@ func (c *Client) newResponse(resp *http.Response) (*Response, error) {
|
||||
|
||||
func (c *Client) do(req *Request) (*Response, error) {
|
||||
|
||||
//log.Printf("\n\nCOOKIES (%s): %v\n\n", req.URL, c.HttpClient.Jar.Cookies(req.URL))
|
||||
//log.Printf("\n\nHEADERS (%s): %v\n\n", req.URL, req.Header)
|
||||
log.Printf("\n\nCOOKIES (%s): %v\n\n", req.URL, c.HttpClient.Jar.Cookies(req.URL))
|
||||
log.Printf("\n\nHEADERS (%s): %v\n\n", req.URL, req.Header)
|
||||
|
||||
resp, err := c.HttpClient.Do(&req.Request)
|
||||
if err != nil {
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 request
|
||||
|
||||
import (
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 request
|
||||
|
||||
import (
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 util
|
||||
|
||||
import (
|
||||
|
68
library.go
68
library.go
@ -1,7 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// LibraryMetaData is the library meta data.
|
||||
@ -30,38 +49,53 @@ type Recording struct {
|
||||
UtcCreatedDate int64 `json:"utcCreatedDate"`
|
||||
CurrentState string `json:"currentState"`
|
||||
MediaDuration string `json:"mediaDuration"`
|
||||
UniqueId string `json:"uniqueId"`
|
||||
}
|
||||
|
||||
type Library []Recording
|
||||
|
||||
func (a *Arlo) GetLibraryMetaData(fromDate, toDate time.Time) (response *LibraryMetaDataResponse, err error) {
|
||||
func (a *Arlo) GetLibraryMetaData(fromDate, toDate time.Time) (libraryMetaData *LibraryMetaData, err error) {
|
||||
msg := "failed to get library metadata"
|
||||
|
||||
body := map[string]string{"dateFrom": fromDate.Format("20060102"), "dateTo": toDate.Format("20060102")}
|
||||
resp, err := a.post(LibraryMetadataUri, "", body, nil)
|
||||
if err := checkHttpRequest(resp, err, "failed to get library metadata"); err != nil {
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, msg)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
response := new(LibraryMetaDataResponse)
|
||||
if err := resp.Decode(&response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := resp.Decode(response); err != nil {
|
||||
return nil, err
|
||||
if !response.Success {
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
return &response.Data, nil
|
||||
}
|
||||
|
||||
func (a *Arlo) GetLibrary(fromDate, toDate time.Time) (response *LibraryResponse, err error) {
|
||||
func (a *Arlo) GetLibrary(fromDate, toDate time.Time) (library *Library, err error) {
|
||||
msg := "failed to get library"
|
||||
|
||||
body := map[string]string{"dateFrom": fromDate.Format("20060102"), "dateTo": toDate.Format("20060102")}
|
||||
resp, err := a.post(LibraryUri, "", body, nil)
|
||||
if err := checkHttpRequest(resp, err, "failed to get library"); err != nil {
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(err, msg)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
response := new(LibraryResponse)
|
||||
if err := resp.Decode(&response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := resp.Decode(response); err != nil {
|
||||
return nil, err
|
||||
if !response.Success {
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
|
||||
return response, nil
|
||||
return &response.Data, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@ -71,9 +105,9 @@ func (a *Arlo) GetLibrary(fromDate, toDate time.Time) (response *LibraryResponse
|
||||
|
||||
NOTE: {"data": [{"createdDate": r.CreatedDate, "utcCreatedDate": r.UtcCreatedDate, "deviceId": r.DeviceId}]} is all that's really required.
|
||||
*/
|
||||
func (a *Arlo) DeleteRecording(r Recording) error {
|
||||
func (a *Arlo) DeleteRecording(r *Recording) error {
|
||||
|
||||
body := map[string]Library{"data": {r}}
|
||||
body := map[string]Library{"data": {*r}}
|
||||
resp, err := a.post(LibraryRecycleUri, "", body, nil)
|
||||
return checkRequest(resp, err, "failed to delete recording")
|
||||
}
|
||||
@ -85,9 +119,11 @@ func (a *Arlo) DeleteRecording(r Recording) error {
|
||||
|
||||
NOTE: {"data": [{"createdDate": r.CreatedDate, "utcCreatedDate": r.UtcCreatedDate, "deviceId": r.DeviceId}]} is all that's really required.
|
||||
*/
|
||||
func (a *Arlo) BatchDeleteRecordings(l Library) error {
|
||||
func (a *Arlo) BatchDeleteRecordings(l *Library) error {
|
||||
|
||||
body := map[string]Library{"data": l}
|
||||
resp, err := a.post(LibraryRecycleUri, "", body, nil)
|
||||
return checkRequest(resp, err, "failed to delete recordings")
|
||||
body := map[string]Library{"data": *l}
|
||||
fmt.Printf("%+v\n", body)
|
||||
return nil
|
||||
//resp, err := a.post(LibraryRecycleUri, "", body, nil)
|
||||
//return checkRequest(resp, err, "failed to delete recordings")
|
||||
}
|
||||
|
20
responses.go
20
responses.go
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
// LoginResponse is an intermediate struct used when parsing data from the Login() call.
|
||||
@ -24,12 +40,12 @@ type LibraryResponse struct {
|
||||
}
|
||||
|
||||
type StreamResponse struct {
|
||||
Data StreamUrl
|
||||
URL string `json:"url"`
|
||||
Status
|
||||
}
|
||||
|
||||
type RecordingResponse struct {
|
||||
Data StreamUrl
|
||||
URL string `json:"url"`
|
||||
Status
|
||||
}
|
||||
|
||||
|
28
types.go
28
types.go
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
/*
|
||||
@ -59,7 +75,7 @@ type Connectivity struct {
|
||||
ActiveNetwork string `json:"activeNetwork,omitempty"`
|
||||
APN string `json:"apn,omitempty"`
|
||||
CarrierFw string `json:"carrierFw,omitempty"`
|
||||
Connected bool `json:"connected"`
|
||||
Connected bool `json:"connected,omitempty"`
|
||||
FWVersion string `json:"fwVersion,omitempty"`
|
||||
ICCID string `json:"iccid,omitempty"`
|
||||
IMEI string `json:"imei,omitempty"`
|
||||
@ -115,10 +131,6 @@ type Favorite struct {
|
||||
Favorite uint8 `json:"Favorite"`
|
||||
}
|
||||
|
||||
type StreamUrl struct {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type BaseDetectionProperties struct {
|
||||
Armed bool `json:"armed"`
|
||||
Sensitivity int `json:"sensitivity"`
|
||||
@ -240,8 +252,8 @@ type EventStreamPayload struct {
|
||||
To string `json:"to"`
|
||||
}
|
||||
|
||||
// Data is part of the Status message fragment returned by most calls to the Arlo API.
|
||||
// Data is only populated when Success is false.
|
||||
// URL is part of the Status message fragment returned by most calls to the Arlo API.
|
||||
// URL is only populated when Success is false.
|
||||
type Data struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
@ -250,6 +262,6 @@ type Data struct {
|
||||
|
||||
// Status is the message fragment returned from most http calls to the Arlo API.
|
||||
type Status struct {
|
||||
Data `json:"Data,omitempty"`
|
||||
Data `json:"URL,omitempty"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
76
util.go
76
util.go
@ -1,10 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Jeffrey Walter <jeffreydwalter@gmail.com>
|
||||
*
|
||||
* 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 (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -15,25 +33,12 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func checkHttpRequest(resp *request.Response, err error, msg string) error {
|
||||
if resp.StatusCode != 200 {
|
||||
return errors.WithMessage(errors.New(fmt.Sprintf("http request failed: %s (%d)", resp.Status, resp.StatusCode)), msg)
|
||||
}
|
||||
|
||||
func checkRequest(resp *request.Response, err error, msg string) error {
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkRequest(resp *request.Response, err error, msg string) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err := checkHttpRequest(resp, err, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var status Status
|
||||
if err := resp.Decode(&status); err != nil {
|
||||
return err
|
||||
@ -59,31 +64,38 @@ func genTransId() string {
|
||||
}
|
||||
|
||||
func (a *Arlo) get(uri, xCloudId string, header http.Header) (*request.Response, error) {
|
||||
if len(xCloudId) > 0 {
|
||||
a.rwmutex.Lock()
|
||||
a.client.BaseHttpHeader.Set("xcloudId", xCloudId)
|
||||
a.rwmutex.Unlock()
|
||||
}
|
||||
|
||||
a.client.AddHeader("xcloudId", xCloudId)
|
||||
return a.client.Get(uri, header)
|
||||
}
|
||||
|
||||
func (a *Arlo) put(uri, xCloudId string, body interface{}, header http.Header) (*request.Response, error) {
|
||||
if len(xCloudId) > 0 {
|
||||
a.rwmutex.Lock()
|
||||
a.client.BaseHttpHeader.Set("xcloudId", xCloudId)
|
||||
a.rwmutex.Unlock()
|
||||
}
|
||||
|
||||
a.client.AddHeader("xcloudId", xCloudId)
|
||||
return a.client.Put(uri, body, header)
|
||||
}
|
||||
|
||||
func (a *Arlo) post(uri, xCloudId string, body interface{}, header http.Header) (*request.Response, error) {
|
||||
if len(xCloudId) > 0 {
|
||||
a.rwmutex.Lock()
|
||||
a.client.BaseHttpHeader.Set("xcloudId", xCloudId)
|
||||
a.rwmutex.Unlock()
|
||||
}
|
||||
|
||||
a.client.AddHeader("xcloudId", xCloudId)
|
||||
return a.client.Post(uri, body, header)
|
||||
}
|
||||
|
||||
func (a *Arlo) DownloadFile(url, to string) error {
|
||||
msg := fmt.Sprintf("failed to download file (%s) => (%s)", url, to)
|
||||
resp, err := a.get(url, "", nil)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, msg)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
f, err := os.Create(to)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user