mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-08 02:34:06 +02:00
Add in-memory caching to td:// and tdp:// schemes
This commit is contained in:
parent
c91f1d0e5e
commit
57b03baad9
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
@ -14,27 +15,9 @@ private static ResourceHandler CreateHandler(byte[] bytes) {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public IResourceHandler Status(HttpStatusCode code, string message) {
|
||||
var handler = CreateHandler(Encoding.UTF8.GetBytes(message));
|
||||
handler.StatusCode = (int) code;
|
||||
return handler;
|
||||
}
|
||||
|
||||
public IResourceHandler File(string path) {
|
||||
try {
|
||||
return FileContents(System.IO.File.ReadAllBytes(path), Path.GetExtension(path));
|
||||
} catch (FileNotFoundException) {
|
||||
return Status(HttpStatusCode.NotFound, "File not found.");
|
||||
} catch (DirectoryNotFoundException) {
|
||||
return Status(HttpStatusCode.NotFound, "Directory not found.");
|
||||
} catch (Exception e) {
|
||||
return Status(HttpStatusCode.InternalServerError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private IResourceHandler FileContents(byte[] bytes, string extension) {
|
||||
private static IResourceHandler CreateFileContentsHandler(byte[] bytes, string extension) {
|
||||
if (bytes.Length == 0) {
|
||||
return Status(HttpStatusCode.NoContent, "File is empty."); // FromByteArray crashes CEF internals with no contents
|
||||
return CreateStatusHandler(HttpStatusCode.NoContent, "File is empty."); // FromByteArray crashes CEF internals with no contents
|
||||
}
|
||||
else {
|
||||
var handler = CreateHandler(bytes);
|
||||
@ -42,5 +25,73 @@ private IResourceHandler FileContents(byte[] bytes, string extension) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
private static IResourceHandler CreateStatusHandler(HttpStatusCode code, string message) {
|
||||
var handler = CreateHandler(Encoding.UTF8.GetBytes(message));
|
||||
handler.StatusCode = (int) code;
|
||||
return handler;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, ICachedResource> cache = new Dictionary<string, ICachedResource>();
|
||||
|
||||
public IResourceHandler Status(HttpStatusCode code, string message) {
|
||||
return CreateStatusHandler(code, message);
|
||||
}
|
||||
|
||||
public IResourceHandler File(string path) {
|
||||
string key = new Uri(path).LocalPath;
|
||||
|
||||
if (cache.TryGetValue(key, out var cachedResource)) {
|
||||
return cachedResource.GetResource();
|
||||
}
|
||||
|
||||
cachedResource = FileWithCaching(path);
|
||||
cache[key] = cachedResource;
|
||||
return cachedResource.GetResource();
|
||||
}
|
||||
|
||||
private ICachedResource FileWithCaching(string path) {
|
||||
try {
|
||||
return new CachedFile(System.IO.File.ReadAllBytes(path), Path.GetExtension(path));
|
||||
} catch (FileNotFoundException) {
|
||||
return new CachedStatus(HttpStatusCode.NotFound, "File not found.");
|
||||
} catch (DirectoryNotFoundException) {
|
||||
return new CachedStatus(HttpStatusCode.NotFound, "Directory not found.");
|
||||
} catch (Exception e) {
|
||||
return new CachedStatus(HttpStatusCode.InternalServerError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private interface ICachedResource {
|
||||
IResourceHandler GetResource();
|
||||
}
|
||||
|
||||
private sealed class CachedFile : ICachedResource {
|
||||
private readonly byte[] bytes;
|
||||
private readonly string extension;
|
||||
|
||||
public CachedFile(byte[] bytes, string extension) {
|
||||
this.bytes = bytes;
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
public IResourceHandler GetResource() {
|
||||
return CreateFileContentsHandler(bytes, extension);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CachedStatus : ICachedResource {
|
||||
private readonly HttpStatusCode code;
|
||||
private readonly string message;
|
||||
|
||||
public CachedStatus(HttpStatusCode code, string message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public IResourceHandler GetResource() {
|
||||
return CreateStatusHandler(code, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,11 @@ namespace TweetDuck.Plugins {
|
||||
sealed class PluginSchemeFactory : ISchemeHandlerFactory {
|
||||
public const string Name = PluginSchemeHandler<IResourceHandler>.Name;
|
||||
|
||||
private readonly PluginSchemeHandler<IResourceHandler> handler = new PluginSchemeHandler<IResourceHandler>(new ResourceProvider());
|
||||
private readonly PluginSchemeHandler<IResourceHandler> handler;
|
||||
|
||||
public PluginSchemeFactory(ResourceProvider resourceProvider) {
|
||||
handler = new PluginSchemeHandler<IResourceHandler>(resourceProvider);
|
||||
}
|
||||
|
||||
internal void Setup(PluginManager plugins) {
|
||||
handler.Setup(plugins);
|
||||
|
@ -133,8 +133,9 @@ private static void Main() {
|
||||
#endif
|
||||
};
|
||||
|
||||
var resourceScheme = new ResourceSchemeFactory();
|
||||
var pluginScheme = new PluginSchemeFactory();
|
||||
var resourceProvider = new ResourceProvider();
|
||||
var resourceScheme = new ResourceSchemeFactory(resourceProvider);
|
||||
var pluginScheme = new PluginSchemeFactory(resourceProvider);
|
||||
|
||||
settings.SetupCustomScheme(ResourceSchemeFactory.Name, resourceScheme);
|
||||
settings.SetupCustomScheme(PluginSchemeFactory.Name, pluginScheme);
|
||||
|
@ -2,7 +2,7 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using CefSharp;
|
||||
using TweetDuck.Browser.Handling;
|
||||
using TweetLib.Core.Browser;
|
||||
using TweetLib.Core.Utils;
|
||||
|
||||
namespace TweetDuck.Resources {
|
||||
@ -10,7 +10,12 @@ public class ResourceSchemeFactory : ISchemeHandlerFactory {
|
||||
public const string Name = "td";
|
||||
|
||||
private static readonly string RootPath = Path.Combine(Program.ResourcesPath);
|
||||
private static readonly ResourceProvider ResourceProvider = new ResourceProvider();
|
||||
|
||||
private readonly IResourceProvider<IResourceHandler> resourceProvider;
|
||||
|
||||
public ResourceSchemeFactory(IResourceProvider<IResourceHandler> resourceProvider) {
|
||||
this.resourceProvider = resourceProvider;
|
||||
}
|
||||
|
||||
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request) {
|
||||
if (!Uri.TryCreate(request.Url, UriKind.Absolute, out var uri) || uri.Scheme != Name) {
|
||||
@ -22,7 +27,7 @@ public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName
|
||||
}
|
||||
|
||||
string filePath = FileUtils.ResolveRelativePathSafely(RootPath, uri.AbsolutePath.TrimStart('/'));
|
||||
return filePath.Length == 0 ? ResourceProvider.Status(HttpStatusCode.Forbidden, "File path has to be relative to the resources root folder.") : ResourceProvider.File(filePath);
|
||||
return filePath.Length == 0 ? resourceProvider.Status(HttpStatusCode.Forbidden, "File path has to be relative to the resources root folder.") : resourceProvider.File(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user