127 lines
4.5 KiB
Go
127 lines
4.5 KiB
Go
//
|
||
// Copyright (C) 2024 IOTech Ltd
|
||
//
|
||
// SPDX-License-Identifier: Apache-2.0
|
||
|
||
package application
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"sync"
|
||
|
||
"github.com/edgexfoundry/device-sdk-go/v4/internal/cache"
|
||
"github.com/edgexfoundry/device-sdk-go/v4/internal/container"
|
||
"github.com/edgexfoundry/device-sdk-go/v4/internal/controller/http/correlation"
|
||
"github.com/edgexfoundry/device-sdk-go/v4/internal/utils"
|
||
"github.com/edgexfoundry/device-sdk-go/v4/pkg/interfaces"
|
||
bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v4/bootstrap/container"
|
||
"github.com/edgexfoundry/go-mod-bootstrap/v4/di"
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos"
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v4/dtos/requests"
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v4/errors"
|
||
"github.com/edgexfoundry/go-mod-core-contracts/v4/models"
|
||
)
|
||
|
||
type profileScanLocker struct {
|
||
mux sync.Mutex
|
||
busyMap map[string]bool
|
||
}
|
||
|
||
var locker = profileScanLocker{busyMap: make(map[string]bool)}
|
||
|
||
func ProfileScanWrapper(busy chan bool, extdriver interfaces.ExtendedProtocolDriver, req requests.ProfileScanRequest, ctx context.Context, dic *di.Container) {
|
||
locker.mux.Lock()
|
||
b := locker.busyMap[req.DeviceName]
|
||
busy <- b
|
||
if b {
|
||
locker.mux.Unlock()
|
||
return
|
||
}
|
||
locker.busyMap[req.DeviceName] = true
|
||
locker.mux.Unlock()
|
||
|
||
lc := bootstrapContainer.LoggingClientFrom(dic.Get)
|
||
dpc := bootstrapContainer.DeviceProfileClientFrom(dic.Get)
|
||
dc := bootstrapContainer.DeviceClientFrom(dic.Get)
|
||
if correlation.IdFromContext(ctx) != req.RequestId {
|
||
// ensure the correlation id matches the request id.
|
||
ctx = context.WithValue(ctx, common.CorrelationHeader, req.RequestId) //nolint: staticcheck
|
||
}
|
||
|
||
utils.PublishProfileScanProgressSystemEvent(req.RequestId, 0, "", ctx, dic)
|
||
lc.Debugf("profile scan triggered with device name '%s' and profile name '%s', Correlation Id: %s", req.DeviceName, req.ProfileName, req.RequestId)
|
||
profile, err := extdriver.ProfileScan(req)
|
||
if err != nil {
|
||
errMsg := fmt.Sprintf("failed to trigger profile scan: %v, Correlation Id: %s", err.Error(), req.RequestId)
|
||
utils.PublishProfileScanProgressSystemEvent(req.RequestId, -1, errMsg, ctx, dic)
|
||
lc.Error(errMsg)
|
||
releaseLock(req.DeviceName)
|
||
return
|
||
}
|
||
// Add profile to metadata
|
||
profileReq := requests.NewDeviceProfileRequest(dtos.FromDeviceProfileModelToDTO(profile))
|
||
_, err = dpc.Add(ctx, []requests.DeviceProfileRequest{profileReq})
|
||
if err != nil {
|
||
errMsg := fmt.Sprintf("failed to add device profile '%s': %v, Correlation Id: %s", profile.Name, err, req.RequestId)
|
||
utils.PublishProfileScanProgressSystemEvent(req.RequestId, -1, errMsg, ctx, dic)
|
||
lc.Error(errMsg)
|
||
releaseLock(req.DeviceName)
|
||
return
|
||
}
|
||
// Update device
|
||
deviceReq := requests.NewUpdateDeviceRequest(dtos.UpdateDevice{Name: &req.DeviceName, ProfileName: &profile.Name})
|
||
_, err = dc.Update(ctx, []requests.UpdateDeviceRequest{deviceReq})
|
||
if err != nil {
|
||
errMsg := fmt.Sprintf("failed to update device '%s' with profile '%s': %v, Correlation Id: %s", req.DeviceName, profile.Name, err, req.RequestId)
|
||
utils.PublishProfileScanProgressSystemEvent(req.RequestId, -1, errMsg, ctx, dic)
|
||
lc.Error(errMsg)
|
||
} else {
|
||
utils.PublishProfileScanProgressSystemEvent(req.RequestId, 100, "", ctx, dic)
|
||
}
|
||
|
||
// ReleaseLock
|
||
releaseLock(req.DeviceName)
|
||
}
|
||
|
||
func releaseLock(deviceName string) {
|
||
locker.mux.Lock()
|
||
locker.busyMap[deviceName] = false
|
||
locker.mux.Unlock()
|
||
}
|
||
|
||
func StopProfileScan(dic *di.Container, deviceName string, options map[string]any) errors.EdgeX {
|
||
lc := bootstrapContainer.LoggingClientFrom(dic.Get)
|
||
extdriver := container.ExtendedProtocolDriverFrom(dic.Get)
|
||
if extdriver == nil {
|
||
return errors.NewCommonEdgeX(errors.KindNotImplemented, "Stop profile scan is not implemented", nil)
|
||
}
|
||
|
||
// check device service AdminState
|
||
ds := container.DeviceServiceFrom(dic.Get)
|
||
if ds.AdminState == models.Locked {
|
||
return errors.NewCommonEdgeX(errors.KindServiceLocked, "service locked", nil)
|
||
}
|
||
|
||
// check requested device exists
|
||
_, exist := cache.Devices().ForName(deviceName)
|
||
if !exist {
|
||
return errors.NewCommonEdgeX(errors.KindEntityDoesNotExist, fmt.Sprintf("device %s not found", deviceName), nil)
|
||
}
|
||
|
||
locker.mux.Lock()
|
||
busy := locker.busyMap[deviceName]
|
||
locker.mux.Unlock()
|
||
if !busy {
|
||
lc.Debugf("no active profile scan process was found")
|
||
return nil
|
||
}
|
||
|
||
lc.Debugf("Stopping profile scan for device – %s", deviceName)
|
||
extdriver.StopProfileScan(deviceName, options)
|
||
lc.Debugf("Profile scan for device – %s stop signal is sent", deviceName)
|
||
|
||
return nil
|
||
}
|