diff --git a/artifacts/exe/Firefly b/artifacts/exe/Firefly
index a6e9ea5..1c3f953 100644
Binary files a/artifacts/exe/Firefly and b/artifacts/exe/Firefly differ
diff --git a/artifacts/exe/Firefly.dbg b/artifacts/exe/Firefly.dbg
index 2321fd4..2fc0bba 100644
Binary files a/artifacts/exe/Firefly.dbg and b/artifacts/exe/Firefly.dbg differ
diff --git a/artifacts/exe/Firefly.exe b/artifacts/exe/Firefly.exe
index 035aeb5..cb1a294 100644
Binary files a/artifacts/exe/Firefly.exe and b/artifacts/exe/Firefly.exe differ
diff --git a/artifacts/exe/Firefly.pdb b/artifacts/exe/Firefly.pdb
index 6ac887d..b61d466 100644
Binary files a/artifacts/exe/Firefly.pdb and b/artifacts/exe/Firefly.pdb differ
diff --git a/artifacts/exe/Firefly.xml b/artifacts/exe/Firefly.xml
index db4c865..40c85ab 100644
--- a/artifacts/exe/Firefly.xml
+++ b/artifacts/exe/Firefly.xml
@@ -320,6 +320,11 @@
The key to execute the action on
The action to execute
+
+
+ Displays Firefly ASCII art in the console
+
+
Handles the AUTH command which authenticates a client.
diff --git a/artifacts/native/Firefly.dll b/artifacts/native/Firefly.dll
index 5a4a6b3..d1f5909 100644
Binary files a/artifacts/native/Firefly.dll and b/artifacts/native/Firefly.dll differ
diff --git a/artifacts/native/Firefly.pdb b/artifacts/native/Firefly.pdb
index f362799..35b8891 100644
Binary files a/artifacts/native/Firefly.pdb and b/artifacts/native/Firefly.pdb differ
diff --git a/artifacts/native/Firefly.so b/artifacts/native/Firefly.so
index bfbd90c..eca2573 100644
Binary files a/artifacts/native/Firefly.so and b/artifacts/native/Firefly.so differ
diff --git a/artifacts/native/Firefly.so.dbg b/artifacts/native/Firefly.so.dbg
index 4fda6ad..da8df45 100644
Binary files a/artifacts/native/Firefly.so.dbg and b/artifacts/native/Firefly.so.dbg differ
diff --git a/artifacts/native/Firefly.xml b/artifacts/native/Firefly.xml
index db4c865..40c85ab 100644
--- a/artifacts/native/Firefly.xml
+++ b/artifacts/native/Firefly.xml
@@ -320,6 +320,11 @@
The key to execute the action on
The action to execute
+
+
+ Displays Firefly ASCII art in the console
+
+
Handles the AUTH command which authenticates a client.
diff --git a/src/BackupSystem.cs b/src/BackupSystem.cs
index f4adf8d..fd05d4a 100644
--- a/src/BackupSystem.cs
+++ b/src/BackupSystem.cs
@@ -8,6 +8,13 @@ namespace Firefly
public partial class Firefly
{
#region Backup System
+ // Track if data has been modified since last backup
+ private static volatile bool dataModified = false;
+ // Debounce period in milliseconds for data modification backups
+ private static readonly int dataModificationBackupDelayMs = 5000;
+ // Timer for debouncing data modification backups
+ private static System.Timers.Timer? modificationBackupTimer;
+
static void InitializeBackupSystem()
{
// Create backup directory if it doesn't exist
@@ -33,7 +40,21 @@ namespace Firefly
backupTimer.AutoReset = true;
backupTimer.Start();
+ // Set up data modification backup timer
+ modificationBackupTimer = new System.Timers.Timer(dataModificationBackupDelayMs);
+ modificationBackupTimer.Elapsed += (sender, e) =>
+ {
+ if (dataModified)
+ {
+ BackupData();
+ dataModified = false;
+ }
+ modificationBackupTimer.Stop(); // Stop timer after backup
+ };
+ modificationBackupTimer.AutoReset = false;
+
Console.WriteLine($"Automatic backup system initialized (every {autoBackupIntervalMinutes} minutes)");
+ Console.WriteLine($"Data modification backup system initialized (after {dataModificationBackupDelayMs/1000} seconds of inactivity)");
Console.WriteLine($"Keeping up to {maxBackupFiles} backup files");
// Register backup on exit
@@ -47,6 +68,22 @@ namespace Firefly
};
}
+ // Call this method whenever data is modified
+ internal static void MarkDataAsModified()
+ {
+ if (!backupsEnabled)
+ return;
+
+ dataModified = true;
+
+ // Reset and start the timer to debounce multiple rapid changes
+ if (modificationBackupTimer != null)
+ {
+ modificationBackupTimer.Stop();
+ modificationBackupTimer.Start();
+ }
+ }
+
static void LoadDataFromBackup()
{
if (!backupsEnabled)
diff --git a/src/HashOperations.cs b/src/HashOperations.cs
index e53161c..6210cb6 100644
--- a/src/HashOperations.cs
+++ b/src/HashOperations.cs
@@ -27,10 +27,11 @@ namespace Firefly
{
var hash = GetOrCreateHash(key);
bool isNewField = hash.TryAdd(field, value);
+
if (!isNewField)
- {
hash[field] = value;
- }
+
+ MarkDataAsModified();
return Encoding.UTF8.GetBytes($":{(isNewField ? 1 : 0)}\r\n");
}
@@ -91,10 +92,11 @@ namespace Firefly
{
bool removed = hash.TryRemove(field, out _);
+ if (removed)
+ MarkDataAsModified();
+
if (hash.IsEmpty)
- {
HashStoreRemove(key);
- }
return Encoding.UTF8.GetBytes($":{(removed ? 1 : 0)}\r\n");
}
@@ -197,6 +199,8 @@ namespace Firefly
return Encoding.UTF8.GetBytes($"-ERR internal error: {ex.Message}\r\n");
}
+ MarkDataAsModified();
+
return Encoding.UTF8.GetBytes("+OK\r\n");
}
@@ -220,7 +224,12 @@ namespace Firefly
}
}
- return hashStoreShards[shardIndex].GetOrAdd(key, _ => new ConcurrentDictionary());
+ var hash = hashStoreShards[shardIndex].GetOrAdd(key, _ => new ConcurrentDictionary());
+
+ if (hash.IsEmpty)
+ MarkDataAsModified();
+
+ return hash;
}
///
@@ -254,7 +263,12 @@ namespace Firefly
private static bool HashStoreRemove(string key)
{
int shardIndex = GetShardIndex(key);
- return hashStoreShards[shardIndex].TryRemove(key, out _);
+ bool result = hashStoreShards[shardIndex].TryRemove(key, out _);
+
+ if (result)
+ MarkDataAsModified();
+
+ return result;
}
#endregion
#endregion
diff --git a/src/ListOperations.cs b/src/ListOperations.cs
index b9ba45d..8368922 100644
--- a/src/ListOperations.cs
+++ b/src/ListOperations.cs
@@ -548,6 +548,13 @@ namespace Firefly
{
throw new InvalidOperationException($"Key '{key}' already exists with a different type");
}
+
+ var newList = new List();
+ if (listStoreShards[shardIndex].TryAdd(key, newList))
+ {
+ MarkDataAsModified();
+ return newList;
+ }
}
return listStoreShards[shardIndex].GetOrAdd(key, _ => []);
@@ -587,7 +594,12 @@ namespace Firefly
listStoreLocks[shardIndex].EnterWriteLock();
try
{
- return listStoreShards[shardIndex].TryRemove(key, out _);
+ bool result = listStoreShards[shardIndex].TryRemove(key, out _);
+
+ if (result)
+ MarkDataAsModified();
+
+ return result;
}
finally
{
@@ -608,6 +620,8 @@ namespace Firefly
{
var list = GetOrCreateList(key);
action(list);
+
+ MarkDataAsModified();
}
finally
{
diff --git a/src/ServerManager.cs b/src/ServerManager.cs
index 9b28f5c..bb79d37 100644
--- a/src/ServerManager.cs
+++ b/src/ServerManager.cs
@@ -9,6 +9,9 @@ namespace Firefly
#region Server Management
static async Task StartServerAsync()
{
+ // Display Firefly ASCII art
+ DisplayFireflyArt();
+
// Set up server on specified port
var listener = new TcpListener(IPAddress.Parse(bindAddress), serverPort);
listener.Start();
@@ -305,6 +308,38 @@ namespace Firefly
}
}
}
+
+ ///
+ /// Displays Firefly ASCII art in the console
+ ///
+ static void DisplayFireflyArt()
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(
+" ,,_\n" +
+" zd$$??=\n" +
+" z$$P? F:`c, _\n" +
+" d$$, `c'cc$$i ,cd$?R\n" +
+" $$$$ cud$,?$$$i ,=P'2?z '\n" +
+" $` ` ?$$$,?$$$. ,-''`>, bzP\n" +
+" 'cLdb,?$$,?$$$ ,h' 'I$'J$P\n" +
+" ... `?$$$,`$$,`$$h $$PxrF'd$'\n" +
+" d$PP``?-,`?$$,?$h`$$,,$$'$F44'\n" +
+" ?,,_`=4c,?=,`?hu?$`?L4$'? '\n" +
+" ```?==``=-`` ```-`'_,,,,\n" +
+" .ccu?m?e?JC,-,\"=?\n" +
+" ```=='?'\n");
+
+ Console.WriteLine(@"
+ ███████╗██╗██████╗ ███████╗███████╗██╗ ██╗ ██╗
+ ██╔════╝██║██╔══██╗██╔════╝██╔════╝██║ ╚██╗ ██╔╝
+ █████╗ ██║██████╔╝█████╗ █████╗ ██║ ╚████╔╝
+ ██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║ ╚██╔╝
+ ██║ ██║██║ ██║███████╗██║ ███████╗██║
+ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚══════╝╚═╝
+");
+ Console.ResetColor();
+ }
#endregion
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/StringOperations.cs b/src/StringOperations.cs
index aad07f1..cdc584a 100644
--- a/src/StringOperations.cs
+++ b/src/StringOperations.cs
@@ -88,6 +88,9 @@ namespace Firefly
int shardIndex = GetShardIndex(key);
stringStoreShards[shardIndex][key] = value;
+
+ MarkDataAsModified();
+
return true;
}
@@ -111,7 +114,12 @@ namespace Firefly
private static bool StringStoreRemove(string key)
{
int shardIndex = GetShardIndex(key);
- return stringStoreShards[shardIndex].TryRemove(key, out _);
+ bool result = stringStoreShards[shardIndex].TryRemove(key, out _);
+
+ if (result)
+ MarkDataAsModified();
+
+ return result;
}
#endregion
#endregion