github.com/enbility/spine-go@v0.7.0/spine/entity_local.go (about)

     1  package spine
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/enbility/spine-go/api"
     8  	"github.com/enbility/spine-go/model"
     9  )
    10  
    11  type EntityLocal struct {
    12  	*Entity
    13  	device   api.DeviceLocalInterface
    14  	features []api.FeatureLocalInterface
    15  
    16  	heartbeatManager api.HeartbeatManagerInterface
    17  
    18  	mux sync.Mutex
    19  }
    20  
    21  func NewEntityLocal(device api.DeviceLocalInterface,
    22  	eType model.EntityTypeType,
    23  	entityAddress []model.AddressEntityType,
    24  	heartbeatTimeout time.Duration) *EntityLocal {
    25  	entity := &EntityLocal{
    26  		Entity: NewEntity(eType, device.Address(), entityAddress),
    27  		device: device,
    28  	}
    29  	// only needed if the entity address is not DeviceInformationEntityId
    30  	if len(entityAddress) > 0 && entityAddress[0] != model.AddressEntityType(DeviceInformationEntityId) {
    31  		entity.heartbeatManager = NewHeartbeatManager(entity, heartbeatTimeout)
    32  	}
    33  
    34  	return entity
    35  }
    36  
    37  var _ api.EntityLocalInterface = (*EntityLocal)(nil)
    38  
    39  /* EntityLocalInterface */
    40  
    41  func (r *EntityLocal) Device() api.DeviceLocalInterface {
    42  	return r.device
    43  }
    44  
    45  func (r *EntityLocal) HeartbeatManager() api.HeartbeatManagerInterface {
    46  	return r.heartbeatManager
    47  }
    48  
    49  // Add a feature to the entity if it is not already added
    50  func (r *EntityLocal) AddFeature(f api.FeatureLocalInterface) {
    51  	r.mux.Lock()
    52  	defer r.mux.Unlock()
    53  
    54  	// check if this feature is already added
    55  	for _, f2 := range r.features {
    56  		if f2.Type() == f.Type() && f2.Role() == f.Role() {
    57  			return
    58  		}
    59  	}
    60  	r.features = append(r.features, f)
    61  }
    62  
    63  // either returns an existing feature or creates a new one
    64  // for a given entity, featuretype and role
    65  func (r *EntityLocal) GetOrAddFeature(featureType model.FeatureTypeType, role model.RoleType) api.FeatureLocalInterface {
    66  	if f := r.FeatureOfTypeAndRole(featureType, role); f != nil {
    67  		return f
    68  	}
    69  
    70  	r.mux.Lock()
    71  	defer r.mux.Unlock()
    72  
    73  	f := NewFeatureLocal(r.NextFeatureId(), r, featureType, role)
    74  
    75  	description := string(featureType)
    76  	switch role {
    77  	case model.RoleTypeClient:
    78  		description += " Client"
    79  	case model.RoleTypeServer:
    80  		description += " Server"
    81  	}
    82  	f.SetDescriptionString(description)
    83  	r.features = append(r.features, f)
    84  
    85  	return f
    86  }
    87  
    88  func (r *EntityLocal) FeatureOfTypeAndRole(featureType model.FeatureTypeType, role model.RoleType) api.FeatureLocalInterface {
    89  	r.mux.Lock()
    90  	defer r.mux.Unlock()
    91  
    92  	for _, f := range r.features {
    93  		if f.Type() == featureType && f.Role() == role {
    94  			return f
    95  		}
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  func (r *EntityLocal) FeatureOfAddress(addressFeature *model.AddressFeatureType) api.FeatureLocalInterface {
   102  	r.mux.Lock()
   103  	defer r.mux.Unlock()
   104  
   105  	if addressFeature == nil {
   106  		return nil
   107  	}
   108  	for _, f := range r.features {
   109  		if f.Address().Feature != nil &&
   110  			*f.Address().Feature == *addressFeature {
   111  			return f
   112  		}
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  func (r *EntityLocal) Features() []api.FeatureLocalInterface {
   119  	r.mux.Lock()
   120  	defer r.mux.Unlock()
   121  
   122  	return r.features
   123  }
   124  
   125  // add a new usecase
   126  func (r *EntityLocal) AddUseCaseSupport(
   127  	actor model.UseCaseActorType,
   128  	useCaseName model.UseCaseNameType,
   129  	useCaseVersion model.SpecificationVersionType,
   130  	useCaseDocumemtSubRevision string,
   131  	useCaseAvailable bool,
   132  	scenarios []model.UseCaseScenarioSupportType,
   133  ) {
   134  	nodeMgmt := r.device.NodeManagement()
   135  
   136  	data, err := LocalFeatureDataCopyOfType[*model.NodeManagementUseCaseDataType](nodeMgmt, model.FunctionTypeNodeManagementUseCaseData)
   137  	if err != nil {
   138  		data = &model.NodeManagementUseCaseDataType{}
   139  	}
   140  
   141  	address := model.FeatureAddressType{
   142  		Device: r.address.Device,
   143  		Entity: r.address.Entity,
   144  	}
   145  
   146  	data.AddUseCaseSupport(address, actor, useCaseName, useCaseVersion, useCaseDocumemtSubRevision, useCaseAvailable, scenarios)
   147  
   148  	nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data)
   149  }
   150  
   151  // Check if a use case is already added
   152  func (r *EntityLocal) HasUseCaseSupport(actor model.UseCaseActorType, useCaseName model.UseCaseNameType) bool {
   153  	nodeMgmt := r.device.NodeManagement()
   154  
   155  	data, err := LocalFeatureDataCopyOfType[*model.NodeManagementUseCaseDataType](nodeMgmt, model.FunctionTypeNodeManagementUseCaseData)
   156  	if err != nil {
   157  		return false
   158  	}
   159  
   160  	address := model.FeatureAddressType{
   161  		Device: r.address.Device,
   162  		Entity: r.address.Entity,
   163  	}
   164  
   165  	return data.HasUseCaseSupport(address, actor, useCaseName)
   166  }
   167  
   168  // Set the availability of a usecase. This may only be used for usescases
   169  // that act as a client within the usecase!
   170  func (r *EntityLocal) SetUseCaseAvailability(
   171  	actor model.UseCaseActorType,
   172  	useCaseName model.UseCaseNameType,
   173  	available bool) {
   174  	nodeMgmt := r.device.NodeManagement()
   175  
   176  	data, err := LocalFeatureDataCopyOfType[*model.NodeManagementUseCaseDataType](nodeMgmt, model.FunctionTypeNodeManagementUseCaseData)
   177  	if err != nil {
   178  		return
   179  	}
   180  
   181  	address := model.FeatureAddressType{
   182  		Device: r.address.Device,
   183  		Entity: r.address.Entity,
   184  	}
   185  
   186  	data.SetAvailability(address, actor, useCaseName, available)
   187  
   188  	nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data)
   189  }
   190  
   191  // Remove a usecase with a given actor ans usecase name
   192  func (r *EntityLocal) RemoveUseCaseSupport(
   193  	actor model.UseCaseActorType,
   194  	useCaseName model.UseCaseNameType,
   195  ) {
   196  	nodeMgmt := r.device.NodeManagement()
   197  
   198  	data, err := LocalFeatureDataCopyOfType[*model.NodeManagementUseCaseDataType](nodeMgmt, model.FunctionTypeNodeManagementUseCaseData)
   199  	if err != nil {
   200  		return
   201  	}
   202  
   203  	address := model.FeatureAddressType{
   204  		Device: r.address.Device,
   205  		Entity: r.address.Entity,
   206  	}
   207  
   208  	data.RemoveUseCaseSupport(address, actor, useCaseName)
   209  
   210  	nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data)
   211  }
   212  
   213  // Remove all usecases
   214  func (r *EntityLocal) RemoveAllUseCaseSupports() {
   215  	nodeMgmt := r.device.NodeManagement()
   216  
   217  	data, err := LocalFeatureDataCopyOfType[*model.NodeManagementUseCaseDataType](nodeMgmt, model.FunctionTypeNodeManagementUseCaseData)
   218  	if err != nil {
   219  		return
   220  	}
   221  
   222  	address := model.FeatureAddressType{
   223  		Device: r.address.Device,
   224  		Entity: r.address.Entity,
   225  	}
   226  
   227  	data.RemoveUseCaseDataForAddress(address)
   228  
   229  	nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data)
   230  }
   231  
   232  // Remove all subscriptions
   233  func (r *EntityLocal) RemoveAllSubscriptions() {
   234  	for _, item := range r.features {
   235  		item.RemoveAllRemoteSubscriptions()
   236  	}
   237  }
   238  
   239  // Remove all bindings
   240  func (r *EntityLocal) RemoveAllBindings() {
   241  	for _, item := range r.features {
   242  		item.RemoveAllRemoteBindings()
   243  	}
   244  }
   245  
   246  func (r *EntityLocal) Information() *model.NodeManagementDetailedDiscoveryEntityInformationType {
   247  	res := &model.NodeManagementDetailedDiscoveryEntityInformationType{
   248  		Description: &model.NetworkManagementEntityDescriptionDataType{
   249  			EntityAddress: r.Address(),
   250  			EntityType:    &r.eType,
   251  		},
   252  	}
   253  
   254  	return res
   255  }