Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 36 additions & 35 deletions src/Gemstone.PhasorProtocols/Anonymous/ConfigurationFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Soap;
using Gemstone.Configuration;
using Gemstone.IO;
using Gemstone.IO.Checksums.ChecksumExtensions;
using Gemstone.StringExtensions;
using Gemstone.Threading.Collections;
using Gemstone.Threading.SynchronizedOperations;

namespace Gemstone.PhasorProtocols.Anonymous
{
Expand Down Expand Up @@ -75,12 +76,12 @@ protected ConfigurationFrame(SerializationInfo info, StreamingContext context)
/// <summary>
/// Gets reference to the <see cref="ConfigurationCellCollection"/> for this <see cref="ConfigurationFrame"/>.
/// </summary>
public new ConfigurationCellCollection Cells => base.Cells as ConfigurationCellCollection;
public new ConfigurationCellCollection Cells => (base.Cells as ConfigurationCellCollection)!;

/// <summary>
/// Gets or sets name of this configuration frame as assigned or useful in an end-use context.
/// </summary>
public virtual string Name { get; set; }
public virtual string Name { get; set; } = string.Empty;

#endregion

Expand All @@ -104,18 +105,17 @@ protected override ushort CalculateChecksum(byte[] buffer, int offset, int lengt
#region [ Static ]

// Static Fields
//private static readonly ProcessQueue<Tuple<IConfigurationFrame, Action<Exception>, string>> s_configurationCacheQueue;
private static string s_configurationCachePath;
private static readonly ProcessQueue<Tuple<IConfigurationFrame, Action<Exception>, string>> s_configurationCacheQueue;
private static string? s_configurationCachePath;
private static int s_configurationBackups;

// Static Constructor
static ConfigurationFrame()
{
// TODO: Move configuration caching to host application - not the best location to have this here
s_configurationBackups = -1;
//s_configurationCacheQueue = ProcessQueue<Tuple<IConfigurationFrame, Action<Exception>, string>>.CreateRealTimeQueue(CacheConfigurationFile);
//s_configurationCacheQueue.SynchronizedOperationType = SynchronizedOperationType.LongBackground;
//s_configurationCacheQueue.Start();
s_configurationCacheQueue = ProcessQueue<Tuple<IConfigurationFrame, Action<Exception>, string>>.CreateRealTimeQueue(CacheConfigurationFile);
s_configurationCacheQueue.SynchronizedOperationType = SynchronizedOperationType.LongBackground;
s_configurationCacheQueue.Start();
}

// Static Properties
Expand All @@ -134,12 +134,12 @@ public static string ConfigurationCachePath
s_configurationCachePath = string.Format("{0}{1}ConfigurationCache{1}", FilePath.GetAbsolutePath(""), Path.DirectorySeparatorChar);

// Make sure configuration cache path setting exists within system settings section of config file
//ConfigurationFile configFile = ConfigurationFile.Current;
//CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"];
//systemSettings.Add("ConfigurationCachePath", s_configurationCachePath, "Defines the path used to cache serialized phasor protocol configurations");
dynamic settings = Settings.Default.System;

settings.ConfigurationCachePath = (s_configurationCachePath, "Defines the path used to cache serialized configurations");

// Retrieve configuration cache directory as defined in the config file
//s_configurationCachePath = FilePath.AddPathSuffix(systemSettings["ConfigurationCachePath"].Value);
s_configurationCachePath = FilePath.AddPathSuffix(settings.ConfigurationCachePath);

// Make sure configuration cache directory exists
if (!Directory.Exists(s_configurationCachePath))
Expand All @@ -162,12 +162,12 @@ public static int ConfigurationBackups
const int DefaultConfigurationBackups = 5;

// Make sure configuration backups setting exists within system settings section of config file
//ConfigurationFile configFile = ConfigurationFile.Current;
//CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"];
//systemSettings.Add("ConfigurationBackups", DefaultConfigurationBackups, "Defines the total number of older backup configurations to maintain.");
dynamic settings = Settings.Default.System;

settings.ConfigurationBackups = (DefaultConfigurationBackups, "Defines the total number of older backup configurations to maintain");

// Retrieve configuration backups value as defined in the config file
//s_configurationBackups = systemSettings["ConfigurationBackups"].ValueAs(DefaultConfigurationBackups);
s_configurationBackups = settings.ConfigurationBackups;
}

return s_configurationBackups;
Expand All @@ -185,16 +185,16 @@ public static int ConfigurationBackups
public static void Cache(IConfigurationFrame configurationFrame, Action<Exception> exceptionHandler, string configurationName)
{
Tuple<IConfigurationFrame, Action<Exception>, string> cacheState = new(configurationFrame, exceptionHandler, configurationName);
//s_configurationCacheQueue.Add(cacheState);
s_configurationCacheQueue.Add(cacheState);
}

// Cache configuration file
private static void CacheConfigurationFile(Tuple<IConfigurationFrame, Action<Exception>, string> args)
private static void CacheConfigurationFile(Tuple<IConfigurationFrame, Action<Exception>, string>? args)
{
if (args is null)
return;

FileStream configFile = null;
FileStream? configFile = null;
IConfigurationFrame configurationFrame = args.Item1;
Action<Exception> exceptionHandler = args.Item2;
string configurationName = args.Item3;
Expand Down Expand Up @@ -246,15 +246,8 @@ private static void CacheConfigurationFile(Tuple<IConfigurationFrame, Action<Exc

try
{
// Serialize configuration frame to a file
SoapFormatter xmlSerializer = new()
{
AssemblyFormat = FormatterAssemblyStyle.Simple,
TypeFormat = FormatterTypeStyle.TypesWhenNeeded
};

configFile = File.Create(configurationCacheFileName);
xmlSerializer.Serialize(configFile, configurationFrame);
LegacySoapSerializer.Serialize(configFile, configurationFrame);
}
catch (Exception ex)
{
Expand All @@ -267,16 +260,24 @@ private static void CacheConfigurationFile(Tuple<IConfigurationFrame, Action<Exc
}

/// <summary>
/// Gets the file name with path of the specified <paramref name="configurationName"/>.
/// Generates the full file name, including the path, for a configuration cache file.
/// </summary>
/// <param name="configurationName">Name of the configuration to get file name for.</param>
/// <returns>File name with path of the specified <paramref name="configurationName"/>.</returns>
public static string GetConfigurationCacheFileName(string configurationName, string extension = "configuration.xml", string basePath = null)
/// <param name="configurationName">The name of the configuration for which to generate the file name.</param>
/// <param name="extension">The file extension to use for the configuration cache file. Defaults to <c>"configuration.xml"</c>.</param>
/// <param name="basePath">The base path where the configuration cache file will be located. If not specified, a default path is used.</param>
/// <returns>
/// A string representing the full file name, including the path, for the specified configuration cache file.
/// </returns>
/// <remarks>
/// Invalid characters in the <paramref name="configurationName"/> or <paramref name="extension"/> are replaced
/// to ensure the resulting file name is valid.
/// </remarks>
public static string GetConfigurationCacheFileName(string configurationName, string extension = "configuration.xml", string? basePath = null)
{
// Path traversal attacks are prevented by replacing invalid file name characters
return $"{basePath ?? ConfigurationCachePath}{RemoveInvalidCharacters(configurationName)}.{RemoveInvalidCharacters(extension)}";
return $"{basePath ?? ConfigurationCachePath}{removeInvalidCharacters(configurationName)}.{removeInvalidCharacters(extension)}";

static string RemoveInvalidCharacters(string name) =>
static string removeInvalidCharacters(string name) =>
name.ReplaceCharacters('_', c => Path.GetInvalidFileNameChars().Contains(c));
}

Expand Down
18 changes: 5 additions & 13 deletions src/Gemstone.PhasorProtocols/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@

using System;
using System.IO;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Soap;
using Gemstone.IO.Parsing;
using Gemstone.StringExtensions;

Expand Down Expand Up @@ -111,19 +109,13 @@ public static void CopyImage(this ISupportBinaryImage channel, byte[] destinatio
/// </summary>
/// <param name="configStream"><see cref="Stream"/> that contains an XML serialized configuration frame.</param>
/// <returns>Deserialized <see cref="IConfigurationFrame"/>.</returns>
/// <remarks>
/// Reads legacy <c>SoapFormatter</c>-produced XML via <see cref="LegacySoapDeserializer"/>, which targets
/// the same wire format but works on .NET Core / .NET 5+ where <c>SoapFormatter</c> is unavailable.
/// </remarks>
public static IConfigurationFrame? DeserializeConfigurationFrame(Stream configStream)
{
SoapFormatter xmlSerializer = new()
{
AssemblyFormat = FormatterAssemblyStyle.Simple,
TypeFormat = FormatterTypeStyle.TypesWhenNeeded,
Binder = Serialization.LegacyBinder
};

//configFrame = xmlSerializer.Deserialize(new MemoryStream(Encoding.Default.GetBytes(xmlFile))) as IConfigurationFrame;
IConfigurationFrame? configFrame = xmlSerializer.Deserialize(configStream) as IConfigurationFrame;

return configFrame;
return LegacySoapDeserializer.Deserialize(configStream) as IConfigurationFrame;
}

/// <summary>
Expand Down
4 changes: 0 additions & 4 deletions src/Gemstone.PhasorProtocols/Gemstone.PhasorProtocols.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@
</None>
</ItemGroup>

<ItemGroup>
<PackageReference Include="SoapFormatter" Version="1.1.9" />
</ItemGroup>

<Target Name="ChangeAliasesOfAmbiguousAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'Newtonsoft.Json'">
Expand Down
Loading