mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-26 02:34:05 +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;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -14,27 +15,9 @@ private static ResourceHandler CreateHandler(byte[] bytes) {
|
|||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IResourceHandler Status(HttpStatusCode code, string message) {
|
private static IResourceHandler CreateFileContentsHandler(byte[] bytes, string extension) {
|
||||||
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) {
|
|
||||||
if (bytes.Length == 0) {
|
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 {
|
else {
|
||||||
var handler = CreateHandler(bytes);
|
var handler = CreateHandler(bytes);
|
||||||
@ -42,5 +25,73 @@ private IResourceHandler FileContents(byte[] bytes, string extension) {
|
|||||||
return handler;
|
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 {
|
sealed class PluginSchemeFactory : ISchemeHandlerFactory {
|
||||||
public const string Name = PluginSchemeHandler<IResourceHandler>.Name;
|
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) {
|
internal void Setup(PluginManager plugins) {
|
||||||
handler.Setup(plugins);
|
handler.Setup(plugins);
|
||||||
|
@ -133,8 +133,9 @@ private static void Main() {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
var resourceScheme = new ResourceSchemeFactory();
|
var resourceProvider = new ResourceProvider();
|
||||||
var pluginScheme = new PluginSchemeFactory();
|
var resourceScheme = new ResourceSchemeFactory(resourceProvider);
|
||||||
|
var pluginScheme = new PluginSchemeFactory(resourceProvider);
|
||||||
|
|
||||||
settings.SetupCustomScheme(ResourceSchemeFactory.Name, resourceScheme);
|
settings.SetupCustomScheme(ResourceSchemeFactory.Name, resourceScheme);
|
||||||
settings.SetupCustomScheme(PluginSchemeFactory.Name, pluginScheme);
|
settings.SetupCustomScheme(PluginSchemeFactory.Name, pluginScheme);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using TweetDuck.Browser.Handling;
|
using TweetLib.Core.Browser;
|
||||||
using TweetLib.Core.Utils;
|
using TweetLib.Core.Utils;
|
||||||
|
|
||||||
namespace TweetDuck.Resources {
|
namespace TweetDuck.Resources {
|
||||||
@ -10,7 +10,12 @@ public class ResourceSchemeFactory : ISchemeHandlerFactory {
|
|||||||
public const string Name = "td";
|
public const string Name = "td";
|
||||||
|
|
||||||
private static readonly string RootPath = Path.Combine(Program.ResourcesPath);
|
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) {
|
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request) {
|
||||||
if (!Uri.TryCreate(request.Url, UriKind.Absolute, out var uri) || uri.Scheme != Name) {
|
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('/'));
|
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