From 1774e5b1ac9f809fd97c1d95666fc563afa87914 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 20 May 2014 20:56:24 -0400 Subject: [PATCH] added upnp ConnectionManager.cs --- MediaBrowser.Api/Dlna/DlnaServerService.cs | 48 +++- .../Dlna/IConnectionManager.cs | 7 + .../Dlna/IContentDirectory.cs | 18 +- MediaBrowser.Controller/Dlna/IUpnpService.cs | 21 ++ .../MediaBrowser.Controller.csproj | 2 + .../ConnectionManager/ConnectionManager.cs | 34 +++ .../ConnectionManagerXmlBuilder.cs | 106 +++++++++ .../ConnectionManager/ControlHandler.cs | 30 +++ .../ServiceActionListBuilder.cs | 205 ++++++++++++++++++ .../ContentDirectory.cs | 11 +- .../ContentDirectoryXmlBuilder.cs | 98 +-------- .../ControlHandler.cs | 156 ++----------- .../ServiceActionListBuilder.cs | 2 +- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 11 +- MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 16 +- .../Server/DescriptionXmlBuilder.cs | 9 + .../Service/BaseControlHandler.cs | 112 ++++++++++ .../Service/ControlErrorHandler.cs | 41 ++++ .../Service/ServiceXmlBuilder.cs | 90 ++++++++ .../Channels/ChannelManager.cs | 2 +- .../Session/HttpSessionController.cs | 32 +-- .../WebSocket/AlchemyServer.cs | 4 +- .../ApplicationHost.cs | 5 + 23 files changed, 779 insertions(+), 281 deletions(-) create mode 100644 MediaBrowser.Controller/Dlna/IConnectionManager.cs create mode 100644 MediaBrowser.Controller/Dlna/IUpnpService.cs create mode 100644 MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs create mode 100644 MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs create mode 100644 MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs create mode 100644 MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs rename MediaBrowser.Dlna/{Server => ContentDirectory}/ContentDirectory.cs (90%) rename MediaBrowser.Dlna/{Server => ContentDirectory}/ContentDirectoryXmlBuilder.cs (52%) rename MediaBrowser.Dlna/{Server => ContentDirectory}/ControlHandler.cs (69%) rename MediaBrowser.Dlna/{Server => ContentDirectory}/ServiceActionListBuilder.cs (99%) create mode 100644 MediaBrowser.Dlna/Service/BaseControlHandler.cs create mode 100644 MediaBrowser.Dlna/Service/ControlErrorHandler.cs create mode 100644 MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs index 05d41c18bc..8e4e559df2 100644 --- a/MediaBrowser.Api/Dlna/DlnaServerService.cs +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -25,8 +25,23 @@ namespace MediaBrowser.Api.Dlna { } + [Route("/Dlna/connectionmanager/connectionmanager.xml", "GET", Summary = "Gets dlna connection manager xml")] + [Route("/Dlna/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")] + public class GetConnnectionManager + { + } + [Route("/Dlna/contentdirectory/{UuId}/control", "POST", Summary = "Processes a control request")] - public class ProcessControlRequest : IRequiresRequestStream + public class ProcessContentDirectoryControlRequest : IRequiresRequestStream + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + + public Stream RequestStream { get; set; } + } + + [Route("/Dlna/connectionmanager/{UuId}/control", "POST", Summary = "Processes a control request")] + public class ProcessConnectionManagerControlRequest : IRequiresRequestStream { [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] public string UuId { get; set; } @@ -35,6 +50,7 @@ namespace MediaBrowser.Api.Dlna } [Route("/Dlna/contentdirectory/{UuId}/events", Summary = "Processes an event subscription request")] + [Route("/Dlna/connectionmanager/{UuId}/events", Summary = "Processes an event subscription request")] public class ProcessEventRequest { [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -53,12 +69,14 @@ namespace MediaBrowser.Api.Dlna private readonly IDlnaManager _dlnaManager; private readonly IContentDirectory _contentDirectory; private readonly IEventManager _eventManager; + private readonly IConnectionManager _connectionManager; - public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IEventManager eventManager) + public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IEventManager eventManager, IConnectionManager connectionManager) { _dlnaManager = dlnaManager; _contentDirectory = contentDirectory; _eventManager = eventManager; + _connectionManager = connectionManager; } public object Get(GetDescriptionXml request) @@ -70,26 +88,40 @@ namespace MediaBrowser.Api.Dlna public object Get(GetContentDirectory request) { - var xml = _contentDirectory.GetContentDirectoryXml(GetRequestHeaders()); + var xml = _contentDirectory.GetServiceXml(GetRequestHeaders()); return ResultFactory.GetResult(xml, "text/xml"); } - public object Post(ProcessControlRequest request) + public object Get(GetConnnectionManager request) + { + var xml = _connectionManager.GetServiceXml(GetRequestHeaders()); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Post(ProcessContentDirectoryControlRequest request) + { + var response = PostAsync(request.RequestStream, _contentDirectory).Result; + + return ResultFactory.GetResult(response.Xml, "text/xml"); + } + + public object Post(ProcessConnectionManagerControlRequest request) { - var response = PostAsync(request).Result; + var response = PostAsync(request.RequestStream, _connectionManager).Result; return ResultFactory.GetResult(response.Xml, "text/xml"); } - private async Task PostAsync(ProcessControlRequest request) + private async Task PostAsync(Stream requestStream, IUpnpService service) { var pathInfo = PathInfo.Parse(Request.PathInfo); var id = pathInfo.GetArgumentValue(2); - using (var reader = new StreamReader(request.RequestStream)) + using (var reader = new StreamReader(requestStream)) { - return _contentDirectory.ProcessControlRequest(new ControlRequest + return service.ProcessControlRequest(new ControlRequest { Headers = GetRequestHeaders(), InputXml = await reader.ReadToEndAsync().ConfigureAwait(false), diff --git a/MediaBrowser.Controller/Dlna/IConnectionManager.cs b/MediaBrowser.Controller/Dlna/IConnectionManager.cs new file mode 100644 index 0000000000..942e523e88 --- /dev/null +++ b/MediaBrowser.Controller/Dlna/IConnectionManager.cs @@ -0,0 +1,7 @@ + +namespace MediaBrowser.Controller.Dlna +{ + public interface IConnectionManager : IUpnpService + { + } +} diff --git a/MediaBrowser.Controller/Dlna/IContentDirectory.cs b/MediaBrowser.Controller/Dlna/IContentDirectory.cs index e48d498dfe..00c236813b 100644 --- a/MediaBrowser.Controller/Dlna/IContentDirectory.cs +++ b/MediaBrowser.Controller/Dlna/IContentDirectory.cs @@ -1,21 +1,7 @@ -using System.Collections.Generic; - + namespace MediaBrowser.Controller.Dlna { - public interface IContentDirectory + public interface IContentDirectory : IUpnpService { - /// - /// Gets the content directory XML. - /// - /// The headers. - /// System.String. - string GetContentDirectoryXml(IDictionary headers); - - /// - /// Processes the control request. - /// - /// The request. - /// ControlResponse. - ControlResponse ProcessControlRequest(ControlRequest request); } } diff --git a/MediaBrowser.Controller/Dlna/IUpnpService.cs b/MediaBrowser.Controller/Dlna/IUpnpService.cs new file mode 100644 index 0000000000..3511740ad2 --- /dev/null +++ b/MediaBrowser.Controller/Dlna/IUpnpService.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Dlna +{ + public interface IUpnpService + { + /// + /// Gets the content directory XML. + /// + /// The headers. + /// System.String. + string GetServiceXml(IDictionary headers); + + /// + /// Processes the control request. + /// + /// The request. + /// ControlResponse. + ControlResponse ProcessControlRequest(ControlRequest request); + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index bab550e451..fa7842a684 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -92,9 +92,11 @@ + + diff --git a/MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs b/MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs new file mode 100644 index 0000000000..3270fca72c --- /dev/null +++ b/MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs @@ -0,0 +1,34 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Model.Logging; +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.ConnectionManager +{ + public class ConnectionManager : IConnectionManager + { + private readonly IDlnaManager _dlna; + private readonly ILogger _logger; + private readonly IServerConfigurationManager _config; + + public ConnectionManager(IDlnaManager dlna, ILogManager logManager, IServerConfigurationManager config) + { + _dlna = dlna; + _config = config; + _logger = logManager.GetLogger("UpnpConnectionManager"); + } + + public string GetServiceXml(IDictionary headers) + { + return new ConnectionManagerXmlBuilder().GetXml(); + } + + public ControlResponse ProcessControlRequest(ControlRequest request) + { + var profile = _dlna.GetProfile(request.Headers) ?? + _dlna.GetDefaultProfile(); + + return new ControlHandler(_logger, profile, _config).ProcessControlRequest(request); + } + } +} diff --git a/MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs b/MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs new file mode 100644 index 0000000000..4efa111591 --- /dev/null +++ b/MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs @@ -0,0 +1,106 @@ +using MediaBrowser.Dlna.Common; +using MediaBrowser.Dlna.Service; +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.ConnectionManager +{ + public class ConnectionManagerXmlBuilder + { + public string GetXml() + { + return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(), GetStateVariables()); + } + + private IEnumerable GetStateVariables() + { + var list = new List(); + + list.Add(new StateVariable + { + Name = "SourceProtocolInfo", + DataType = "string", + SendsEvents = true + }); + + list.Add(new StateVariable + { + Name = "SinkProtocolInfo", + DataType = "string", + SendsEvents = true + }); + + list.Add(new StateVariable + { + Name = "CurrentConnectionIDs", + DataType = "string", + SendsEvents = true + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_ConnectionStatus", + DataType = "string", + SendsEvents = false, + + AllowedValues = new List + { + "OK", + "ContentFormatMismatch", + "InsufficientBandwidth", + "UnreliableChannel", + "Unknown" + } + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_ConnectionManager", + DataType = "string", + SendsEvents = false + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_Direction", + DataType = "string", + SendsEvents = false, + + AllowedValues = new List + { + "Output", + "Input" + } + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_ProtocolInfo", + DataType = "string", + SendsEvents = false + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_ConnectionID", + DataType = "ui4", + SendsEvents = false + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_AVTransportID", + DataType = "ui4", + SendsEvents = false + }); + + list.Add(new StateVariable + { + Name = "A_ARG_TYPE_RcsID", + DataType = "ui4", + SendsEvents = false + }); + + return list; + } + } +} diff --git a/MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs b/MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs new file mode 100644 index 0000000000..842e9380ab --- /dev/null +++ b/MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs @@ -0,0 +1,30 @@ +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Dlna.Server; +using MediaBrowser.Dlna.Service; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Logging; +using System.Collections.Generic; +using System.Globalization; + +namespace MediaBrowser.Dlna.ConnectionManager +{ + public class ControlHandler : BaseControlHandler + { + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private readonly DeviceProfile _profile; + + public ControlHandler(ILogger logger, DeviceProfile profile, IServerConfigurationManager config) + : base(config, logger) + { + _profile = profile; + } + + protected override IEnumerable> GetResult(string methodName, Headers methodParams) + { + var deviceId = "test"; + + throw new ResourceNotFoundException("Unexpected control request name: " + methodName); + } + } +} diff --git a/MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs b/MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs new file mode 100644 index 0000000000..9dbd4e0e23 --- /dev/null +++ b/MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs @@ -0,0 +1,205 @@ +using MediaBrowser.Dlna.Common; +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.ConnectionManager +{ + public class ServiceActionListBuilder + { + public IEnumerable GetActions() + { + var list = new List + { + GetCurrentConnectionInfo(), + GetProtocolInfo(), + GetCurrentConnectionIDs(), + ConnectionComplete(), + PrepareForConnection() + }; + + return list; + } + + private ServiceAction PrepareForConnection() + { + var action = new ServiceAction + { + Name = "PrepareForConnection" + }; + + action.ArgumentList.Add(new Argument + { + Name = "RemoteProtocolInfo", + Direction = "in", + RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo" + }); + + action.ArgumentList.Add(new Argument + { + Name = "PeerConnectionManager", + Direction = "in", + RelatedStateVariable = "A_ARG_TYPE_ConnectionManager" + }); + + action.ArgumentList.Add(new Argument + { + Name = "PeerConnectionID", + Direction = "in", + RelatedStateVariable = "A_ARG_TYPE_ConnectionID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "Direction", + Direction = "in", + RelatedStateVariable = "A_ARG_TYPE_Direction" + }); + + action.ArgumentList.Add(new Argument + { + Name = "ConnectionID", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_ConnectionID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "AVTransportID", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_AVTransportID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "RcsID", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_RcsID" + }); + + return action; + } + + private ServiceAction GetCurrentConnectionInfo() + { + var action = new ServiceAction + { + Name = "GetCurrentConnectionInfo" + }; + + action.ArgumentList.Add(new Argument + { + Name = "ConnectionID", + Direction = "in", + RelatedStateVariable = "A_ARG_TYPE_ConnectionID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "RcsID", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_RcsID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "AVTransportID", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_AVTransportID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "ProtocolInfo", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo" + }); + + action.ArgumentList.Add(new Argument + { + Name = "PeerConnectionManager", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_ConnectionManager" + }); + + action.ArgumentList.Add(new Argument + { + Name = "PeerConnectionID", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_ConnectionID" + }); + + action.ArgumentList.Add(new Argument + { + Name = "Direction", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_Direction" + }); + + action.ArgumentList.Add(new Argument + { + Name = "Status", + Direction = "out", + RelatedStateVariable = "A_ARG_TYPE_ConnectionStatus" + }); + + return action; + } + + private ServiceAction GetProtocolInfo() + { + var action = new ServiceAction + { + Name = "GetProtocolInfo" + }; + + action.ArgumentList.Add(new Argument + { + Name = "Source", + Direction = "out", + RelatedStateVariable = "SourceProtocolInfo" + }); + + action.ArgumentList.Add(new Argument + { + Name = "Sink", + Direction = "out", + RelatedStateVariable = "SinkProtocolInfo" + }); + + return action; + } + + private ServiceAction GetCurrentConnectionIDs() + { + var action = new ServiceAction + { + Name = "GetCurrentConnectionIDs" + }; + + action.ArgumentList.Add(new Argument + { + Name = "ConnectionIDs", + Direction = "out", + RelatedStateVariable = "CurrentConnectionIDs" + }); + + return action; + } + + private ServiceAction ConnectionComplete() + { + var action = new ServiceAction + { + Name = "ConnectionComplete" + }; + + action.ArgumentList.Add(new Argument + { + Name = "ConnectionID", + Direction = "in", + RelatedStateVariable = "A_ARG_TYPE_ConnectionID" + }); + + return action; + } + } +} diff --git a/MediaBrowser.Dlna/Server/ContentDirectory.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs similarity index 90% rename from MediaBrowser.Dlna/Server/ContentDirectory.cs rename to MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs index e2f53aeafa..d1b29502d7 100644 --- a/MediaBrowser.Dlna/Server/ContentDirectory.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs @@ -10,7 +10,7 @@ using System; using System.Collections.Generic; using System.Linq; -namespace MediaBrowser.Dlna.Server +namespace MediaBrowser.Dlna.ContentDirectory { public class ContentDirectory : IContentDirectory, IDisposable { @@ -43,7 +43,7 @@ namespace MediaBrowser.Dlna.Server _config = config; _userManager = userManager; _eventManager = eventManager; - _logger = logManager.GetLogger("DlnaContentDirectory"); + _logger = logManager.GetLogger("UpnpContentDirectory"); } private int SystemUpdateId @@ -56,12 +56,9 @@ namespace MediaBrowser.Dlna.Server } } - public string GetContentDirectoryXml(IDictionary headers) + public string GetServiceXml(IDictionary headers) { - var profile = _dlna.GetProfile(headers) ?? - _dlna.GetDefaultProfile(); - - return new ContentDirectoryXmlBuilder(profile).GetXml(); + return new ContentDirectoryXmlBuilder().GetXml(); } public ControlResponse ProcessControlRequest(ControlRequest request) diff --git a/MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs similarity index 52% rename from MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs rename to MediaBrowser.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs index 58ccf49bda..0e5a2671c9 100644 --- a/MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs @@ -1,98 +1,15 @@ using MediaBrowser.Dlna.Common; -using MediaBrowser.Model.Dlna; +using MediaBrowser.Dlna.Service; using System.Collections.Generic; -using System.Security; -using System.Text; -namespace MediaBrowser.Dlna.Server +namespace MediaBrowser.Dlna.ContentDirectory { public class ContentDirectoryXmlBuilder { - private readonly DeviceProfile _profile; - - public ContentDirectoryXmlBuilder(DeviceProfile profile) - { - _profile = profile; - } - public string GetXml() { - var builder = new StringBuilder(); - - builder.Append(""); - builder.Append(""); - - builder.Append(""); - builder.Append("1"); - builder.Append("0"); - builder.Append(""); - - AppendActionList(builder); - AppendServiceStateTable(builder); - - builder.Append(""); - - return builder.ToString(); - } - - private void AppendActionList(StringBuilder builder) - { - builder.Append(""); - - foreach (var item in new ServiceActionListBuilder().GetActions()) - { - builder.Append(""); - - builder.Append("" + SecurityElement.Escape(item.Name ?? string.Empty) + ""); - - builder.Append(""); - - foreach (var argument in item.ArgumentList) - { - builder.Append(""); - - builder.Append("" + SecurityElement.Escape(argument.Name ?? string.Empty) + ""); - builder.Append("" + SecurityElement.Escape(argument.Direction ?? string.Empty) + ""); - builder.Append("" + SecurityElement.Escape(argument.RelatedStateVariable ?? string.Empty) + ""); - - builder.Append(""); - } - - builder.Append(""); - - builder.Append(""); - } - - builder.Append(""); - } - - private void AppendServiceStateTable(StringBuilder builder) - { - builder.Append(""); - - foreach (var item in GetStateVariables()) - { - var sendEvents = item.SendsEvents ? "yes" : "no"; - - builder.Append(""); - - builder.Append("" + SecurityElement.Escape(item.Name ?? string.Empty) + ""); - builder.Append("" + SecurityElement.Escape(item.DataType ?? string.Empty) + ""); - - if (item.AllowedValues.Count > 0) - { - builder.Append(""); - foreach (var allowedValue in item.AllowedValues) - { - builder.Append("" + SecurityElement.Escape(allowedValue) + ""); - } - builder.Append(""); - } - - builder.Append(""); - } - - builder.Append(""); + return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(), + GetStateVariables()); } private IEnumerable GetStateVariables() @@ -223,13 +140,8 @@ namespace MediaBrowser.Dlna.Server DataType = "string", SendsEvents = false }); - - return list; - } - public override string ToString() - { - return GetXml(); + return list; } } } diff --git a/MediaBrowser.Dlna/Server/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs similarity index 69% rename from MediaBrowser.Dlna/Server/ControlHandler.cs rename to MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index a3eb7f0552..0e4f0d8f92 100644 --- a/MediaBrowser.Dlna/Server/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -1,15 +1,16 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Dlna.Didl; +using MediaBrowser.Dlna.Server; +using MediaBrowser.Dlna.Service; using MediaBrowser.Model.Dlna; -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; @@ -21,20 +22,17 @@ using System.Text; using System.Threading; using System.Xml; -namespace MediaBrowser.Dlna.Server +namespace MediaBrowser.Dlna.ContentDirectory { - public class ControlHandler + public class ControlHandler : BaseControlHandler { - private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IUserDataManager _userDataManager; - private readonly IServerConfigurationManager _config; private readonly User _user; private const string NS_DC = "http://purl.org/dc/elements/1.1/"; private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"; private const string NS_DLNA = "urn:schemas-dlna-org:metadata-1-0/"; - private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/"; private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/"; private readonly int _systemUpdateId; @@ -45,151 +43,45 @@ namespace MediaBrowser.Dlna.Server private readonly DeviceProfile _profile; public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IDtoService dtoService, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config) + : base(config, logger) { - _logger = logger; _libraryManager = libraryManager; _userDataManager = userDataManager; _user = user; _systemUpdateId = systemUpdateId; - _config = config; _profile = profile; _didlBuilder = new DidlBuilder(profile, imageProcessor, serverAddress, dtoService); } - public ControlResponse ProcessControlRequest(ControlRequest request) - { - try - { - if (_config.Configuration.DlnaOptions.EnableDebugLogging) - { - LogRequest(request); - } - - return ProcessControlRequestInternal(request); - } - catch (Exception ex) - { - _logger.ErrorException("Error processing control request", ex); - - return GetErrorResponse(ex); - } - } - - 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 ControlResponse ProcessControlRequestInternal(ControlRequest request) + protected override IEnumerable> GetResult(string methodName, Headers methodParams) { - 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()); - } - var deviceId = "test"; - IEnumerable> result; - - _logger.Debug("Received control request {0}", method.Name); - var user = _user; - if (string.Equals(method.LocalName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase)) - result = HandleGetSearchCapabilities(); - else if (string.Equals(method.LocalName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase)) - result = HandleGetSortCapabilities(); - else if (string.Equals(method.LocalName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase)) - result = HandleGetSystemUpdateID(); - else if (string.Equals(method.LocalName, "Browse", StringComparison.OrdinalIgnoreCase)) - result = HandleBrowse(sparams, user, deviceId); - else if (string.Equals(method.LocalName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase)) - result = HandleXGetFeatureList(); - else if (string.Equals(method.LocalName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase)) - result = HandleXSetBookmark(sparams, user); - else if (string.Equals(method.LocalName, "Search", StringComparison.OrdinalIgnoreCase)) - result = HandleSearch(sparams, user, deviceId); - else - throw new ResourceNotFoundException("Unexpected control request name: " + method.LocalName); + if (string.Equals(methodName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase)) + return HandleGetSearchCapabilities(); - 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/"); + if (string.Equals(methodName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase)) + return HandleGetSortCapabilities(); - var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV); - env.DocumentElement.AppendChild(rbody); + if (string.Equals(methodName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase)) + return HandleGetSystemUpdateID(); - var response = env.CreateElement(String.Format("u:{0}Response", method.LocalName), method.NamespaceURI); - rbody.AppendChild(response); + if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase)) + return HandleBrowse(methodParams, user, deviceId); - foreach (var i in result) - { - var ri = env.CreateElement(i.Key); - ri.InnerText = i.Value; - response.AppendChild(ri); - } - - var controlResponse = new ControlResponse - { - Xml = env.OuterXml, - IsSuccessful = true - }; + if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase)) + return HandleXGetFeatureList(); - controlResponse.Headers.Add("EXT", string.Empty); + if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase)) + return HandleXSetBookmark(methodParams, user); - return controlResponse; - } + if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase)) + return HandleSearch(methodParams, user, deviceId); - private ControlResponse GetErrorResponse(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 = "401Invalid Action"; - fault.AppendChild(detail); - rbody.AppendChild(fault); - - return new ControlResponse - { - Xml = env.OuterXml, - IsSuccessful = false - }; + throw new ResourceNotFoundException("Unexpected control request name: " + methodName); } private IEnumerable> HandleXSetBookmark(IDictionary sparams, User user) @@ -224,7 +116,7 @@ namespace MediaBrowser.Dlna.Server { var headers = new Headers(true); headers.Add("Id", _systemUpdateId.ToString(_usCulture)); - return headers; + return headers; } private IEnumerable> HandleXGetFeatureList() diff --git a/MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs b/MediaBrowser.Dlna/ContentDirectory/ServiceActionListBuilder.cs similarity index 99% rename from MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs rename to MediaBrowser.Dlna/ContentDirectory/ServiceActionListBuilder.cs index 9ccfaf603c..cd8119048e 100644 --- a/MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ServiceActionListBuilder.cs @@ -1,7 +1,7 @@ using MediaBrowser.Dlna.Common; using System.Collections.Generic; -namespace MediaBrowser.Dlna.Server +namespace MediaBrowser.Dlna.ContentDirectory { public class ServiceActionListBuilder { diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 1cd4a4cbdf..c60b3a49a0 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -345,7 +345,9 @@ namespace MediaBrowser.Dlna.Didl /// The filter. private void AddCommonFields(BaseItem item, XmlElement element, Filter filter) { - if (filter.Contains("dc:title")) + // Don't filter on dc:title because not all devices will include it in the filter + // MediaMonkey for example won't display content without a title + //if (filter.Contains("dc:title")) { AddValue(element, "dc", "title", item.Name, NS_DC); } @@ -360,9 +362,12 @@ namespace MediaBrowser.Dlna.Didl } } - foreach (var genre in item.Genres) + if (filter.Contains("upnp:genre")) { - AddValue(element, "upnp", "genre", genre, NS_UPNP); + foreach (var genre in item.Genres) + { + AddValue(element, "upnp", "genre", genre, NS_UPNP); + } } foreach (var studio in item.Studios) diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index d39bcbefec..caef50d36e 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -51,6 +51,10 @@ Properties\SharedVersion.cs + + + + @@ -79,10 +83,13 @@ - - - - + + + + + + + @@ -159,6 +166,7 @@ +