refacto
This commit is contained in:
parent
b58279176c
commit
36735458f8
161
basestation.go
161
basestation.go
@ -114,50 +114,48 @@ func (bs *Basestations) Find(deviceId string) *Basestation {
|
||||
}
|
||||
|
||||
// makeEventStreamRequest is a helper function sets up a response channel, sends a message to the event stream, and blocks waiting for the response.
|
||||
func (b *Basestation) makeEventStreamRequest(payload EventStreamPayload) (*EventStreamResponse, error) {
|
||||
func (b *Basestation) makeEventStreamRequest(ctx context.Context, payload EventStreamPayload) (*EventStreamResponse, error) {
|
||||
|
||||
if !b.IsConnected() {
|
||||
log.Infof("event stream not connected: reconnecting")
|
||||
err := b.Subscribe(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reconnecting to event stream: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
transId := genTransId()
|
||||
payload.TransId = transId
|
||||
|
||||
if err := b.IsConnected(); err != nil {
|
||||
return nil, fmt.Errorf("event stream not connected")
|
||||
}
|
||||
|
||||
responseChan := make(chan *EventStreamResponse)
|
||||
errorChan := make(chan error)
|
||||
b.eventStream.subscribe(transId, responseChan, errorChan)
|
||||
b.eventStream.subscribe(transId, responseChan)
|
||||
defer b.eventStream.unsubscribe(transId)
|
||||
|
||||
// Send the payload to the event stream.
|
||||
if err := b.NotifyEventStream(payload); err != nil {
|
||||
return nil, fmt.Errorf("notifying event stream: %v", err)
|
||||
}
|
||||
|
||||
timer := time.NewTimer(eventStreamTimeout)
|
||||
defer timer.Stop()
|
||||
|
||||
// Wait for the response to come back from the event stream on the response channel.
|
||||
select {
|
||||
// If we get a response, return it to the caller.
|
||||
case response := <-responseChan:
|
||||
return response, nil
|
||||
case err := <-b.eventStream.Error:
|
||||
return nil, fmt.Errorf("event stream error: %v", err)
|
||||
// If the event stream is closed, return an error about it.
|
||||
case <-b.eventStream.DisconnectedChan:
|
||||
return nil, fmt.Errorf("event stream was closed before response was read")
|
||||
// If we timeout, return an error about it.
|
||||
case <-b.eventStream.disconnectedChan:
|
||||
log.Warn("event stream was closed before response was read")
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
case <-timer.C:
|
||||
return nil, fmt.Errorf("event stream response timed out after %.0f second", eventStreamTimeout.Seconds())
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Basestation) IsConnected() error {
|
||||
// If the event stream is closed, return an error about it.
|
||||
func (b *Basestation) IsConnected() bool {
|
||||
select {
|
||||
case <-b.eventStream.DisconnectedChan:
|
||||
return fmt.Errorf("basestation not connected to event stream")
|
||||
case <-b.eventStream.disconnectedChan:
|
||||
return false
|
||||
default:
|
||||
return nil
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,12 +176,10 @@ forLoop:
|
||||
return fmt.Errorf("failed to subscribe to the event stream")
|
||||
}
|
||||
break forLoop
|
||||
case <-b.eventStream.DisconnectedChan:
|
||||
return fmt.Errorf("failed to subscribe to the event stream: event stream was closed")
|
||||
}
|
||||
}
|
||||
|
||||
if err := b.Ping(); err != nil {
|
||||
if err := b.Ping(ctx); err != nil {
|
||||
_ = b.Disconnect()
|
||||
return fmt.Errorf("Pingloop > error while pinging: %v > disconnect event stream", err)
|
||||
}
|
||||
@ -196,7 +192,7 @@ forLoop:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case _ = <-ticker.C:
|
||||
if err := b.Ping(); err != nil {
|
||||
if err := b.Ping(ctx); err != nil {
|
||||
log.Errorf("Pingloop > error while pinging: %v > disconnect event stream", err)
|
||||
_ = b.Disconnect()
|
||||
return
|
||||
@ -246,7 +242,7 @@ func (b *Basestation) NotifyEventStream(payload EventStreamPayload) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) makeRequest(action string, resource string, publishResponse bool, properties interface{}, result interface{}) error {
|
||||
func (b *Basestation) makeRequest(ctx context.Context, action string, resource string, publishResponse bool, properties interface{}, result interface{}) error {
|
||||
payload := EventStreamPayload{
|
||||
Action: action,
|
||||
Resource: resource,
|
||||
@ -255,7 +251,7 @@ func (b *Basestation) makeRequest(action string, resource string, publishRespons
|
||||
From: fmt.Sprintf("%s_%s", b.UserId, TransIdPrefix),
|
||||
To: b.DeviceId,
|
||||
}
|
||||
resp, err := b.makeEventStreamRequest(payload)
|
||||
resp, err := b.makeEventStreamRequest(ctx, payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("making event stream request: %v", err)
|
||||
}
|
||||
@ -268,44 +264,44 @@ func (b *Basestation) makeRequest(action string, resource string, publishRespons
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) Ping() error {
|
||||
err := b.makeRequest("set", fmt.Sprintf("subscriptions/%s_%s", b.UserId, TransIdPrefix), false, map[string][1]string{"devices": {b.DeviceId}}, nil)
|
||||
func (b *Basestation) Ping(ctx context.Context) error {
|
||||
err := b.makeRequest(ctx, "set", fmt.Sprintf("subscriptions/%s_%s", b.UserId, TransIdPrefix), false, map[string][1]string{"devices": {b.DeviceId}}, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting basestation %s state: %v", b.DeviceName, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) GetState() (*BaseStationState, error) {
|
||||
func (b *Basestation) GetState(ctx context.Context) (*BaseStationState, error) {
|
||||
var state BaseStationState
|
||||
err := b.makeRequest("get", "basestation", false, nil, &state)
|
||||
err := b.makeRequest(ctx, "get", "basestation", false, nil, &state)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting basestation %s state: %v", b.DeviceName, err)
|
||||
}
|
||||
return &state, nil
|
||||
}
|
||||
|
||||
func (b *Basestation) GetAllCameraState() ([]CameraState, error) {
|
||||
func (b *Basestation) GetAllCameraState(ctx context.Context) ([]CameraState, error) {
|
||||
var states []CameraState
|
||||
err := b.makeRequest("get", "cameras", false, nil, &states)
|
||||
err := b.makeRequest(ctx, "get", "cameras", false, nil, &states)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting associated cameras state: %v", err)
|
||||
}
|
||||
return states, nil
|
||||
}
|
||||
|
||||
func (b *Basestation) GetRules() ([]Rule, error) {
|
||||
func (b *Basestation) GetRules(ctx context.Context) ([]Rule, error) {
|
||||
var resp GetRulesResponse
|
||||
err := b.makeRequest("get", "rules", false, nil, &resp)
|
||||
err := b.makeRequest(ctx, "get", "rules", false, nil, &resp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting rules: %v", err)
|
||||
}
|
||||
return resp.Rules, nil
|
||||
}
|
||||
|
||||
func (b *Basestation) GetCalendarMode() (*CalendarMode, error) {
|
||||
func (b *Basestation) GetCalendarMode(ctx context.Context) (*CalendarMode, error) {
|
||||
var calendarMode CalendarMode
|
||||
err := b.makeRequest("get", "schedule", false, nil, &calendarMode)
|
||||
err := b.makeRequest(ctx, "get", "schedule", false, nil, &calendarMode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting calendar mode: %v", err)
|
||||
}
|
||||
@ -315,9 +311,9 @@ func (b *Basestation) GetCalendarMode() (*CalendarMode, error) {
|
||||
// SetCalendarMode toggles calendar mode.
|
||||
// NOTE: The Arlo API seems to disable calendar mode when switching to other modes, if it's enabled.
|
||||
// You should probably do the same, although, the UI reflects the switch from calendar mode to say armed mode without explicitly setting calendar mode to inactive.
|
||||
func (b *Basestation) SetCalendarMode(active bool) error {
|
||||
func (b *Basestation) SetCalendarMode(ctx context.Context, active bool) error {
|
||||
resp := make(map[string]bool)
|
||||
err := b.makeRequest("set", "schedule", true, struct {
|
||||
err := b.makeRequest(ctx, "set", "schedule", true, struct {
|
||||
Active bool `json:"active"`
|
||||
}{
|
||||
Active: active,
|
||||
@ -335,18 +331,18 @@ func (b *Basestation) SetCalendarMode(active bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) GetModes() (*GetModesResponse, error) {
|
||||
func (b *Basestation) GetModes(ctx context.Context) (*GetModesResponse, error) {
|
||||
var resp GetModesResponse
|
||||
err := b.makeRequest("get", "modes", false, nil, &resp)
|
||||
err := b.makeRequest(ctx, "get", "modes", false, nil, &resp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting modes: %v", err)
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (b *Basestation) SetCustomMode(mode string) error {
|
||||
func (b *Basestation) SetCustomMode(ctx context.Context, mode string) error {
|
||||
resp := make(map[string]string)
|
||||
err := b.makeRequest("set", "modes", true, struct {
|
||||
err := b.makeRequest(ctx, "set", "modes", true, struct {
|
||||
Active string `json:"active"`
|
||||
}{
|
||||
Active: mode,
|
||||
@ -364,62 +360,67 @@ func (b *Basestation) SetCustomMode(mode string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) DeleteMode(mode string) error {
|
||||
err := b.makeRequest("delete", fmt.Sprintf("modes/%s", mode), true, nil, nil)
|
||||
func (b *Basestation) DeleteMode(ctx context.Context, mode string) error {
|
||||
err := b.makeRequest(ctx, "delete", fmt.Sprintf("modes/%s", mode), true, nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("deleting mode %s: %v", mode, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) Arm() error {
|
||||
err := b.SetCustomMode("mode1")
|
||||
func (b *Basestation) Arm(ctx context.Context) error {
|
||||
err := b.SetCustomMode(ctx, "mode1")
|
||||
if err != nil {
|
||||
return fmt.Errorf("arming (mode1): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) Disarm() error {
|
||||
err := b.SetCustomMode("mode0")
|
||||
func (b *Basestation) Disarm(ctx context.Context) error {
|
||||
err := b.SetCustomMode(ctx, "mode0")
|
||||
if err != nil {
|
||||
return fmt.Errorf("disarming (mode0): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) SirenOn() (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: "siren",
|
||||
PublishResponse: true,
|
||||
Properties: SirenProperties{
|
||||
SirenState: "on",
|
||||
Duration: 300,
|
||||
Volume: 8,
|
||||
Pattern: "alarm",
|
||||
},
|
||||
From: fmt.Sprintf("%s_%s", b.UserId, TransIdPrefix),
|
||||
To: b.DeviceId,
|
||||
}
|
||||
|
||||
return b.makeEventStreamRequest(payload)
|
||||
type SetSirenResponse struct {
|
||||
SirenState string `json:"sirenState"`
|
||||
SirenTrigger string `json:"sirenTrigger"`
|
||||
Duration int `json:"duration"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (b *Basestation) SirenOff() (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: "siren",
|
||||
PublishResponse: true,
|
||||
Properties: SirenProperties{
|
||||
SirenState: "off",
|
||||
Duration: 300,
|
||||
Volume: 8,
|
||||
Pattern: "alarm",
|
||||
},
|
||||
From: fmt.Sprintf("%s_%s", b.UserId, TransIdPrefix),
|
||||
To: b.DeviceId,
|
||||
func (b *Basestation) SirenOn(ctx context.Context) error {
|
||||
var response SetSirenResponse
|
||||
err := b.makeRequest(ctx, "set", "siren", true, SirenProperties{
|
||||
SirenState: "on",
|
||||
Duration: 300,
|
||||
Volume: 8,
|
||||
Pattern: "alarm",
|
||||
}, &response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("making request: %v", err)
|
||||
}
|
||||
|
||||
return b.makeEventStreamRequest(payload)
|
||||
if response.SirenState != "on" {
|
||||
return fmt.Errorf("siren not on in response")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Basestation) SirenOff(ctx context.Context) error {
|
||||
var response SetSirenResponse
|
||||
err := b.makeRequest(ctx, "set", "siren", true, SirenProperties{
|
||||
SirenState: "off",
|
||||
Duration: 300,
|
||||
Volume: 8,
|
||||
Pattern: "alarm",
|
||||
}, &response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("making request: %v", err)
|
||||
}
|
||||
if response.SirenState != "off" {
|
||||
return fmt.Errorf("siren not off in response")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
54
camera.go
54
camera.go
@ -1,6 +1,7 @@
|
||||
package arlo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@ -90,28 +91,23 @@ func (cs *Cameras) Find(deviceId string) *Camera {
|
||||
return nil
|
||||
}
|
||||
|
||||
// On turns a camera on; meaning it will detect and record events.
|
||||
func (c *Camera) On() (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
PublishResponse: true,
|
||||
Properties: CameraProperties{
|
||||
PrivacyActive: false,
|
||||
},
|
||||
From: fmt.Sprintf("%s_%s", c.UserId, TransIdPrefix),
|
||||
To: c.ParentId,
|
||||
}
|
||||
|
||||
func (c *Camera) On(ctx context.Context) error {
|
||||
b := c.arlo.Basestations.Find(c.ParentId)
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
return fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
|
||||
err := b.makeRequest(ctx, "set", fmt.Sprintf("cameras/%s", c.DeviceId), true, CameraProperties{
|
||||
PrivacyActive: false,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// On turns a camera off; meaning it won't detect and record events.
|
||||
func (c *Camera) Off() (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) Off(ctx context.Context) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
@ -127,13 +123,13 @@ func (c *Camera) Off() (response *EventStreamResponse, err error) {
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
||||
// SetBrightness sets the camera brightness.
|
||||
// NOTE: Brightness is between -2 and 2 in increments of 1 (-2, -1, 0, 1, 2).
|
||||
// Setting it to an invalid value has no effect.
|
||||
func (c *Camera) SetBrightness(brightness int) (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) SetBrightness(ctx context.Context, brightness int) (response *EventStreamResponse, err error) {
|
||||
// Sanity check; if the values are above or below the allowed limits, set them to their limit.
|
||||
if brightness < -2 {
|
||||
brightness = -2
|
||||
@ -155,10 +151,10 @@ func (c *Camera) SetBrightness(brightness int) (response *EventStreamResponse, e
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
||||
func (c *Camera) EnableMotionAlerts(sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) EnableMotionAlerts(ctx context.Context, sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
@ -177,10 +173,10 @@ func (c *Camera) EnableMotionAlerts(sensitivity int, zones []string) (response *
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
||||
func (c *Camera) DisableMotionAlerts(sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) DisableMotionAlerts(ctx context.Context, sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
@ -200,10 +196,10 @@ func (c *Camera) DisableMotionAlerts(sensitivity int, zones []string) (response
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
||||
func (c *Camera) EnableAudioAlerts(sensitivity int) (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) EnableAudioAlerts(ctx context.Context, sensitivity int) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
@ -222,10 +218,10 @@ func (c *Camera) EnableAudioAlerts(sensitivity int) (response *EventStreamRespon
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
||||
func (c *Camera) DisableAudioAlerts(sensitivity int) (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) DisableAudioAlerts(ctx context.Context, sensitivity int) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
@ -244,11 +240,11 @@ func (c *Camera) DisableAudioAlerts(sensitivity int) (response *EventStreamRespo
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
||||
// action: disabled OR recordSnapshot OR recordVideo
|
||||
func (c *Camera) SetAlertNotificationMethods(action string, email, push bool) (response *EventStreamResponse, err error) {
|
||||
func (c *Camera) SetAlertNotificationMethods(ctx context.Context, action string, email, push bool) (response *EventStreamResponse, err error) {
|
||||
payload := EventStreamPayload{
|
||||
Action: "set",
|
||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
||||
@ -273,5 +269,5 @@ func (c *Camera) SetAlertNotificationMethods(action string, email, push bool) (r
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||
}
|
||||
return b.makeEventStreamRequest(payload)
|
||||
return b.makeEventStreamRequest(ctx, payload)
|
||||
}
|
||||
|
29
cmd/main.go
Normal file
29
cmd/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.lehouerou.net/laurent/arlo-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
a := arlo.NewArlo()
|
||||
err := a.Login(ctx, "hass@lehouerou.net", "TiPXMVLUeZfUg6RrmwzK")
|
||||
if err != nil {
|
||||
log.Errorf("login: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, device := range a.Cameras {
|
||||
log.Infof("%s", device.DeviceName)
|
||||
err := device.On(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("setting camera %s on: %v", device.DeviceName, err)
|
||||
}
|
||||
}
|
||||
|
||||
select {}
|
||||
|
||||
}
|
2
const.go
2
const.go
@ -9,7 +9,7 @@ const (
|
||||
DeviceTypeSiren = "siren"
|
||||
|
||||
TransIdPrefix = "web"
|
||||
BaseUrl = "https://my.arlo.com/hmsweb"
|
||||
BaseUrl = "https://myapi.arlo.com/hmsweb"
|
||||
|
||||
// TODO: Implement all of the following urls. There are many here I don't have devices for. :/
|
||||
ActiveAutomationUri = "/users/devices/automation/active"
|
||||
|
@ -17,25 +17,20 @@ type eventStream struct {
|
||||
Events chan *sse.Event
|
||||
Error chan error
|
||||
Verbose bool
|
||||
DisconnectedChan chan interface{}
|
||||
disconnectedChan chan interface{}
|
||||
once *sync.Once
|
||||
|
||||
subscribers map[string]chan *EventStreamResponse
|
||||
subscribersMutex sync.RWMutex
|
||||
|
||||
errorsubsribers map[string]chan error
|
||||
errorMutex sync.RWMutex
|
||||
transactionSubscribers map[string]chan *EventStreamResponse
|
||||
transactionSubscribersMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func newEventStream(url string, client *http.Client) *eventStream {
|
||||
e := &eventStream{
|
||||
Events: make(chan *sse.Event),
|
||||
subscribers: make(map[string]chan *EventStreamResponse),
|
||||
subscribersMutex: sync.RWMutex{},
|
||||
errorsubsribers: make(map[string]chan error),
|
||||
errorMutex: sync.RWMutex{},
|
||||
DisconnectedChan: make(chan interface{}),
|
||||
once: new(sync.Once),
|
||||
Events: make(chan *sse.Event),
|
||||
transactionSubscribers: make(map[string]chan *EventStreamResponse),
|
||||
transactionSubscribersMutex: sync.RWMutex{},
|
||||
disconnectedChan: make(chan interface{}),
|
||||
once: new(sync.Once),
|
||||
}
|
||||
|
||||
SSEClient := sse.NewClient(url)
|
||||
@ -49,17 +44,19 @@ func newEventStream(url string, client *http.Client) *eventStream {
|
||||
|
||||
func (e *eventStream) disconnect() {
|
||||
e.once.Do(func() {
|
||||
close(e.DisconnectedChan)
|
||||
close(e.disconnectedChan)
|
||||
})
|
||||
}
|
||||
|
||||
func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
|
||||
connectedChan := make(chan bool)
|
||||
|
||||
err := e.SSEClient.SubscribeChanRaw(e.Events)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to subscribe to seeclient")
|
||||
}
|
||||
|
||||
connectedChan := make(chan bool)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
@ -104,14 +101,14 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
|
||||
e.disconnect()
|
||||
continue
|
||||
}
|
||||
e.subscribersMutex.RLock()
|
||||
subscriber, ok := e.subscribers[notifyResponse.TransId]
|
||||
e.subscribersMutex.RUnlock()
|
||||
e.transactionSubscribersMutex.RLock()
|
||||
subscriber, ok := e.transactionSubscribers[notifyResponse.TransId]
|
||||
e.transactionSubscribersMutex.RUnlock()
|
||||
if ok {
|
||||
subscriber <- ¬ifyResponse
|
||||
}
|
||||
|
||||
case <-e.DisconnectedChan:
|
||||
case <-e.disconnectedChan:
|
||||
connectedChan <- false
|
||||
return
|
||||
}
|
||||
@ -122,28 +119,16 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
|
||||
}
|
||||
|
||||
func (e *eventStream) unsubscribe(transId string) {
|
||||
e.subscribersMutex.Lock()
|
||||
if c, ok := e.subscribers[transId]; ok {
|
||||
e.transactionSubscribersMutex.Lock()
|
||||
if c, ok := e.transactionSubscribers[transId]; ok {
|
||||
close(c)
|
||||
delete(e.subscribers, transId)
|
||||
delete(e.transactionSubscribers, transId)
|
||||
}
|
||||
e.subscribersMutex.Unlock()
|
||||
|
||||
e.errorMutex.Lock()
|
||||
if c, ok := e.errorsubsribers[transId]; ok {
|
||||
close(c)
|
||||
delete(e.errorsubsribers, transId)
|
||||
}
|
||||
e.errorMutex.Unlock()
|
||||
|
||||
e.transactionSubscribersMutex.Unlock()
|
||||
}
|
||||
|
||||
func (e *eventStream) subscribe(transId string, subscriber chan *EventStreamResponse, errorChan chan error) {
|
||||
e.subscribersMutex.Lock()
|
||||
e.subscribers[transId] = subscriber
|
||||
e.subscribersMutex.Unlock()
|
||||
|
||||
e.errorMutex.Lock()
|
||||
e.errorsubsribers[transId] = errorChan
|
||||
e.errorMutex.Unlock()
|
||||
func (e *eventStream) subscribe(transId string, subscriber chan *EventStreamResponse) {
|
||||
e.transactionSubscribersMutex.Lock()
|
||||
e.transactionSubscribers[transId] = subscriber
|
||||
e.transactionSubscribersMutex.Unlock()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user