diff --git a/upnp/devices/device.go b/upnp/devices/device.go new file mode 100644 index 00000000..a71b43df --- /dev/null +++ b/upnp/devices/device.go @@ -0,0 +1,16 @@ +package devices + +type Device struct { + deviceType string + friendlyName string + manufacturer string + manufacturerURL string + modelDescription string + modelName string + modelNumber string + modelURL string + serialNumber string + specVersion string + presentationURL string + UDN string +} diff --git a/upnp/devices/mediarenderer/AVTransport/avtransport.go b/upnp/devices/mediarenderer/AVTransport/avtransport.go new file mode 100644 index 00000000..48be64c7 --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/avtransport.go @@ -0,0 +1,17 @@ +package mediarenderer + +import "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services" + +var AVTransport = func() *services.Service { + svc := services.NewService("AVTransport") + + svc.AddVariable(AVTransportURI) + svc.AddVariable(AVTransportURIMetaData) + svc.AddVariable(CurrentTrackDuration) + svc.AddVariable(SeekMode) + svc.AddVariable(TransportPlaySpeed) + svc.AddVariable(TransportState) + svc.AddVariable(TransportStatus) + + return svc +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_AVTransportURI.go b/upnp/devices/mediarenderer/AVTransport/sv_AVTransportURI.go new file mode 100644 index 00000000..074ceba7 --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_AVTransportURI.go @@ -0,0 +1,10 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var AVTransportURI = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("AVTransportURI") + + return ts +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_AVTransportURIMetaData.go b/upnp/devices/mediarenderer/AVTransport/sv_AVTransportURIMetaData.go new file mode 100644 index 00000000..7650e1de --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_AVTransportURIMetaData.go @@ -0,0 +1,10 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var AVTransportURIMetaData = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("AVTransportURIMetaData") + + return ts +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_CurrentTrackDuration.go b/upnp/devices/mediarenderer/AVTransport/sv_CurrentTrackDuration.go new file mode 100644 index 00000000..93ab9216 --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_CurrentTrackDuration.go @@ -0,0 +1,10 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var CurrentTrackDuration = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("CurrentTrackDuration") + + return ts +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_SeekMode.go b/upnp/devices/mediarenderer/AVTransport/sv_SeekMode.go new file mode 100644 index 00000000..4e7b6a0a --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_SeekMode.go @@ -0,0 +1,10 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var SeekMode = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("SeekMode") + + return ts +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_TransportPlaySpeed.go b/upnp/devices/mediarenderer/AVTransport/sv_TransportPlaySpeed.go new file mode 100644 index 00000000..4313a814 --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_TransportPlaySpeed.go @@ -0,0 +1,10 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var TransportPlaySpeed = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("TransportPlaySpeed") + + return ts +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_TransportState.go b/upnp/devices/mediarenderer/AVTransport/sv_TransportState.go new file mode 100644 index 00000000..1f42648a --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_TransportState.go @@ -0,0 +1,20 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var TransportState = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("TransportState") + + ts.SetAllowedValues( + "STOPPED", + "PLAYING", + "PAUSED_PLAYBACK", + "TRANSITIONING", + "NO_MEDIA_PRESENT", + ) + + ts.SetSendingEvents() + + return ts +}() diff --git a/upnp/devices/mediarenderer/AVTransport/sv_TransportStatus.go b/upnp/devices/mediarenderer/AVTransport/sv_TransportStatus.go new file mode 100644 index 00000000..c3c4fefd --- /dev/null +++ b/upnp/devices/mediarenderer/AVTransport/sv_TransportStatus.go @@ -0,0 +1,17 @@ +package mediarenderer + +import sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + +var TransportStatus = func() *sv.StateVariable { + + ts := sv.StateType_String.NewStateValue("TransportStatus") + + ts.SetAllowedValues( + "OK", + "ERROR_OCCURRED", + ) + + ts.SetSendingEvents() + + return ts +}() diff --git a/upnp/devices/mediarenderer/ConnectionManager/sv_SourceProtocolInfo.go b/upnp/devices/mediarenderer/ConnectionManager/sv_SourceProtocolInfo.go new file mode 100644 index 00000000..61eae595 --- /dev/null +++ b/upnp/devices/mediarenderer/ConnectionManager/sv_SourceProtocolInfo.go @@ -0,0 +1 @@ +package connectionmanager diff --git a/upnp/devices/services/actions/action.go b/upnp/devices/services/actions/action.go new file mode 100644 index 00000000..6057a5f6 --- /dev/null +++ b/upnp/devices/services/actions/action.go @@ -0,0 +1,39 @@ +package actions + +import "github.com/beevik/etree" + +type Action struct { + name string + + arguments ArgumentSet +} + +func NewAction(name string) *Action { + ac := &Action{ + name: name, + } + + return ac +} + +func (a *Action) Name() string { + return a.name +} + +func (a *Action) TypeID() string { + return "Action" +} + +func (a *Action) AddArgument(arg *Argument) { + a.arguments.Insert(arg) +} + +func (a *Action) ToXMLElement() *etree.Element { + elem := etree.NewElement("action") + + name := elem.CreateElement("name") + name.SetText(a.Name()) + + elem.AddChild(a.arguments.ToXMLElement()) + return elem +} diff --git a/upnp/devices/services/actions/actionset.go b/upnp/devices/services/actions/actionset.go new file mode 100644 index 00000000..e0d350f3 --- /dev/null +++ b/upnp/devices/services/actions/actionset.go @@ -0,0 +1,32 @@ +package actions + +import ( + "iter" + + "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/objectstore" + "github.com/beevik/etree" +) + +type ActionSet objectstore.ObjectSet[*Action] + +func (m *ActionSet) Insert(obj *Action) { + (*objectstore.ObjectSet[*Action])(m).Insert(obj) +} + +func (set *ActionSet) Contains(obj *Action) bool { + return (*objectstore.ObjectSet[*Action])(set).Contains(obj) +} + +func (m *ActionSet) All() iter.Seq[*Action] { + return (*objectstore.ObjectSet[*Action])(m).All() +} + +func (m *ActionSet) ToXMLElement() *etree.Element { + elem := etree.NewElement("ActionList") + + for sv := range m.All() { + elem.AddChild(sv.ToXMLElement()) + } + + return elem +} diff --git a/upnp/devices/services/actions/argument.go b/upnp/devices/services/actions/argument.go new file mode 100644 index 00000000..4aaaa8c3 --- /dev/null +++ b/upnp/devices/services/actions/argument.go @@ -0,0 +1,100 @@ +package actions + +import ( + "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" + "github.com/beevik/etree" +) + +type Argument struct { + name string + statevariables *statevariables.StateVariable + in bool + out bool +} + +func newArgument(name string, statevariable *statevariables.StateVariable) *Argument { + arg := &Argument{ + name: name, + statevariables: statevariable, + } + return arg +} + +func NewInArgument(name string, statevariable *statevariables.StateVariable) *Argument { + arg := newArgument(name, statevariable) + arg.in = true + return arg +} + +func NewOutArgument(name string, statevariable *statevariables.StateVariable) *Argument { + arg := newArgument(name, statevariable) + arg.out = true + return arg +} + +func NewInOutArgument(name string, statevariable *statevariables.StateVariable) *Argument { + arg := newArgument(name, statevariable) + arg.in = true + arg.out = true + return arg +} + +func (a *Argument) Name() string { + return a.name +} + +func (sv Argument) TypeID() string { + return "Argument" +} + +func (a *Argument) StateVariable() *statevariables.StateVariable { + return a.statevariables +} + +func (a *Argument) IsIn() bool { + return a.in +} + +func (a *Argument) IsOut() bool { + return a.out +} + +func (a *Argument) ToXMLElement() *etree.Element { + var elem, arg *etree.Element + + if a.IsIn() && a.IsOut() { + elem = etree.NewElement("") + arg = elem.CreateElement("argument") + } else { + elem = etree.NewElement("argument") + arg = elem + } + + if a.IsIn() { + name := arg.CreateElement("name") + name.SetText(a.Name()) + + direction := arg.CreateElement("direction") + direction.SetText("in") + + relatedStateVariable := arg.CreateElement("relatedStateVariable") + relatedStateVariable.SetText(a.StateVariable().Name()) + } + + if a.IsIn() && a.IsOut() { + arg = elem.CreateElement("argument") + } + + if a.IsOut() { + name := arg.CreateElement("name") + name.SetText(a.Name()) + + direction := arg.CreateElement("direction") + direction.SetText("out") + + relatedStateVariable := arg.CreateElement("relatedStateVariable") + relatedStateVariable.SetText(a.StateVariable().Name()) + } + + return elem +} diff --git a/upnp/devices/services/actions/argumentset.go b/upnp/devices/services/actions/argumentset.go new file mode 100644 index 00000000..967037c0 --- /dev/null +++ b/upnp/devices/services/actions/argumentset.go @@ -0,0 +1,32 @@ +package actions + +import ( + "iter" + + "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/objectstore" + "github.com/beevik/etree" +) + +type ArgumentSet objectstore.ObjectSet[*Argument] + +func (m *ArgumentSet) Insert(obj *Argument) { + (*objectstore.ObjectSet[*Argument])(m).Insert(obj) +} + +func (set *ArgumentSet) Contains(obj *Argument) bool { + return (*objectstore.ObjectSet[*Argument])(set).Contains(obj) +} + +func (m *ArgumentSet) All() iter.Seq[*Argument] { + return (*objectstore.ObjectSet[*Argument])(m).All() +} + +func (m *ArgumentSet) ToXMLElement() *etree.Element { + elem := etree.NewElement("argumentList") + + for sv := range m.All() { + elem.AddChild(sv.ToXMLElement()) + } + + return elem +} diff --git a/upnp/devices/services/service.go b/upnp/devices/services/service.go new file mode 100644 index 00000000..3a3fddc2 --- /dev/null +++ b/upnp/devices/services/service.go @@ -0,0 +1,129 @@ +package services + +import ( + "fmt" + "iter" + + "github.com/beevik/etree" + + "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/actions" + sv "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/devices/services/statevariables" +) + +type Service struct { + name string + identifier string + version int + + controlURL string + eventSubURL string + scpdURL string + + actions actions.ActionSet + stateTable sv.StateVariableSet +} + +func NewService(name string) *Service { + svc := &Service{ + name: name, + identifier: name, + controlURL: "/service/" + name + "/control", + eventSubURL: "/service/" + name + "/event", + scpdURL: "/service/" + name + "/desc.xml", + version: 1, + } + + return svc +} + +func (svc *Service) Name() string { + return svc.name +} + +func (svc *Service) TypeID() string { + return "Service" +} + +func (svc *Service) ServiceType() string { + return fmt.Sprintf("urn:schemas-upnp-org:service:%s:%d", svc.name, svc.version) +} + +func (svc *Service) ServiceId() string { + return fmt.Sprintf("urn:upnp-org:serviceId:%s", svc.identifier) +} + +func (svc *Service) SetIdentifier(id string) { + svc.identifier = id +} + +func (svc *Service) ControlURL() string { + return svc.controlURL +} + +func (svc *Service) SetControlURL(url string) { + svc.controlURL = url +} + +func (svc *Service) EventSubURL() string { + return svc.eventSubURL +} + +func (svc *Service) SetEventSubURL(url string) { + svc.eventSubURL = url +} + +func (svc *Service) SCPDURL() string { + return svc.scpdURL +} + +func (svc *Service) SetSCPDURL(url string) { + svc.scpdURL = url +} + +func (svc *Service) SetVersion(version int) error { + if version < 1 { + return fmt.Errorf("%s", "version must be greater than or equal to 1") + } + svc.version = version + return nil +} + +func (svc *Service) Version() int { + return svc.version +} + +func (svc *Service) AddVariable(sv *sv.StateVariable) { + svc.stateTable.Insert(sv) +} + +func (svc *Service) ContaintsVariable(sv *sv.StateVariable) bool { + return svc.stateTable.Contains(sv) +} + +func (svc *Service) Variables() iter.Seq[*sv.StateVariable] { + return svc.stateTable.All() +} + +func (svc *Service) AddAction(ac *actions.Action) { +} + +func (svc *Service) ToXMLElement() *etree.Element { + elem := etree.NewElement("service") + + st := elem.CreateElement("serviceType") + st.SetText(svc.ServiceType()) + + sid := elem.CreateElement("serviceId") + sid.SetText(svc.ServiceId()) + + spcd := elem.CreateElement("SCPDURL") + spcd.SetText(svc.SCPDURL()) + + ctrl := elem.CreateElement("controlURL") + ctrl.SetText(svc.ControlURL()) + + event := elem.CreateElement("eventSubURL") + event.SetText(svc.EventSubURL()) + + return elem +} diff --git a/upnp/devices/services/serviceset.go b/upnp/devices/services/serviceset.go new file mode 100644 index 00000000..79464ee1 --- /dev/null +++ b/upnp/devices/services/serviceset.go @@ -0,0 +1,32 @@ +package services + +import ( + "iter" + + "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/objectstore" + "github.com/beevik/etree" +) + +type ServiceSet objectstore.ObjectSet[*Service] + +func (m *ServiceSet) Insert(obj *Service) { + (*objectstore.ObjectSet[*Service])(m).Insert(obj) +} + +func (set *ServiceSet) Contains(obj *Service) bool { + return (*objectstore.ObjectSet[*Service])(set).Contains(obj) +} + +func (m *ServiceSet) All() iter.Seq[*Service] { + return (*objectstore.ObjectSet[*Service])(m).All() +} + +func (m *ServiceSet) ToXMLElement() *etree.Element { + elem := etree.NewElement("ServiceList") + + for sv := range m.All() { + elem.AddChild(sv.ToXMLElement()) + } + + return elem +} diff --git a/upnp/statevariables/statevalueinstance.go b/upnp/devices/services/statevariables/statevalueinstance.go similarity index 100% rename from upnp/statevariables/statevalueinstance.go rename to upnp/devices/services/statevariables/statevalueinstance.go diff --git a/upnp/statevariables/statevariable.go b/upnp/devices/services/statevariables/statevariable.go similarity index 99% rename from upnp/statevariables/statevariable.go rename to upnp/devices/services/statevariables/statevariable.go index 38c216df..8c21a980 100644 --- a/upnp/statevariables/statevariable.go +++ b/upnp/devices/services/statevariables/statevariable.go @@ -49,6 +49,10 @@ func (sv StateVariable) Name() string { return sv.name } +func (sv StateVariable) TypeID() string { + return "StateVariable" +} + // Type returns the UPnP data type of the state variable. func (state *StateVariable) Type() StateVarType { return state.valueType @@ -431,7 +435,6 @@ func (state *StateVariable) NewInstance() *StateVarInstance { func (sv *StateVariable) ToXMLElement() *etree.Element { // Create root element elem := etree.NewElement("stateVariable") - elem.CreateAttr("name", sv.name) // Add sendEvents attribute (UPnP eventing capability) if sv.sendEvents { @@ -440,6 +443,9 @@ func (sv *StateVariable) ToXMLElement() *etree.Element { elem.CreateAttr("sendEvents", "no") // Disable event notifications } + name := elem.CreateElement("name") + name.SetText(sv.Name()) + // Add data type element dataType := elem.CreateElement("dataType") dataType.SetText(sv.valueType.String()) // Set UPnP type name (e.g., "ui1", "boolean") diff --git a/upnp/statevariables/statevariable_TransferStatus.go b/upnp/devices/services/statevariables/statevariable_TransferStatus.go similarity index 100% rename from upnp/statevariables/statevariable_TransferStatus.go rename to upnp/devices/services/statevariables/statevariable_TransferStatus.go diff --git a/upnp/statevariables/statevariable_Volume.go b/upnp/devices/services/statevariables/statevariable_Volume.go similarity index 100% rename from upnp/statevariables/statevariable_Volume.go rename to upnp/devices/services/statevariables/statevariable_Volume.go diff --git a/upnp/statevariables/statevariable_arithm.go b/upnp/devices/services/statevariables/statevariable_arithm.go similarity index 100% rename from upnp/statevariables/statevariable_arithm.go rename to upnp/devices/services/statevariables/statevariable_arithm.go diff --git a/upnp/statevariables/statevariable_cast.go b/upnp/devices/services/statevariables/statevariable_cast.go similarity index 100% rename from upnp/statevariables/statevariable_cast.go rename to upnp/devices/services/statevariables/statevariable_cast.go diff --git a/upnp/statevariables/statevariable_cmp.go b/upnp/devices/services/statevariables/statevariable_cmp.go similarity index 100% rename from upnp/statevariables/statevariable_cmp.go rename to upnp/devices/services/statevariables/statevariable_cmp.go diff --git a/upnp/statevariables/statevariable_typechecking.go b/upnp/devices/services/statevariables/statevariable_typechecking.go similarity index 100% rename from upnp/statevariables/statevariable_typechecking.go rename to upnp/devices/services/statevariables/statevariable_typechecking.go diff --git a/upnp/devices/services/statevariables/statevariableset.go b/upnp/devices/services/statevariables/statevariableset.go new file mode 100644 index 00000000..79bf8fb6 --- /dev/null +++ b/upnp/devices/services/statevariables/statevariableset.go @@ -0,0 +1,32 @@ +package statevariables + +import ( + "iter" + + "gargoton.petite-maison-orange.fr/eric/pmomusic/upnp/objectstore" + "github.com/beevik/etree" +) + +type StateVariableSet objectstore.ObjectSet[*StateVariable] + +func (m *StateVariableSet) Insert(obj *StateVariable) { + (*objectstore.ObjectSet[*StateVariable])(m).Insert(obj) +} + +func (set *StateVariableSet) Contains(obj *StateVariable) bool { + return (*objectstore.ObjectSet[*StateVariable])(set).Contains(obj) +} + +func (m *StateVariableSet) All() iter.Seq[*StateVariable] { + return (*objectstore.ObjectSet[*StateVariable])(m).All() +} + +func (m *StateVariableSet) ToXMLElement() *etree.Element { + elem := etree.NewElement("serviceStateTable") + + for sv := range m.All() { + elem.AddChild(sv.ToXMLElement()) + } + + return elem +} diff --git a/upnp/statevariables/statevartype.go b/upnp/devices/services/statevariables/statevartype.go similarity index 100% rename from upnp/statevariables/statevartype.go rename to upnp/devices/services/statevariables/statevartype.go diff --git a/upnp/statevariables/statevartype_arithm.go b/upnp/devices/services/statevariables/statevartype_arithm.go similarity index 100% rename from upnp/statevariables/statevartype_arithm.go rename to upnp/devices/services/statevariables/statevartype_arithm.go diff --git a/upnp/statevariables/statevartype_cast.go b/upnp/devices/services/statevariables/statevartype_cast.go similarity index 100% rename from upnp/statevariables/statevartype_cast.go rename to upnp/devices/services/statevariables/statevartype_cast.go diff --git a/upnp/statevariables/statevartype_cmp.go b/upnp/devices/services/statevariables/statevartype_cmp.go similarity index 100% rename from upnp/statevariables/statevartype_cmp.go rename to upnp/devices/services/statevariables/statevartype_cmp.go diff --git a/upnp/statevariables/statevartype_typechecking.go b/upnp/devices/services/statevariables/statevartype_typechecking.go similarity index 100% rename from upnp/statevariables/statevartype_typechecking.go rename to upnp/devices/services/statevariables/statevartype_typechecking.go diff --git a/upnp/statevariables/utils_binary.go b/upnp/devices/services/statevariables/utils_binary.go similarity index 100% rename from upnp/statevariables/utils_binary.go rename to upnp/devices/services/statevariables/utils_binary.go diff --git a/upnp/statevariables/utils_bool.go b/upnp/devices/services/statevariables/utils_bool.go similarity index 100% rename from upnp/statevariables/utils_bool.go rename to upnp/devices/services/statevariables/utils_bool.go diff --git a/upnp/statevariables/utils_float.go b/upnp/devices/services/statevariables/utils_float.go similarity index 100% rename from upnp/statevariables/utils_float.go rename to upnp/devices/services/statevariables/utils_float.go diff --git a/upnp/statevariables/utils_int.go b/upnp/devices/services/statevariables/utils_int.go similarity index 100% rename from upnp/statevariables/utils_int.go rename to upnp/devices/services/statevariables/utils_int.go diff --git a/upnp/statevariables/utils_numeric_operandes.go b/upnp/devices/services/statevariables/utils_numeric_operandes.go similarity index 100% rename from upnp/statevariables/utils_numeric_operandes.go rename to upnp/devices/services/statevariables/utils_numeric_operandes.go diff --git a/upnp/statevariables/utils_string.go b/upnp/devices/services/statevariables/utils_string.go similarity index 100% rename from upnp/statevariables/utils_string.go rename to upnp/devices/services/statevariables/utils_string.go diff --git a/upnp/statevariables/utils_time.go b/upnp/devices/services/statevariables/utils_time.go similarity index 98% rename from upnp/statevariables/utils_time.go rename to upnp/devices/services/statevariables/utils_time.go index 379dcc73..58405d4f 100644 --- a/upnp/statevariables/utils_time.go +++ b/upnp/devices/services/statevariables/utils_time.go @@ -55,7 +55,7 @@ func toTime(v interface{}) (time.Time, error) { func parseUPnPTime(t StateVarType, s string) (time.Time, error) { s = strings.TrimSpace(s) - layouts := []string{} + var layouts []string = nil switch t { case StateType_Date: @@ -86,6 +86,7 @@ func parseUPnPTime(t StateVarType, s string) (time.Time, error) { return ts, nil } } + return time.Time{}, fmt.Errorf("invalid %v value: %q", t, s) } diff --git a/upnp/statevariables/utils_uint.go b/upnp/devices/services/statevariables/utils_uint.go similarity index 100% rename from upnp/statevariables/utils_uint.go rename to upnp/devices/services/statevariables/utils_uint.go diff --git a/upnp/statevariables/utils_uri.go b/upnp/devices/services/statevariables/utils_uri.go similarity index 100% rename from upnp/statevariables/utils_uri.go rename to upnp/devices/services/statevariables/utils_uri.go diff --git a/upnp/statevariables/utils_uuid.go b/upnp/devices/services/statevariables/utils_uuid.go similarity index 100% rename from upnp/statevariables/utils_uuid.go rename to upnp/devices/services/statevariables/utils_uuid.go diff --git a/upnp/statevariables/valuerange.go b/upnp/devices/services/statevariables/valuerange.go similarity index 100% rename from upnp/statevariables/valuerange.go rename to upnp/devices/services/statevariables/valuerange.go diff --git a/upnp/objectstore/object.go b/upnp/objectstore/object.go new file mode 100644 index 00000000..922067dd --- /dev/null +++ b/upnp/objectstore/object.go @@ -0,0 +1,69 @@ +package objectstore + +import ( + "iter" + + "github.com/google/uuid" + log "github.com/sirupsen/logrus" +) + +type ObjectIdSet map[uuid.UUID]struct{} + +func (set ObjectIdSet) Contains(id uuid.UUID) bool { + _, ok := set[id] + return ok +} + +func (set ObjectIdSet) Add(id uuid.UUID) { + set[id] = struct{}{} +} + +func (set ObjectIdSet) Remove(id uuid.UUID) { + delete(set, id) +} + +func (set ObjectIdSet) Clear() { + for k := range set { + delete(set, k) + } +} + +func (set ObjectIdSet) Len() int { + return len(set) +} + +func (set ObjectIdSet) All() iter.Seq[uuid.UUID] { + return func(yield func(uuid.UUID) bool) { + for uuid := range set { + if !yield(uuid) { + return + } + } + } +} + +var objectstore = make(map[uuid.UUID]Object) + +func RegisterObject(o Object) uuid.UUID { + id := uuid.New() + objectstore[id] = o + + return id +} + +func GetObject(id uuid.UUID) (Object, bool) { + o, ok := objectstore[id] + return o, ok +} + +func RemoveObject(id uuid.UUID) { + if _, ok := objectstore[id]; !ok { + delete(objectstore, id) + return + } + log.Warnf("Object %s not found in objectstore", id) +} + +func CountOfStoredObjects() int { + return len(objectstore) +} diff --git a/upnp/objectstore/objectset.go b/upnp/objectstore/objectset.go new file mode 100644 index 00000000..affea4e2 --- /dev/null +++ b/upnp/objectstore/objectset.go @@ -0,0 +1,29 @@ +package objectstore + +import "iter" + +type Object interface { + Name() string + TypeID() string +} + +type ObjectSet[T Object] map[string]T + +func (m *ObjectSet[T]) Insert(obj T) { + (*m)[obj.Name()] = obj +} + +func (set *ObjectSet[T]) Contains(obj T) bool { + _, ok := (*set)[obj.Name()] + return ok +} + +func (m *ObjectSet[T]) All() iter.Seq[T] { + return func(yield func(T) bool) { + for _, sv := range *m { + if !yield(sv) { + return + } + } + } +}