clean up pdb files on client, hash assembly file names

This commit is contained in:
Shaun Walker 2022-09-14 10:09:50 -04:00
parent c0f4069a9b
commit 45df729711
3 changed files with 115 additions and 93 deletions

View File

@ -117,6 +117,7 @@ namespace Oqtane.Client
try try
{ {
await interop.RemoveIndexedDBItem(file); await interop.RemoveIndexedDBItem(file);
await interop.RemoveIndexedDBItem(file.Replace(".dll", ".pdb"));
} }
catch catch
{ {

View File

@ -127,7 +127,10 @@ public static class MauiProgram
{ {
try try
{ {
File.Delete(Path.Combine(folder, file)); foreach (var path in Directory.EnumerateFiles(folder, Path.GetFileNameWithoutExtension(file) + ".*"))
{
File.Delete(path);
}
} }
catch catch
{ {
@ -159,11 +162,6 @@ public static class MauiProgram
// save assembly to local folder // save assembly to local folder
try try
{ {
int subfolder = entry.FullName.IndexOf('/');
if (subfolder != -1 && !Directory.Exists(Path.Combine(folder, entry.FullName.Substring(0, subfolder))))
{
Directory.CreateDirectory(Path.Combine(folder, entry.FullName.Substring(0, subfolder)));
}
using var stream = File.Create(Path.Combine(folder, entry.FullName)); using var stream = File.Create(Path.Combine(folder, entry.FullName));
stream.Write(file, 0, file.Length); stream.Write(file, 0, file.Length);
} }

View File

@ -103,10 +103,7 @@ namespace Oqtane.Controllers
[HttpGet("list")] [HttpGet("list")]
public List<string> List() public List<string> List()
{ {
return _cache.GetOrCreate("assemblieslist", entry => return GetAssemblyList().Select(item => item.HashedName).ToList();
{
return GetAssemblyList();
});
} }
// GET api/<controller>/load?list=x,y // GET api/<controller>/load?list=x,y
@ -116,81 +113,90 @@ namespace Oqtane.Controllers
return File(GetAssemblies(list), System.Net.Mime.MediaTypeNames.Application.Octet, "oqtane.dll"); return File(GetAssemblies(list), System.Net.Mime.MediaTypeNames.Application.Octet, "oqtane.dll");
} }
private List<string> GetAssemblyList() private List<ClientAssembly> GetAssemblyList()
{ {
// get list of assemblies which should be downloaded to client return _cache.GetOrCreate("assemblieslist", entry =>
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies();
var list = assemblies.Select(a => a.GetName().Name).ToList();
// include version numbers
for (int i = 0; i < list.Count; i++)
{ {
list[i] = Path.GetFileName(AddFileDate(Path.Combine(binFolder, list[i] + ".dll"))); var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
} var assemblyList = new List<ClientAssembly>();
// insert satellite assemblies at beginning of list // get list of assemblies which should be downloaded to client
foreach (var culture in _localizationManager.GetInstalledCultures()) var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies();
{ var list = assemblies.Select(a => a.GetName().Name).ToList();
var assembliesFolderPath = Path.Combine(binFolder, culture);
if (culture == Constants.DefaultCulture) // populate assemblies
for (int i = 0; i < list.Count; i++)
{ {
continue; assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, list[i] + ".dll")));
} }
if (Directory.Exists(assembliesFolderPath)) // insert satellite assemblies at beginning of list
foreach (var culture in _localizationManager.GetInstalledCultures())
{ {
foreach (var resourceFile in Directory.EnumerateFiles(assembliesFolderPath)) var assembliesFolderPath = Path.Combine(binFolder, culture);
if (culture == Constants.DefaultCulture)
{ {
list.Insert(0, culture + "/" + Path.GetFileName(AddFileDate(resourceFile))); continue;
}
if (Directory.Exists(assembliesFolderPath))
{
foreach (var resourceFile in Directory.EnumerateFiles(assembliesFolderPath))
{
assemblyList.Insert(0, new ClientAssembly(resourceFile));
}
}
else
{
_filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist"));
} }
} }
else
{
_filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist"));
}
}
// insert module and theme dependencies at beginning of list // insert module and theme dependencies at beginning of list
foreach (var assembly in assemblies) foreach (var assembly in assemblies)
{
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule))))
{ {
var instance = Activator.CreateInstance(type) as IModule; foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule))))
foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{ {
var path = Path.Combine(binFolder, name + ".dll"); var instance = Activator.CreateInstance(type) as IModule;
if (System.IO.File.Exists(path)) foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
{ {
path = Path.GetFileName(AddFileDate(path)); var filepath = Path.Combine(binFolder, name + ".dll");
if (!list.Contains(path)) list.Insert(0, path); if (System.IO.File.Exists(filepath))
{
if (!assemblyList.Exists(item => item.FilePath == filepath))
{
assemblyList.Insert(0, new ClientAssembly(filepath));
}
}
else
{
_filelogger.LogError(Utilities.LogMessage(this, $"Module {instance.ModuleDefinition.ModuleDefinitionName} Dependency {name}.dll Does Not Exist"));
}
} }
else }
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))))
{
var instance = Activator.CreateInstance(type) as ITheme;
foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
{ {
_filelogger.LogError(Utilities.LogMessage(this, $"Module {instance.ModuleDefinition.ModuleDefinitionName} Dependency {name}.dll Does Not Exist")); var filepath = Path.Combine(binFolder, name + ".dll");
if (System.IO.File.Exists(filepath))
{
if (!assemblyList.Exists(item => item.FilePath == filepath))
{
assemblyList.Insert(0, new ClientAssembly(filepath));
}
}
else
{
_filelogger.LogError(Utilities.LogMessage(this, $"Theme {instance.Theme.ThemeName} Dependency {name}.dll Does Not Exist"));
}
} }
} }
} }
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))))
{
var instance = Activator.CreateInstance(type) as ITheme;
foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
var path = Path.Combine(binFolder, name + ".dll");
if (System.IO.File.Exists(path))
{
path = Path.GetFileName(AddFileDate(path));
if (!list.Contains(path)) list.Insert(0, path);
}
else
{
_filelogger.LogError(Utilities.LogMessage(this, $"Theme {instance.Theme.ThemeName} Dependency {name}.dll Does Not Exist"));
}
}
}
}
return list; return assemblyList;
});
} }
private byte[] GetAssemblies(string list) private byte[] GetAssemblies(string list)
@ -213,14 +219,11 @@ namespace Oqtane.Controllers
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
// get list of assemblies which should be downloaded to client // get list of assemblies which should be downloaded to client
List<string> assemblies; List<ClientAssembly> assemblies = GetAssemblyList();
if (list == "*") if (list != "*")
{ {
assemblies = GetAssemblyList(); var filter = list.Split(',').ToList();
} assemblies.RemoveAll(item => !filter.Contains(item.HashedName));
else
{
assemblies = list.Split(',').ToList();
} }
// create zip file containing assemblies and debug symbols // create zip file containing assemblies and debug symbols
@ -228,22 +231,21 @@ namespace Oqtane.Controllers
{ {
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{ {
foreach (string file in assemblies) foreach (var assembly in assemblies)
{ {
var filename = RemoveFileDate(file); if (System.IO.File.Exists(assembly.FilePath))
if (System.IO.File.Exists(Path.Combine(binFolder, filename)))
{ {
using (var filestream = new FileStream(Path.Combine(binFolder, filename), FileMode.Open, FileAccess.Read)) using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read))
using (var entrystream = archive.CreateEntry(file).Open()) using (var entrystream = archive.CreateEntry(assembly.HashedName).Open())
{ {
filestream.CopyTo(entrystream); filestream.CopyTo(entrystream);
} }
} }
filename = filename.Replace(".dll", ".pdb"); var pdb = assembly.FilePath.Replace(".dll", ".pdb");
if (System.IO.File.Exists(Path.Combine(binFolder, filename))) if (System.IO.File.Exists(pdb))
{ {
using (var filestream = new FileStream(Path.Combine(binFolder, filename), FileMode.Open, FileAccess.Read)) using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read))
using (var entrystream = archive.CreateEntry(file.Replace(".dll", ".pdb")).Open()) using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open())
{ {
filestream.CopyTo(entrystream); filestream.CopyTo(entrystream);
} }
@ -255,18 +257,6 @@ namespace Oqtane.Controllers
} }
} }
private string AddFileDate(string filepath)
{
DateTime lastwritetime = System.IO.File.GetLastWriteTime(filepath);
return Path.GetFileNameWithoutExtension(filepath) + "." + lastwritetime.ToString("yyyyMMddHHmmss") + Path.GetExtension(filepath);
}
private string RemoveFileDate(string filepath)
{
var segments = filepath.Split(".");
return string.Join(".", segments, 0, segments.Length - 2) + Path.GetExtension(filepath);
}
private async Task RegisterContact(string email) private async Task RegisterContact(string email)
{ {
try try
@ -292,5 +282,38 @@ namespace Oqtane.Controllers
{ {
await RegisterContact(email); await RegisterContact(email);
} }
public struct ClientAssembly
{
public ClientAssembly(string filepath)
{
FilePath = filepath;
DateTime lastwritetime = System.IO.File.GetLastWriteTime(filepath);
HashedName = GetDeterministicHashCode(filepath).ToString("X8") + "." + lastwritetime.ToString("yyyyMMddHHmmss") + Path.GetExtension(filepath);
}
public string FilePath { get; private set; }
public string HashedName { get; private set; }
}
private static int GetDeterministicHashCode(string value)
{
unchecked
{
int hash1 = (5381 << 16) + 5381;
int hash2 = hash1;
for (int i = 0; i < value.Length; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ value[i];
if (i == value.Length - 1)
break;
hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
}
return hash1 + (hash2 * 1566083941);
}
}
} }
} }