289b30715d
This commit converts the dependency management from Godeps to the vendor folder, also switching the tool from godep to trash. Since the upstream tool lacks a few features proposed via a few PRs, until those PRs are merged in (if), use github.com/karalabe/trash. You can update dependencies via trash --update. All dependencies have been updated to their latest version. Parts of the build system are reworked to drop old notions of Godeps and invocation of the go vet command so that it doesn't run against the vendor folder, as that will just blow up during vetting. The conversion drops OpenCL (and hence GPU mining support) from ethash and our codebase. The short reasoning is that there's noone to maintain and having opencl libs in our deps messes up builds as go install ./... tries to build them, failing with unsatisfied link errors for the C OpenCL deps. golang.org/x/net/context is not vendored in. We expect it to be fetched by the user (i.e. using go get). To keep ci.go builds reproducible the package is "vendored" in build/_vendor.
132 lines
3.7 KiB
Go
132 lines
3.7 KiB
Go
// goupnp is an implementation of a client for various UPnP services.
|
|
//
|
|
// For most uses, it is recommended to use the code-generated packages under
|
|
// github.com/huin/goupnp/dcps. Example use is shown at
|
|
// http://godoc.org/github.com/huin/goupnp/example
|
|
//
|
|
// A commonly used client is internetgateway1.WANPPPConnection1:
|
|
// http://godoc.org/github.com/huin/goupnp/dcps/internetgateway1#WANPPPConnection1
|
|
//
|
|
// Currently only a couple of schemas have code generated for them from the
|
|
// UPnP example XML specifications. Not all methods will work on these clients,
|
|
// because the generated stubs contain the full set of specified methods from
|
|
// the XML specifications, and the discovered services will likely support a
|
|
// subset of those methods.
|
|
package goupnp
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"golang.org/x/net/html/charset"
|
|
|
|
"github.com/huin/goupnp/httpu"
|
|
"github.com/huin/goupnp/ssdp"
|
|
)
|
|
|
|
// ContextError is an error that wraps an error with some context information.
|
|
type ContextError struct {
|
|
Context string
|
|
Err error
|
|
}
|
|
|
|
func (err ContextError) Error() string {
|
|
return fmt.Sprintf("%s: %v", err.Context, err.Err)
|
|
}
|
|
|
|
// MaybeRootDevice contains either a RootDevice or an error.
|
|
type MaybeRootDevice struct {
|
|
// Set iff Err == nil.
|
|
Root *RootDevice
|
|
|
|
// 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
|
|
// typically the entry-point for this package. searchTarget is typically a URN
|
|
// in the form "urn:schemas-upnp-org:device:..." or
|
|
// "urn:schemas-upnp-org:service:...". A single error is returned for errors
|
|
// while attempting to send the query. An error or RootDevice is returned for
|
|
// each discovered RootDevice.
|
|
func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
|
|
httpu, err := httpu.NewHTTPUClient()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer httpu.Close()
|
|
responses, err := ssdp.SSDPRawSearch(httpu, string(searchTarget), 2, 3)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
results := make([]MaybeRootDevice, len(responses))
|
|
for i, response := range responses {
|
|
maybe := &results[i]
|
|
loc, err := response.Location()
|
|
if err != nil {
|
|
maybe.Err = ContextError{"unexpected bad location from search", err}
|
|
continue
|
|
}
|
|
maybe.Location = loc
|
|
if root, err := DeviceByURL(loc); err != nil {
|
|
maybe.Err = err
|
|
} else {
|
|
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{
|
|
Timeout: timeout,
|
|
}
|
|
resp, err := client.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return fmt.Errorf("goupnp: got response status %s from %q",
|
|
resp.Status, url)
|
|
}
|
|
|
|
decoder := xml.NewDecoder(resp.Body)
|
|
decoder.DefaultSpace = defaultSpace
|
|
decoder.CharsetReader = charset.NewReaderLabel
|
|
|
|
return decoder.Decode(doc)
|
|
}
|