public void Initialize(CommandLineApplication app, FileOperation fileOperation) { fileOperation.OperationStarted += FileOperationOnOperationStarted; fileOperation.ChunkFinished += FileOperationOnChunkFinished; //fileOperation.OperationCompleted += FileOperationOnOperationCompleted; fileOperation.Error += FileOperationOnError; fileOperation.RetryStarted += FileOperationOnRetryStarted; verification = fileOperation.Handlers.OfType <MD5Verification>().SingleOrDefault(); if (verification != null) { fileOperation.Handlers.Remove(verification); verification.FileHashComputed += FileOperationOnFileHashComputed; verification.MD5VerificationStarted += FileOperationOnMd5VerificationStarted; verification.MD5VerificationFinished += FileOperationOnMd5VerificationFinished; fileOperation.Handlers.Add(verification); } if ((fileOperation is FileCopyOperation || fileOperation is MultiThreadedFileCopy) && fileOperation.Options.HasFlag(FileOperationOptions.VerifyMD5)) { showVerificationStatus = true; OutputFormat += " {7}"; } ZCopyOutput.Print(OutputFormat, "File", "Size", "Copied", "Prog", "Speed", "Eta", "Elapsed", showVerificationStatus ? "MD5" : null); copyTimer = new Stopwatch(); hashTimer = new Stopwatch(); }
//private void OperationOnRetryStarted(object sender, FileOperationRetryStartedEventArgs e) //{ // throw new NotImplementedException(); //} #endregion #region Private methods private void ProgressThreadProc(object state) { var cancel = (CancellationToken)state; var progressFormat = new StringBuilder() .SavePosition() .Append("{0:N0} files(s) found | ") .Append($"{{1,-4}} {(isCopy ? "copied" : "moved")} | ") .Append("{2,-6} (avg.)" + EscapeCodes.EraseCharacters(10)) .RestorePosition() .ToString(); // Wait for at least 1 file to be found while (fileCount < 1 && !cancel.IsCancellationRequested) { Thread.Sleep(500); } // Loop throughout the lifetime of the file operation, displaying average stats while (!cancel.IsCancellationRequested) { var(speedBase, uom) = Helpers.GetCopySpeedBase(ZCopyConfiguration.CopySpeedUom); var speed = Helpers.GetCopySpeed(bytesCopied, speedBase, stopwatch.Elapsed); lock (lockObj) ZCopyOutput.Print(progressFormat, fileCount, new FileSize(bytesCopied), Helpers.CopySpeedToString(uom, speed)); Thread.Sleep(ZCopyConfiguration.RefreshInterval); } }
private static void PrintError(Exception e) { switch (e) { case AggregateException ae: foreach (var ie in ae.InnerExceptions) { PrintException(ie); } return; case TargetInvocationException _: e = e.InnerException; break; } if (ZCopyConfiguration.DisableAnsiConsole || (ZCopyConfiguration.Environment.DisableAnsiConsole ?? false)) { PrintException(e); } else { PrintExceptionAnsi(e); } #region Local functions void PrintExceptionAnsi(Exception ex) => ZCopyOutput.PrintError(ex.Message + " " + ex.InnerException?.Message); void PrintException(Exception ex) => Helpers.Print(ex.Message + " " + ex.InnerException?.Message, color: ConsoleColor.Red); #endregion }
private void FileOperationOnError(object sender, FileOperationErrorEventArgs e) { if (e.Exception is OperationCanceledException) { return; } ZCopyOutput.PrintError((e.Exception.Message + " " + e.Exception.InnerException?.Message).TrimEnd('\r', '\n'), false); }
private void MtfoOnError(object sender, FileOperationErrorEventArgs e) { if (e.Exception is OperationCanceledException) { return; } lock (lockObj) ZCopyOutput.PrintError(e.Exception.Message + " " + e.Exception.InnerException?.Message); }
public static void PrintHeader(CommandLineApplication app, FileOperation operation) { var zcopyMetadata = typeof(ZCopyCommand).GetCustomAttribute <CommandAttribute>(); ZCopyOutput.Print($"\r\n{GetVersion()}\r\n"); ZCopyOutput.Print($"{zcopyMetadata.Name} - {zcopyMetadata.Description}\r\n"); ZCopyOutput.Print($"Started {(ZCopyConfiguration.UseUtc ? DateTime.UtcNow : DateTime.Now).ToString("dddd, MMM dd yyyy hh:mm tt" + (ZCopyConfiguration.UseUtc ? "" : " (zzzz)"))}\r\n"); const string fmt = " {0} {1}\r\n"; ZCopyOutput.Print(fmt, FormatHeader("Source"), operation.Source.FullName); ZCopyOutput.Print(fmt, FormatHeader("Destination"), operation.Destination.FullName); ZCopyOutput.Print(fmt, FormatHeader("Files"), app.Arguments[2].Values.Any() ? string.Join(", ", app.Arguments[2].Values) : "*.*"); ZCopyOutput.Print(fmt, FormatHeader("Options"), GetUserOptions()); ZCopyOutput.Print(); #region Local functions string FormatHeader(string value) { return(value.PadLeft(12).ColorText(EscapeCodes.ForegroundCyan)); } string GetUserOptions() { var args = Environment.GetCommandLineArgs(); var userOptBldr = new StringBuilder(); for (var i = 0; i < args.Length; i++) { if (args[i][0] != '-' && i <= 3) { continue; } userOptBldr.Append(args[i] + " "); } return(userOptBldr.ToString()); } #endregion }
private void FileOperationOnOperationStarted(object sender, FileOperationStartedEventArgs e) { handlerControl.WaitOne(); currentFile = e.FullPath.Replace("\\\\?\\UNC", "\\"); sourceVerificationComplete = false; targetVerificationComplete = false; verificationResult = false; var dir = Path.GetDirectoryName(currentFile); if (currentDir != dir) { currentDir = dir; ZCopyOutput.Print($"\r\n\r\n Directory: {currentDir}"); } Console.SetCursorPosition(0, currentCursorTop = cursorTop + 1); copyTimer.Restart(); handlerControl.ReleaseMutex(); }
public static void PrintFooter(FileOperation operation) { Console.SetCursorPosition(0, Console.CursorTop + 2); var stats = operation.Statistics; var transferred = new FileSize(stats.BytesTransferred); var elapsed = stopwatch.Elapsed; var elapsedFmt = new StringBuilder() .AppendIf(elapsed.TotalDays > 1, "dd\\d") .AppendIf(elapsed.TotalHours > 1, "hh\\h") .AppendIf(elapsed.TotalMinutes > 1, "mm\\m") .Append("ss\\.fff\\s").ToString(); var(speedbase, uom) = Helpers.GetCopySpeedBase(ZCopyConfiguration.CopySpeedUom); var speed = Helpers.GetCopySpeed(stats.BytesTransferred, speedbase, elapsed); ZCopyOutput.Print($"{elapsed.ToString(elapsedFmt)} elapsed | " + $"{stats.TotalFiles} file(s) ({transferred}) {(operation is FileMoveOperation ? "moved" : "copied")} | " + $"{Helpers.CopySpeedToString(uom, speed)} (avg)"); ZCopyOutput.Print(cancellation.IsCancellationRequested? "\r\nThe operation was cancelled" : "The operation completed successfully"); }
private void FileOperationOnRetryStarted(object sender, FileOperationRetryStartedEventArgs e) { // Using a ThreadPool thread so that the caller is not blocked ThreadPool.QueueUserWorkItem(RetryIntervalProgressProc); void RetryIntervalProgressProc(object state) { var timer = Stopwatch.StartNew(); var format = $"{EscapeCodes.SavePosition()}{{0}}{EscapeCodes.RestorePosition()}"; ZCopyOutput.PrintError(e.Reason.Message + " " + e.Reason.InnerException?.Message, false); while (timer.ElapsedMilliseconds < e.RetryInterval.TotalMilliseconds) { ZCopyOutput.Print(format, $"Retrying in {e.RetryInterval - timer.Elapsed:mm\\mss\\s}"); } timer.Stop(); ZCopyOutput.Print(); } }
public void Deinitialize(CommandLineApplication app, FileOperation operation) { ZCopyOutput.Print("\u001b[1M\u001b[2A"); cancellation?.Cancel(); cancellation?.Dispose(); }
//private void FileOperationOnOperationCompleted(object sender, FileOperationCompletedEventArgs e) //{ // // Not used currently //} private void FileOperationOnChunkFinished(object sender, FileOperationChunkFinishedEventArgs e) { handlerControl.WaitOne(); currentCursorTop = cursorTop; if (DateTime.Now - refreshed < ZCopyConfiguration.RefreshInterval && e.PercentComplete < 100.00) { return; } var(speedBase, uom) = Helpers.GetCopySpeedBase(ZCopyConfiguration.CopySpeedUom); var speed = Helpers.GetCopySpeed(e.BytesCopied, speedBase, copyTimer.Elapsed - hashTimer.Elapsed); var elapsed = copyTimer.ElapsedMilliseconds < 1000 ? "<1s" : copyTimer.Elapsed.ToString("hh\\hmm\\mss\\s"); ZCopyOutput.Print(OutputFormat, TruncateFileName(Path.GetFileName(currentFile), 50), new FileSize(e.SourceFile.Length), new FileSize(e.BytesCopied), PercentComplete(), Helpers.CopySpeedToString(uom, speed).PadLeft(uom.Length < 3 ? 10 : 11), Helpers.EtaToString(Helpers.GetTimeRemaining(e.SourceFile.Length, e.BytesCopied, speed, speedBase)), elapsed, VerificationStatus()?.PadRight(10)); Console.SetCursorPosition(0, currentCursorTop); refreshed = DateTime.Now; handlerControl.ReleaseMutex(); #region Local functions string TruncateFileName(string value, int maxLength) { if (value.Length <= maxLength) { return(value); } return(value.Substring(0, maxLength / 2 - 3) + "..." + value.Substring(value.Length - maxLength / 2)); } string PercentComplete() { return(e.PercentComplete.ToString("N0") + '%'); } string VerificationStatus() { if (!showVerificationStatus) { return(null); } if (!sourceVerificationComplete) { return("Waiting"); } if (targetVerificationComplete) { return((verificationResult ? "OK".ColorText(EscapeCodes.ForegroundGreen) : "Failed".ColorText(EscapeCodes.ForegroundRed)) + EscapeCodes.EraseCharacters(8)); } return("Verifying"); } #endregion }