// Copyright (C) 2013, Duplicati Team // http://www.duplicati.com, info@duplicati.com // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; namespace Duplicati.Library.Main { /// /// Interface for recieving messages from the Duplicati operations /// public interface IMessageSink { void BackendEvent(BackendActionType action, BackendEventType type, string path, long size); void VerboseEvent(string message, object[] args); void MessageEvent(string message); void RetryEvent(string message, Exception ex); void WarningEvent(string message, Exception ex); void ErrorEvent(string message, Exception ex); void DryrunEvent(string message); /// /// Sets the backend progress update object /// /// The backend progress update object IBackendProgress BackendProgress { set; } /// /// Sets the operation progress update object /// /// The operation progress update object IOperationProgress OperationProgress { set; } } /// /// Backend progress update object. /// The engine updates these statistics very often, /// so an event based system would take up too many resources. /// Instead, this interface allows the client to poll /// for updates as often as desired. /// public interface IBackendProgress { /// /// Update with the current action, path, size, progress and bytes_pr_second. /// /// The current action /// The current path /// The current size /// The current number of transferred bytes /// Transfer speed in bytes pr second, -1 for unknown void Update(out BackendActionType action, out string path, out long size, out long progress, out long bytes_pr_second); } /// /// Interface for updating the backend progress /// internal interface IBackendProgressUpdater { /// /// Register the start of a new action /// /// The action that is starting /// The path being operated on /// The size of the file being transferred void StartAction(BackendActionType action, string path, long size); /// /// Updates the current progress /// /// he current number of transferred bytes void UpdateProgress(long progress); } /// /// Combined interface for the backend progress updater and the backend progress item /// internal interface IBackendProgressUpdaterAndReporter : IBackendProgressUpdater, IBackendProgress { } /// /// Backend progress updater instance /// internal class BackendProgressUpdater : IBackendProgressUpdaterAndReporter { /// /// Lock object to provide snapshot-like access to the data /// private readonly object m_lock = new object(); /// /// The current action /// private BackendActionType m_action; /// /// The current path /// private string m_path; /// /// The current file size /// private long m_size; /// /// The current number of transferred bytes /// private long m_progress; /// /// The time the last action started /// private DateTime m_actionStart; /// /// Register the start of a new action /// /// The action that is starting /// The path being operated on /// The size of the file being transferred public void StartAction(BackendActionType action, string path, long size) { lock(m_lock) { m_action = action; m_path = path; m_size = size; m_progress = 0; m_actionStart = DateTime.Now; } } /// /// Updates the progress /// /// The current number of transferred bytes public void UpdateProgress(long progress) { lock(m_lock) m_progress = progress; } /// /// Update with the current action, path, size, progress and bytes_pr_second. /// /// The current action /// The current path /// The current size /// The current number of transferred bytes /// Transfer speed in bytes pr second, -1 for unknown public void Update(out BackendActionType action, out string path, out long size, out long progress, out long bytes_pr_second) { lock(m_lock) { action = m_action; path = m_path; size = m_size; progress = m_progress; //TODO: The speed should be more dynamic, // so we need a sample window instead of always // calculating from the beginning if (m_progress <= 0 || m_size <= 0 || m_actionStart.Ticks == 0) bytes_pr_second = -1; else bytes_pr_second = (long)(m_progress / (DateTime.Now - m_actionStart).TotalSeconds); } } } public delegate void PhaseChangedDelegate(OperationPhase phase, OperationPhase previousPhase); /// /// Operation progress update object. /// The engine updates these statistics very often, /// so an event based system would take up too many resources. /// Instead, this interface allows the client to poll /// for updates as often as desired. /// public interface IOperationProgress { /// /// Update the phase, progress, filesprocessed, filesizeprocessed, filecount, filesize and countingfiles. /// /// Phase. /// Progress. /// Filesprocessed. /// Filesizeprocessed. /// Filecount. /// Filesize. /// True if the filecount and filesize is incomplete, false otherwise void UpdateOverall(out OperationPhase phase, out float progress, out long filesprocessed, out long filesizeprocessed, out long filecount, out long filesize, out bool countingfiles); /// /// Update the filename, filesize, and fileoffset. /// /// Filename. /// Filesize. /// Fileoffset. void UpdateFile(out string filename, out long filesize, out long fileoffset); /// /// Occurs when the phase has changed /// event PhaseChangedDelegate PhaseChanged; } /// /// Interface for updating the backend progress /// internal interface IOperationProgressUpdater { void UpdatePhase(OperationPhase phase); void UpdateProgress(float progress); void StartFile(string filename, long size); void UpdateFileProgress(long offset); void UpdatefileCount(long filecount, long filesize, bool done); void UpdatefilesProcessed(long count, long size); } internal interface IOperationProgressUpdaterAndReporter : IOperationProgressUpdater, IOperationProgress { } internal class OperationProgressUpdater : IOperationProgressUpdaterAndReporter { private readonly object m_lock = new object(); private OperationPhase m_phase; private float m_progress; private string m_curfilename; private long m_curfilesize; private long m_curfileoffset; private long m_filesprocessed; private long m_filesizeprocessed; private long m_filecount; private long m_filesize; private bool m_countingFiles; public event PhaseChangedDelegate PhaseChanged; public void UpdatePhase(OperationPhase phase) { OperationPhase prev_phase; lock(m_lock) { prev_phase = m_phase; m_phase = phase; m_curfilename = null; m_curfilesize = 0; m_curfileoffset = 0; } if (prev_phase != phase && PhaseChanged != null) PhaseChanged(phase, prev_phase); } public void UpdateProgress(float progress) { lock(m_lock) m_progress = progress; } public void StartFile(string filename, long size) { lock(m_lock) { m_curfilename = filename; m_curfilesize = size; m_curfileoffset = 0; } } public void UpdateFileProgress(long offset) { lock(m_lock) m_curfileoffset = offset; } public void UpdatefileCount(long filecount, long filesize, bool done) { lock(m_lock) { m_filecount = filecount; m_filesize = filesize; m_countingFiles = !done; } } public void UpdatefilesProcessed(long count, long size) { lock(m_lock) { m_filesprocessed = count; m_filesizeprocessed = size; } } /// /// Update the phase, progress, filesprocessed, filesizeprocessed, filecount, filesize and countingfiles. /// /// Phase. /// Progress. /// Filesprocessed. /// Filesizeprocessed. /// Filecount. /// Filesize. /// True if the filecount and filesize is incomplete, false otherwise public void UpdateOverall(out OperationPhase phase, out float progress, out long filesprocessed, out long filesizeprocessed, out long filecount, out long filesize, out bool countingfiles) { lock(m_lock) { phase = m_phase; filesize = m_filesize; progress = m_progress; filesprocessed = m_filesprocessed; filesizeprocessed = m_filesizeprocessed; filecount = m_filecount; countingfiles = m_countingFiles; } } /// /// Update the filename, filesize, and fileoffset. /// /// Filename. /// Filesize. /// Fileoffset. public void UpdateFile(out string filename, out long filesize, out long fileoffset) { lock(m_lock) { filename = m_curfilename; filesize = m_curfilesize; fileoffset = m_curfileoffset; } } } }