diff --git a/AcceptanceTest/TestBase.cs b/AcceptanceTest/TestBase.cs
index 07acedab8..cc9dba3dd 100644
--- a/AcceptanceTest/TestBase.cs
+++ b/AcceptanceTest/TestBase.cs
@@ -2,6 +2,8 @@
using QuickFix;
using System.IO;
using System.Net;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace AcceptanceTest;
diff --git a/Examples/Executor/Program.cs b/Examples/Executor/Program.cs
index 1c38f7caf..a4c74ce31 100644
--- a/Examples/Executor/Program.cs
+++ b/Examples/Executor/Program.cs
@@ -4,6 +4,8 @@
using System.Runtime.ConstrainedExecution;
using System.Text;
using QuickFix;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace Executor
{
diff --git a/Examples/SimpleAcceptor/Program.cs b/Examples/SimpleAcceptor/Program.cs
index 47b29441d..e880f4bfb 100644
--- a/Examples/SimpleAcceptor/Program.cs
+++ b/Examples/SimpleAcceptor/Program.cs
@@ -3,6 +3,8 @@
using System.Linq;
using System.Text;
using QuickFix;
+using QuickFix.Logger;
+using QuickFix.Store;
using QuickFix.Transport;
namespace SimpleAcceptor
diff --git a/Examples/TradeClient/Program.cs b/Examples/TradeClient/Program.cs
index a79dca86c..cbf8cd616 100644
--- a/Examples/TradeClient/Program.cs
+++ b/Examples/TradeClient/Program.cs
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace TradeClient
{
@@ -31,8 +33,8 @@ static void Main(string[] args)
{
QuickFix.SessionSettings settings = new QuickFix.SessionSettings(file);
TradeClientApp application = new TradeClientApp();
- QuickFix.IMessageStoreFactory storeFactory = new QuickFix.FileStoreFactory(settings);
- QuickFix.ILogFactory logFactory = new QuickFix.ScreenLogFactory(settings);
+ IMessageStoreFactory storeFactory = new FileStoreFactory(settings);
+ ILogFactory logFactory = new ScreenLogFactory(settings);
QuickFix.Transport.SocketInitiator initiator = new QuickFix.Transport.SocketInitiator(application, storeFactory, settings, logFactory);
// this is a developer-test kludge. do not emulate.
diff --git a/QuickFIXn/AbstractInitiator.cs b/QuickFIXn/AbstractInitiator.cs
index a02607ca3..915fef9fb 100644
--- a/QuickFIXn/AbstractInitiator.cs
+++ b/QuickFIXn/AbstractInitiator.cs
@@ -2,6 +2,8 @@
using System.Threading;
using System.Collections.Generic;
using System;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace QuickFix
{
diff --git a/QuickFIXn/ClientHandlerThread.cs b/QuickFIXn/ClientHandlerThread.cs
index a5cbb074f..365d0372a 100755
--- a/QuickFIXn/ClientHandlerThread.cs
+++ b/QuickFIXn/ClientHandlerThread.cs
@@ -2,6 +2,7 @@
using System.Net.Sockets;
using System.Threading;
using System;
+using QuickFix.Logger;
namespace QuickFix
{
diff --git a/QuickFIXn/CompositeLog.cs b/QuickFIXn/CompositeLog.cs
deleted file mode 100644
index f09a23a1c..000000000
--- a/QuickFIXn/CompositeLog.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-
-using System;
-
-namespace QuickFix
-{
- ///
- /// File log implementation
- ///
- internal class CompositeLog : ILog
- {
- private ILog[] logs_;
-
- private bool _disposed = false;
-
- public CompositeLog(ILog[] logs)
- {
- logs_ = logs;
- }
-
- public void Clear()
- {
- DisposedCheck();
- foreach (var log in logs_)
- log.Clear();
- }
-
- public void OnIncoming(string msg)
- {
- DisposedCheck();
- foreach (var log in logs_)
- log.OnIncoming(msg);
- }
-
- public void OnOutgoing(string msg)
- {
- DisposedCheck();
- foreach (var log in logs_)
- log.OnOutgoing(msg);
- }
-
- public void OnEvent(string s)
- {
- DisposedCheck();
- foreach (var log in logs_)
- log.OnEvent(s);
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed) return;
- if (disposing)
- {
- foreach (var log in logs_)
- log.Dispose();
- }
- _disposed = true;
- }
-
- private void DisposedCheck()
- {
- if (_disposed)
- throw new System.ObjectDisposedException(this.GetType().Name);
- }
-
- ~CompositeLog() => Dispose(false);
- }
-}
diff --git a/QuickFIXn/CompositeLogFactory.cs b/QuickFIXn/CompositeLogFactory.cs
deleted file mode 100644
index e83a969ae..000000000
--- a/QuickFIXn/CompositeLogFactory.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-
-namespace QuickFix
-{
- ///
- /// Allows multiple log factories to be used with QuickFIX/N. For example, you could log events to the console and also log all events and messages to a file.
- ///
- public class CompositeLogFactory : ILogFactory
- {
- private ILogFactory[] factories_;
-
- public CompositeLogFactory(ILogFactory[] factories)
- {
- factories_ = factories;
- }
-
- ///
- /// Creates a composite log
- ///
- /// session ID for the message store
- ///
- public ILog Create(SessionID sessionID)
- {
- return new CompositeLog(factories_.Select(f => f.Create(sessionID)).ToArray());
- }
- }
-}
diff --git a/QuickFIXn/FileLog.cs b/QuickFIXn/FileLog.cs
deleted file mode 100755
index 43401a07d..000000000
--- a/QuickFIXn/FileLog.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-
-using System;
-
-namespace QuickFix
-{
- ///
- /// File log implementation
- ///
- public class FileLog : ILog, System.IDisposable
- {
- private object sync_ = new object();
-
- private System.IO.StreamWriter messageLog_;
- private System.IO.StreamWriter eventLog_;
-
- private string messageLogFileName_;
- private string eventLogFileName_;
-
-
- public FileLog(string fileLogPath)
- {
- Init(fileLogPath, "GLOBAL");
- }
-
- public FileLog(string fileLogPath, SessionID sessionID)
- {
- Init(fileLogPath, Prefix(sessionID));
- }
-
-
- private void Init(string fileLogPath, string prefix)
- {
- if (!System.IO.Directory.Exists(fileLogPath))
- System.IO.Directory.CreateDirectory(fileLogPath);
-
- messageLogFileName_ = System.IO.Path.Combine(fileLogPath, prefix + ".messages.current.log");
- eventLogFileName_ = System.IO.Path.Combine(fileLogPath, prefix + ".event.current.log");
-
- messageLog_ = new System.IO.StreamWriter(messageLogFileName_,true);
- eventLog_ = new System.IO.StreamWriter(eventLogFileName_,true);
-
- messageLog_.AutoFlush = true;
- eventLog_.AutoFlush = true;
- }
-
- public static string Prefix(SessionID sessionID)
- {
- System.Text.StringBuilder prefix = new System.Text.StringBuilder(sessionID.BeginString)
- .Append('-').Append(sessionID.SenderCompID);
- if (SessionID.IsSet(sessionID.SenderSubID))
- prefix.Append('_').Append(sessionID.SenderSubID);
- if (SessionID.IsSet(sessionID.SenderLocationID))
- prefix.Append('_').Append(sessionID.SenderLocationID);
- prefix.Append('-').Append(sessionID.TargetCompID);
- if (SessionID.IsSet(sessionID.TargetSubID))
- prefix.Append('_').Append(sessionID.TargetSubID);
- if (SessionID.IsSet(sessionID.TargetLocationID))
- prefix.Append('_').Append(sessionID.TargetLocationID);
-
- if (SessionID.IsSet(sessionID.SessionQualifier))
- prefix.Append('-').Append(sessionID.SessionQualifier);
-
- return prefix.ToString();
- }
-
- private void DisposedCheck()
- {
- if (_disposed)
- throw new System.ObjectDisposedException(this.GetType().Name);
- }
-
- #region Log Members
-
- public void Clear()
- {
- DisposedCheck();
-
- lock (sync_)
- {
- messageLog_.Close();
- eventLog_.Close();
-
- messageLog_ = new System.IO.StreamWriter(messageLogFileName_, false);
- eventLog_ = new System.IO.StreamWriter(eventLogFileName_, false);
-
- messageLog_.AutoFlush = true;
- eventLog_.AutoFlush = true;
- }
- }
-
- public void OnIncoming(string msg)
- {
- DisposedCheck();
-
- lock (sync_)
- {
- messageLog_.WriteLine(Fields.Converters.DateTimeConverter.Convert(System.DateTime.UtcNow) + " : " + msg);
- }
- }
-
- public void OnOutgoing(string msg)
- {
- DisposedCheck();
-
- lock (sync_)
- {
- messageLog_.WriteLine(Fields.Converters.DateTimeConverter.Convert(System.DateTime.UtcNow) + " : " + msg);
- }
- }
-
- public void OnEvent(string s)
- {
- DisposedCheck();
-
- lock (sync_)
- {
- eventLog_.WriteLine(Fields.Converters.DateTimeConverter.Convert(System.DateTime.UtcNow) + " : "+ s);
- }
- }
-
- #endregion
-
- #region IDisposable Members
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed) return;
- if (disposing)
- {
- if (messageLog_ != null) { messageLog_.Dispose(); }
- if (eventLog_ != null) { eventLog_.Dispose(); }
-
- messageLog_ = null;
- eventLog_ = null;
- }
- _disposed = true;
- }
- ~FileLog() => Dispose(false);
- #endregion
- }
-}
diff --git a/QuickFIXn/FileLogFactory.cs b/QuickFIXn/FileLogFactory.cs
deleted file mode 100755
index 9bdc0371d..000000000
--- a/QuickFIXn/FileLogFactory.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-
-namespace QuickFix
-{
- ///
- /// Creates a message store that stores messages in a file
- ///
- public class FileLogFactory : ILogFactory
- {
- SessionSettings settings_;
-
- #region LogFactory Members
-
- public FileLogFactory(SessionSettings settings)
- {
- settings_ = settings;
- }
-
- ///
- /// Creates a file-based message store
- ///
- /// session ID for the message store
- ///
- public ILog Create(SessionID sessionID)
- {
- return new FileLog(settings_.Get(sessionID).GetString(SessionSettings.FILE_LOG_PATH), sessionID);
- }
-
- #endregion
- }
-}
diff --git a/QuickFIXn/FileStore.cs b/QuickFIXn/FileStore.cs
deleted file mode 100755
index afb221af7..000000000
--- a/QuickFIXn/FileStore.cs
+++ /dev/null
@@ -1,310 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using QuickFix.Util;
-
-namespace QuickFix
-{
- ///
- /// File store implementation
- ///
- public class FileStore : IMessageStore
- {
- private class MsgDef
- {
- public long index { get; private set; }
- public int size { get; private set; }
-
- public MsgDef(long index, int size)
- {
- this.index = index;
- this.size = size;
- }
- }
-
- private string seqNumsFileName_;
- private string msgFileName_;
- private string headerFileName_;
- private string sessionFileName_;
-
- private System.IO.FileStream seqNumsFile_;
- private System.IO.FileStream msgFile_;
- private System.IO.StreamWriter headerFile_;
-
- private MemoryStore cache_ = new MemoryStore();
-
- System.Collections.Generic.Dictionary offsets_ = new Dictionary();
-
- public static string Prefix(SessionID sessionID)
- {
- System.Text.StringBuilder prefix = new System.Text.StringBuilder(sessionID.BeginString)
- .Append('-').Append(sessionID.SenderCompID);
- if (SessionID.IsSet(sessionID.SenderSubID))
- prefix.Append('_').Append(sessionID.SenderSubID);
- if (SessionID.IsSet(sessionID.SenderLocationID))
- prefix.Append('_').Append(sessionID.SenderLocationID);
- prefix.Append('-').Append(sessionID.TargetCompID);
- if (SessionID.IsSet(sessionID.TargetSubID))
- prefix.Append('_').Append(sessionID.TargetSubID);
- if (SessionID.IsSet(sessionID.TargetLocationID))
- prefix.Append('_').Append(sessionID.TargetLocationID);
-
- if (SessionID.IsSet(sessionID.SessionQualifier))
- prefix.Append('-').Append(sessionID.SessionQualifier);
-
- return prefix.ToString();
- }
-
- public FileStore(string path, SessionID sessionID)
- {
- if (!System.IO.Directory.Exists(path))
- System.IO.Directory.CreateDirectory(path);
-
- string prefix = Prefix(sessionID);
-
- seqNumsFileName_ = System.IO.Path.Combine(path, prefix + ".seqnums");
- msgFileName_ = System.IO.Path.Combine(path, prefix + ".body");
- headerFileName_ = System.IO.Path.Combine(path, prefix + ".header");
- sessionFileName_ = System.IO.Path.Combine(path, prefix + ".session");
- open();
- }
-
- private void open()
- {
- close();
-
- ConstructFromFileCache();
- InitializeSessionCreateTime();
-
- seqNumsFile_ = new System.IO.FileStream(seqNumsFileName_, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
- msgFile_ = new System.IO.FileStream(msgFileName_, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
- headerFile_ = new System.IO.StreamWriter(headerFileName_, true);
- }
-
- private void close()
- {
- seqNumsFile_?.Dispose();
- msgFile_?.Dispose();
- headerFile_?.Dispose();
- }
-
- private void PurgeSingleFile(System.IO.Stream stream, string filename)
- {
- if (stream != null)
- stream.Close();
- if (System.IO.File.Exists(filename))
- System.IO.File.Delete(filename);
- }
-
- private void PurgeSingleFile(System.IO.StreamWriter stream, string filename)
- {
- if (stream != null)
- stream.Close();
- if (System.IO.File.Exists(filename))
- System.IO.File.Delete(filename);
- }
-
- private void PurgeSingleFile(string filename)
- {
- if (System.IO.File.Exists(filename))
- System.IO.File.Delete(filename);
- }
-
- private void PurgeFileCache()
- {
- PurgeSingleFile(seqNumsFile_, seqNumsFileName_);
- PurgeSingleFile(msgFile_, msgFileName_);
- PurgeSingleFile(headerFile_, headerFileName_);
- PurgeSingleFile(sessionFileName_);
- }
-
-
- private void ConstructFromFileCache()
- {
- offsets_.Clear();
- if (System.IO.File.Exists(headerFileName_))
- {
- using (System.IO.StreamReader reader = new System.IO.StreamReader(headerFileName_))
- {
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- string[] headerParts = line.Split(',');
- if (headerParts.Length == 3)
- {
- offsets_[Convert.ToUInt64(headerParts[0])] = new MsgDef(
- Convert.ToInt64(headerParts[1]), Convert.ToInt32(headerParts[2]));
- }
- }
- }
- }
-
- if (System.IO.File.Exists(seqNumsFileName_))
- {
- using (System.IO.StreamReader seqNumReader = new System.IO.StreamReader(seqNumsFileName_))
- {
- string[] parts = seqNumReader.ReadToEnd().Split(':');
- if (parts.Length == 2)
- {
- cache_.NextSenderMsgSeqNum = Convert.ToUInt64(parts[0]);
- cache_.NextTargetMsgSeqNum = Convert.ToUInt64(parts[1]);
- }
- }
- }
- }
-
- private void InitializeSessionCreateTime()
- {
- if (System.IO.File.Exists(sessionFileName_) && new System.IO.FileInfo(sessionFileName_).Length > 0)
- {
- using (System.IO.StreamReader reader = new System.IO.StreamReader(sessionFileName_))
- {
- string s = reader.ReadToEnd();
- cache_.CreationTime = UtcDateTimeSerializer.FromString(s);
- }
- }
- else
- {
- using (System.IO.StreamWriter writer = new System.IO.StreamWriter(sessionFileName_, false))
- {
- writer.Write(UtcDateTimeSerializer.ToString(cache_.CreationTime.Value));
- }
- }
- }
-
-
- #region MessageStore Members
-
- ///
- /// Get messages within the range of sequence numbers
- ///
- ///
- ///
- ///
- public void Get(SeqNumType startSeqNum, SeqNumType endSeqNum, List messages)
- {
- for (SeqNumType i = startSeqNum; i <= endSeqNum; i++)
- {
- if (offsets_.ContainsKey(i))
- {
- msgFile_.Seek(offsets_[i].index, System.IO.SeekOrigin.Begin);
- byte[] msgBytes = new byte[offsets_[i].size];
- msgFile_.Read(msgBytes, 0, msgBytes.Length);
-
- messages.Add(CharEncoding.DefaultEncoding.GetString(msgBytes));
- }
- }
-
- }
-
- ///
- /// Store a message
- ///
- ///
- ///
- ///
- public bool Set(SeqNumType msgSeqNum, string msg)
- {
- msgFile_.Seek(0, System.IO.SeekOrigin.End);
-
- long offset = msgFile_.Position;
- byte[] msgBytes = CharEncoding.DefaultEncoding.GetBytes(msg);
- int size = msgBytes.Length;
-
- StringBuilder b = new StringBuilder();
- b.Append(msgSeqNum).Append(",").Append(offset).Append(",").Append(size);
- headerFile_.WriteLine(b.ToString());
- headerFile_.Flush();
-
- offsets_[msgSeqNum] = new MsgDef(offset, size);
-
- msgFile_.Write(msgBytes, 0, size);
- msgFile_.Flush();
-
-
- return true;
- }
-
- public SeqNumType NextSenderMsgSeqNum {
- get { return cache_.NextSenderMsgSeqNum; }
- set {
- cache_.NextSenderMsgSeqNum = value;
- setSeqNum();
- }
- }
-
- public SeqNumType NextTargetMsgSeqNum {
- get { return cache_.NextTargetMsgSeqNum; }
- set {
- cache_.NextTargetMsgSeqNum = value;
- setSeqNum();
- }
- }
-
- public void IncrNextSenderMsgSeqNum()
- {
- cache_.IncrNextSenderMsgSeqNum();
- setSeqNum();
- }
-
- public void IncrNextTargetMsgSeqNum()
- {
- cache_.IncrNextTargetMsgSeqNum();
- setSeqNum();
- }
-
- private void setSeqNum()
- {
- seqNumsFile_.Seek(0, System.IO.SeekOrigin.Begin);
- System.IO.StreamWriter writer = new System.IO.StreamWriter(seqNumsFile_);
-
- writer.Write(NextSenderMsgSeqNum.ToString("D20") + " : " + NextTargetMsgSeqNum.ToString("D20") + " ");
- writer.Flush();
- }
-
- public DateTime? CreationTime
- {
- get
- {
- return cache_.CreationTime;
- }
- }
-
- public void Reset()
- {
- cache_.Reset();
- PurgeFileCache();
- open();
- }
-
- public void Refresh()
- {
- cache_.Reset();
- open();
- }
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
-
- }
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed) return;
- if (disposing)
- {
- close();
- }
- _disposed = true;
- }
-
- ~FileStore() => Dispose(false);
- #endregion
- }
-}
diff --git a/QuickFIXn/FileStoreFactory.cs b/QuickFIXn/FileStoreFactory.cs
deleted file mode 100755
index b20f3c0eb..000000000
--- a/QuickFIXn/FileStoreFactory.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace QuickFix
-{
- ///
- /// Creates a message store that stores messages in a file
- ///
- public class FileStoreFactory : IMessageStoreFactory
- {
- private SessionSettings settings_;
-
- ///
- /// Create the factory with configuration in session settings
- ///
- ///
- public FileStoreFactory(SessionSettings settings)
- {
- settings_ = settings;
- }
-
- ///
- /// Creates a file-based message store
- ///
- /// session ID for the message store
- ///
- public IMessageStore Create(SessionID sessionID)
- {
- return new FileStore(settings_.Get(sessionID).GetString(SessionSettings.FILE_STORE_PATH), sessionID);
- }
- }
-}
diff --git a/QuickFIXn/ILog.cs b/QuickFIXn/ILog.cs
deleted file mode 100755
index 5e2ca6956..000000000
--- a/QuickFIXn/ILog.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-
-namespace QuickFix
-{
- ///
- /// Session log for messages and events
- ///
- public interface ILog : IDisposable
- {
- ///
- /// Clears the log and removes any persistent log data
- ///
- void Clear();
-
- ///
- /// Logs an incoming message
- ///
- /// a raw FIX message
- void OnIncoming(string msg);
-
- ///
- /// Logs an outgoing message
- ///
- /// a raw FIX message
- void OnOutgoing(string msg);
-
- ///
- /// Logs a session event
- ///
- /// event description
- void OnEvent(string s);
- }
-}
diff --git a/QuickFIXn/ILogFactory.cs b/QuickFIXn/ILogFactory.cs
deleted file mode 100755
index 581dd6671..000000000
--- a/QuickFIXn/ILogFactory.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-
-namespace QuickFix
-{
- ///
- /// Used by a session to create a log implementation
- ///
- public interface ILogFactory
- {
- ///
- /// Create a log implementation
- ///
- /// session ID usually used for configuration access
- ///
- ILog Create(SessionID sessionID);
- }
-}
diff --git a/QuickFIXn/IMessageStore.cs b/QuickFIXn/IMessageStore.cs
deleted file mode 100755
index 8ea8e7b84..000000000
--- a/QuickFIXn/IMessageStore.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System.Collections.Generic;
-using System;
-
-namespace QuickFix
-{
-
- ///
- /// Used by a Session to store and retrieve messages for resend purposes
- ///
- public interface IMessageStore : IDisposable
- {
- ///
- /// Get messages within sequence number range (inclusive). Used for
- /// message resend requests
- ///
- /// the starting message sequence number
- /// the ending message sequence number
- /// the retrieved messages (out parameter)
- void Get(SeqNumType startSeqNum, SeqNumType endSeqNum, List messages);
-
- ///
- /// Adds a raw fix message to the store with the give sequence number
- ///
- /// the sequence number
- /// the raw FIX message string
- /// true if successful, false otherwise
- bool Set(SeqNumType msgSeqNum, string msg);
-
- SeqNumType NextSenderMsgSeqNum { get; set; }
- SeqNumType NextTargetMsgSeqNum { get; set; }
-
- void IncrNextSenderMsgSeqNum();
- void IncrNextTargetMsgSeqNum();
-
-
- DateTime? CreationTime { get; }
-
- ///
- /// Reset the message store. Sequence numbers are set back to 1 and stored
- /// messages are erased. The session creation time is also set to the time of
- /// the reset
- ///
- void Reset();
-
- ///
- /// Refreshes session state from a shared state storage (e.g. database,
- /// file, ...). Refresh will not work for message stores without shared state
- /// (e.g. MemoryStore). These stores should log a session error, at a minimum,
- /// or throw an exception.
- ///
- void Refresh();
- }
-}
diff --git a/QuickFIXn/IMessageStoreFactory.cs b/QuickFIXn/IMessageStoreFactory.cs
deleted file mode 100755
index b9c5600eb..000000000
--- a/QuickFIXn/IMessageStoreFactory.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace QuickFix
-{
- ///
- /// Used by a Session to create a message store implementation
- ///
- public interface IMessageStoreFactory
- {
- ///
- /// Creates a message store implementation
- ///
- /// the session ID, often used to access session configurations
- /// the message store implementation
- IMessageStore Create(SessionID sessionID);
- }
-}
diff --git a/QuickFIXn/Logger/CompositeLog.cs b/QuickFIXn/Logger/CompositeLog.cs
new file mode 100644
index 000000000..61722c144
--- /dev/null
+++ b/QuickFIXn/Logger/CompositeLog.cs
@@ -0,0 +1,72 @@
+#nullable enable
+using System;
+
+namespace QuickFix.Logger;
+
+///
+/// File log implementation
+///
+internal class CompositeLog : ILog
+{
+ private readonly ILog[] _logs;
+
+ private bool _disposed = false;
+
+ public CompositeLog(ILog[] logs)
+ {
+ _logs = logs;
+ }
+
+ public void Clear()
+ {
+ DisposedCheck();
+ foreach (var log in _logs)
+ log.Clear();
+ }
+
+ public void OnIncoming(string msg)
+ {
+ DisposedCheck();
+ foreach (var log in _logs)
+ log.OnIncoming(msg);
+ }
+
+ public void OnOutgoing(string msg)
+ {
+ DisposedCheck();
+ foreach (var log in _logs)
+ log.OnOutgoing(msg);
+ }
+
+ public void OnEvent(string s)
+ {
+ DisposedCheck();
+ foreach (var log in _logs)
+ log.OnEvent(s);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing)
+ {
+ foreach (var log in _logs)
+ log.Dispose();
+ }
+ _disposed = true;
+ }
+
+ private void DisposedCheck()
+ {
+ if (_disposed)
+ throw new ObjectDisposedException(GetType().Name);
+ }
+
+ ~CompositeLog() => Dispose(false);
+}
diff --git a/QuickFIXn/Logger/CompositeLogFactory.cs b/QuickFIXn/Logger/CompositeLogFactory.cs
new file mode 100644
index 000000000..f63c1d6fa
--- /dev/null
+++ b/QuickFIXn/Logger/CompositeLogFactory.cs
@@ -0,0 +1,27 @@
+#nullable enable
+using System.Linq;
+
+namespace QuickFix.Logger;
+
+///
+/// Allows multiple log factories to be used with QuickFIX/N. For example, you could log events to the console and also log all events and messages to a file.
+///
+public class CompositeLogFactory : ILogFactory
+{
+ private readonly ILogFactory[] _factories;
+
+ public CompositeLogFactory(ILogFactory[] factories)
+ {
+ _factories = factories;
+ }
+
+ ///
+ /// Creates a composite log
+ ///
+ /// session ID for the message store
+ ///
+ public ILog Create(SessionID sessionID)
+ {
+ return new CompositeLog(_factories.Select(f => f.Create(sessionID)).ToArray());
+ }
+}
diff --git a/QuickFIXn/Logger/FileLog.cs b/QuickFIXn/Logger/FileLog.cs
new file mode 100755
index 000000000..d7addf67a
--- /dev/null
+++ b/QuickFIXn/Logger/FileLog.cs
@@ -0,0 +1,144 @@
+#nullable enable
+using System;
+using QuickFix.Util;
+
+namespace QuickFix.Logger;
+
+///
+/// File log implementation
+///
+public class FileLog : ILog
+{
+ private readonly object _sync = new();
+
+ private System.IO.StreamWriter _messageLog;
+ private System.IO.StreamWriter _eventLog;
+
+ private readonly string _messageLogFileName;
+ private readonly string _eventLogFileName;
+
+ ///
+ ///
+ ///
+ ///
+ /// All back or forward slashes in this path will be converted as needed to the running platform's preferred
+ /// path separator (i.e. "/" will become "\" on windows, else "\" will become "/" on all other platforms)
+ ///
+ ///
+ public FileLog(string fileLogPath, SessionID sessionId)
+ {
+ string prefix = Prefix(sessionId);
+
+ string normalizedPath = StringUtil.FixSlashes(fileLogPath);
+
+ if (!System.IO.Directory.Exists(normalizedPath))
+ System.IO.Directory.CreateDirectory(normalizedPath);
+
+ _messageLogFileName = System.IO.Path.Combine(normalizedPath, prefix + ".messages.current.log");
+ _eventLogFileName = System.IO.Path.Combine(normalizedPath, prefix + ".event.current.log");
+
+ _messageLog = new System.IO.StreamWriter(_messageLogFileName, true);
+ _eventLog = new System.IO.StreamWriter(_eventLogFileName, true);
+
+ _messageLog.AutoFlush = true;
+ _eventLog.AutoFlush = true;
+ }
+
+ public static string Prefix(SessionID sessionId)
+ {
+ System.Text.StringBuilder prefix = new System.Text.StringBuilder(sessionId.BeginString)
+ .Append('-').Append(sessionId.SenderCompID);
+ if (SessionID.IsSet(sessionId.SenderSubID))
+ prefix.Append('_').Append(sessionId.SenderSubID);
+ if (SessionID.IsSet(sessionId.SenderLocationID))
+ prefix.Append('_').Append(sessionId.SenderLocationID);
+ prefix.Append('-').Append(sessionId.TargetCompID);
+ if (SessionID.IsSet(sessionId.TargetSubID))
+ prefix.Append('_').Append(sessionId.TargetSubID);
+ if (SessionID.IsSet(sessionId.TargetLocationID))
+ prefix.Append('_').Append(sessionId.TargetLocationID);
+
+ if (SessionID.IsSet(sessionId.SessionQualifier))
+ prefix.Append('-').Append(sessionId.SessionQualifier);
+
+ return prefix.ToString();
+ }
+
+ private void DisposedCheck()
+ {
+ if (_disposed)
+ throw new ObjectDisposedException(GetType().Name);
+ }
+
+ #region Log Members
+
+ public void Clear()
+ {
+ DisposedCheck();
+
+ lock (_sync)
+ {
+ _messageLog.Close();
+ _eventLog.Close();
+
+ _messageLog = new System.IO.StreamWriter(_messageLogFileName, false);
+ _eventLog = new System.IO.StreamWriter(_eventLogFileName, false);
+
+ _messageLog.AutoFlush = true;
+ _eventLog.AutoFlush = true;
+ }
+ }
+
+ public void OnIncoming(string msg)
+ {
+ DisposedCheck();
+
+ lock (_sync)
+ {
+ _messageLog.WriteLine(Fields.Converters.DateTimeConverter.Convert(DateTime.UtcNow) + " : " + msg);
+ }
+ }
+
+ public void OnOutgoing(string msg)
+ {
+ DisposedCheck();
+
+ lock (_sync)
+ {
+ _messageLog.WriteLine(Fields.Converters.DateTimeConverter.Convert(DateTime.UtcNow) + " : " + msg);
+ }
+ }
+
+ public void OnEvent(string s)
+ {
+ DisposedCheck();
+
+ lock (_sync)
+ {
+ _eventLog.WriteLine(Fields.Converters.DateTimeConverter.Convert(DateTime.UtcNow) + " : "+ s);
+ }
+ }
+
+ #endregion
+
+ #region IDisposable Members
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private bool _disposed = false;
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing)
+ {
+ _messageLog.Dispose();
+ _eventLog.Dispose();
+ }
+ _disposed = true;
+ }
+ ~FileLog() => Dispose(false);
+ #endregion
+}
diff --git a/QuickFIXn/Logger/FileLogFactory.cs b/QuickFIXn/Logger/FileLogFactory.cs
new file mode 100755
index 000000000..9b71e7ead
--- /dev/null
+++ b/QuickFIXn/Logger/FileLogFactory.cs
@@ -0,0 +1,30 @@
+#nullable enable
+
+namespace QuickFix.Logger;
+
+///
+/// Creates a message store that stores messages in a file
+///
+public class FileLogFactory : ILogFactory
+{
+ private readonly SessionSettings _settings;
+
+ #region LogFactory Members
+
+ public FileLogFactory(SessionSettings settings)
+ {
+ _settings = settings;
+ }
+
+ ///
+ /// Creates a file-based message store
+ ///
+ /// session ID for the message store
+ ///
+ public ILog Create(SessionID sessionId)
+ {
+ return new FileLog(_settings.Get(sessionId).GetString(SessionSettings.FILE_LOG_PATH), sessionId);
+ }
+
+ #endregion
+}
diff --git a/QuickFIXn/Logger/ILog.cs b/QuickFIXn/Logger/ILog.cs
new file mode 100755
index 000000000..c77166dbc
--- /dev/null
+++ b/QuickFIXn/Logger/ILog.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace QuickFix.Logger;
+
+///
+/// Session log for messages and events
+///
+public interface ILog : IDisposable
+{
+ ///
+ /// Clears the log and removes any persistent log data
+ ///
+ void Clear();
+
+ ///
+ /// Logs an incoming message
+ ///
+ /// a raw FIX message
+ void OnIncoming(string msg);
+
+ ///
+ /// Logs an outgoing message
+ ///
+ /// a raw FIX message
+ void OnOutgoing(string msg);
+
+ ///
+ /// Logs a session event
+ ///
+ /// event description
+ void OnEvent(string s);
+}
diff --git a/QuickFIXn/Logger/ILogFactory.cs b/QuickFIXn/Logger/ILogFactory.cs
new file mode 100755
index 000000000..c2ddb4376
--- /dev/null
+++ b/QuickFIXn/Logger/ILogFactory.cs
@@ -0,0 +1,16 @@
+#nullable enable
+
+namespace QuickFix.Logger;
+
+///
+/// Used by a session to create a log implementation
+///
+public interface ILogFactory
+{
+ ///
+ /// Create a log implementation
+ ///
+ /// session ID usually used for configuration access
+ ///
+ ILog Create(SessionID sessionId);
+}
diff --git a/QuickFIXn/Logger/NullLog.cs b/QuickFIXn/Logger/NullLog.cs
new file mode 100755
index 000000000..cccf6cdac
--- /dev/null
+++ b/QuickFIXn/Logger/NullLog.cs
@@ -0,0 +1,27 @@
+
+namespace QuickFix.Logger;
+
+///
+/// Log implementation that does not do anything
+///
+public sealed class NullLog : ILog
+{
+ #region ILog Members
+
+ public void Clear()
+ { }
+
+ public void OnIncoming(string msg)
+ { }
+
+ public void OnOutgoing(string msg)
+ { }
+
+ public void OnEvent(string s)
+ { }
+
+ public void Dispose()
+ { }
+
+ #endregion
+}
diff --git a/QuickFIXn/Logger/NullLogFactory.cs b/QuickFIXn/Logger/NullLogFactory.cs
new file mode 100644
index 000000000..90b65025e
--- /dev/null
+++ b/QuickFIXn/Logger/NullLogFactory.cs
@@ -0,0 +1,13 @@
+#nullable enable
+
+namespace QuickFix.Logger;
+
+public class NullLogFactory : ILogFactory
+{
+ public NullLogFactory() { }
+
+ public ILog Create(SessionID _x)
+ {
+ return new NullLog();
+ }
+}
diff --git a/QuickFIXn/Logger/ScreenLog.cs b/QuickFIXn/Logger/ScreenLog.cs
new file mode 100755
index 000000000..1dc8bd6f2
--- /dev/null
+++ b/QuickFIXn/Logger/ScreenLog.cs
@@ -0,0 +1,73 @@
+#nullable enable
+
+namespace QuickFix.Logger;
+
+///
+/// FIXME - needs to log sessionIDs, timestamps, etc.
+///
+public class ScreenLog : ILog
+{
+ private readonly object _sync = new ();
+ private readonly bool _logIncoming;
+ private readonly bool _logOutgoing;
+ private readonly bool _logEvent;
+
+ public ScreenLog(bool logIncoming, bool logOutgoing, bool logEvent)
+ {
+ _logIncoming = logIncoming;
+ _logOutgoing = logOutgoing;
+ _logEvent = logEvent;
+ }
+
+ #region ILog Members
+
+ public void Clear()
+ { }
+
+ public void OnIncoming(string msg)
+ {
+ if (!_logIncoming)
+ return;
+
+ lock (_sync)
+ {
+ System.Console.WriteLine(" " + msg);
+ }
+ }
+
+ public void OnOutgoing(string msg)
+ {
+ if (!_logOutgoing)
+ return;
+
+ lock (_sync)
+ {
+ System.Console.WriteLine(" " + msg);
+ }
+ }
+
+ public void OnEvent(string s)
+ {
+ if (!_logEvent)
+ return;
+
+ lock (_sync)
+ {
+ System.Console.WriteLine(" " + s);
+ }
+ }
+ #endregion
+
+ #region IDisposable implementation
+ public void Dispose()
+ {
+ Dispose(true);
+ System.GC.SuppressFinalize(this);
+ }
+ protected virtual void Dispose(bool disposing)
+ {
+ // Nothing to dispose of...
+ }
+ ~ScreenLog() => Dispose(false);
+ #endregion
+}
diff --git a/QuickFIXn/Logger/ScreenLogFactory.cs b/QuickFIXn/Logger/ScreenLogFactory.cs
new file mode 100755
index 000000000..15d13ca03
--- /dev/null
+++ b/QuickFIXn/Logger/ScreenLogFactory.cs
@@ -0,0 +1,40 @@
+#nullable enable
+
+namespace QuickFix.Logger;
+
+public class ScreenLogFactory : ILogFactory
+{
+ private const string SCREEN_LOG_SHOW_INCOMING = "ScreenLogShowIncoming";
+ private const string SCREEN_LOG_SHOW_OUTGOING = "ScreenLogShowOutgoing";
+ private const string SCREEN_LOG_SHOW_EVENTS = "ScreenLogShowEvents";
+
+ private readonly SessionSettings _settings;
+
+ public ScreenLogFactory(SessionSettings settings)
+ {
+ _settings = settings;
+ }
+
+ #region LogFactory Members
+
+ public ILog Create(SessionID sessionId) {
+ bool logIncoming = false;
+ bool logOutgoing = false;
+ bool logEvent = false;
+
+ if(_settings.Has(sessionId))
+ {
+ Dictionary dict = _settings.Get(sessionId);
+ if (dict.Has(SCREEN_LOG_SHOW_INCOMING))
+ logIncoming = dict.GetBool(SCREEN_LOG_SHOW_INCOMING);
+ if (dict.Has(SCREEN_LOG_SHOW_OUTGOING))
+ logOutgoing = dict.GetBool(SCREEN_LOG_SHOW_OUTGOING);
+ if (dict.Has(SCREEN_LOG_SHOW_EVENTS))
+ logEvent = dict.GetBool(SCREEN_LOG_SHOW_EVENTS);
+ }
+
+ return new ScreenLog(logIncoming, logOutgoing, logEvent);
+ }
+
+ #endregion
+}
diff --git a/QuickFIXn/MemoryStore.cs b/QuickFIXn/MemoryStore.cs
deleted file mode 100755
index a32a25af3..000000000
--- a/QuickFIXn/MemoryStore.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace QuickFix
-{
- ///
- /// In-memory message store implementation
- ///
- public class MemoryStore : IMessageStore
- {
- #region Private Members
-
- System.Collections.Generic.Dictionary messages_;
- DateTime? creationTime;
-
- #endregion
-
- public MemoryStore()
- {
- messages_ = new System.Collections.Generic.Dictionary();
- Reset();
- }
-
- public void Get(SeqNumType begSeqNo, SeqNumType endSeqNo, List messages)
- {
- for (SeqNumType current = begSeqNo; current <= endSeqNo; current++)
- {
- if (messages_.ContainsKey(current))
- messages.Add(messages_[current]);
- }
- }
-
- #region MessageStore Members
-
- public bool Set(SeqNumType msgSeqNum, string msg)
- {
- messages_[msgSeqNum] = msg;
- return true;
- }
-
- public SeqNumType NextSenderMsgSeqNum { get; set; }
- public SeqNumType NextTargetMsgSeqNum { get; set; }
-
- public void IncrNextSenderMsgSeqNum()
- { ++NextSenderMsgSeqNum; }
-
- public void IncrNextTargetMsgSeqNum()
- { ++NextTargetMsgSeqNum; }
-
- public System.DateTime? CreationTime
- {
- get { return creationTime; }
- internal set { creationTime = value; }
- }
-
- public void Reset()
- {
- NextSenderMsgSeqNum = 1;
- NextTargetMsgSeqNum = 1;
- messages_.Clear();
- creationTime = DateTime.UtcNow;
- }
-
- public void Refresh()
- { }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed) return;
- if (disposing)
- {
- messages_ = null;
- }
- _disposed = true;
- }
-
- ~MemoryStore() => Dispose(false);
- #endregion
- }
-}
diff --git a/QuickFIXn/MemoryStoreFactory.cs b/QuickFIXn/MemoryStoreFactory.cs
deleted file mode 100755
index f6c5ac129..000000000
--- a/QuickFIXn/MemoryStoreFactory.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-
-namespace QuickFix
-{
- ///
- /// Creates a message store that stores all data in memory
- ///
- public class MemoryStoreFactory : IMessageStoreFactory
- {
- #region MessageStoreFactory Members
-
- public IMessageStore Create(SessionID sessionID)
- {
- return new MemoryStore();
- }
-
- #endregion
- }
-}
diff --git a/QuickFIXn/NullLog.cs b/QuickFIXn/NullLog.cs
deleted file mode 100755
index ab5ef47e6..000000000
--- a/QuickFIXn/NullLog.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-
-namespace QuickFix
-{
- ///
- /// Log implementation that does not do anything
- ///
- public sealed class NullLog : ILog
- {
- #region ILog Members
-
- public void Clear()
- { }
-
- public void OnIncoming(string msg)
- { }
-
- public void OnOutgoing(string msg)
- { }
-
- public void OnEvent(string s)
- { }
-
- public void Dispose()
- { }
-
- #endregion
- }
-}
diff --git a/QuickFIXn/NullLogFactory.cs b/QuickFIXn/NullLogFactory.cs
deleted file mode 100644
index 17700fe11..000000000
--- a/QuickFIXn/NullLogFactory.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace QuickFix
-{
- public class NullLogFactory : ILogFactory
- {
- public NullLogFactory() { }
-
- public ILog Create(SessionID _x)
- {
- return new NullLog();
- }
- }
-}
diff --git a/QuickFIXn/ScreenLog.cs b/QuickFIXn/ScreenLog.cs
deleted file mode 100755
index c6b6ed8c4..000000000
--- a/QuickFIXn/ScreenLog.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-
-namespace QuickFix
-{
- ///
- /// FIXME - needs to log sessionIDs, timestamps, etc.
- ///
- public class ScreenLog : ILog
- {
- private object sync_ = new object();
- private bool logIncoming_;
- private bool logOutgoing_;
- private bool logEvent_;
-
- public ScreenLog(SessionID sessionID, bool logIncoming, bool logOutgoing, bool logEvent)
- {
- logIncoming_ = logIncoming;
- logOutgoing_ = logOutgoing;
- logEvent_ = logEvent;
- }
-
- #region ILog Members
-
- public void Clear()
- { }
-
- public void OnIncoming(string msg)
- {
- if (!logIncoming_)
- return;
-
- lock (sync_)
- {
- System.Console.WriteLine(" " + msg);
- }
- }
-
- public void OnOutgoing(string msg)
- {
- if (!logOutgoing_)
- return;
-
- lock (sync_)
- {
- System.Console.WriteLine(" " + msg);
- }
- }
-
- public void OnEvent(string s)
- {
- if (!logEvent_)
- return;
-
- lock (sync_)
- {
- System.Console.WriteLine(" " + s);
- }
- }
- #endregion
-
- #region IDisposable implementation
- public void Dispose()
- {
- Dispose(true);
- System.GC.SuppressFinalize(this);
- }
- protected virtual void Dispose(bool disposing)
- {
- // Nothing to dispose of...
- }
- ~ScreenLog() => Dispose(false);
- #endregion
- }
-}
diff --git a/QuickFIXn/ScreenLogFactory.cs b/QuickFIXn/ScreenLogFactory.cs
deleted file mode 100755
index 36501ab60..000000000
--- a/QuickFIXn/ScreenLogFactory.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-
-namespace QuickFix
-{
- public class ScreenLogFactory : ILogFactory
- {
- public const string SCREEN_LOG_SHOW_INCOMING = "ScreenLogShowIncoming";
- public const string SCREEN_LOG_SHOW_OUTGOING = "ScreenLogShowOutgoing";
- public const string SCREEN_LOG_SHOW_EVENTS = "ScreenLogShowEvents";
-
- private SessionSettings settings_ = null;
- private bool logIncoming_ = true;
- private bool logOutgoing_ = true;
- private bool logEvent_ = true;
-
- public ScreenLogFactory(SessionSettings settings)
- {
- settings_ = settings;
- }
-
- public ScreenLogFactory(bool logIncoming, bool logOutgoing, bool logEvent)
- {
- logIncoming_ = logIncoming;
- logOutgoing_ = logOutgoing;
- logEvent_ = logEvent;
- }
-
- #region LogFactory Members
-
- public ILog Create(SessionID sessionID)
- {
- bool logIncoming = logIncoming_;
- bool logOutgoing = logOutgoing_;
- bool logEvent = logEvent_;
-
- if(settings_ != null && settings_.Has(sessionID))
- {
- Dictionary dict = settings_.Get(sessionID);
- if (dict.Has(SCREEN_LOG_SHOW_INCOMING))
- logIncoming = dict.GetBool(SCREEN_LOG_SHOW_INCOMING);
- if (dict.Has(SCREEN_LOG_SHOW_OUTGOING))
- logOutgoing = dict.GetBool(SCREEN_LOG_SHOW_OUTGOING);
- if (dict.Has(SCREEN_LOG_SHOW_EVENTS))
- logEvent = dict.GetBool(SCREEN_LOG_SHOW_EVENTS);
- }
-
- return new ScreenLog(sessionID, logIncoming, logOutgoing, logEvent);
- }
-
- #endregion
- }
-}
diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs
index a4251cf85..8b3beb119 100755
--- a/QuickFIXn/Session.cs
+++ b/QuickFIXn/Session.cs
@@ -4,6 +4,8 @@
using System.Threading;
using QuickFix.Fields;
using QuickFix.Fields.Converters;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace QuickFix
{
diff --git a/QuickFIXn/SessionFactory.cs b/QuickFIXn/SessionFactory.cs
index 7ceca116d..bd7055e8b 100755
--- a/QuickFIXn/SessionFactory.cs
+++ b/QuickFIXn/SessionFactory.cs
@@ -1,6 +1,8 @@
#nullable enable
using System;
using System.Collections.Generic;
+using QuickFix.Logger;
+using QuickFix.Store;
using QuickFix.Util;
namespace QuickFix
diff --git a/QuickFIXn/SessionState.cs b/QuickFIXn/SessionState.cs
index e6524410f..7742a41ff 100755
--- a/QuickFIXn/SessionState.cs
+++ b/QuickFIXn/SessionState.cs
@@ -1,6 +1,8 @@
#nullable enable
using System;
using System.Collections.Generic;
+using QuickFix.Logger;
+using QuickFix.Store;
using MessagesBySeqNum = System.Collections.Generic.Dictionary;
namespace QuickFix
diff --git a/QuickFIXn/Store/FileStore.cs b/QuickFIXn/Store/FileStore.cs
new file mode 100755
index 000000000..4a9651dc6
--- /dev/null
+++ b/QuickFIXn/Store/FileStore.cs
@@ -0,0 +1,316 @@
+#nullable enable
+using System;
+using System.Collections.Generic;
+using System.Text;
+using QuickFix.Util;
+
+namespace QuickFix.Store;
+
+///
+/// File store implementation
+///
+public class FileStore : IMessageStore
+{
+ private class MsgDef
+ {
+ public long Index { get; }
+ public int Size { get; }
+
+ public MsgDef(long index, int size)
+ {
+ Index = index;
+ Size = size;
+ }
+ }
+
+ private readonly string _seqNumsFileName;
+ private readonly string _msgFileName;
+ private readonly string _headerFileName;
+ private readonly string _sessionFileName;
+
+ private System.IO.FileStream _seqNumsFile;
+ private System.IO.FileStream _msgFile;
+ private System.IO.StreamWriter _headerFile;
+
+ private readonly MemoryStore _cache = new();
+
+ private readonly Dictionary _offsets = new();
+
+ public static string Prefix(SessionID sessionId)
+ {
+ StringBuilder prefix = new StringBuilder(sessionId.BeginString)
+ .Append('-').Append(sessionId.SenderCompID);
+ if (SessionID.IsSet(sessionId.SenderSubID))
+ prefix.Append('_').Append(sessionId.SenderSubID);
+ if (SessionID.IsSet(sessionId.SenderLocationID))
+ prefix.Append('_').Append(sessionId.SenderLocationID);
+ prefix.Append('-').Append(sessionId.TargetCompID);
+ if (SessionID.IsSet(sessionId.TargetSubID))
+ prefix.Append('_').Append(sessionId.TargetSubID);
+ if (SessionID.IsSet(sessionId.TargetLocationID))
+ prefix.Append('_').Append(sessionId.TargetLocationID);
+
+ if (SessionID.IsSet(sessionId.SessionQualifier))
+ prefix.Append('-').Append(sessionId.SessionQualifier);
+
+ return prefix.ToString();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// All back or forward slashes in this path will be converted as needed to the running platform's preferred
+ /// path separator (i.e. "/" will become "\" on windows, else "\" will become "/" on all other platforms)
+ ///
+ ///
+ public FileStore(string path, SessionID sessionId)
+ {
+ string normalizedPath = StringUtil.FixSlashes(path);
+
+ if (!System.IO.Directory.Exists(normalizedPath))
+ System.IO.Directory.CreateDirectory(normalizedPath);
+
+ string prefix = Prefix(sessionId);
+
+ _seqNumsFileName = System.IO.Path.Combine(normalizedPath, prefix + ".seqnums");
+ _msgFileName = System.IO.Path.Combine(normalizedPath, prefix + ".body");
+ _headerFileName = System.IO.Path.Combine(normalizedPath, prefix + ".header");
+ _sessionFileName = System.IO.Path.Combine(normalizedPath, prefix + ".session");
+
+ // The compiler isn't smart enough to see that Open() initializes these 3 vars,
+ // but we can use "= null!" to make it accept that these are non-null
+ _seqNumsFile = null!;
+ _msgFile = null!;
+ _headerFile = null!;
+ Open();
+ }
+
+ private void Open()
+ {
+ Close();
+
+ ConstructFromFileCache();
+ InitializeSessionCreateTime();
+
+ _seqNumsFile = new System.IO.FileStream(_seqNumsFileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
+ _msgFile = new System.IO.FileStream(_msgFileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);
+ _headerFile = new System.IO.StreamWriter(_headerFileName, true);
+ }
+
+ private void Close()
+ {
+ // these vars will be null only during construction (ctor()->Open()->Close())
+ _seqNumsFile?.Dispose();
+ _msgFile?.Dispose();
+ _headerFile?.Dispose();
+ }
+
+ private static void PurgeSingleFile(System.IO.Stream stream, string filename)
+ {
+ stream.Close();
+ if (System.IO.File.Exists(filename))
+ System.IO.File.Delete(filename);
+ }
+
+ private static void PurgeSingleFile(System.IO.StreamWriter stream, string filename)
+ {
+ stream.Close();
+ if (System.IO.File.Exists(filename))
+ System.IO.File.Delete(filename);
+ }
+
+ private static void PurgeSingleFile(string filename)
+ {
+ if (System.IO.File.Exists(filename))
+ System.IO.File.Delete(filename);
+ }
+
+ private void PurgeFileCache()
+ {
+ PurgeSingleFile(_seqNumsFile, _seqNumsFileName);
+ PurgeSingleFile(_msgFile, _msgFileName);
+ PurgeSingleFile(_headerFile, _headerFileName);
+ PurgeSingleFile(_sessionFileName);
+ }
+
+
+ private void ConstructFromFileCache()
+ {
+ _offsets.Clear();
+ if (System.IO.File.Exists(_headerFileName))
+ {
+ using (System.IO.StreamReader reader = new System.IO.StreamReader(_headerFileName))
+ {
+ while (reader.ReadLine() is { } line)
+ {
+ string[] headerParts = line.Split(',');
+ if (headerParts.Length == 3)
+ {
+ _offsets[Convert.ToUInt64(headerParts[0])] = new MsgDef(
+ Convert.ToInt64(headerParts[1]), Convert.ToInt32(headerParts[2]));
+ }
+ }
+ }
+ }
+
+ if (System.IO.File.Exists(_seqNumsFileName))
+ {
+ using (System.IO.StreamReader seqNumReader = new System.IO.StreamReader(_seqNumsFileName))
+ {
+ string[] parts = seqNumReader.ReadToEnd().Split(':');
+ if (parts.Length == 2)
+ {
+ _cache.NextSenderMsgSeqNum = Convert.ToUInt64(parts[0]);
+ _cache.NextTargetMsgSeqNum = Convert.ToUInt64(parts[1]);
+ }
+ }
+ }
+ }
+
+ private void InitializeSessionCreateTime()
+ {
+ if (System.IO.File.Exists(_sessionFileName) && new System.IO.FileInfo(_sessionFileName).Length > 0)
+ {
+ using (System.IO.StreamReader reader = new System.IO.StreamReader(_sessionFileName))
+ {
+ string s = reader.ReadToEnd();
+ _cache.CreationTime = UtcDateTimeSerializer.FromString(s);
+ }
+ }
+ else
+ {
+ using (System.IO.StreamWriter writer = new System.IO.StreamWriter(_sessionFileName, false)) {
+ writer.Write(UtcDateTimeSerializer.ToString(_cache.CreationTime ?? new DateTime()));
+ }
+ }
+ }
+
+
+ #region MessageStore Members
+
+ ///
+ /// Get messages within the range of sequence numbers
+ ///
+ ///
+ ///
+ ///
+ public void Get(SeqNumType startSeqNum, SeqNumType endSeqNum, List messages)
+ {
+ for (SeqNumType i = startSeqNum; i <= endSeqNum; i++)
+ {
+ if (_offsets.ContainsKey(i))
+ {
+ _msgFile.Seek(_offsets[i].Index, System.IO.SeekOrigin.Begin);
+ byte[] msgBytes = new byte[_offsets[i].Size];
+ _msgFile.Read(msgBytes, 0, msgBytes.Length);
+
+ messages.Add(CharEncoding.DefaultEncoding.GetString(msgBytes));
+ }
+ }
+
+ }
+
+ ///
+ /// Store a message
+ ///
+ ///
+ ///
+ ///
+ public bool Set(SeqNumType msgSeqNum, string msg)
+ {
+ _msgFile.Seek(0, System.IO.SeekOrigin.End);
+
+ long offset = _msgFile.Position;
+ byte[] msgBytes = CharEncoding.DefaultEncoding.GetBytes(msg);
+ int size = msgBytes.Length;
+
+ StringBuilder b = new StringBuilder();
+ b.Append(msgSeqNum).Append(',').Append(offset).Append(',').Append(size);
+ _headerFile.WriteLine(b.ToString());
+ _headerFile.Flush();
+
+ _offsets[msgSeqNum] = new MsgDef(offset, size);
+
+ _msgFile.Write(msgBytes, 0, size);
+ _msgFile.Flush();
+
+
+ return true;
+ }
+
+ public SeqNumType NextSenderMsgSeqNum {
+ get => _cache.NextSenderMsgSeqNum;
+ set {
+ _cache.NextSenderMsgSeqNum = value;
+ SetSeqNum();
+ }
+ }
+
+ public SeqNumType NextTargetMsgSeqNum {
+ get => _cache.NextTargetMsgSeqNum;
+ set {
+ _cache.NextTargetMsgSeqNum = value;
+ SetSeqNum();
+ }
+ }
+
+ public void IncrNextSenderMsgSeqNum()
+ {
+ _cache.IncrNextSenderMsgSeqNum();
+ SetSeqNum();
+ }
+
+ public void IncrNextTargetMsgSeqNum()
+ {
+ _cache.IncrNextTargetMsgSeqNum();
+ SetSeqNum();
+ }
+
+ private void SetSeqNum()
+ {
+ _seqNumsFile.Seek(0, System.IO.SeekOrigin.Begin);
+ System.IO.StreamWriter writer = new System.IO.StreamWriter(_seqNumsFile);
+
+ writer.Write(NextSenderMsgSeqNum.ToString("D20") + " : " + NextTargetMsgSeqNum.ToString("D20") + " ");
+ writer.Flush();
+ }
+
+ public DateTime? CreationTime => _cache.CreationTime;
+
+ public void Reset()
+ {
+ _cache.Reset();
+ PurgeFileCache();
+ Open();
+ }
+
+ public void Refresh()
+ {
+ _cache.Reset();
+ Open();
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ private bool _disposed = false;
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing)
+ {
+ Close();
+ }
+ _disposed = true;
+ }
+
+ ~FileStore() => Dispose(false);
+ #endregion
+}
diff --git a/QuickFIXn/Store/FileStoreFactory.cs b/QuickFIXn/Store/FileStoreFactory.cs
new file mode 100755
index 000000000..c3ecc945d
--- /dev/null
+++ b/QuickFIXn/Store/FileStoreFactory.cs
@@ -0,0 +1,30 @@
+#nullable enable
+
+namespace QuickFix.Store;
+
+///
+/// Creates a message store that stores messages in a file
+///
+public class FileStoreFactory : IMessageStoreFactory
+{
+ private readonly SessionSettings _settings;
+
+ ///
+ /// Create the factory with configuration in session settings
+ ///
+ ///
+ public FileStoreFactory(SessionSettings settings)
+ {
+ _settings = settings;
+ }
+
+ ///
+ /// Creates a file-based message store
+ ///
+ /// session ID for the message store
+ ///
+ public IMessageStore Create(SessionID sessionId)
+ {
+ return new FileStore(_settings.Get(sessionId).GetString(SessionSettings.FILE_STORE_PATH), sessionId);
+ }
+}
diff --git a/QuickFIXn/Store/IMessageStore.cs b/QuickFIXn/Store/IMessageStore.cs
new file mode 100755
index 000000000..0a77f3539
--- /dev/null
+++ b/QuickFIXn/Store/IMessageStore.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+
+namespace QuickFix.Store;
+
+///
+/// Used by a Session to store and retrieve messages for resend purposes
+///
+public interface IMessageStore : IDisposable
+{
+ ///
+ /// Get messages within sequence number range (inclusive). Used for
+ /// message resend requests
+ ///
+ /// the starting message sequence number
+ /// the ending message sequence number
+ /// the retrieved messages (out parameter)
+ void Get(SeqNumType startSeqNum, SeqNumType endSeqNum, List messages);
+
+ ///
+ /// Adds a raw fix message to the store with the give sequence number
+ ///
+ /// the sequence number
+ /// the raw FIX message string
+ /// true if successful, false otherwise
+ bool Set(SeqNumType msgSeqNum, string msg);
+
+ SeqNumType NextSenderMsgSeqNum { get; set; }
+ SeqNumType NextTargetMsgSeqNum { get; set; }
+
+ void IncrNextSenderMsgSeqNum();
+ void IncrNextTargetMsgSeqNum();
+
+
+ DateTime? CreationTime { get; }
+
+ ///
+ /// Reset the message store. Sequence numbers are set back to 1 and stored
+ /// messages are erased. The session creation time is also set to the time of
+ /// the reset
+ ///
+ void Reset();
+
+ ///
+ /// Refreshes session state from a shared state storage (e.g. database,
+ /// file, ...). Refresh will not work for message stores without shared state
+ /// (e.g. MemoryStore). These stores should log a session error, at a minimum,
+ /// or throw an exception.
+ ///
+ void Refresh();
+}
diff --git a/QuickFIXn/Store/IMessageStoreFactory.cs b/QuickFIXn/Store/IMessageStoreFactory.cs
new file mode 100755
index 000000000..2fab87937
--- /dev/null
+++ b/QuickFIXn/Store/IMessageStoreFactory.cs
@@ -0,0 +1,14 @@
+namespace QuickFix.Store;
+
+///
+/// Used by a Session to create a message store implementation
+///
+public interface IMessageStoreFactory
+{
+ ///
+ /// Creates a message store implementation
+ ///
+ /// the session ID, often used to access session configurations
+ /// the message store implementation
+ IMessageStore Create(SessionID sessionId);
+}
diff --git a/QuickFIXn/Store/MemoryStore.cs b/QuickFIXn/Store/MemoryStore.cs
new file mode 100755
index 000000000..573f82db7
--- /dev/null
+++ b/QuickFIXn/Store/MemoryStore.cs
@@ -0,0 +1,77 @@
+#nullable enable
+using System;
+using System.Collections.Generic;
+
+namespace QuickFix.Store;
+
+///
+/// In-memory message store implementation
+///
+public class MemoryStore : IMessageStore
+{
+ private readonly Dictionary _messages;
+
+ public MemoryStore()
+ {
+ _messages = new Dictionary();
+ Reset();
+ }
+
+ public void Get(SeqNumType begSeqNo, SeqNumType endSeqNo, List messages)
+ {
+ for (SeqNumType current = begSeqNo; current <= endSeqNo; current++)
+ {
+ if (_messages.TryGetValue(current, out var message))
+ messages.Add(message);
+ }
+ }
+
+ #region MessageStore Members
+
+ public bool Set(SeqNumType msgSeqNum, string msg)
+ {
+ _messages[msgSeqNum] = msg;
+ return true;
+ }
+
+ public SeqNumType NextSenderMsgSeqNum { get; set; }
+ public SeqNumType NextTargetMsgSeqNum { get; set; }
+
+ public void IncrNextSenderMsgSeqNum()
+ { ++NextSenderMsgSeqNum; }
+
+ public void IncrNextTargetMsgSeqNum()
+ { ++NextTargetMsgSeqNum; }
+
+ public DateTime? CreationTime { get; internal set; }
+
+ public void Reset()
+ {
+ NextSenderMsgSeqNum = 1;
+ NextTargetMsgSeqNum = 1;
+ _messages.Clear();
+ CreationTime = DateTime.UtcNow;
+ }
+
+ public void Refresh()
+ { }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ private bool _disposed = false;
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing)
+ {
+ _messages.Clear();
+ }
+ _disposed = true;
+ }
+
+ ~MemoryStore() => Dispose(false);
+ #endregion
+}
diff --git a/QuickFIXn/Store/MemoryStoreFactory.cs b/QuickFIXn/Store/MemoryStoreFactory.cs
new file mode 100755
index 000000000..9f338c070
--- /dev/null
+++ b/QuickFIXn/Store/MemoryStoreFactory.cs
@@ -0,0 +1,16 @@
+namespace QuickFix.Store;
+
+///
+/// Creates a message store that stores all data in memory
+///
+public class MemoryStoreFactory : IMessageStoreFactory
+{
+ #region MessageStoreFactory Members
+
+ public IMessageStore Create(SessionID sessionId)
+ {
+ return new MemoryStore();
+ }
+
+ #endregion
+}
diff --git a/QuickFIXn/ThreadedSocketAcceptor.cs b/QuickFIXn/ThreadedSocketAcceptor.cs
index ce9993aa3..735dcb432 100755
--- a/QuickFIXn/ThreadedSocketAcceptor.cs
+++ b/QuickFIXn/ThreadedSocketAcceptor.cs
@@ -3,6 +3,8 @@
using System.Linq;
using System.Net;
using System;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace QuickFix
{
diff --git a/QuickFIXn/Transport/SocketInitiator.cs b/QuickFIXn/Transport/SocketInitiator.cs
index af1b5dc51..a150dc69a 100755
--- a/QuickFIXn/Transport/SocketInitiator.cs
+++ b/QuickFIXn/Transport/SocketInitiator.cs
@@ -6,6 +6,8 @@
using System.Net;
using System.Threading;
using System.IO;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace QuickFix.Transport
{
diff --git a/QuickFIXn/Transport/StreamFactory.cs b/QuickFIXn/Transport/StreamFactory.cs
index 8b637fea9..d25f6edad 100644
--- a/QuickFIXn/Transport/StreamFactory.cs
+++ b/QuickFIXn/Transport/StreamFactory.cs
@@ -9,6 +9,7 @@
using System.Net.Security;
using System.Diagnostics;
using System.Net;
+using QuickFix.Logger;
namespace QuickFix.Transport
{
diff --git a/QuickFIXn/Util/StringUtil.cs b/QuickFIXn/Util/StringUtil.cs
index 89b40b743..7df33d047 100644
--- a/QuickFIXn/Util/StringUtil.cs
+++ b/QuickFIXn/Util/StringUtil.cs
@@ -1,11 +1,16 @@
-using System;
+#nullable enable
using System.Runtime.InteropServices;
-using QuickFix.Fields;
namespace QuickFix.Util
{
public static class StringUtil
{
+ ///
+ /// Convert forward-slashes to backslashes (windows) or backslashes to forward-slashes (not windows)
+ /// and return the result
+ ///
+ ///
+ ///
public static string FixSlashes(string s) {
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? s.Replace('/', '\\')
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 6cbc6dac4..f5bc6a31b 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -44,7 +44,12 @@ What's New
* #827 - cleanup/nullable-ize StreamFactory, SessionID, Settings, SessionSettings, SessionSchedule (gbirchmeier)
* StreamFactory: privatized a lot of members; I don't think users are inheriting from this
* SessionSchedule: remove unused LastEndTime()
-
+* #831 - cleanup/nullable-ize Logging/Store classes, fix path-separator bug (gbirchmeier)
+ * Move all logger classes to new QuickFix.Logger namespace
+ * Move all store classes to new QuickFix.Store namespace
+ * FileLog: remove the single-param ctor, no reason for anyone to use it
+ * ScreenLog ctor: removed unused sessionId param
+ * ScreenLogFactory: remove public vars and a ctor that no one should be using
**Non-breaking changes**
* #400 - added DDTool, a C#-based codegen, and deleted Ruby-based generator (gbirchmeier)
diff --git a/UnitTests/FileLogTests.cs b/UnitTests/FileLogTests.cs
deleted file mode 100644
index 7fd950341..000000000
--- a/UnitTests/FileLogTests.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using NUnit.Framework;
-
-namespace UnitTests
-{
- [TestFixture]
- public class FileLogTests
- {
- QuickFix.FileLog log;
-
- [SetUp]
- public void setup()
- { }
-
- [TearDown]
- public void teardown()
- {
- if (log != null)
- {
- log.Dispose();
- log = null;
- }
- }
-
- [Test]
- public void testPrefix()
- {
- QuickFix.SessionID someSessionID = new QuickFix.SessionID("FIX.4.4", "sender", "target");
- QuickFix.SessionID someSessionIDWithQualifier = new QuickFix.SessionID("FIX.4.3", "sender", "target", "foo");
-
- Assert.AreEqual("FIX.4.4-sender-target", QuickFix.FileLog.Prefix(someSessionID));
- Assert.AreEqual("FIX.4.3-sender-target-foo", QuickFix.FileLog.Prefix(someSessionIDWithQualifier));
- }
-
- [Test]
- public void testPrefixForSubsAndLocation()
- {
- QuickFix.SessionID sessionIDWithSubsAndLocation = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "SENDERSUB", "SENDERLOC", "TARGETCOMP", "TARGETSUB", "TARGETLOC");
- Assert.That(QuickFix.FileLog.Prefix(sessionIDWithSubsAndLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB_SENDERLOC-TARGETCOMP_TARGETSUB_TARGETLOC"));
-
- QuickFix.SessionID sessionIDWithSubsNoLocation = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "SENDERSUB", "TARGETCOMP", "TARGETSUB");
- Assert.That(QuickFix.FileLog.Prefix(sessionIDWithSubsNoLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB-TARGETCOMP_TARGETSUB"));
- }
-
- [Test]
- public void testGeneratedFileName()
- {
- var logDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "log");
-
- if (System.IO.Directory.Exists(logDirectory))
- System.IO.Directory.Delete(logDirectory, true);
-
- QuickFix.SessionID sessionID = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "TARGETCOMP");
- QuickFix.SessionSettings settings = new QuickFix.SessionSettings();
-
- QuickFix.Dictionary config = new QuickFix.Dictionary();
- config.SetString(QuickFix.SessionSettings.CONNECTION_TYPE, "initiator");
- config.SetString(QuickFix.SessionSettings.FILE_LOG_PATH, logDirectory);
-
- settings.Set(sessionID, config);
-
- QuickFix.FileLogFactory factory = new QuickFix.FileLogFactory(settings);
- log = (QuickFix.FileLog)factory.Create(sessionID);
-
- log.OnEvent("some event");
- log.OnIncoming("some incoming");
- log.OnOutgoing("some outgoing");
-
- Assert.That(System.IO.File.Exists(Path.Combine(logDirectory, "FIX.4.2-SENDERCOMP-TARGETCOMP.event.current.log")));
- Assert.That(System.IO.File.Exists(Path.Combine(logDirectory, "FIX.4.2-SENDERCOMP-TARGETCOMP.messages.current.log")));
- }
-
- [Test]
- public void testThrowsIfNoConfig()
- {
- QuickFix.SessionID sessionID = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "TARGETCOMP");
- QuickFix.Dictionary config = new QuickFix.Dictionary();
- config.SetString(QuickFix.SessionSettings.CONNECTION_TYPE, "initiator");
- QuickFix.SessionSettings settings = new QuickFix.SessionSettings();
- settings.Set(sessionID, config);
-
- QuickFix.FileLogFactory factory = new QuickFix.FileLogFactory(settings);
-
- Assert.Throws(delegate { factory.Create(sessionID); });
- }
- }
-}
diff --git a/UnitTests/FileStoreTests.cs b/UnitTests/FileStoreTests.cs
index e6a8ea92a..165945e2d 100755
--- a/UnitTests/FileStoreTests.cs
+++ b/UnitTests/FileStoreTests.cs
@@ -3,14 +3,15 @@
using System.IO;
using NUnit.Framework;
using System.Threading;
+using QuickFix.Store;
namespace UnitTests
{
[TestFixture]
public class FileStoreTests
{
- private QuickFix.FileStore _store;
- private QuickFix.FileStoreFactory _factory;
+ private FileStore _store;
+ private FileStoreFactory _factory;
private QuickFix.SessionSettings _settings;
private QuickFix.SessionID _sessionID;
@@ -33,9 +34,9 @@ public void Setup()
_settings = new QuickFix.SessionSettings();
_settings.Set(_sessionID, config);
- _factory = new QuickFix.FileStoreFactory(_settings);
+ _factory = new FileStoreFactory(_settings);
- _store = (QuickFix.FileStore)_factory.Create(_sessionID);
+ _store = (FileStore)_factory.Create(_sessionID);
}
void RebuildStore()
@@ -45,7 +46,7 @@ void RebuildStore()
_store.Dispose();
}
- _store = (QuickFix.FileStore)_factory.Create(_sessionID);
+ _store = (FileStore)_factory.Create(_sessionID);
}
@@ -60,10 +61,10 @@ public void Teardown()
public void TestPrefixForSessionWithSubsAndLoc()
{
QuickFix.SessionID sessionIDWithSubsAndLocation = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "SENDERSUB", "SENDERLOC", "TARGETCOMP", "TARGETSUB", "TARGETLOC");
- Assert.That(QuickFix.FileStore.Prefix(sessionIDWithSubsAndLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB_SENDERLOC-TARGETCOMP_TARGETSUB_TARGETLOC"));
+ Assert.That(FileStore.Prefix(sessionIDWithSubsAndLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB_SENDERLOC-TARGETCOMP_TARGETSUB_TARGETLOC"));
QuickFix.SessionID sessionIDWithSubsNoLocation = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "SENDERSUB", "TARGETCOMP", "TARGETSUB");
- Assert.That(QuickFix.FileStore.Prefix(sessionIDWithSubsNoLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB-TARGETCOMP_TARGETSUB"));
+ Assert.That(FileStore.Prefix(sessionIDWithSubsNoLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB-TARGETCOMP_TARGETSUB"));
}
[Test]
diff --git a/UnitTests/Logger/FileLogTests.cs b/UnitTests/Logger/FileLogTests.cs
new file mode 100644
index 000000000..20c5a2e98
--- /dev/null
+++ b/UnitTests/Logger/FileLogTests.cs
@@ -0,0 +1,86 @@
+#nullable enable
+
+using System.IO;
+using NUnit.Framework;
+using QuickFix.Logger;
+
+namespace UnitTests.Logger;
+
+[TestFixture]
+public class FileLogTests
+{
+ private FileLog? _log;
+
+ [SetUp]
+ public void Setup()
+ { }
+
+ [TearDown]
+ public void Teardown()
+ {
+ _log?.Dispose();
+ _log = null;
+ }
+
+ [Test]
+ public void TestPrefix()
+ {
+ QuickFix.SessionID someSessionId = new QuickFix.SessionID("FIX.4.4", "sender", "target");
+ QuickFix.SessionID someSessionIdWithQualifier = new QuickFix.SessionID("FIX.4.3", "sender", "target", "foo");
+
+ Assert.AreEqual("FIX.4.4-sender-target", FileLog.Prefix(someSessionId));
+ Assert.AreEqual("FIX.4.3-sender-target-foo", FileLog.Prefix(someSessionIdWithQualifier));
+ }
+
+ [Test]
+ public void TestPrefixForSubsAndLocation()
+ {
+ QuickFix.SessionID sessionIdWithSubsAndLocation = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "SENDERSUB", "SENDERLOC", "TARGETCOMP", "TARGETSUB", "TARGETLOC");
+ Assert.That(FileLog.Prefix(sessionIdWithSubsAndLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB_SENDERLOC-TARGETCOMP_TARGETSUB_TARGETLOC"));
+
+ QuickFix.SessionID sessionIdWithSubsNoLocation = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "SENDERSUB", "TARGETCOMP", "TARGETSUB");
+ Assert.That(FileLog.Prefix(sessionIdWithSubsNoLocation), Is.EqualTo("FIX.4.2-SENDERCOMP_SENDERSUB-TARGETCOMP_TARGETSUB"));
+ }
+
+ [Test]
+ public void TestGeneratedFileName()
+ {
+ var logDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "log");
+
+ if (Directory.Exists(logDirectory))
+ Directory.Delete(logDirectory, true);
+
+ QuickFix.SessionID sessionId = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "TARGETCOMP");
+ QuickFix.SessionSettings settings = new QuickFix.SessionSettings();
+
+ QuickFix.Dictionary config = new QuickFix.Dictionary();
+ config.SetString(QuickFix.SessionSettings.CONNECTION_TYPE, "initiator");
+ config.SetString(QuickFix.SessionSettings.FILE_LOG_PATH, logDirectory);
+
+ settings.Set(sessionId, config);
+
+ FileLogFactory factory = new FileLogFactory(settings);
+ _log = (FileLog)factory.Create(sessionId);
+
+ _log.OnEvent("some event");
+ _log.OnIncoming("some incoming");
+ _log.OnOutgoing("some outgoing");
+
+ Assert.That(File.Exists(Path.Combine(logDirectory, "FIX.4.2-SENDERCOMP-TARGETCOMP.event.current.log")));
+ Assert.That(File.Exists(Path.Combine(logDirectory, "FIX.4.2-SENDERCOMP-TARGETCOMP.messages.current.log")));
+ }
+
+ [Test]
+ public void TestThrowsIfNoConfig()
+ {
+ QuickFix.SessionID sessionId = new QuickFix.SessionID("FIX.4.2", "SENDERCOMP", "TARGETCOMP");
+ QuickFix.Dictionary config = new QuickFix.Dictionary();
+ config.SetString(QuickFix.SessionSettings.CONNECTION_TYPE, "initiator");
+ QuickFix.SessionSettings settings = new QuickFix.SessionSettings();
+ settings.Set(sessionId, config);
+
+ FileLogFactory factory = new FileLogFactory(settings);
+
+ Assert.Throws(delegate { factory.Create(sessionId); });
+ }
+}
diff --git a/UnitTests/MemoryStoreTest.cs b/UnitTests/MemoryStoreTest.cs
index 81042c5b3..9d153e2bd 100644
--- a/UnitTests/MemoryStoreTest.cs
+++ b/UnitTests/MemoryStoreTest.cs
@@ -2,6 +2,7 @@
using NUnit.Framework;
using QuickFix;
using QuickFix.Fields;
+using QuickFix.Store;
namespace UnitTests
{
diff --git a/UnitTests/SessionDynamicTest.cs b/UnitTests/SessionDynamicTest.cs
index 94112da31..a29dc3e51 100644
--- a/UnitTests/SessionDynamicTest.cs
+++ b/UnitTests/SessionDynamicTest.cs
@@ -8,6 +8,8 @@
using NUnit.Framework;
using QuickFix;
+using QuickFix.Logger;
+using QuickFix.Store;
using QuickFix.Transport;
namespace UnitTests
diff --git a/UnitTests/SessionFactoryTest.cs b/UnitTests/SessionFactoryTest.cs
index 46515c975..cab6bcd62 100755
--- a/UnitTests/SessionFactoryTest.cs
+++ b/UnitTests/SessionFactoryTest.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using NUnit.Framework;
using QuickFix;
+using QuickFix.Store;
namespace UnitTests
{
diff --git a/UnitTests/SessionStateTest.cs b/UnitTests/SessionStateTest.cs
index 28722cff2..614458a51 100755
--- a/UnitTests/SessionStateTest.cs
+++ b/UnitTests/SessionStateTest.cs
@@ -5,6 +5,8 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace UnitTests
{
diff --git a/UnitTests/SessionTest.cs b/UnitTests/SessionTest.cs
index ccfa316f4..808796eb7 100755
--- a/UnitTests/SessionTest.cs
+++ b/UnitTests/SessionTest.cs
@@ -4,6 +4,8 @@
using System.Text.RegularExpressions;
using NUnit.Framework;
using System.Threading;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace UnitTests
{
@@ -194,16 +196,16 @@ public void Setup()
config.SetString(QuickFix.SessionSettings.END_TIME, "00:00:00");
settings.Set(sessionID, config);
- var logFactory = new QuickFix.NullLogFactory(); // use QuickFix.ScreenLogFactory(settings) if you need to see output
+ var logFactory = new NullLogFactory(); // use QuickFix.ScreenLogFactory(settings) if you need to see output
// acceptor
- session = new QuickFix.Session(false, application, new QuickFix.MemoryStoreFactory(), sessionID,
+ session = new QuickFix.Session(false, application, new MemoryStoreFactory(), sessionID,
new QuickFix.DataDictionaryProvider(),new QuickFix.SessionSchedule(config), 0, logFactory, new QuickFix.DefaultMessageFactory(), "blah");
session.SetResponder(responder);
session.CheckLatency = false;
// initiator
- session2 = new QuickFix.Session(true, application, new QuickFix.MemoryStoreFactory(), new QuickFix.SessionID("FIX.4.2", "OTHER_SENDER", "OTHER_TARGET"),
+ session2 = new QuickFix.Session(true, application, new MemoryStoreFactory(), new QuickFix.SessionID("FIX.4.2", "OTHER_SENDER", "OTHER_TARGET"),
new QuickFix.DataDictionaryProvider(), new QuickFix.SessionSchedule(config), 0, logFactory, new QuickFix.DefaultMessageFactory(), "blah");
session2.SetResponder(responder);
session2.CheckLatency = false;
@@ -919,8 +921,8 @@ public void TestToAppResendDoNotSend()
public void TestApplicationExtension()
{
var mockApp = new MockApplicationExt();
- session = new QuickFix.Session(true, mockApp, new QuickFix.MemoryStoreFactory(), sessionID,
- new QuickFix.DataDictionaryProvider(), new QuickFix.SessionSchedule(config), 0, new QuickFix.NullLogFactory(), new QuickFix.DefaultMessageFactory(), "blah");
+ session = new QuickFix.Session(true, mockApp, new MemoryStoreFactory(), sessionID,
+ new QuickFix.DataDictionaryProvider(), new QuickFix.SessionSchedule(config), 0, new NullLogFactory(), new QuickFix.DefaultMessageFactory(), "blah");
session.SetResponder(responder);
session.CheckLatency = false;
diff --git a/UnitTests/ThreadedSocketAcceptorTests.cs b/UnitTests/ThreadedSocketAcceptorTests.cs
index 229a65108..1f334b31c 100644
--- a/UnitTests/ThreadedSocketAcceptorTests.cs
+++ b/UnitTests/ThreadedSocketAcceptorTests.cs
@@ -5,6 +5,8 @@
using System.Text;
using NUnit.Framework;
using QuickFix;
+using QuickFix.Logger;
+using QuickFix.Store;
namespace UnitTests
{