132 lines
3.4 KiB
Go
132 lines
3.4 KiB
Go
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|
//
|
|
// Copyright (C) 2019-2024 IOTech Ltd
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package autoevent
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/container"
|
|
"github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/startup"
|
|
"github.com/edgexfoundry/go-mod-bootstrap/v4/di"
|
|
"github.com/edgexfoundry/go-mod-core-contracts/v4/models"
|
|
"github.com/panjf2000/ants/v2"
|
|
|
|
"github.com/edgexfoundry/device-sdk-go/v4/internal/cache"
|
|
"github.com/edgexfoundry/device-sdk-go/v4/internal/container"
|
|
)
|
|
|
|
type manager struct {
|
|
executorMap map[string][]*Executor
|
|
ctx context.Context
|
|
wg *sync.WaitGroup
|
|
mutex sync.Mutex
|
|
autoeventBuffer chan bool
|
|
dic *di.Container
|
|
pool *ants.Pool
|
|
}
|
|
|
|
type Bootstrap struct {
|
|
pool *ants.Pool
|
|
}
|
|
|
|
func NewBootstrap(p *ants.Pool) *Bootstrap {
|
|
return &Bootstrap{
|
|
pool: p,
|
|
}
|
|
}
|
|
|
|
func (b *Bootstrap) BootstrapHandler(
|
|
ctx context.Context,
|
|
wg *sync.WaitGroup,
|
|
_ startup.Timer,
|
|
dic *di.Container) bool {
|
|
config := container.ConfigurationFrom(dic.Get)
|
|
m := &manager{
|
|
ctx: ctx,
|
|
wg: wg,
|
|
executorMap: make(map[string][]*Executor),
|
|
dic: dic,
|
|
autoeventBuffer: make(chan bool, config.Device.AsyncBufferSize),
|
|
pool: b.pool,
|
|
}
|
|
|
|
dic.Update(di.ServiceConstructorMap{
|
|
container.AutoEventManagerName: func(get di.Get) interface{} {
|
|
return m
|
|
},
|
|
})
|
|
|
|
return true
|
|
}
|
|
|
|
func (m *manager) StartAutoEvents() {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
for _, d := range cache.Devices().All() {
|
|
if len(d.ProfileName) == 0 || d.AdminState == models.Locked {
|
|
// don't run the auto event if the device doesn't define the profile, or it is locked
|
|
continue
|
|
}
|
|
if _, ok := m.executorMap[d.Name]; !ok {
|
|
executors := m.triggerExecutors(d.Name, d.AutoEvents, m.dic)
|
|
m.executorMap[d.Name] = executors
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *manager) triggerExecutors(deviceName string, autoEvents []models.AutoEvent, dic *di.Container) []*Executor {
|
|
var executors []*Executor
|
|
lc := bootstrapContainer.LoggingClientFrom(dic.Get)
|
|
|
|
for _, autoEvent := range autoEvents {
|
|
executor, err := NewExecutor(deviceName, autoEvent, m.pool)
|
|
if err != nil {
|
|
lc.Errorf("failed to create executor of AutoEvent %s for Device %s: %v", autoEvent.SourceName, deviceName, err)
|
|
// skip this AutoEvent if it causes error during creation
|
|
continue
|
|
}
|
|
executors = append(executors, executor)
|
|
go executor.Run(m.ctx, m.wg, m.autoeventBuffer, dic)
|
|
}
|
|
return executors
|
|
}
|
|
|
|
func (m *manager) RestartForDevice(deviceName string) {
|
|
lc := bootstrapContainer.LoggingClientFrom(m.dic.Get)
|
|
|
|
m.StopForDevice(deviceName)
|
|
d, ok := cache.Devices().ForName(deviceName)
|
|
if !ok {
|
|
lc.Errorf("failed to find device %s in cache to start AutoEvent", deviceName)
|
|
}
|
|
|
|
if len(d.ProfileName) == 0 || d.AdminState == models.Locked {
|
|
// don't run the auto event if the device doesn't define the profile, or it is locked
|
|
return
|
|
}
|
|
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
executors := m.triggerExecutors(deviceName, d.AutoEvents, m.dic)
|
|
m.executorMap[deviceName] = executors
|
|
}
|
|
|
|
func (m *manager) StopForDevice(deviceName string) {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
executors, ok := m.executorMap[deviceName]
|
|
if ok {
|
|
for _, executor := range executors {
|
|
executor.Stop()
|
|
}
|
|
delete(m.executorMap, deviceName)
|
|
}
|
|
}
|