From 9e7590f139932aeb07ef945ba57c6564c0ffcebe Mon Sep 17 00:00:00 2001 From: John Beisley Date: Sat, 6 Jun 2015 11:01:33 +0100 Subject: [PATCH] Fixes #9 - reacquire previously discovered device by URL. Some more changes will be required for this to be supported by the dcps packages. --- example/example_test.go | 31 +++++++++++++++++++++++ goupnp.go | 54 ++++++++++++++++++++++++++--------------- service_client.go | 1 + 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/example/example_test.go b/example/example_test.go index 1f3667d..6554c65 100644 --- a/example/example_test.go +++ b/example/example_test.go @@ -2,6 +2,7 @@ package example_test import ( "fmt" + "net/url" "os" "github.com/huin/goupnp" @@ -60,3 +61,33 @@ func DisplayExternalIPResults(clients []GetExternalIPAddresser, errors []error, } } } + +func Example_ReuseDiscoveredDevice() { + var allMaybeRootDevices []goupnp.MaybeRootDevice + for _, urn := range []string{internetgateway1.URN_WANPPPConnection_1, internetgateway1.URN_WANIPConnection_1} { + maybeRootDevices, err := goupnp.DiscoverDevices(internetgateway1.URN_WANPPPConnection_1) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not discover %s devices: %v\n", urn, err) + } + allMaybeRootDevices = append(allMaybeRootDevices, maybeRootDevices...) + } + locations := make([]*url.URL, 0, len(allMaybeRootDevices)) + fmt.Fprintf(os.Stderr, "Found %d devices:\n", len(allMaybeRootDevices)) + for _, maybeRootDevice := range allMaybeRootDevices { + if maybeRootDevice.Err != nil { + fmt.Fprintln(os.Stderr, " Failed to probe device at ", maybeRootDevice.Location.String()) + } else { + locations = append(locations, maybeRootDevice.Location) + fmt.Fprintln(os.Stderr, " Successfully probed device at ", maybeRootDevice.Location.String()) + } + } + fmt.Fprintf(os.Stderr, "Attempt to re-acquire %d devices:\n", len(locations)) + for _, location := range locations { + if _, err := goupnp.DeviceByURL(location); err != nil { + fmt.Fprintf(os.Stderr, " Failed to reacquire device at %s: %v\n", location.String(), err) + } else { + fmt.Fprintf(os.Stderr, " Successfully reacquired device at %s\n", location.String()) + } + } + // Output: +} diff --git a/goupnp.go b/goupnp.go index 7799a32..377a572 100644 --- a/goupnp.go +++ b/goupnp.go @@ -20,6 +20,7 @@ import ( "net/http" "net/url" "time" + "golang.org/x/net/html/charset" "github.com/huin/goupnp/httpu" @@ -36,10 +37,18 @@ func (err ContextError) Error() string { return fmt.Sprintf("%s: %v", err.Context, err.Err) } -// MaybeRootDevice contains either a RootDevice or an error. +// MaybeRootDevice contains either a RootDevice (and URL) or an error. type MaybeRootDevice struct { + // Set iff Err == nil. Root *RootDevice - Err error + + // The location the device was discovered at. This can be used with + // DeviceByURL, assuming the device is still present. A location represents + // the discovery of a device, regardless of if there was an error probing it. + Location *url.URL + + // Any error encountered probing a discovered device. + Err error } // DiscoverDevices attempts to find targets of the given type. This is @@ -67,30 +76,37 @@ func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) { maybe.Err = ContextError{"unexpected bad location from search", err} continue } - locStr := loc.String() - root := new(RootDevice) - if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil { - maybe.Err = ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err} - continue - } - var urlBaseStr string - if root.URLBaseStr != "" { - urlBaseStr = root.URLBaseStr + maybe.Location = loc + if root, err := DeviceByURL(loc); err != nil { + maybe.Err = err } else { - urlBaseStr = locStr + maybe.Root = root } - urlBase, err := url.Parse(urlBaseStr) - if err != nil { - maybe.Err = ContextError{fmt.Sprintf("error parsing location URL %q", locStr), err} - continue - } - root.SetURLBase(urlBase) - maybe.Root = root } return results, nil } +func DeviceByURL(loc *url.URL) (*RootDevice, error) { + locStr := loc.String() + root := new(RootDevice) + if err := requestXml(locStr, DeviceXMLNamespace, root); err != nil { + return nil, ContextError{fmt.Sprintf("error requesting root device details from %q", locStr), err} + } + var urlBaseStr string + if root.URLBaseStr != "" { + urlBaseStr = root.URLBaseStr + } else { + urlBaseStr = locStr + } + urlBase, err := url.Parse(urlBaseStr) + if err != nil { + return nil, ContextError{fmt.Sprintf("error parsing location URL %q", locStr), err} + } + root.SetURLBase(urlBase) + return root, nil +} + func requestXml(url string, defaultSpace string, doc interface{}) error { timeout := time.Duration(3 * time.Second) client := http.Client{ diff --git a/service_client.go b/service_client.go index c0d16ce..c4ff0d9 100644 --- a/service_client.go +++ b/service_client.go @@ -2,6 +2,7 @@ package goupnp import ( "fmt" + "github.com/huin/goupnp/soap" )