starting resource subscribers implementation
This commit is contained in:
parent
36735458f8
commit
551716051f
@ -127,9 +127,7 @@ func (b *Basestation) makeEventStreamRequest(ctx context.Context, payload EventS
|
|||||||
transId := genTransId()
|
transId := genTransId()
|
||||||
payload.TransId = transId
|
payload.TransId = transId
|
||||||
|
|
||||||
responseChan := make(chan *EventStreamResponse)
|
responseChan := b.eventStream.subscribeTransaction(transId)
|
||||||
b.eventStream.subscribe(transId, responseChan)
|
|
||||||
defer b.eventStream.unsubscribe(transId)
|
|
||||||
|
|
||||||
// Send the payload to the event stream.
|
// Send the payload to the event stream.
|
||||||
if err := b.NotifyEventStream(payload); err != nil {
|
if err := b.NotifyEventStream(payload); err != nil {
|
||||||
@ -166,8 +164,6 @@ func (b *Basestation) Subscribe(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("setting up event stream: %v", err)
|
return fmt.Errorf("setting up event stream: %v", err)
|
||||||
}
|
}
|
||||||
forLoop:
|
|
||||||
for {
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return fmt.Errorf("failed to subscribe to the event stream: requesting shutdown")
|
return fmt.Errorf("failed to subscribe to the event stream: requesting shutdown")
|
||||||
@ -175,8 +171,6 @@ forLoop:
|
|||||||
if !connected {
|
if !connected {
|
||||||
return fmt.Errorf("failed to subscribe to the event stream")
|
return fmt.Errorf("failed to subscribe to the event stream")
|
||||||
}
|
}
|
||||||
break forLoop
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.Ping(ctx); err != nil {
|
if err := b.Ping(ctx); err != nil {
|
||||||
|
25
camera.go
25
camera.go
@ -154,26 +154,23 @@ func (c *Camera) SetBrightness(ctx context.Context, brightness int) (response *E
|
|||||||
return b.makeEventStreamRequest(ctx, payload)
|
return b.makeEventStreamRequest(ctx, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Camera) EnableMotionAlerts(ctx context.Context, sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
func (c *Camera) EnableMotionAlerts(ctx context.Context, sensitivity int, zones []string) error {
|
||||||
payload := EventStreamPayload{
|
b := c.arlo.Basestations.Find(c.ParentId)
|
||||||
Action: "set",
|
if b == nil {
|
||||||
Resource: fmt.Sprintf("cameras/%s", c.DeviceId),
|
return fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
||||||
PublishResponse: true,
|
}
|
||||||
Properties: MotionDetectionProperties{
|
err := b.makeRequest(ctx, "set", fmt.Sprintf("cameras/%s", c.DeviceId), true, MotionDetectionProperties{
|
||||||
BaseDetectionProperties: BaseDetectionProperties{
|
BaseDetectionProperties: BaseDetectionProperties{
|
||||||
Armed: true,
|
Armed: true,
|
||||||
Sensitivity: sensitivity,
|
Sensitivity: sensitivity,
|
||||||
Zones: zones,
|
Zones: zones,
|
||||||
},
|
},
|
||||||
},
|
}, nil)
|
||||||
From: fmt.Sprintf("%s_%s", c.UserId, TransIdPrefix),
|
|
||||||
To: c.ParentId,
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
b := c.arlo.Basestations.Find(c.ParentId)
|
return nil
|
||||||
if b == nil {
|
|
||||||
return nil, fmt.Errorf("basestation (%s) not found for camera (%s)", c.ParentId, c.DeviceId)
|
|
||||||
}
|
|
||||||
return b.makeEventStreamRequest(ctx, payload)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Camera) DisableMotionAlerts(ctx context.Context, sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
func (c *Camera) DisableMotionAlerts(ctx context.Context, sensitivity int, zones []string) (response *EventStreamResponse, err error) {
|
||||||
|
@ -18,7 +18,7 @@ func main() {
|
|||||||
|
|
||||||
for _, device := range a.Cameras {
|
for _, device := range a.Cameras {
|
||||||
log.Infof("%s", device.DeviceName)
|
log.Infof("%s", device.DeviceName)
|
||||||
err := device.On(ctx)
|
err := device.EnableMotionAlerts(ctx, 70, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("setting camera %s on: %v", device.DeviceName, err)
|
log.Errorf("setting camera %s on: %v", device.DeviceName, err)
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@ type eventStream struct {
|
|||||||
|
|
||||||
transactionSubscribers map[string]chan *EventStreamResponse
|
transactionSubscribers map[string]chan *EventStreamResponse
|
||||||
transactionSubscribersMutex sync.RWMutex
|
transactionSubscribersMutex sync.RWMutex
|
||||||
|
|
||||||
|
resourceSubscribers map[string][]chan *EventStreamResponse
|
||||||
|
resourceSubscribersMutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEventStream(url string, client *http.Client) *eventStream {
|
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),
|
Events: make(chan *sse.Event),
|
||||||
transactionSubscribers: make(map[string]chan *EventStreamResponse),
|
transactionSubscribers: make(map[string]chan *EventStreamResponse),
|
||||||
transactionSubscribersMutex: sync.RWMutex{},
|
transactionSubscribersMutex: sync.RWMutex{},
|
||||||
|
resourceSubscribers: make(map[string][]chan *EventStreamResponse),
|
||||||
|
resourceSubscribersMutex: sync.RWMutex{},
|
||||||
disconnectedChan: make(chan interface{}),
|
disconnectedChan: make(chan interface{}),
|
||||||
once: new(sync.Once),
|
once: new(sync.Once),
|
||||||
}
|
}
|
||||||
@ -58,6 +63,11 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
|
|||||||
connectedChan := make(chan bool)
|
connectedChan := make(chan bool)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
e.clearResourceSubscriptions()
|
||||||
|
e.clearTransactionSubscriptions()
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@ -106,6 +116,16 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
|
|||||||
e.transactionSubscribersMutex.RUnlock()
|
e.transactionSubscribersMutex.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
subscriber <- ¬ifyResponse
|
subscriber <- ¬ifyResponse
|
||||||
|
e.removeTransactionSubscription(notifyResponse.TransId)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.resourceSubscribersMutex.RLock()
|
||||||
|
subscribers, ok := e.resourceSubscribers[notifyResponse.Resource]
|
||||||
|
e.resourceSubscribersMutex.RUnlock()
|
||||||
|
if ok {
|
||||||
|
for _, s := range subscribers {
|
||||||
|
s <- ¬ifyResponse
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-e.disconnectedChan:
|
case <-e.disconnectedChan:
|
||||||
@ -118,17 +138,48 @@ func (e *eventStream) listen(ctx context.Context) (chan bool, error) {
|
|||||||
return connectedChan, nil
|
return connectedChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventStream) unsubscribe(transId string) {
|
func (e *eventStream) subscribeTransaction(transId string) chan *EventStreamResponse {
|
||||||
|
msgchan := make(chan *EventStreamResponse)
|
||||||
e.transactionSubscribersMutex.Lock()
|
e.transactionSubscribersMutex.Lock()
|
||||||
if c, ok := e.transactionSubscribers[transId]; ok {
|
e.transactionSubscribers[transId] = msgchan
|
||||||
close(c)
|
|
||||||
delete(e.transactionSubscribers, transId)
|
|
||||||
}
|
|
||||||
e.transactionSubscribersMutex.Unlock()
|
e.transactionSubscribersMutex.Unlock()
|
||||||
|
return msgchan
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventStream) subscribe(transId string, subscriber chan *EventStreamResponse) {
|
func (e *eventStream) subscribeResource(resource string) chan *EventStreamResponse {
|
||||||
e.transactionSubscribersMutex.Lock()
|
msgchan := make(chan *EventStreamResponse)
|
||||||
e.transactionSubscribers[transId] = subscriber
|
e.resourceSubscribersMutex.Lock()
|
||||||
e.transactionSubscribersMutex.Unlock()
|
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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user