92 lines
2.5 KiB
C#
92 lines
2.5 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
namespace Inspectron.Epson.Templates.Storage;
|
|
|
|
public class FileTemplateStorage : ITemplateStorage
|
|
{
|
|
private readonly string _basePath;
|
|
private readonly string _templateExtension;
|
|
private readonly ConcurrentDictionary<string, string> _cache = new();
|
|
|
|
public FileTemplateStorage(string basePath, string templateExtension = ".template")
|
|
{
|
|
_basePath = Path.GetFullPath(basePath);
|
|
_templateExtension = templateExtension;
|
|
|
|
if (!Directory.Exists(_basePath))
|
|
{
|
|
Directory.CreateDirectory(_basePath);
|
|
}
|
|
}
|
|
|
|
public string? Load(string templatePath)
|
|
{
|
|
var normalizedPath = NormalizePath(templatePath);
|
|
|
|
if (_cache.TryGetValue(normalizedPath, out var cached))
|
|
{
|
|
return cached;
|
|
}
|
|
|
|
var fullPath = GetFullPath(normalizedPath);
|
|
if (!File.Exists(fullPath))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var content = File.ReadAllText(fullPath);
|
|
_cache[normalizedPath] = content;
|
|
return content;
|
|
}
|
|
|
|
public bool Exists(string templatePath)
|
|
{
|
|
var normalizedPath = NormalizePath(templatePath);
|
|
var fullPath = GetFullPath(normalizedPath);
|
|
return File.Exists(fullPath);
|
|
}
|
|
|
|
public void Reload()
|
|
{
|
|
_cache.Clear();
|
|
}
|
|
|
|
public IEnumerable<string> ListTemplates()
|
|
{
|
|
if (!Directory.Exists(_basePath))
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
var files = Directory.GetFiles(_basePath, $"*{_templateExtension}", SearchOption.AllDirectories);
|
|
foreach (var file in files)
|
|
{
|
|
var relativePath = Path.GetRelativePath(_basePath, file);
|
|
yield return relativePath.Replace('\\', '/');
|
|
}
|
|
}
|
|
|
|
private string NormalizePath(string path)
|
|
{
|
|
// Ensure the path has the correct extension
|
|
if (!path.EndsWith(_templateExtension, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
path += _templateExtension;
|
|
}
|
|
|
|
// Normalize path separators
|
|
return path.Replace('\\', '/');
|
|
}
|
|
|
|
private string GetFullPath(string normalizedPath)
|
|
{
|
|
// Security: prevent directory traversal
|
|
var fullPath = Path.GetFullPath(Path.Combine(_basePath, normalizedPath));
|
|
if (!fullPath.StartsWith(_basePath, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
throw new InvalidOperationException($"Invalid template path: {normalizedPath}");
|
|
}
|
|
return fullPath;
|
|
}
|
|
}
|