added upnp ConnectionManager.cs
This commit is contained in:
parent
ad3c30c145
commit
1774e5b1ac
|
@ -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 response = PostAsync(request).Result;
|
||||
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");
|
||||
}
|
||||
|
||||
private async Task<ControlResponse> PostAsync(ProcessControlRequest request)
|
||||
public object Post(ProcessConnectionManagerControlRequest request)
|
||||
{
|
||||
var response = PostAsync(request.RequestStream, _connectionManager).Result;
|
||||
|
||||
return ResultFactory.GetResult(response.Xml, "text/xml");
|
||||
}
|
||||
|
||||
private async Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = pathInfo.GetArgumentValue<string>(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),
|
||||
|
|
7
MediaBrowser.Controller/Dlna/IConnectionManager.cs
Normal file
7
MediaBrowser.Controller/Dlna/IConnectionManager.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public interface IConnectionManager : IUpnpService
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,21 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public interface IContentDirectory
|
||||
public interface IContentDirectory : IUpnpService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the content directory XML.
|
||||
/// </summary>
|
||||
/// <param name="headers">The headers.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetContentDirectoryXml(IDictionary<string, string> headers);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the control request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>ControlResponse.</returns>
|
||||
ControlResponse ProcessControlRequest(ControlRequest request);
|
||||
}
|
||||
}
|
||||
|
|
21
MediaBrowser.Controller/Dlna/IUpnpService.cs
Normal file
21
MediaBrowser.Controller/Dlna/IUpnpService.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public interface IUpnpService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the content directory XML.
|
||||
/// </summary>
|
||||
/// <param name="headers">The headers.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetServiceXml(IDictionary<string, string> headers);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the control request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>ControlResponse.</returns>
|
||||
ControlResponse ProcessControlRequest(ControlRequest request);
|
||||
}
|
||||
}
|
|
@ -92,9 +92,11 @@
|
|||
<Compile Include="Dlna\ControlResponse.cs" />
|
||||
<Compile Include="Dlna\DlnaIconResponse.cs" />
|
||||
<Compile Include="Dlna\EventSubscriptionResponse.cs" />
|
||||
<Compile Include="Dlna\IConnectionManager.cs" />
|
||||
<Compile Include="Dlna\IContentDirectory.cs" />
|
||||
<Compile Include="Dlna\IDlnaManager.cs" />
|
||||
<Compile Include="Dlna\IEventManager.cs" />
|
||||
<Compile Include="Dlna\IUpnpService.cs" />
|
||||
<Compile Include="Drawing\IImageProcessor.cs" />
|
||||
<Compile Include="Drawing\ImageFormat.cs" />
|
||||
<Compile Include="Drawing\ImageProcessingOptions.cs" />
|
||||
|
|
34
MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs
Normal file
34
MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs
Normal file
|
@ -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<string, string> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<StateVariable> GetStateVariables()
|
||||
{
|
||||
var list = new List<StateVariable>();
|
||||
|
||||
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<string>
|
||||
{
|
||||
"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<string>
|
||||
{
|
||||
"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;
|
||||
}
|
||||
}
|
||||
}
|
30
MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs
Normal file
30
MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs
Normal file
|
@ -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<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||
{
|
||||
var deviceId = "test";
|
||||
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
}
|
||||
}
|
205
MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs
Normal file
205
MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs
Normal file
|
@ -0,0 +1,205 @@
|
|||
using MediaBrowser.Dlna.Common;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Dlna.ConnectionManager
|
||||
{
|
||||
public class ServiceActionListBuilder
|
||||
{
|
||||
public IEnumerable<ServiceAction> GetActions()
|
||||
{
|
||||
var list = new List<ServiceAction>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<string, string> headers)
|
||||
public string GetServiceXml(IDictionary<string, string> headers)
|
||||
{
|
||||
var profile = _dlna.GetProfile(headers) ??
|
||||
_dlna.GetDefaultProfile();
|
||||
|
||||
return new ContentDirectoryXmlBuilder(profile).GetXml();
|
||||
return new ContentDirectoryXmlBuilder().GetXml();
|
||||
}
|
||||
|
||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
|
@ -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("<?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);
|
||||
AppendServiceStateTable(builder);
|
||||
|
||||
builder.Append("</scpd>");
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private void AppendActionList(StringBuilder builder)
|
||||
{
|
||||
builder.Append("<actionList>");
|
||||
|
||||
foreach (var item in new ServiceActionListBuilder().GetActions())
|
||||
{
|
||||
builder.Append("<action>");
|
||||
|
||||
builder.Append("<name>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
|
||||
|
||||
builder.Append("<argumentList>");
|
||||
|
||||
foreach (var argument in item.ArgumentList)
|
||||
{
|
||||
builder.Append("<argument>");
|
||||
|
||||
builder.Append("<name>" + SecurityElement.Escape(argument.Name ?? string.Empty) + "</name>");
|
||||
builder.Append("<direction>" + SecurityElement.Escape(argument.Direction ?? string.Empty) + "</direction>");
|
||||
builder.Append("<relatedStateVariable>" + SecurityElement.Escape(argument.RelatedStateVariable ?? string.Empty) + "</relatedStateVariable>");
|
||||
|
||||
builder.Append("</argument>");
|
||||
}
|
||||
|
||||
builder.Append("</argumentList>");
|
||||
|
||||
builder.Append("</action>");
|
||||
}
|
||||
|
||||
builder.Append("</actionList>");
|
||||
}
|
||||
|
||||
private void AppendServiceStateTable(StringBuilder builder)
|
||||
{
|
||||
builder.Append("<serviceStateTable>");
|
||||
|
||||
foreach (var item in GetStateVariables())
|
||||
{
|
||||
var sendEvents = item.SendsEvents ? "yes" : "no";
|
||||
|
||||
builder.Append("<stateVariable sendEvents=\"" + sendEvents + "\">");
|
||||
|
||||
builder.Append("<name>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
|
||||
builder.Append("<dataType>" + SecurityElement.Escape(item.DataType ?? string.Empty) + "</dataType>");
|
||||
|
||||
if (item.AllowedValues.Count > 0)
|
||||
{
|
||||
builder.Append("<allowedValueList>");
|
||||
foreach (var allowedValue in item.AllowedValues)
|
||||
{
|
||||
builder.Append("<allowedValue>" + SecurityElement.Escape(allowedValue) + "</allowedValue>");
|
||||
}
|
||||
builder.Append("</allowedValueList>");
|
||||
}
|
||||
|
||||
builder.Append("</stateVariable>");
|
||||
}
|
||||
|
||||
builder.Append("</serviceStateTable>");
|
||||
return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(),
|
||||
GetStateVariables());
|
||||
}
|
||||
|
||||
private IEnumerable<StateVariable> GetStateVariables()
|
||||
|
@ -226,10 +143,5 @@ namespace MediaBrowser.Dlna.Server
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GetXml();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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<KeyValuePair<string, string>> 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);
|
||||
}
|
||||
if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleXGetFeatureList();
|
||||
|
||||
var controlResponse = new ControlResponse
|
||||
{
|
||||
Xml = env.OuterXml,
|
||||
IsSuccessful = true
|
||||
};
|
||||
if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleXSetBookmark(methodParams, user);
|
||||
|
||||
controlResponse.Headers.Add("EXT", string.Empty);
|
||||
if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase))
|
||||
return HandleSearch(methodParams, user, deviceId);
|
||||
|
||||
return controlResponse;
|
||||
}
|
||||
|
||||
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 = "<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
|
||||
};
|
||||
throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> HandleXSetBookmark(IDictionary<string, string> sparams, User user)
|
|
@ -1,7 +1,7 @@
|
|||
using MediaBrowser.Dlna.Common;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Dlna.Server
|
||||
namespace MediaBrowser.Dlna.ContentDirectory
|
||||
{
|
||||
public class ServiceActionListBuilder
|
||||
{
|
|
@ -345,7 +345,9 @@ namespace MediaBrowser.Dlna.Didl
|
|||
/// <param name="filter">The filter.</param>
|
||||
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,10 +362,13 @@ namespace MediaBrowser.Dlna.Didl
|
|||
}
|
||||
}
|
||||
|
||||
if (filter.Contains("upnp:genre"))
|
||||
{
|
||||
foreach (var genre in item.Genres)
|
||||
{
|
||||
AddValue(element, "upnp", "genre", genre, NS_UPNP);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var studio in item.Studios)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,10 @@
|
|||
<Compile Include="..\SharedVersion.cs">
|
||||
<Link>Properties\SharedVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="ConnectionManager\ConnectionManager.cs" />
|
||||
<Compile Include="ConnectionManager\ConnectionManagerXmlBuilder.cs" />
|
||||
<Compile Include="ConnectionManager\ControlHandler.cs" />
|
||||
<Compile Include="ConnectionManager\ServiceActionListBuilder.cs" />
|
||||
<Compile Include="DlnaManager.cs" />
|
||||
<Compile Include="Common\Argument.cs" />
|
||||
<Compile Include="Eventing\EventManager.cs" />
|
||||
|
@ -79,10 +83,13 @@
|
|||
<Compile Include="Profiles\Windows81Profile.cs" />
|
||||
<Compile Include="Profiles\WindowsMediaCenterProfile.cs" />
|
||||
<Compile Include="Profiles\WindowsPhoneProfile.cs" />
|
||||
<Compile Include="Server\ContentDirectory.cs" />
|
||||
<Compile Include="Server\ControlHandler.cs" />
|
||||
<Compile Include="Server\ServiceActionListBuilder.cs" />
|
||||
<Compile Include="Server\ContentDirectoryXmlBuilder.cs" />
|
||||
<Compile Include="ContentDirectory\ContentDirectory.cs" />
|
||||
<Compile Include="ContentDirectory\ControlHandler.cs" />
|
||||
<Compile Include="ContentDirectory\ServiceActionListBuilder.cs" />
|
||||
<Compile Include="ContentDirectory\ContentDirectoryXmlBuilder.cs" />
|
||||
<Compile Include="Service\BaseControlHandler.cs" />
|
||||
<Compile Include="Service\ControlErrorHandler.cs" />
|
||||
<Compile Include="Service\ServiceXmlBuilder.cs" />
|
||||
<Compile Include="Ssdp\Datagram.cs" />
|
||||
<Compile Include="Server\DescriptionXmlBuilder.cs" />
|
||||
<Compile Include="Ssdp\SsdpHelper.cs" />
|
||||
|
@ -159,6 +166,7 @@
|
|||
<EmbeddedResource Include="Images\logo48.jpg" />
|
||||
<EmbeddedResource Include="Images\logo48.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
|
|
@ -185,6 +185,15 @@ namespace MediaBrowser.Dlna.Server
|
|||
EventSubUrl = "/mediabrowser/dlna/contentdirectory/" + _serverUdn + "/events"
|
||||
});
|
||||
|
||||
list.Add(new DeviceService
|
||||
{
|
||||
ServiceType = "urn:schemas-upnp-org:service:ConnectionManager:1",
|
||||
ServiceId = "urn:upnp-org:serviceId:ConnectionManager",
|
||||
ScpdUrl = "/mediabrowser/dlna/connectionmanager/connectionmanager.xml",
|
||||
ControlUrl = "/mediabrowser/dlna/connectionmanager/" + _serverUdn + "/control",
|
||||
EventSubUrl = "/mediabrowser/dlna/connectionmanager/" + _serverUdn + "/events"
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
112
MediaBrowser.Dlna/Service/BaseControlHandler.cs
Normal file
112
MediaBrowser.Dlna/Service/BaseControlHandler.cs
Normal file
|
@ -0,0 +1,112 @@
|
|||
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
|
||||
{
|
||||
if (Config.Configuration.DlnaOptions.EnableDebugLogging)
|
||||
{
|
||||
LogRequest(request);
|
||||
}
|
||||
|
||||
return ProcessControlRequestInternal(request);
|
||||
}
|
||||
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);
|
||||
|
||||
IEnumerable<KeyValuePair<string, string>> 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 controlResponse = new ControlResponse
|
||||
{
|
||||
Xml = env.OuterXml,
|
||||
IsSuccessful = true
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
41
MediaBrowser.Dlna/Service/ControlErrorHandler.cs
Normal file
41
MediaBrowser.Dlna/Service/ControlErrorHandler.cs
Normal file
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
90
MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs
Normal file
90
MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using MediaBrowser.Dlna.Common;
|
||||
using System.Collections.Generic;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
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>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
|
||||
|
||||
builder.Append("<argumentList>");
|
||||
|
||||
foreach (var argument in item.ArgumentList)
|
||||
{
|
||||
builder.Append("<argument>");
|
||||
|
||||
builder.Append("<name>" + SecurityElement.Escape(argument.Name ?? string.Empty) + "</name>");
|
||||
builder.Append("<direction>" + SecurityElement.Escape(argument.Direction ?? string.Empty) + "</direction>");
|
||||
builder.Append("<relatedStateVariable>" + SecurityElement.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>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
|
||||
builder.Append("<dataType>" + SecurityElement.Escape(item.DataType ?? string.Empty) + "</dataType>");
|
||||
|
||||
if (item.AllowedValues.Count > 0)
|
||||
{
|
||||
builder.Append("<allowedValueList>");
|
||||
foreach (var allowedValue in item.AllowedValues)
|
||||
{
|
||||
builder.Append("<allowedValue>" + SecurityElement.Escape(allowedValue) + "</allowedValue>");
|
||||
}
|
||||
builder.Append("</allowedValueList>");
|
||||
}
|
||||
|
||||
builder.Append("</stateVariable>");
|
||||
}
|
||||
|
||||
builder.Append("</serviceStateTable>");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -267,7 +267,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
{
|
||||
providerStartIndex = query.StartIndex;
|
||||
|
||||
if (!query.Limit.HasValue || query.Limit.Value > channelInfo.MaxPageSize.Value)
|
||||
if (query.Limit.HasValue && query.Limit.Value > channelInfo.MaxPageSize.Value)
|
||||
{
|
||||
throw new ArgumentException(string.Format("Channel {0} only supports a maximum of {1} records at a time.", channel.Name, channelInfo.MaxPageSize.Value));
|
||||
}
|
||||
|
|
|
@ -63,17 +63,18 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||
|
||||
private Task SendMessage(string name, CancellationToken cancellationToken)
|
||||
{
|
||||
return SendMessage(name, new NameValueCollection(), cancellationToken);
|
||||
return SendMessage(name, new Dictionary<string, string>(), cancellationToken);
|
||||
}
|
||||
|
||||
private Task SendMessage(string name, NameValueCollection args, CancellationToken cancellationToken)
|
||||
private Task SendMessage(string name, Dictionary<string, string> args, CancellationToken cancellationToken)
|
||||
{
|
||||
return SendMessage(new WebSocketMessage<string>
|
||||
{
|
||||
MessageType = name,
|
||||
Data = string.Empty
|
||||
var url = _postUrl + "/" + name + ToQueryString(args);
|
||||
|
||||
}, cancellationToken);
|
||||
return _httpClient.Post(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
CancellationToken = cancellationToken
|
||||
});
|
||||
}
|
||||
|
||||
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
|
||||
|
@ -141,12 +142,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||
|
||||
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
return SendMessage(new WebSocketMessage<GeneralCommand>
|
||||
{
|
||||
MessageType = "GeneralCommand",
|
||||
Data = command
|
||||
|
||||
}, cancellationToken);
|
||||
return SendMessage(command.Name, command.Arguments, cancellationToken);
|
||||
}
|
||||
|
||||
private string ToQueryString(Dictionary<string, string> nvc)
|
||||
|
@ -154,7 +150,15 @@ namespace MediaBrowser.Server.Implementations.Session
|
|||
var array = (from item in nvc
|
||||
select string.Format("{0}={1}", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)))
|
||||
.ToArray();
|
||||
return "?" + string.Join("&", array);
|
||||
|
||||
var args = string.Join("&", array);
|
||||
|
||||
if (string.IsNullOrEmpty(args))
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
return "?" + args;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,9 +154,9 @@ namespace MediaBrowser.Server.Implementations.WebSocket
|
|||
{
|
||||
if (WebSocketServer != null)
|
||||
{
|
||||
// Calling dispose will also call stop
|
||||
_logger.Debug("Disposing alchemy server");
|
||||
WebSocketServer.Stop();
|
||||
|
||||
WebSocketServer.Dispose();
|
||||
WebSocketServer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ using MediaBrowser.Controller.Sorting;
|
|||
using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Controller.Themes;
|
||||
using MediaBrowser.Dlna;
|
||||
using MediaBrowser.Dlna.ConnectionManager;
|
||||
using MediaBrowser.Dlna.ContentDirectory;
|
||||
using MediaBrowser.Dlna.Eventing;
|
||||
using MediaBrowser.Dlna.Main;
|
||||
using MediaBrowser.Dlna.Server;
|
||||
|
@ -526,6 +528,9 @@ namespace MediaBrowser.ServerApplication
|
|||
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, DtoService, LibraryManager, LogManager, ServerConfigurationManager, UserManager, dlnaEventManager);
|
||||
RegisterSingleInstance<IContentDirectory>(contentDirectory);
|
||||
|
||||
var connectionManager = new ConnectionManager(dlnaManager, LogManager, ServerConfigurationManager);
|
||||
RegisterSingleInstance<IConnectionManager>(connectionManager);
|
||||
|
||||
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
|
||||
RegisterSingleInstance<ICollectionManager>(collectionManager);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user