diff --git a/SimpleCDN.Tests/CDNLoaderTests.cs b/SimpleCDN.Tests/CDNLoaderTests.cs index fa3490e..df251fc 100644 --- a/SimpleCDN.Tests/CDNLoaderTests.cs +++ b/SimpleCDN.Tests/CDNLoaderTests.cs @@ -1,4 +1,5 @@ using SimpleCDN.Configuration; +using SimpleCDN.Helpers; using System; using System.Collections.Generic; using System.Linq; @@ -27,7 +28,9 @@ public class CDNLoaderTests private static CDNLoader CreateLoader() { - return new CDNLoader(new MockWebHostEnvironment(), new OptionsMock(new() { DataRoot = TempFolder })); + var options = new OptionsMock(new() { DataRoot = TempFolder }); + + return new CDNLoader(new MockWebHostEnvironment(), options, new IndexGenerator(options)); } [SetUp] diff --git a/SimpleCDN/CDNLoader.cs b/SimpleCDN/CDNLoader.cs index ba5ced5..7d17b26 100644 --- a/SimpleCDN/CDNLoader.cs +++ b/SimpleCDN/CDNLoader.cs @@ -72,22 +72,45 @@ public class CDNLoader(IWebHostEnvironment environment, IOptionsMonitor + /// Attempts to load an index file from the directory at . If no index file is found, generates one. + /// + /// The absolute path to the directory + /// The path to the directory, how it was requested + /// private (MimeType type, byte[]? content) TryLoadIndex(string absolutePath, string rootRelativePath) { if (!Directory.Exists(absolutePath)) return MimeTypeHelpers.Empty; @@ -150,10 +180,12 @@ public class CDNLoader(IWebHostEnvironment environment, IOptionsMonitor? compare { public SizeLimitedCache(long maxSize) : this(maxSize, null) { } - private readonly Dictionary _dictionary = new(comparer); + private readonly ConcurrentDictionary _dictionary = new(comparer); private readonly long _maxSize = maxSize; public CachedFile this[string key] @@ -51,7 +52,7 @@ private void SetValue(string key, CachedFile value) { (var oldest, byOldest) = byOldest.RemoveFirst(); - _dictionary.Remove(oldest.Key); + _dictionary.TryRemove(oldest.Key, out _); } } diff --git a/SimpleCDN/Configuration/CDNConfiguration.cs b/SimpleCDN/Configuration/CDNConfiguration.cs index d6763d7..a4e6560 100644 --- a/SimpleCDN/Configuration/CDNConfiguration.cs +++ b/SimpleCDN/Configuration/CDNConfiguration.cs @@ -12,5 +12,6 @@ public class CDNConfiguration public uint MaxMemoryCacheSize { get; set; } = 500; public string Footer { get; set; } = """Powered by SimpleCDN"""; + public string PageTitle { get; set; } = "SimpleCDN"; } } diff --git a/SimpleCDN/Helpers/IndexGenerator.cs b/SimpleCDN/Helpers/IndexGenerator.cs index e7e3f90..f25e33d 100644 --- a/SimpleCDN/Helpers/IndexGenerator.cs +++ b/SimpleCDN/Helpers/IndexGenerator.cs @@ -26,6 +26,7 @@ public class IndexGenerator(IOptionsMonitor options) + {1} · Index of {2}
@@ -34,12 +35,13 @@ public class IndexGenerator(IOptionsMonitor options)
+ - """, rootRelativePath.Replace("/", "/")); + """, rootRelativePath.Replace("/", "/"), _options.CurrentValue.PageTitle, rootRelativePath); if (rootRelativePath is not "/" and not "" && directory.Parent is DirectoryInfo parent) { @@ -55,21 +57,21 @@ public class IndexGenerator(IOptionsMonitor options) parentRootRelativePath = rootRelativePath[..lastSlashIndex]; } - AppendRow(index, parentRootRelativePath, "Parent Directory", -1, parent.LastWriteTimeUtc); + AppendRow(index, parentRootRelativePath, "Parent Directory", "parent", -1, parent.LastWriteTimeUtc); } foreach (var subDirectory in directory.EnumerateDirectories()) { var name = subDirectory.Name; - AppendRow(index, Path.Combine(rootRelativePath, name), name, -1, subDirectory.LastWriteTimeUtc); + AppendRow(index, Path.Combine(rootRelativePath, name), name, "folder", -1, subDirectory.LastWriteTimeUtc); } foreach (var file in directory.EnumerateFiles()) { var name = file.Name; - AppendRow(index, Path.Combine(rootRelativePath, name), name, file.Length, file.LastWriteTimeUtc); + AppendRow(index, Path.Combine(rootRelativePath, name), name, "file", file.Length, file.LastWriteTimeUtc); } index.AppendFormat("
Name Size Last Modified (UTC)
{0}
", _options.CurrentValue.Footer); @@ -79,11 +81,14 @@ public class IndexGenerator(IOptionsMonitor options) return bytes; } - private static void AppendRow(StringBuilder index, string href, string name, long size, DateTimeOffset lastModified) + private static void AppendRow(StringBuilder index, string href, string name, string icon, long size, DateTimeOffset lastModified) { - index.AppendFormat("""{1}""", href, name); + index.Append(""); + index.AppendFormat("""{0}""", icon); + index.AppendFormat("""{1}""", href, name); index.AppendFormat("""{0}""", size < 0 ? "-" : size.FormatByteCount()); - index.AppendFormat("""{0}""", lastModified.ToString("dd/MM/yyyy HH:mm")); + index.AppendFormat("""{0}""", lastModified.ToString("dd/MM/yyyy HH:mm")); + index.Append(""); } } } diff --git a/SimpleCDN/SimpleCDN.csproj b/SimpleCDN/SimpleCDN.csproj index f88e9c2..7a9bc79 100644 --- a/SimpleCDN/SimpleCDN.csproj +++ b/SimpleCDN/SimpleCDN.csproj @@ -14,6 +14,11 @@ none + + + + + diff --git a/SimpleCDN/wwwroot/file.svg b/SimpleCDN/wwwroot/file.svg new file mode 100644 index 0000000..30a9f19 --- /dev/null +++ b/SimpleCDN/wwwroot/file.svg @@ -0,0 +1,4 @@ + + + + diff --git a/SimpleCDN/wwwroot/folder.svg b/SimpleCDN/wwwroot/folder.svg new file mode 100644 index 0000000..977915f --- /dev/null +++ b/SimpleCDN/wwwroot/folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/SimpleCDN/wwwroot/parent.svg b/SimpleCDN/wwwroot/parent.svg new file mode 100644 index 0000000..74e2b4d --- /dev/null +++ b/SimpleCDN/wwwroot/parent.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/SimpleCDN/wwwroot/styles.css b/SimpleCDN/wwwroot/styles.css index 4f4f8c1..f4bb70c 100644 --- a/SimpleCDN/wwwroot/styles.css +++ b/SimpleCDN/wwwroot/styles.css @@ -52,4 +52,13 @@ thead th { footer { text-align: center; +} + +img { + transform: translateY(0); +} + +td:has(img) { + display: inline-flex; + align-items: center; } \ No newline at end of file diff --git a/docker-compose.dcproj b/docker-compose.dcproj index d162663..bc29f16 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -6,7 +6,7 @@ False 81dded9d-158b-e303-5f62-77a2896d2a5a LaunchBrowser - {Scheme}://localhost:{ServicePort}/weatherforecast + {Scheme}://localhost:{ServicePort} simplecdn