Various improvements

This commit is contained in:
Chris 2017-02-18 13:12:36 +01:00
parent ccc70650f2
commit a9c1a3ccbe
7 changed files with 185 additions and 22 deletions

View File

@ -40,6 +40,14 @@ object to get the devices.
print_r($device); print_r($device);
} }
## Experimental Features
### DCP
The DCPs (Device Control Protocol) are used to interact with services. This
can be f.ex. managing UPnP portmapping in your router or controlling a media
player.
## Search targets ## Search targets
To find everything, use `ALL`: To find everything, use `ALL`:

View File

@ -10,10 +10,11 @@
require_once __DIR__."/../vendor/autoload.php"; require_once __DIR__."/../vendor/autoload.php";
use NoccyLabs\UPnP\SSDP\Device;
use NoccyLabs\UPnP\SSDP\Discovery; use NoccyLabs\UPnP\SSDP\Discovery;
use NoccyLabs\UPnP\SSDP\SearchTarget; use NoccyLabs\UPnP\SSDP\SearchTarget;
$opt_short = "hARd:s:u:D:l"; $opt_short = "hARd:s:u:D:lj";
$opt_long = [ $opt_long = [
"help", // -h "help", // -h
"all", // -A "all", // -A
@ -22,7 +23,8 @@ $opt_long = [
"service:", // -s: "service:", // -s:
"uuid:", // -u: "uuid:", // -u:
"domain:", // -D: "domain:", // -D:
"long", "long", // -l
"json", // -j
]; ];
$help = <<<EOH $help = <<<EOH
upnp-discover - Discover UPnP devices on the local network upnp-discover - Discover UPnP devices on the local network
@ -39,6 +41,7 @@ Options:
-D, --domain Combine with -d or -s to search for specific vendor domains. -D, --domain Combine with -d or -s to search for specific vendor domains.
-u, --uuid Find by UUID -u, --uuid Find by UUID
-l, --long Include all info in output -l, --long Include all info in output
-j, --json Output JSON
Examples: Examples:
@ -69,7 +72,8 @@ $opts = (object)[
'service'=>null, 'service'=>null,
'domain'=>null, 'domain'=>null,
'uuid'=>null, 'uuid'=>null,
'long'=>null 'long'=>null,
'json'=>null
]; ];
foreach (getopt($opt_short, $opt_long) as $opt=>$value) switch ($opt) { foreach (getopt($opt_short, $opt_long) as $opt=>$value) switch ($opt) {
@ -97,6 +101,9 @@ foreach (getopt($opt_short, $opt_long) as $opt=>$value) switch ($opt) {
case 'long': case 'long':
case 'l': case 'l':
$opts->long = true; break; $opts->long = true; break;
case 'json':
case 'j':
$opts->json = true; break;
} }
if ($opts->device && $opts->service) { if ($opts->device && $opts->service) {
@ -190,17 +197,54 @@ function discover_root() {
} }
function show_results(Discovery $discovery) { function show_results(Discovery $discovery) {
foreach ($discovery as $device) { global $opts;
printf(" %s: %s (%s) %s [%s]\n", if ($opts->long) {
$device->getFriendlyName(), show_results_long($discovery);
$device->getModelName(), } elseif ($opts->json) {
$device->getManufacturer(), show_results_json($discovery);
$device->getDeviceType(), } else {
$device->getIp() show_results_short($discovery);
);
foreach ($device->getServices() as $service) {
printf(" + %s\n", $service->getServiceType());
} }
} }
function show_results_short(Discovery $discovery) {
foreach ($discovery as $device) {
printf(" * \e[94m%s: %s \e[1m%s\e[21m (%s) [%s]\e[0m\n",
$device->getFriendlyName(),
$device->getManufacturer(),
$device->getModelName(),
$device->getDeviceType(),
$device->getIp()
);
}
}
function show_results_long(Discovery $discovery) {
foreach ($discovery as $device) {
show_device_long($device);
}
}
function show_device_long(Device $device, $level=0) {
$indent = str_repeat(" ",$level);
printf("{$indent} * \e[92m%s\e[94m: %s \e[1m%s\e[21m (\e[34m%s\e[94m) [%s]\e[0m\n",
$device->getFriendlyName(),
$device->getManufacturer(),
$device->getModelName(),
$device->getDeviceType(),
$device->getIp()
);
printf("{$indent} \e[32m%s\e[0m\n", $device->getUrl());
foreach ($device->getServices() as $service) {
printf("{$indent} + \e[36m%s\e[0m\n{$indent} \e[32m%s\e[0m\n", $service->getServiceType(), $service->getServiceUrl());
}
foreach ($device->getDevices() as $subdevice) {
show_device_long($subdevice, $level+1);
}
}
function show_results_json(Discovery $discovery) {
echo json_encode($discovery, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)."\n";
} }

View File

@ -0,0 +1,22 @@
<?php
namespace NoccyLabs\UPnP\DCP;
use NoccyLabs\UPnP\DCP\AbstractDevice;
use NoccyLabs\UPnP\SSDP\Device;
abstract class AbstractDevice
{
/** @var Device The device this DCP operates on */
protected $device;
/**
*
*
* @param Device $device The device for the DCP
*/
public function __construct(Device $device)
{
$this->device = $device;
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace NoccyLabs\UPnP\DCP;
use NoccyLabs\UPnP\DCP\AbstractService;
use NoccyLabs\UPnP\SSDP\Device;
use NoccyLabs\UPnP\SSDP\Service;
abstract class AbstractService
{
/** @var Service The service this DCP operates on */
protected $service;
/** @var Device The device this DCP operates on */
protected $device;
/**
*
*
* @param Device $device The device for the DCP
* @param Service $service The service for the DCP
*/
public function __construct(Device $device, Service $service)
{
$this->device = $device;
$this->service = $service;
}
private function readScpdServiceDefinition($url)
{}
/**
* Get the schema to pass as the XML namespace when sending the SOAP request
* to the device.
*
* @return string The schema
*/
abstract protected function getSchemaUrn();
}

View File

@ -17,8 +17,9 @@ namespace NoccyLabs\UPnP\SSDP;
*/ */
use SimpleXMLElement; use SimpleXMLElement;
use JsonSerializable;
class Device class Device implements JsonSerializable
{ {
protected $deviceType; protected $deviceType;
@ -86,7 +87,7 @@ class Device
$services = $spec->serviceList; $services = $spec->serviceList;
if (count($services)>0) { if (count($services)>0) {
foreach ($services->children() as $service) { foreach ($services->children() as $service) {
$this->services[] = new Service($service); $this->services[] = new Service($this, $service);
} }
} }
@ -163,5 +164,16 @@ class Device
return $info; return $info;
} }
public function createServiceWrapper($type)
{
}
public function jsonSerialize()
{
return get_object_vars($this);
}
} }

View File

@ -4,6 +4,7 @@ namespace NoccyLabs\UPnP\SSDP;
use IteratorAggregate; use IteratorAggregate;
use ArrayIterator; use ArrayIterator;
use JsonSerializable;
use NoccyLabs\UPnP\HTTPU\Endpoint; use NoccyLabs\UPnP\HTTPU\Endpoint;
use NoccyLabs\UPnP\HTTPU\EndpointException; use NoccyLabs\UPnP\HTTPU\EndpointException;
use NoccyLabs\UPnP\HTTPU\MSearchRequest; use NoccyLabs\UPnP\HTTPU\MSearchRequest;
@ -14,7 +15,7 @@ use NoccyLabs\UPnP\HTTPU\MSearchResponse;
* *
* *
*/ */
class Discovery implements IteratorAggregate class Discovery implements IteratorAggregate, JsonSerializable
{ {
protected $devices = []; protected $devices = [];
@ -52,9 +53,13 @@ class Discovery implements IteratorAggregate
continue; continue;
} }
$device = Device::createFromSchema($response->getLocation(), $response->getIp()); $device = Device::createFromSchema($response->getLocation(), $response->getIp());
if ($device) {
$this->devices[$loc] = $device; $this->devices[$loc] = $device;
} }
} }
}
$this->devices = array_values($this->devices);
return count($this->devices); return count($this->devices);
@ -65,5 +70,10 @@ class Discovery implements IteratorAggregate
return new ArrayIterator($this->devices); return new ArrayIterator($this->devices);
} }
public function jsonSerialize()
{
return $this->devices;
}
} }

View File

@ -10,10 +10,13 @@ namespace NoccyLabs\UPnP\SSDP;
<eventSubURL>/evt/L3F</eventSubURL> <eventSubURL>/evt/L3F</eventSubURL>
*/ */
use JsonSerializable;
use SimpleXMLElement; use SimpleXMLElement;
class Service class Service implements JsonSerializable
{ {
protected $device;
protected $serviceType; protected $serviceType;
protected $serviceId; protected $serviceId;
@ -24,9 +27,10 @@ class Service
protected $eventSubUrl; protected $eventSubUrl;
public function __construct(SimpleXMLElement $spec) public function __construct(Device $device, SimpleXMLElement $spec)
{ {
$this->device = $device;
$this->serviceType = (string)$spec->serviceType; $this->serviceType = (string)$spec->serviceType;
$this->serviceId = (string)$spec->serviceId; $this->serviceId = (string)$spec->serviceId;
$this->scpdUrl = (string)$spec->SCPDURL; $this->scpdUrl = (string)$spec->SCPDURL;
@ -50,6 +54,26 @@ class Service
return $this->scpdUrl; return $this->scpdUrl;
} }
public function getServiceUrl()
{
if (strpos($this->scpdUrl,"://")!==false) {
return $this->scpdUrl;
}
$dev = ['user'=>null, 'pass'=>null, 'port'=>80, 'path'=>null];
$dev = array_merge($dev, parse_url($this->device->getUrl()));
$url = $this->scpdUrl;
$auth = $dev['user']?($dev['user'].":".$dev['path']):"";
$base = $dev['scheme']."://".$dev['host'].":".($dev['port']?:80);
if ($url[0]=="/") {
return $base.$url;
} else {
return $base.rtrim($dev['path'],"/")."/".$url;
}
}
public function getControlUrl() public function getControlUrl()
{ {
return $this->controlUrl; return $this->controlUrl;
@ -71,5 +95,10 @@ class Service
); );
} }
public function jsonSerialize()
{
return get_object_vars($this);
}
} }