diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-10-29 18:22:20 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-10-29 18:22:20 -0400 |
| commit | dca78b13411db96366dddfa0d68bb6d36d28ad14 (patch) | |
| tree | 7d41e670f1cadec0db9e1ed7115e151da891f7ea /Emby.Dlna/Service | |
| parent | 597e27d1c6199a40398abb068282711a9cb9db1b (diff) | |
rework dlna project
Diffstat (limited to 'Emby.Dlna/Service')
| -rw-r--r-- | Emby.Dlna/Service/BaseControlHandler.cs | 137 | ||||
| -rw-r--r-- | Emby.Dlna/Service/BaseService.cs | 37 | ||||
| -rw-r--r-- | Emby.Dlna/Service/ControlErrorHandler.cs | 41 | ||||
| -rw-r--r-- | Emby.Dlna/Service/ServiceXmlBuilder.cs | 91 |
4 files changed, 306 insertions, 0 deletions
diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs new file mode 100644 index 0000000000..c5de76eb5f --- /dev/null +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -0,0 +1,137 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Dlna.Server; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml; + +namespace MediaBrowser.Dlna.Service +{ + public abstract class BaseControlHandler + { + private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; + + protected readonly IServerConfigurationManager Config; + protected readonly ILogger Logger; + + protected BaseControlHandler(IServerConfigurationManager config, ILogger logger) + { + Config = config; + Logger = logger; + } + + public ControlResponse ProcessControlRequest(ControlRequest request) + { + try + { + var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLog; + + if (enableDebugLogging) + { + LogRequest(request); + } + + var response = ProcessControlRequestInternal(request); + + if (enableDebugLogging) + { + LogResponse(response); + } + + return response; + } + catch (Exception ex) + { + Logger.ErrorException("Error processing control request", ex); + + return new ControlErrorHandler().GetResponse(ex); + } + } + + private ControlResponse ProcessControlRequestInternal(ControlRequest request) + { + var soap = new XmlDocument(); + soap.LoadXml(request.InputXml); + var sparams = new Headers(); + var body = soap.GetElementsByTagName("Body", NS_SOAPENV).Item(0); + + var method = body.FirstChild; + + foreach (var p in method.ChildNodes) + { + var e = p as XmlElement; + if (e == null) + { + continue; + } + sparams.Add(e.LocalName, e.InnerText.Trim()); + } + + Logger.Debug("Received control request {0}", method.LocalName); + + var result = GetResult(method.LocalName, sparams); + + var env = new XmlDocument(); + env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", string.Empty)); + var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV); + env.AppendChild(envelope); + envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/"); + + var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV); + env.DocumentElement.AppendChild(rbody); + + var response = env.CreateElement(String.Format("u:{0}Response", method.LocalName), method.NamespaceURI); + rbody.AppendChild(response); + + foreach (var i in result) + { + var ri = env.CreateElement(i.Key); + ri.InnerText = i.Value; + response.AppendChild(ri); + } + + var xml = env.OuterXml.Replace("xmlns:m=", "xmlns:u="); + + var controlResponse = new ControlResponse + { + Xml = xml, + IsSuccessful = true + }; + + //Logger.Debug(xml); + + controlResponse.Headers.Add("EXT", string.Empty); + + return controlResponse; + } + + protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams); + + private void LogRequest(ControlRequest request) + { + var builder = new StringBuilder(); + + var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); + builder.AppendFormat("Headers: {0}", headers); + builder.AppendLine(); + builder.Append(request.InputXml); + + Logger.LogMultiline("Control request", LogSeverity.Debug, builder); + } + + private void LogResponse(ControlResponse response) + { + var builder = new StringBuilder(); + + var headers = string.Join(", ", response.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray()); + builder.AppendFormat("Headers: {0}", headers); + builder.AppendLine(); + builder.Append(response.Xml); + + Logger.LogMultiline("Control response", LogSeverity.Debug, builder); + } + } +} diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs new file mode 100644 index 0000000000..aeea7b8f34 --- /dev/null +++ b/Emby.Dlna/Service/BaseService.cs @@ -0,0 +1,37 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Dlna.Eventing; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.Dlna.Service +{ + public class BaseService : IEventManager + { + protected IEventManager EventManager; + protected IHttpClient HttpClient; + protected ILogger Logger; + + protected BaseService(ILogger logger, IHttpClient httpClient) + { + Logger = logger; + HttpClient = httpClient; + + EventManager = new EventManager(Logger, HttpClient); + } + + public EventSubscriptionResponse CancelEventSubscription(string subscriptionId) + { + return EventManager.CancelEventSubscription(subscriptionId); + } + + public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, int? timeoutSeconds) + { + return EventManager.RenewEventSubscription(subscriptionId, timeoutSeconds); + } + + public EventSubscriptionResponse CreateEventSubscription(string notificationType, int? timeoutSeconds, string callbackUrl) + { + return EventManager.CreateEventSubscription(notificationType, timeoutSeconds, callbackUrl); + } + } +} diff --git a/Emby.Dlna/Service/ControlErrorHandler.cs b/Emby.Dlna/Service/ControlErrorHandler.cs new file mode 100644 index 0000000000..42b1fcbc99 --- /dev/null +++ b/Emby.Dlna/Service/ControlErrorHandler.cs @@ -0,0 +1,41 @@ +using MediaBrowser.Controller.Dlna; +using System; +using System.Xml; + +namespace MediaBrowser.Dlna.Service +{ + public class ControlErrorHandler + { + private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; + + public ControlResponse GetResponse(Exception ex) + { + var env = new XmlDocument(); + env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", "yes")); + var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV); + env.AppendChild(envelope); + envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/"); + + var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV); + env.DocumentElement.AppendChild(rbody); + + var fault = env.CreateElement("SOAP-ENV", "Fault", NS_SOAPENV); + var faultCode = env.CreateElement("faultcode"); + faultCode.InnerText = "500"; + fault.AppendChild(faultCode); + var faultString = env.CreateElement("faultstring"); + faultString.InnerText = ex.ToString(); + fault.AppendChild(faultString); + var detail = env.CreateDocumentFragment(); + detail.InnerXml = "<detail><UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>401</errorCode><errorDescription>Invalid Action</errorDescription></UPnPError></detail>"; + fault.AppendChild(detail); + rbody.AppendChild(fault); + + return new ControlResponse + { + Xml = env.OuterXml, + IsSuccessful = false + }; + } + } +} diff --git a/Emby.Dlna/Service/ServiceXmlBuilder.cs b/Emby.Dlna/Service/ServiceXmlBuilder.cs new file mode 100644 index 0000000000..615a4bdb37 --- /dev/null +++ b/Emby.Dlna/Service/ServiceXmlBuilder.cs @@ -0,0 +1,91 @@ +using MediaBrowser.Dlna.Common; +using System.Collections.Generic; +using System.Security; +using System.Text; +using MediaBrowser.Dlna.Server; + +namespace MediaBrowser.Dlna.Service +{ + public class ServiceXmlBuilder + { + public string GetXml(IEnumerable<ServiceAction> actions, IEnumerable<StateVariable> stateVariables) + { + var builder = new StringBuilder(); + + builder.Append("<?xml version=\"1.0\"?>"); + builder.Append("<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">"); + + builder.Append("<specVersion>"); + builder.Append("<major>1</major>"); + builder.Append("<minor>0</minor>"); + builder.Append("</specVersion>"); + + AppendActionList(builder, actions); + AppendServiceStateTable(builder, stateVariables); + + builder.Append("</scpd>"); + + return builder.ToString(); + } + + private void AppendActionList(StringBuilder builder, IEnumerable<ServiceAction> actions) + { + builder.Append("<actionList>"); + + foreach (var item in actions) + { + builder.Append("<action>"); + + builder.Append("<name>" + DescriptionXmlBuilder.Escape(item.Name ?? string.Empty) + "</name>"); + + builder.Append("<argumentList>"); + + foreach (var argument in item.ArgumentList) + { + builder.Append("<argument>"); + + builder.Append("<name>" + DescriptionXmlBuilder.Escape(argument.Name ?? string.Empty) + "</name>"); + builder.Append("<direction>" + DescriptionXmlBuilder.Escape(argument.Direction ?? string.Empty) + "</direction>"); + builder.Append("<relatedStateVariable>" + DescriptionXmlBuilder.Escape(argument.RelatedStateVariable ?? string.Empty) + "</relatedStateVariable>"); + + builder.Append("</argument>"); + } + + builder.Append("</argumentList>"); + + builder.Append("</action>"); + } + + builder.Append("</actionList>"); + } + + private void AppendServiceStateTable(StringBuilder builder, IEnumerable<StateVariable> stateVariables) + { + builder.Append("<serviceStateTable>"); + + foreach (var item in stateVariables) + { + var sendEvents = item.SendsEvents ? "yes" : "no"; + + builder.Append("<stateVariable sendEvents=\"" + sendEvents + "\">"); + + builder.Append("<name>" + DescriptionXmlBuilder.Escape(item.Name ?? string.Empty) + "</name>"); + builder.Append("<dataType>" + DescriptionXmlBuilder.Escape(item.DataType ?? string.Empty) + "</dataType>"); + + if (item.AllowedValues.Count > 0) + { + builder.Append("<allowedValueList>"); + foreach (var allowedValue in item.AllowedValues) + { + builder.Append("<allowedValue>" + DescriptionXmlBuilder.Escape(allowedValue) + "</allowedValue>"); + } + builder.Append("</allowedValueList>"); + } + + builder.Append("</stateVariable>"); + } + + builder.Append("</serviceStateTable>"); + } + } +} |
