Skip to content

Commit

Permalink
feat: 获取 Service description
Browse files Browse the repository at this point in the history
  • Loading branch information
SALTWOOD committed Aug 7, 2024
1 parent 3d90dd1 commit 6d8e981
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 65 deletions.
9 changes: 1 addition & 8 deletions UpnpSharp/HttpPacketParser.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;

namespace UpnpSharp
namespace UpnpSharp
{
public class HttpPacketParser
{
Expand Down
13 changes: 0 additions & 13 deletions UpnpSharp/Ssdp/Ssdp.cs

This file was deleted.

9 changes: 3 additions & 6 deletions UpnpSharp/Ssdp/SsdpDevice.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;

Expand All @@ -24,7 +20,7 @@ public class SsdpDevice
return this.SsdpDeviceInfo?.Device.GetServices();
}

public string? BaseUrl => this.SsdpDeviceInfo?.Device.UrlBase != null ? this.SsdpDeviceInfo.Device.UrlBase : this.parser["Location"];
public string? BaseUrl => string.IsNullOrWhiteSpace(this.SsdpDeviceInfo?.Device.UrlBase) ? this.parser["Location"] : this.SsdpDeviceInfo?.Device.UrlBase;

string response;
protected HttpPacketParser parser;
Expand All @@ -39,6 +35,7 @@ public SsdpDevice(IPEndPoint address, string message)

this.GetDescription(this.parser["Location"]).Wait();
this.ParseXml();
this.SsdpDeviceInfo.Device.GetServices().Select(service => new SsdpService(BaseUrl, service)).ToList();
}

public async Task<string?> GetDescription(string? url)
Expand Down
7 changes: 1 addition & 6 deletions UpnpSharp/Ssdp/SsdpRequest.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UpnpSharp.Ssdp
{
Expand Down
76 changes: 76 additions & 0 deletions UpnpSharp/Ssdp/SsdpService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UpnpSharp.Utils;

namespace UpnpSharp.Ssdp
{
public class SsdpService
{
string baseUrl, scpdUrl;
protected SsdpDeviceService serviceXml;

public string Type => this.serviceXml.ServiceType;
public string Id => this.serviceXml.ServiceId;
public string ScpdUrl => scpdUrl;
public string ControlUrl => this.serviceXml.ControlUrl;
public string EventSubUrl => this.serviceXml.EventSubUrl;
public string BaseUrl => baseUrl;
public string? Description { get; protected set; }
public Dictionary<string, string> Actions { get; protected set; } = new();

public SsdpService(string baseUrl, SsdpDeviceService service)
{
this.serviceXml = service;

this.baseUrl = baseUrl;
this.scpdUrl = service.ScpdUrl;

UrlParser baseUri = new UrlParser(baseUrl);
UrlParser scpdUri = new UrlParser(scpdUrl);
if (baseUri.Scheme != Uri.UriSchemeHttp)
{
throw new Exception($"Unsupported url scheme: {baseUri.Scheme}");
}

if (scpdUri.Scheme == Uri.UriSchemeHttp)
{
if (scpdUri.Host != baseUri.Host) throw new Exception($"Host doesn't match: \"{scpdUri.Host}\" and \"{baseUri.Host}\"");
}
else if (string.IsNullOrWhiteSpace(scpdUri.Scheme))
{
if (scpdUrl.StartsWith('/')) this.scpdUrl = $"{baseUri.Scheme}://{baseUri.Host}:{baseUri.Port}{scpdUrl}";
else this.scpdUrl = $"{baseUri.Scheme}://{baseUri.Host}:{baseUri.Port}/{scpdUri.ToString()}";
}
else throw new Exception($"Unsupported url scheme: {scpdUri.Scheme}");

RequestDescription().Wait();
RequestStateVariables();
RequestActions();
}

private void RequestActions()
{
Console.WriteLine(this.Description);
}

private void RequestStateVariables()
{
return;
}

public async Task RequestDescription()
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(this.ScpdUrl);
if (!response.IsSuccessStatusCode)
{
this.Description = null;
throw new Exception($"Unsuccessful request: 2xx or 3xx status code expected, got {response.StatusCode}.");
}
this.Description = await response.Content.ReadAsStringAsync();
}
}
}
17 changes: 6 additions & 11 deletions UpnpSharp/Ssdp/SsdpXml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Xml.Serialization;

namespace UpnpSharp.Ssdp
{
Expand Down Expand Up @@ -44,7 +39,7 @@ public partial class SsdpDeviceXml
public string ModelName { get; set; } = string.Empty;

[XmlElement(ElementName = "modelNumber")]
public byte ModelNumber { get; set; }
public string ModelNumber { get; set; } = string.Empty;

[XmlElement(ElementName = "modelURL")]
public string ModelUrl { get; set; } = string.Empty;
Expand All @@ -59,10 +54,10 @@ public partial class SsdpDeviceXml
public string UrlBase { get; set; } = string.Empty;

[XmlElement(ElementName = "UPC")]
public byte Upc { get; set; }
public string Upc { get; set; }

[XmlElement(ElementName = "serviceList")]
public SsdpDeviceServiceXml ServiceList { get; set; } = new();
public SsdpDeviceServiceList ServiceList { get; set; } = new();

/// <remarks/>
[XmlElement(ElementName = "deviceList")]
Expand All @@ -79,7 +74,7 @@ public IEnumerable<SsdpDeviceService> GetServices()
public IEnumerable<SsdpDeviceService> GetServices(SsdpDeviceXml? xml)
{
var thisService = xml?.ServiceList.Service;
if (!string.IsNullOrWhiteSpace(thisService?.ServiceType)) yield return thisService;
if (!string.IsNullOrWhiteSpace(thisService?.ServiceType)) yield return thisService;
SsdpDeviceXml[]? subDevices = xml?.DeviceList.Devices;
if (subDevices != null)
{
Expand Down Expand Up @@ -109,7 +104,7 @@ public class SsdpDevices
[Serializable]
[System.ComponentModel.DesignerCategory("code")]
[XmlType(AnonymousType = true, Namespace = "urn:schemas-upnp-org:device-1-0")]
public partial class SsdpDeviceServiceXml
public partial class SsdpDeviceServiceList
{
[XmlElement(ElementName = "service")]
public SsdpDeviceService Service { get; set; } = new SsdpDeviceService();
Expand Down
10 changes: 2 additions & 8 deletions UpnpSharp/Upnp/Upnp.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using UpnpSharp.Ssdp;
using UpnpSharp.Ssdp;

namespace UpnpSharp.Upnp
{
Expand Down Expand Up @@ -32,7 +26,7 @@ public IEnumerable<SsdpDevice> Discover(int delay = 2000)
yield return device;
}
}

public SsdpDevice? GetIgd()
{
List<SsdpDevice> igds = new List<SsdpDevice>();
Expand Down
13 changes: 0 additions & 13 deletions UpnpSharp/Utils.cs

This file was deleted.

62 changes: 62 additions & 0 deletions UpnpSharp/Utils/UrlParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Text.RegularExpressions;

namespace UpnpSharp.Utils
{
public class UrlParser
{
public string Scheme { get; protected set; } = string.Empty;
public string Host { get; protected set; } = string.Empty;
public ushort Port { get; protected set; } = 0;
public string Path { get; protected set; } = string.Empty;

public UrlParser(string uri)
{
if (string.IsNullOrEmpty(uri))
throw new ArgumentNullException(nameof(uri), "The URI cannot be null or empty.");

ParseUri(uri);
}

private void ParseUri(string uri)
{
var schemeMatch = Regex.Match(uri, @"^(?<scheme>[a-zA-Z][a-zA-Z0-9+.-]*):");
if (schemeMatch.Success)
{
Scheme = schemeMatch.Groups["scheme"].Value;
uri = uri.Substring(Scheme.Length + 1); // Remove scheme from uri
}

var authorityMatch = Regex.Match(uri, @"^//(?<authority>[^/]+)");
if (authorityMatch.Success)
{
var authority = authorityMatch.Groups["authority"].Value;
uri = uri.Substring(authority.Length + 2); // Remove authority from uri

var hostPortMatch = Regex.Match(authority, @"^(?<host>[^:]+)(:(?<port>\d+))?$");
if (hostPortMatch.Success)
{
Host = hostPortMatch.Groups["host"].Value;
Port = hostPortMatch.Groups["port"].Success ? ushort.Parse(hostPortMatch.Groups["port"].Value) : GetDefaultPort(Scheme);
}
}

Path = uri;
}

private ushort GetDefaultPort(string scheme)
{
switch (scheme?.ToLower())
{
case "http":
return 80;
case "https":
return 443;
case "ftp":
return 21;
default:
return 0;
}
}
}
}

0 comments on commit 6d8e981

Please sign in to comment.