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 }