starting resource subscribers implementation

This commit is contained in:
Laurent Le Houerou 2020-06-06 16:23:15 +04:00
parent 36735458f8
commit 551716051f
4 changed files with 82 additions and 40 deletions

View File

@ -127,9 +127,7 @@ func (b *Basestation) makeEventStreamRequest(ctx context.Context, payload EventS
transId := genTransId()
payload.TransId = transId
responseChan := make(chan *EventStreamResponse)
b.eventStream.subscribe(transId, responseChan)
defer b.eventStream.unsubscribe(transId)
responseChan := b.eventStream.subscribeTransaction(transId)
// Send the payload to the event stream.
if err := b.NotifyEventStream(payload); err != nil {
@ -166,8 +164,6 @@ func (b *Basestation) Subscribe(ctx context.Context) error {
if err != nil {
return fmt.Errorf("setting up event stream: %v", err)
}
forLoop:
for {
select {
case <-ctx.Done():
return fmt.Errorf("failed to subscribe to the event stream: requesting shutdown")
@ -175,8 +171,6 @@ forLoop:
if !connected {
return fmt.Errorf("failed to subscribe to the event stream")
}
break forLoop
}
}
if err := b.Ping(ctx); err != nil {

View File

@ -154,26 +154,23 @@ func (c *Camera) SetBrightness(ctx context.Context, brightness int) (response *E
return b.makeEventStreamRequest(ctx, payload)
}
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),
PublishResponse: true,
Properties: MotionDetectionProperties{
func (c *Camera) EnableMotionAlerts(ctx context.Context, sensitivity int, zones []string) error {
b := c.arlo.Basestations.Find(c.ParentId)
if b == nil {
return fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
}
err := b.makeRequest(ctx, "set", fmt.Sprintf("cameras/%s", c.DeviceId), true, MotionDetectionProperties{
BaseDetectionProperties: BaseDetectionProperties{
Armed: true,
Sensitivity: sensitivity,
Zones: zones,
},
},
From: fmt.Sprintf("%s_%s", c.UserId, TransIdPrefix),
To: c.ParentId,
}, nil)
if err != nil {
return err
}
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 b.makeEventStreamRequest(ctx, payload)
return nil
}
func (c *Camera) DisableMotionAlerts(ctx context.Context, sensitivity int, zones []string) (response *EventStreamResponse, err error) {

View File

@ -18,7 +18,7 @@ func main() {
for _, device := range a.Cameras {
log.Infof("%s", device.DeviceName)
err := device.On(ctx)
err := device.EnableMotionAlerts(ctx, 70, nil)
if err != nil {
log.Errorf("setting camera %s on: %v", device.DeviceName, err)
}

View File

@ -22,6 +22,9 @@ type eventStream struct {
transactionSubscribers map[string]chan *EventStreamResponse
transactionSubscribersMutex sync.RWMutex
resourceSubscribers map[string][]chan *EventStreamResponse
resourceSubscribersMutex sync.RWMutex
}
func newEventStream(url string, client *http.Client) *eventStream {
@ -29,6 +32,8 @@ func newEventStream(url string, client *http.Client) *eventStream {
Events: make(chan *sse.Event),
transactionSubscribers: make(map[string]chan *EventStreamResponse),
transactionSubscribersMutex: sync.RWMutex{},
resourceSubscribers: make(map[string][]chan *EventStreamResponse),
resourceSubscribersMutex: sync.RWMutex{},
disconnectedChan: make(chan interface{}),
once: new(sync.Once),
}
@ -58,6 +63,11 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
connectedChan := make(chan bool)
go func() {
defer func() {
e.clearResourceSubscriptions()
e.clearTransactionSubscriptions()
}()
for {
select {
case <-ctx.Done():
@ -106,6 +116,16 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
e.transactionSubscribersMutex.RUnlock()
if ok {
subscriber <- &notifyResponse
e.removeTransactionSubscription(notifyResponse.TransId)
}
e.resourceSubscribersMutex.RLock()
subscribers, ok := e.resourceSubscribers[notifyResponse.Resource]
e.resourceSubscribersMutex.RUnlock()
if ok {
for _, s := range subscribers {
s <- &notifyResponse
}
}
case <-e.disconnectedChan:
@ -118,17 +138,48 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
return connectedChan, nil
}
func (e *eventStream) unsubscribe(transId string) {
func (e *eventStream) subscribeTransaction(transId string) chan *EventStreamResponse {
msgchan := make(chan *EventStreamResponse)
e.transactionSubscribersMutex.Lock()
if c, ok := e.transactionSubscribers[transId]; ok {
close(c)
delete(e.transactionSubscribers, transId)
}
e.transactionSubscribers[transId] = msgchan
e.transactionSubscribersMutex.Unlock()
return msgchan
}
func (e *eventStream) subscribe(transId string, subscriber chan *EventStreamResponse) {
e.transactionSubscribersMutex.Lock()
e.transactionSubscribers[transId] = subscriber
e.transactionSubscribersMutex.Unlock()
func (e *eventStream) subscribeResource(resource string) chan *EventStreamResponse {
msgchan := make(chan *EventStreamResponse)
e.resourceSubscribersMutex.Lock()
e.resourceSubscribers[resource] = append(e.resourceSubscribers[resource], msgchan)
e.resourceSubscribersMutex.Unlock()
return msgchan
}
func (e *eventStream) removeTransactionSubscription(transId string) {
e.transactionSubscribersMutex.Lock()
defer e.transactionSubscribersMutex.Unlock()
subscriber, ok := e.transactionSubscribers[transId]
if ok {
close(subscriber)
delete(e.transactionSubscribers, transId)
}
}
func (e *eventStream) clearResourceSubscriptions() {
e.resourceSubscribersMutex.Lock()
defer e.resourceSubscribersMutex.Unlock()
for _, subscribers := range e.resourceSubscribers {
for _, subscriber := range subscribers {
close(subscriber)
}
}
e.resourceSubscribers = make(map[string][]chan *EventStreamResponse)
}
func (e *eventStream) clearTransactionSubscriptions() {
e.transactionSubscribersMutex.Lock()
defer e.transactionSubscribersMutex.Unlock()
for _, subscriber := range e.transactionSubscribers {
close(subscriber)
}
e.transactionSubscribers = make(map[string]chan *EventStreamResponse)
}