EdgexAgent/device-gps-go/internal/application/profilescan.go
2025-07-10 20:30:06 +08:00

127 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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
}