diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj index 4305f2e02..030ee6c9f 100644 --- a/src/NzbDrone.Common/NzbDrone.Common.csproj +++ b/src/NzbDrone.Common/NzbDrone.Common.csproj @@ -215,9 +215,11 @@ + + diff --git a/src/NzbDrone.Common/Timeline/ProgressReporter.cs b/src/NzbDrone.Common/Timeline/ProgressReporter.cs new file mode 100644 index 000000000..6bf4ac6bb --- /dev/null +++ b/src/NzbDrone.Common/Timeline/ProgressReporter.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Common.Timeline +{ + public interface IProgressReporter + { + long Raw { get; } + long Total { get; } + double Progress { get; } + + void UpdateProgress(long currentProgress, long maxProgress); + void FinishProgress(); + } + + public class ProgressReporter : IProgressReporter + { + private readonly int _maxSteps; + + public long Raw { get; protected set; } + public long Total { get; private set; } + + public double Progress => Total == 0 ? 1.0 : Math.Min(Raw, Total) / Total; + + //public TimeSpan? EstimatedDurationRemaining { get; private set; } + + public ProgressReporter(long initialProgress, long maxProgress, int maxSteps = 100) + { + _maxSteps = maxSteps; + + Raw = initialProgress; + Total = maxProgress; + } + + public void UpdateProgress(long currentProgress, long maxProgress) + { + bool shouldRaiseEvent; + + lock (this) + { + var oldRaw = Raw; + var oldTotal = Total; + + Raw = currentProgress; + Total = Total; + + var oldStep = oldTotal <= 0 ? _maxSteps : oldRaw * _maxSteps / oldTotal; + var newStep = Total <= 0 ? _maxSteps : Raw * _maxSteps / Total; + + shouldRaiseEvent = (oldStep != newStep); + } + + if (shouldRaiseEvent) + { + RaiseEvent(); + } + } + + public void FinishProgress() + { + lock (this) + { + Raw = Total; + } + + RaiseEvent(); + } + + protected virtual void RaiseEvent() + { + // TODO + } + + } +} diff --git a/src/NzbDrone.Common/Timeline/TimelineContext.cs b/src/NzbDrone.Common/Timeline/TimelineContext.cs new file mode 100644 index 000000000..b140a4e6e --- /dev/null +++ b/src/NzbDrone.Common/Timeline/TimelineContext.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Common.Timeline +{ + public enum TimelineState + { + Pending, + Started, + Completed, + Failed + } + + public interface ITimelineContext : IProgressReporter + { + string Name { get; } + TimelineState State { get; } + + void UpdateState(TimelineState state); + ITimelineContext AppendTimeline(string name, long initialProgress = 0, long maxProgress = 1); + void AppendTimeline(ITimelineContext timeline); + } + + public class TimelineContext : ProgressReporter, ITimelineContext + { + private List _timelines = new List(); + + public string Name { get; private set; } + public TimelineState State { get; private set; } + + public IEnumerable Timelines + { + get + { + lock (this) + { + return _timelines.ToArray(); + } + } + } + + public TimelineContext(string name, long initialProgress, long maxProgress) + : base(initialProgress, maxProgress) + { + Name = name; + } + + public void UpdateState(TimelineState state) + { + lock (this) + { + State = state; + + if (State == TimelineState.Completed || State == TimelineState.Failed) + { + Raw = Total; + } + } + + RaiseEvent(); + } + + public ITimelineContext AppendTimeline(string name, long initialProgress = 0, long maxProgress = 1) + { + lock (this) + { + var timeline = new TimelineContext(name, initialProgress, maxProgress); + _timelines.Add(timeline); + return timeline; + } + } + + public void AppendTimeline(ITimelineContext timeline) + { + lock (this) + { + _timelines.Add(timeline); + } + } + + protected override void RaiseEvent() + { + lock (this) + { + if (Raw == Total) + { + State = TimelineState.Completed; + } + else + { + State = TimelineState.Started; + } + } + + base.RaiseEvent(); + } + } +}