Merge pull request #2297 from Bond-009/asyncio

Kestrel doesn't like sync IO operations
This commit is contained in:
dkanada 2020-01-23 01:59:52 +09:00 committed by GitHub
commit 1dd4abebbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 74 deletions

View File

@ -170,32 +170,32 @@ namespace Emby.Dlna.Api
return _resultFactory.GetResult(Request, xml, XMLContentType);
}
public object Post(ProcessMediaReceiverRegistrarControlRequest request)
public async Task<object> Post(ProcessMediaReceiverRegistrarControlRequest request)
{
var response = PostAsync(request.RequestStream, MediaReceiverRegistrar);
var response = await PostAsync(request.RequestStream, MediaReceiverRegistrar).ConfigureAwait(false);
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
}
public object Post(ProcessContentDirectoryControlRequest request)
public async Task<object> Post(ProcessContentDirectoryControlRequest request)
{
var response = PostAsync(request.RequestStream, ContentDirectory);
var response = await PostAsync(request.RequestStream, ContentDirectory).ConfigureAwait(false);
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
}
public object Post(ProcessConnectionManagerControlRequest request)
public async Task<object> Post(ProcessConnectionManagerControlRequest request)
{
var response = PostAsync(request.RequestStream, ConnectionManager);
var response = await PostAsync(request.RequestStream, ConnectionManager).ConfigureAwait(false);
return _resultFactory.GetResult(Request, response.Xml, XMLContentType);
}
private ControlResponse PostAsync(Stream requestStream, IUpnpService service)
private Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
{
var id = GetPathValue(2).ToString();
return service.ProcessControlRequest(new ControlRequest
return service.ProcessControlRequestAsync(new ControlRequest
{
Headers = Request.Headers,
InputXml = requestStream,

View File

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Emby.Dlna.Service;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
@ -20,17 +21,19 @@ namespace Emby.Dlna.ConnectionManager
_logger = logger;
}
/// <inheritdoc />
public string GetServiceXml()
{
return new ConnectionManagerXmlBuilder().GetXml();
}
public ControlResponse ProcessControlRequest(ControlRequest request)
/// <inheritdoc />
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
{
var profile = _dlna.GetProfile(request.Headers) ??
_dlna.GetDefaultProfile();
return new ControlHandler(_config, _logger, profile).ProcessControlRequest(request);
return new ControlHandler(_config, _logger, profile).ProcessControlRequestAsync(request);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Emby.Dlna.Service;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
@ -66,12 +67,14 @@ namespace Emby.Dlna.ContentDirectory
}
}
/// <inheritdoc />
public string GetServiceXml()
{
return new ContentDirectoryXmlBuilder().GetXml();
}
public ControlResponse ProcessControlRequest(ControlRequest request)
/// <inheritdoc />
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
{
var profile = _dlna.GetProfile(request.Headers) ??
_dlna.GetDefaultProfile();
@ -96,7 +99,7 @@ namespace Emby.Dlna.ContentDirectory
_userViewManager,
_mediaEncoder,
_tvSeriesManager)
.ProcessControlRequest(request);
.ProcessControlRequestAsync(request);
}
private User GetUser(DeviceProfile profile)

View File

@ -76,7 +76,7 @@ namespace Emby.Dlna.ContentDirectory
_profile = profile;
_config = config;
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, _logger, mediaEncoder);
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, mediaEncoder);
}
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
@ -1336,7 +1336,7 @@ namespace Emby.Dlna.ContentDirectory
};
}
_logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
Logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
return new ServerItem(_libraryManager.GetUserRootFolder());
}

View File

@ -1,3 +1,5 @@
using System.Threading.Tasks;
namespace Emby.Dlna
{
public interface IUpnpService
@ -13,6 +15,6 @@ namespace Emby.Dlna
/// </summary>
/// <param name="request">The request.</param>
/// <returns>ControlResponse.</returns>
ControlResponse ProcessControlRequest(ControlRequest request);
Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request);
}
}

View File

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Emby.Dlna.Service;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
@ -15,17 +16,19 @@ namespace Emby.Dlna.MediaReceiverRegistrar
_config = config;
}
/// <inheritdoc />
public string GetServiceXml()
{
return new MediaReceiverRegistrarXmlBuilder().GetXml();
}
public ControlResponse ProcessControlRequest(ControlRequest request)
/// <inheritdoc />
public Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
{
return new ControlHandler(
_config,
Logger)
.ProcessControlRequest(request);
.ProcessControlRequestAsync(request);
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Emby.Dlna.Didl;
using MediaBrowser.Controller.Configuration;
@ -15,44 +16,34 @@ namespace Emby.Dlna.Service
{
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
protected readonly IServerConfigurationManager Config;
protected readonly ILogger _logger;
protected IServerConfigurationManager Config { get; }
protected ILogger Logger { get; }
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
{
Config = config;
_logger = logger;
Logger = logger;
}
public ControlResponse ProcessControlRequest(ControlRequest request)
public async Task<ControlResponse> ProcessControlRequestAsync(ControlRequest request)
{
try
{
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLog;
if (enableDebugLogging)
{
LogRequest(request);
}
var response = ProcessControlRequestInternal(request);
if (enableDebugLogging)
{
LogResponse(response);
}
LogRequest(request);
var response = await ProcessControlRequestInternalAsync(request).ConfigureAwait(false);
LogResponse(response);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing control request");
Logger.LogError(ex, "Error processing control request");
return new ControlErrorHandler().GetResponse(ex);
return ControlErrorHandler.GetResponse(ex);
}
}
private ControlResponse ProcessControlRequestInternal(ControlRequest request)
private async Task<ControlResponse> ProcessControlRequestInternalAsync(ControlRequest request)
{
ControlRequestInfo requestInfo = null;
@ -63,16 +54,17 @@ namespace Emby.Dlna.Service
ValidationType = ValidationType.None,
CheckCharacters = false,
IgnoreProcessingInstructions = true,
IgnoreComments = true
IgnoreComments = true,
Async = true
};
using (var reader = XmlReader.Create(streamReader, readerSettings))
{
requestInfo = ParseRequest(reader);
requestInfo = await ParseRequestAsync(reader).ConfigureAwait(false);
}
}
_logger.LogDebug("Received control request {0}", requestInfo.LocalName);
Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
@ -114,17 +106,15 @@ namespace Emby.Dlna.Service
IsSuccessful = true
};
//logger.LogDebug(xml);
controlResponse.Headers.Add("EXT", string.Empty);
return controlResponse;
}
private ControlRequestInfo ParseRequest(XmlReader reader)
private async Task<ControlRequestInfo> ParseRequestAsync(XmlReader reader)
{
reader.MoveToContent();
reader.Read();
await reader.MoveToContentAsync().ConfigureAwait(false);
await reader.ReadAsync().ConfigureAwait(false);
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
@ -139,37 +129,38 @@ namespace Emby.Dlna.Service
{
using (var subReader = reader.ReadSubtree())
{
return ParseBodyTag(subReader);
return await ParseBodyTagAsync(subReader).ConfigureAwait(false);
}
}
else
{
reader.Read();
await reader.ReadAsync().ConfigureAwait(false);
}
break;
}
default:
{
reader.Skip();
await reader.SkipAsync().ConfigureAwait(false);
break;
}
}
}
else
{
reader.Read();
await reader.ReadAsync().ConfigureAwait(false);
}
}
return new ControlRequestInfo();
}
private ControlRequestInfo ParseBodyTag(XmlReader reader)
private async Task<ControlRequestInfo> ParseBodyTagAsync(XmlReader reader)
{
var result = new ControlRequestInfo();
reader.MoveToContent();
reader.Read();
await reader.MoveToContentAsync().ConfigureAwait(false);
await reader.ReadAsync().ConfigureAwait(false);
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
@ -183,28 +174,28 @@ namespace Emby.Dlna.Service
{
using (var subReader = reader.ReadSubtree())
{
ParseFirstBodyChild(subReader, result.Headers);
await ParseFirstBodyChildAsync(subReader, result.Headers).ConfigureAwait(false);
return result;
}
}
else
{
reader.Read();
await reader.ReadAsync().ConfigureAwait(false);
}
}
else
{
reader.Read();
await reader.ReadAsync().ConfigureAwait(false);
}
}
return result;
}
private void ParseFirstBodyChild(XmlReader reader, IDictionary<string, string> headers)
private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary<string, string> headers)
{
reader.MoveToContent();
reader.Read();
await reader.MoveToContentAsync().ConfigureAwait(false);
await reader.ReadAsync().ConfigureAwait(false);
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
@ -212,20 +203,20 @@ namespace Emby.Dlna.Service
if (reader.NodeType == XmlNodeType.Element)
{
// TODO: Should we be doing this here, or should it be handled earlier when decoding the request?
headers[reader.LocalName.RemoveDiacritics()] = reader.ReadElementContentAsString();
headers[reader.LocalName.RemoveDiacritics()] = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);
}
else
{
reader.Read();
await reader.ReadAsync().ConfigureAwait(false);
}
}
}
private class ControlRequestInfo
{
public string LocalName;
public string NamespaceURI;
public IDictionary<string, string> Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public string LocalName { get; set; }
public string NamespaceURI { get; set; }
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
@ -237,10 +228,7 @@ namespace Emby.Dlna.Service
return;
}
var originalHeaders = request.Headers;
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
_logger.LogDebug("Control request. Headers: {0}", headers);
Logger.LogDebug("Control request. Headers: {@Headers}", request.Headers);
}
private void LogResponse(ControlResponse response)
@ -250,11 +238,7 @@ namespace Emby.Dlna.Service
return;
}
var originalHeaders = response.Headers;
var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
//builder.Append(response.Xml);
_logger.LogDebug("Control response. Headers: {0}", headers);
Logger.LogDebug("Control response. Headers: {@Headers}\n{Xml}", response.Headers, response.Xml);
}
}
}

View File

@ -6,11 +6,11 @@ using Emby.Dlna.Didl;
namespace Emby.Dlna.Service
{
public class ControlErrorHandler
public static class ControlErrorHandler
{
private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
public ControlResponse GetResponse(Exception ex)
public static ControlResponse GetResponse(Exception ex)
{
var settings = new XmlWriterSettings
{