2025-02-27 09:15:28 +01:00
using Logging ;
2025-04-10 14:54:49 +02:00
using Utils ;
2025-02-26 16:17:20 +01:00
namespace AutoClient.Modes.FolderStore
{
2025-04-03 13:10:01 +02:00
public class FolderSaver : IFileSaverEventHandler
2025-02-26 16:17:20 +01:00
{
private const string FolderSaverFilename = "foldersaver.json" ;
private readonly App app ;
2025-04-03 13:10:01 +02:00
private readonly LoadBalancer loadBalancer ;
2025-02-26 16:17:20 +01:00
private readonly JsonFile < FolderStatus > statusFile ;
private readonly FolderStatus status ;
2025-03-04 10:03:30 +01:00
private readonly BalanceChecker balanceChecker ;
2025-05-02 08:21:56 +02:00
private readonly SlowModeHandler slowModeHandler ;
2025-02-28 16:19:26 +01:00
private int changeCounter = 0 ;
2025-05-02 08:21:56 +02:00
private int saveFolderJsonCounter = 0 ;
2025-02-26 16:17:20 +01:00
2025-04-03 13:10:01 +02:00
public FolderSaver ( App app , LoadBalancer loadBalancer )
2025-02-26 16:17:20 +01:00
{
this . app = app ;
2025-04-03 13:10:01 +02:00
this . loadBalancer = loadBalancer ;
2025-03-04 10:03:30 +01:00
balanceChecker = new BalanceChecker ( app ) ;
2025-05-02 08:21:56 +02:00
slowModeHandler = new SlowModeHandler ( app ) ;
2025-02-26 16:17:20 +01:00
statusFile = new JsonFile < FolderStatus > ( app , Path . Combine ( app . Config . FolderToStore , FolderSaverFilename ) ) ;
status = statusFile . Load ( ) ;
}
2025-04-04 08:31:27 +02:00
public void Run ( )
2025-02-26 16:17:20 +01:00
{
2025-05-02 08:21:56 +02:00
saveFolderJsonCounter = 0 ;
2025-02-26 16:17:20 +01:00
var folderFiles = Directory . GetFiles ( app . Config . FolderToStore ) ;
if ( ! folderFiles . Any ( ) ) throw new Exception ( "No files found in " + app . Config . FolderToStore ) ;
2025-03-04 10:03:30 +01:00
balanceChecker . Check ( ) ;
2025-02-26 16:17:20 +01:00
foreach ( var folderFile in folderFiles )
{
2025-04-04 08:31:27 +02:00
if ( app . Cts . IsCancellationRequested ) return ;
2025-04-03 14:18:27 +02:00
loadBalancer . CheckErrors ( ) ;
2025-02-26 16:17:20 +01:00
if ( ! folderFile . ToLowerInvariant ( ) . EndsWith ( FolderSaverFilename ) )
{
2025-02-28 16:19:26 +01:00
SaveFile ( folderFile ) ;
2025-02-26 16:17:20 +01:00
}
2025-05-02 08:21:56 +02:00
slowModeHandler . Check ( ) ;
CheckAndSaveChanges ( ) ;
2025-02-26 16:17:20 +01:00
2025-02-27 09:15:28 +01:00
statusFile . Save ( status ) ;
2025-02-27 10:18:35 +01:00
Thread . Sleep ( 100 ) ;
2025-02-26 16:17:20 +01:00
}
}
2025-05-02 08:21:56 +02:00
private void CheckAndSaveChanges ( )
{
if ( changeCounter > 1 )
{
changeCounter = 0 ;
saveFolderJsonCounter + + ;
if ( saveFolderJsonCounter > 5 )
{
saveFolderJsonCounter = 0 ;
balanceChecker . Check ( ) ;
SaveFolderSaverJsonFile ( ) ;
}
}
}
2025-02-28 16:19:26 +01:00
private void SaveFile ( string folderFile )
2025-02-26 16:17:20 +01:00
{
var localFilename = Path . GetFileName ( folderFile ) ;
var entry = status . Files . SingleOrDefault ( f = > f . Filename = = localFilename ) ;
if ( entry = = null )
{
2025-02-26 16:24:11 +01:00
entry = new FileStatus
{
Filename = localFilename
} ;
2025-02-26 16:17:20 +01:00
status . Files . Add ( entry ) ;
}
2025-02-28 16:19:26 +01:00
ProcessFileEntry ( folderFile , entry ) ;
2025-02-26 16:17:20 +01:00
}
2025-02-28 16:19:26 +01:00
private void ProcessFileEntry ( string folderFile , FileStatus entry )
2025-02-26 16:17:20 +01:00
{
var fileSaver = CreateFileSaver ( folderFile , entry ) ;
fileSaver . Process ( ) ;
}
private void SaveFolderSaverJsonFile ( )
{
2025-02-28 16:19:26 +01:00
app . Log . Log ( $"Saving {FolderSaverFilename}..." ) ;
2025-02-26 16:17:20 +01:00
var entry = new FileStatus
{
Filename = FolderSaverFilename
} ;
var folderFile = Path . Combine ( app . Config . FolderToStore , FolderSaverFilename ) ;
2025-02-27 09:15:28 +01:00
ApplyPadding ( folderFile ) ;
2025-02-26 16:17:20 +01:00
var fileSaver = CreateFileSaver ( folderFile , entry ) ;
fileSaver . Process ( ) ;
2025-02-28 16:19:26 +01:00
2025-03-03 18:56:18 +01:00
if ( ! string . IsNullOrEmpty ( entry . EncodedCid ) )
{
app . Log . Log ( $"!!! {FolderSaverFilename} saved to CID '{entry.EncodedCid}' !!!" ) ;
}
else
{
app . Log . Error ( $"Failed to store {FolderSaverFilename} :|" ) ;
}
2025-02-26 16:17:20 +01:00
}
2025-02-27 09:15:28 +01:00
private const int MinCodexStorageFilesize = 262144 ;
private readonly string paddingMessage = $"Codex currently requires a minimum filesize of {MinCodexStorageFilesize} bytes for datasets used in storage contracts. " +
$"Anything smaller, and the erasure-coding algorithms used for data durability won't function. Therefore, we apply this padding field to make sure this " +
$"file is larger than the minimal size. The following is pseudo-random: " ;
private void ApplyPadding ( string folderFile )
{
var info = new FileInfo ( folderFile ) ;
var min = MinCodexStorageFilesize * 2 ;
if ( info . Length < min )
{
2025-02-27 09:22:57 +01:00
var required = Math . Max ( 1024 , min - info . Length ) ;
2025-04-10 14:54:49 +02:00
status . Padding = paddingMessage + RandomUtils . GenerateRandomString ( required ) ;
2025-02-27 10:09:03 +01:00
statusFile . Save ( status ) ;
2025-02-27 09:15:28 +01:00
}
}
2025-02-26 16:17:20 +01:00
private FileSaver CreateFileSaver ( string folderFile , FileStatus entry )
{
var fixedLength = entry . Filename . PadRight ( 35 ) ;
var prefix = $"[{fixedLength}] " ;
2025-05-02 08:21:56 +02:00
return new FileSaver ( new LogPrefixer ( app . Log , prefix ) , loadBalancer , status . Stats , folderFile , entry , this , slowModeHandler ) ;
2025-04-03 13:10:01 +02:00
}
public void SaveChanges ( )
{
statusFile . Save ( status ) ;
changeCounter + + ;
}
2025-02-26 16:17:20 +01:00
}
}