From 489c180de9d272bc0bb4647f0b43b2c8c4003696 Mon Sep 17 00:00:00 2001 From: John Beisley Date: Sat, 28 Sep 2013 20:05:21 +0100 Subject: [PATCH] Add SCPD parsing. --- device.go | 17 +++++++++++++++++ scpd.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 scpd.go diff --git a/device.go b/device.go index 0a75fa0..a4ddfbe 100644 --- a/device.go +++ b/device.go @@ -4,14 +4,20 @@ package goupnp import ( "encoding/xml" + "errors" "fmt" "net/url" ) +// TODO: Do the sub-structures have to be pointers? + const ( DeviceXMLNamespace = "urn:schemas-upnp-org:device-1-0" ) +// RootDevice is the device description as described by section 2.3 "Device +// description" in +// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf type RootDevice struct { Name xml.Name `xml:"root` SpecVersion SpecVersion `xml:"specVersion"` @@ -100,6 +106,17 @@ func (srv *Service) String() string { return fmt.Sprintf("Service ID %s : %s", srv.ServiceId, srv.ServiceType) } +func (srv *Service) RequestSCDP() (*SCPD, error) { + if !srv.SCPDURL.Ok { + return nil, errors.New("bad/missing SCPD URL, or no URLBase has been set") + } + scpd := new(SCPD) + if err := requestXml(srv.SCPDURL.URL.String(), SCPDXMLNamespace, scpd); err != nil { + return nil, err + } + return scpd, nil +} + type URLField struct { URL url.URL `xml:"-"` Ok bool `xml:"-"` diff --git a/scpd.go b/scpd.go new file mode 100644 index 0000000..00a9de4 --- /dev/null +++ b/scpd.go @@ -0,0 +1,53 @@ +package goupnp + +import ( + "encoding/xml" +) + +const ( + SCPDXMLNamespace = "urn:schemas-upnp-org:service-1-0" +) + +// SCPD is the service description as described by section 2.5 "Service +// description" in +// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf +type SCPD struct { + Name xml.Name `xml:"scpd"` + ConfigId string `xml:"configId,attr"` + SpecVersion SpecVersion `xml:"specVersion"` + Actions []Action `xml:"actionList>action"` + StateVariables []StateVariable `xml:"serviceStateTable>stateVariable"` +} + +type Action struct { + Name string `xml:"name"` + Arguments []Argument `xml:"argumentList>argument"` +} + +type Argument struct { + Name string `xml:"name"` + Direction string `xml:"direction"` // in|out + RelatedStateVariable string `xml:"relatedStateVariable"` // ? + Retval string `xml:"retval"` // ? +} + +type StateVariable struct { + Name string `xml:"name"` + SendEvents string `xml:"sendEvents,attr"` // yes|no + Multicast string `xml:"multicast,attr"` // yes|no + DataType DataType `xml:"dataType"` + DefaultValue string `xml:"defaultValue"` + AllowedValueRange AllowedValueRange `xml:"allowedValueRange"` + AllowedValue []string `xml:"allowedValueList>allowedValue"` +} + +type AllowedValueRange struct { + Minimum string `xml:"minimum"` + Maximum string `xml:"maximum"` + Step string `xml:"step"` +} + +type DataType struct { + Name string `xml:",chardata"` + Type string `xml:"type,attr"` +}