EdgexAgent/device-gps-go/internal/application/profilescan.go

127 lines
4.5 KiB
Go
Raw Normal View History

2025-07-10 20:30:06 +08:00
//
// 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
}