2015-02-16 15:28:33 +02:00
|
|
|
package goupnp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-10-30 00:53:53 +03:00
|
|
|
"net/url"
|
|
|
|
|
2015-02-17 14:10:11 +02:00
|
|
|
"github.com/huin/goupnp/soap"
|
2015-02-16 15:28:33 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// ServiceClient is a SOAP client, root device and the service for the SOAP
|
2015-10-30 00:53:53 +03:00
|
|
|
// client rolled into one value. The root device, location, and service are
|
|
|
|
// intended to be informational. Location can be used to later recreate a
|
|
|
|
// ServiceClient with NewServiceClientByURL if the service is still present;
|
|
|
|
// bypassing the discovery process.
|
2015-02-16 15:28:33 +02:00
|
|
|
type ServiceClient struct {
|
|
|
|
SOAPClient *soap.SOAPClient
|
|
|
|
RootDevice *RootDevice
|
2015-10-30 00:53:53 +03:00
|
|
|
Location *url.URL
|
2015-02-16 15:28:33 +02:00
|
|
|
Service *Service
|
|
|
|
}
|
|
|
|
|
2015-10-30 00:53:53 +03:00
|
|
|
// NewServiceClients discovers services, and returns clients for them. err will
|
|
|
|
// report any error with the discovery process (blocking any device/service
|
|
|
|
// discovery), errors reports errors on a per-root-device basis.
|
2015-02-16 15:28:33 +02:00
|
|
|
func NewServiceClients(searchTarget string) (clients []ServiceClient, errors []error, err error) {
|
|
|
|
var maybeRootDevices []MaybeRootDevice
|
|
|
|
if maybeRootDevices, err = DiscoverDevices(searchTarget); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
clients = make([]ServiceClient, 0, len(maybeRootDevices))
|
|
|
|
|
|
|
|
for _, maybeRootDevice := range maybeRootDevices {
|
|
|
|
if maybeRootDevice.Err != nil {
|
|
|
|
errors = append(errors, maybeRootDevice.Err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-10-30 00:53:53 +03:00
|
|
|
deviceClients, err := NewServiceClientsFromRootDevice(maybeRootDevice.Root, maybeRootDevice.Location, searchTarget)
|
|
|
|
if err != nil {
|
|
|
|
errors = append(errors, err)
|
2015-02-16 15:28:33 +02:00
|
|
|
continue
|
|
|
|
}
|
2015-10-30 00:53:53 +03:00
|
|
|
clients = append(clients, deviceClients...)
|
2015-02-16 15:28:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-10-30 00:53:53 +03:00
|
|
|
// NewServiceClientsByURL creates client(s) for the given service URN, for a
|
|
|
|
// root device at the given URL.
|
|
|
|
func NewServiceClientsByURL(loc *url.URL, searchTarget string) ([]ServiceClient, error) {
|
|
|
|
rootDevice, err := DeviceByURL(loc)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return NewServiceClientsFromRootDevice(rootDevice, loc, searchTarget)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewServiceClientsFromDevice creates client(s) for the given service URN, in
|
|
|
|
// a given root device. The loc parameter is simply assigned to the
|
|
|
|
// Location attribute of the returned ServiceClient(s).
|
|
|
|
func NewServiceClientsFromRootDevice(rootDevice *RootDevice, loc *url.URL, searchTarget string) ([]ServiceClient, error) {
|
|
|
|
device := &rootDevice.Device
|
|
|
|
srvs := device.FindService(searchTarget)
|
|
|
|
if len(srvs) == 0 {
|
|
|
|
return nil, fmt.Errorf("goupnp: service %q not found within device %q (UDN=%q)",
|
|
|
|
searchTarget, device.FriendlyName, device.UDN)
|
|
|
|
}
|
|
|
|
|
|
|
|
clients := make([]ServiceClient, 0, len(srvs))
|
|
|
|
for _, srv := range srvs {
|
|
|
|
clients = append(clients, ServiceClient{
|
|
|
|
SOAPClient: srv.NewSOAPClient(),
|
|
|
|
RootDevice: rootDevice,
|
|
|
|
Location: loc,
|
|
|
|
Service: srv,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return clients, nil
|
|
|
|
}
|
|
|
|
|
2015-02-16 15:28:33 +02:00
|
|
|
// GetServiceClient returns the ServiceClient itself. This is provided so that the
|
|
|
|
// service client attributes can be accessed via an interface method on a
|
|
|
|
// wrapping type.
|
|
|
|
func (client *ServiceClient) GetServiceClient() *ServiceClient {
|
|
|
|
return client
|
|
|
|
}
|