Switched to MEF to register http handlers

This commit is contained in:
LukePulverenti Luke Pulverenti luke pulverenti 2012-09-08 10:52:13 -04:00
parent a95e868300
commit 93b42641d2
26 changed files with 240 additions and 154 deletions

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net;
namespace MediaBrowser.Api
{
@ -374,5 +375,10 @@ namespace MediaBrowser.Api
LastLoginDate = user.LastLoginDate
};
}
public static bool IsApiUrlMatch(string url, HttpListenerRequest request)
{
return request.Url.LocalPath.EndsWith(url, StringComparison.OrdinalIgnoreCase);
}
}
}

View File

@ -1,15 +1,24 @@
using System.Collections.Generic;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using MediaBrowser.Model.Entities;
using System.Net;
namespace MediaBrowser.Api.HttpHandlers
{
/// <summary>
/// Supported output formats are: mp3,flac,ogg,wav,asf,wma,aac
/// </summary>
[Export(typeof(BaseHandler))]
public class AudioHandler : BaseMediaHandler<Audio>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("audio", request);
}
/// <summary>
/// Overriding to provide mp3 as a default, since pretty much every device supports it
/// </summary>

View File

@ -1,15 +1,15 @@
using System;
using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{

View File

@ -4,7 +4,9 @@ using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
@ -12,8 +14,14 @@ namespace MediaBrowser.Api.HttpHandlers
/// <summary>
/// Gets a single genre
/// </summary>
[Export(typeof(BaseHandler))]
public class GenreHandler : BaseSerializationHandler<IBNItem>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("genre", request);
}
protected override Task<IBNItem> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -3,13 +3,21 @@ using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class GenresHandler : BaseSerializationHandler<IBNItem[]>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("genres", request);
}
protected override Task<IBNItem[]> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -4,14 +4,22 @@ using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class ImageHandler : BaseHandler
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("image", request);
}
private string _ImagePath = null;
private async Task<string> GetImagePath()
{

View File

@ -1,12 +1,20 @@
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class ItemHandler : BaseSerializationHandler<DTOBaseItem>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("item", request);
}
protected override Task<DTOBaseItem> GetObjectToSerialize()
{
User user = ApiService.GetUserById(QueryString["userid"], true);

View File

@ -3,13 +3,21 @@ using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class ItemListHandler : BaseSerializationHandler<DTOBaseItem[]>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("itemlist", request);
}
protected override Task<DTOBaseItem[]> GetObjectToSerialize()
{
User user = ApiService.GetUserById(QueryString["userid"], true);

View File

@ -3,6 +3,8 @@ using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
@ -10,8 +12,14 @@ namespace MediaBrowser.Api.HttpHandlers
/// <summary>
/// Gets a single Person
/// </summary>
[Export(typeof(BaseHandler))]
public class PersonHandler : BaseSerializationHandler<IBNItem>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("person", request);
}
protected override Task<IBNItem> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -1,14 +1,21 @@
using System;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
class PluginAssemblyHandler : BaseHandler
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("pluginassembly", request);
}
public override Task<string> GetContentType()
{
throw new NotImplementedException();

View File

@ -1,15 +1,23 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller;
using MediaBrowser.Model.Plugins;
using System;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class PluginConfigurationHandler : BaseSerializationHandler<BasePluginConfiguration>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("pluginconfiguration", request);
}
private BasePlugin _Plugin = null;
private BasePlugin Plugin
{

View File

@ -1,17 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
/// <summary>
/// Provides information about installed plugins
/// </summary>
[Export(typeof(BaseHandler))]
public class PluginsHandler : BaseSerializationHandler<IEnumerable<PluginInfo>>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("plugins", request);
}
protected override Task<IEnumerable<PluginInfo>> GetObjectToSerialize()
{
var plugins = Kernel.Instance.Plugins.Select(p =>

View File

@ -1,14 +1,22 @@
using System;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Configuration;
using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
class ServerConfigurationHandler : BaseSerializationHandler<ServerConfiguration>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("serverconfiguration", request);
}
protected override Task<ServerConfiguration> GetObjectToSerialize()
{
return Task.FromResult<ServerConfiguration>(Kernel.Instance.Configuration);

View File

@ -4,7 +4,9 @@ using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
@ -12,8 +14,14 @@ namespace MediaBrowser.Api.HttpHandlers
/// <summary>
/// Gets a single studio
/// </summary>
[Export(typeof(BaseHandler))]
public class StudioHandler : BaseSerializationHandler<IBNItem>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("studio", request);
}
protected override Task<IBNItem> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -3,13 +3,21 @@ using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class StudiosHandler : BaseSerializationHandler<IBNItem[]>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("studios", request);
}
protected override Task<IBNItem[]> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -1,12 +1,20 @@
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
class UserAuthenticationHandler : BaseSerializationHandler<AuthenticationResult>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("UserAuthentication", request);
}
protected override async Task<AuthenticationResult> GetObjectToSerialize()
{
string userId = await GetFormValue("userid").ConfigureAwait(false);

View File

@ -1,12 +1,20 @@
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
class UserHandler : BaseSerializationHandler<DTOUser>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("user", request);
}
protected override Task<DTOUser> GetObjectToSerialize()
{
string id = QueryString["id"];

View File

@ -2,13 +2,21 @@
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
class UsersHandler : BaseSerializationHandler<IEnumerable<DTOUser>>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("users", request);
}
protected override Task<IEnumerable<DTOUser>> GetObjectToSerialize()
{
return Task.FromResult<IEnumerable<DTOUser>>(Kernel.Instance.Users.Select(u => ApiService.GetDTOUser(u)));

View File

@ -1,18 +1,27 @@
using System;
using MediaBrowser.Common.Drawing;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Drawing;
using System.IO;
using System.Linq;
using MediaBrowser.Common.Drawing;
using MediaBrowser.Model.Entities;
using System.Net;
namespace MediaBrowser.Api.HttpHandlers
{
/// <summary>
/// Supported output formats: mkv,m4v,mp4,asf,wmv,mov,webm,ogv,3gp,avi,ts,flv
/// </summary>
[Export(typeof(BaseHandler))]
class VideoHandler : BaseMediaHandler<Video>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("video", request);
}
/// <summary>
/// We can output these files directly, but we can't encode them
/// </summary>

View File

@ -1,13 +1,21 @@
using System;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Weather;
using System;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
class WeatherHandler : BaseSerializationHandler<WeatherInfo>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("weather", request);
}
protected override Task<WeatherInfo> GetObjectToSerialize()
{
// If a specific zip code was requested on the query string, use that. Otherwise use the value from configuration

View File

@ -3,6 +3,8 @@ using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
@ -10,8 +12,14 @@ namespace MediaBrowser.Api.HttpHandlers
/// <summary>
/// Gets a single year
/// </summary>
[Export(typeof(BaseHandler))]
public class YearHandler : BaseSerializationHandler<IBNItem>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("year", request);
}
protected override Task<IBNItem> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -3,13 +3,21 @@ using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace MediaBrowser.Api.HttpHandlers
{
[Export(typeof(BaseHandler))]
public class YearsHandler : BaseSerializationHandler<IBNItem[]>
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return ApiService.IsApiUrlMatch("years", request);
}
protected override Task<IBNItem[]> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;

View File

@ -1,12 +1,6 @@
using MediaBrowser.Api.HttpHandlers;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Controller;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
using System;
using System.ComponentModel.Composition;
using System.Net;
using System.Reactive.Linq;
namespace MediaBrowser.Api
{
@ -17,117 +11,5 @@ namespace MediaBrowser.Api
{
get { return "Media Browser API"; }
}
protected override void InitializeOnServer()
{
var httpServer = Kernel.Instance.HttpServer;
httpServer.Where(ctx => ctx.Request.Url.LocalPath.IndexOf("/api/", StringComparison.OrdinalIgnoreCase) != -1).Subscribe((ctx) =>
{
BaseHandler handler = GetHandler(ctx);
if (handler != null)
{
handler.ProcessRequest(ctx);
}
});
}
private BaseHandler GetHandler(HttpListenerContext ctx)
{
string localPath = ctx.Request.Url.LocalPath;
if (IsUrlMatch("/api/item", localPath))
{
return new ItemHandler();
}
else if (IsUrlMatch("/api/image", localPath))
{
return new ImageHandler();
}
else if (IsUrlMatch("/api/users", localPath))
{
return new UsersHandler();
}
else if (IsUrlMatch("/api/itemlist", localPath))
{
return new ItemListHandler();
}
else if (IsUrlMatch("/api/genres", localPath))
{
return new GenresHandler();
}
else if (IsUrlMatch("/api/years", localPath))
{
return new YearsHandler();
}
else if (IsUrlMatch("/api/studios", localPath))
{
return new StudiosHandler();
}
else if (IsUrlMatch("/api/plugins", localPath))
{
return new PluginsHandler();
}
else if (IsUrlMatch("/api/pluginconfiguration", localPath))
{
return new PluginConfigurationHandler();
}
else if (IsUrlMatch("/api/static", localPath))
{
return new StaticFileHandler();
}
else if (IsUrlMatch("/api/audio", localPath))
{
return new AudioHandler();
}
else if (IsUrlMatch("/api/video", localPath))
{
return new VideoHandler();
}
else if (IsUrlMatch("/api/person", localPath))
{
return new PersonHandler();
}
else if (IsUrlMatch("/api/genre", localPath))
{
return new GenreHandler();
}
else if (IsUrlMatch("/api/year", localPath))
{
return new YearHandler();
}
else if (IsUrlMatch("/api/studio", localPath))
{
return new StudioHandler();
}
else if (IsUrlMatch("/api/weather", localPath))
{
return new WeatherHandler();
}
else if (IsUrlMatch("/api/serverconfiguration", localPath))
{
return new ServerConfigurationHandler();
}
else if (IsUrlMatch("/api/user", localPath))
{
return new UserHandler();
}
else if (IsUrlMatch("/api/pluginassembly", localPath))
{
return new PluginAssemblyHandler();
}
else if (IsUrlMatch("/api/UserAuthentication", localPath))
{
return new UserAuthenticationHandler();
}
return null;
}
private bool IsUrlMatch(string url, string localPath)
{
return localPath.EndsWith(url, StringComparison.OrdinalIgnoreCase);
}
}
}

View File

@ -1,5 +1,6 @@
using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Serialization;
using MediaBrowser.Model.Configuration;
@ -35,12 +36,23 @@ namespace MediaBrowser.Common.Kernel
[ImportMany(typeof(BasePlugin))]
public IEnumerable<BasePlugin> Plugins { get; private set; }
/// <summary>
/// Gets the list of currently registered http handlers
/// </summary>
[ImportMany(typeof(BaseHandler))]
private IEnumerable<BaseHandler> HttpHandlers { get; set; }
/// <summary>
/// Both the UI and server will have a built-in HttpServer.
/// People will inevitably want remote control apps so it's needed in the UI too.
/// </summary>
public HttpServer HttpServer { get; private set; }
/// <summary>
/// This subscribes to HttpListener requests and finds the appropate BaseHandler to process it
/// </summary>
private IDisposable HttpListener { get; set; }
protected virtual string HttpServerUrlPrefix
{
get
@ -186,6 +198,21 @@ namespace MediaBrowser.Common.Kernel
DisposeHttpServer();
HttpServer = new HttpServer(HttpServerUrlPrefix);
HttpListener = HttpServer.Subscribe((ctx) =>
{
BaseHandler handler = HttpHandlers.FirstOrDefault(h => h.HandlesRequest(ctx.Request));
// Find the appropiate http handler
if (handler != null)
{
// Need to create a new instance because handlers are currently stateful
handler = Activator.CreateInstance(handler.GetType()) as BaseHandler;
// No need to await this, despite the compiler warning
handler.ProcessRequest(ctx);
}
});
}
/// <summary>
@ -249,6 +276,11 @@ namespace MediaBrowser.Common.Kernel
{
HttpServer.Dispose();
}
if (HttpListener != null)
{
HttpListener.Dispose();
}
}
/// <summary>

View File

@ -1,4 +1,5 @@
using System;
using MediaBrowser.Common.Logging;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
@ -6,15 +7,14 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using MediaBrowser.Common.Logging;
namespace MediaBrowser.Common.Net.Handlers
{
public abstract class BaseHandler
{
public abstract bool HandlesRequest(HttpListenerRequest request);
private Stream CompressedStream { get; set; }
public virtual bool? UseChunkedEncoding

View File

@ -1,15 +1,20 @@
using System;
using MediaBrowser.Common.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using MediaBrowser.Common.Logging;
namespace MediaBrowser.Common.Net.Handlers
{
public class StaticFileHandler : BaseHandler
{
public override bool HandlesRequest(HttpListenerRequest request)
{
return false;
}
private string _Path;
public virtual string Path
{