using System; using System.IO; namespace AppLimit.CloudComputing.SharpBox.Common.IO { /// /// Defines the action which will done from the streamhelper after calling the callback /// internal enum StreamHelperResultCodes { /// /// go forward with stream transfer /// OK, /// /// abort stream transfer /// Aborted, /// /// Parameters are invalid /// InvalidParameter } internal class StreamHelperResult { public StreamHelperResultCodes ResultCode; public long TransferedBytes; } internal class StreamHelperProgressEvent : EventArgs { /// /// Amount of bytes transfered in during this process /// public long ReadBytesTotal { get; set; } /// /// Amount of bytes which has to be transfered in this process /// public long TotalLength { get; set; } /// /// Amount of bytes transfered between this and the last event /// public long ReadBytesCurrentOperation { get; set; } /// /// The transfer rate in KBits per Second related to bytes totally transfered (ReadBytesTotal) /// public long TransferRateTotal { get; set; } /// /// The transfer rate in KBits per Second related to the last 500ms /// public long TransferRateCurrent { get; internal set; } /// /// Overall progress in percent /// public int PercentageProgress { get { if (TotalLength == -1) return -1; if (TotalLength == 0) return 100; return (int)((100*ReadBytesTotal)/TotalLength); } } } internal delegate StreamHelperResultCodes StreamHelperProgressCallback(object sender, StreamHelperProgressEvent e, params object[] data); internal class StreamHelper { private const int BufferSize = 4096; public static StreamHelperResult CopyStreamData(object sender, Stream src, Stream trg, StreamHelperProgressCallback status, params object[] data) { return CopyStreamData(sender, src, trg, -1, status, data); } public static StreamHelperResult CopyStreamData(object sender, Stream src, Stream trg, long MaxSize, StreamHelperProgressCallback status, params object[] data) { // validate parameter if (src == null || trg == null) return new StreamHelperResult { ResultCode = StreamHelperResultCodes.InvalidParameter }; if (src.CanRead == false || trg.CanWrite == false) return new StreamHelperResult { ResultCode = StreamHelperResultCodes.InvalidParameter }; // build the buffer as configured var buffer = new byte[BufferSize]; // set the real buffer size var RealBufferSize = BufferSize; // build the event for the status callback var e = new StreamHelperProgressEvent(); // copy the stream data int readBytes; var readBytesTotal = 0; var readBytes500msFrame = 0; var dtStart = DateTime.Now; var dt500MsWatch = DateTime.Now; var ts500MsWatch = new TimeSpan(); // set the total length if possible try { e.TotalLength = src.Length; } catch (Exception) { if (MaxSize != -1) e.TotalLength = MaxSize; else e.TotalLength = -1; } if (MaxSize != -1 && e.TotalLength > MaxSize) e.TotalLength = MaxSize; do { // Read the bytes readBytes = src.Read(buffer, 0, RealBufferSize); // add readBytesTotal += readBytes; readBytes500msFrame += readBytes; // check for interuption if (readBytes <= 0) break; // Write the bytes trg.Write(buffer, 0, readBytes); // notify state if (status != null) { // upadte the event e.ReadBytesTotal = readBytesTotal; e.ReadBytesCurrentOperation = readBytes; // call the callback var action = status(sender, e, data); // result if (action == StreamHelperResultCodes.Aborted) return new StreamHelperResult { ResultCode = StreamHelperResultCodes.Aborted, TransferedBytes = readBytesTotal }; } // stop measurement var dtLocalStop = DateTime.Now; // set the 500 ms span ts500MsWatch = dtLocalStop - dt500MsWatch; // check if we achieved 500 ms if (ts500MsWatch.TotalMilliseconds >= 500) { // update the current transfer rate e.TransferRateCurrent = readBytes500msFrame/Convert.ToInt64(ts500MsWatch.TotalMilliseconds); // bits per millisecond == kbits per second e.TransferRateCurrent *= 8; // reset the bytes readBytes500msFrame = 0; // reset the timespan ts500MsWatch = new TimeSpan(); // reset the start timer dt500MsWatch = DateTime.Now; } // recalc the overall transfer rate var consumedTimeAllOver = dtLocalStop - dtStart; if (Convert.ToInt64(consumedTimeAllOver.TotalMilliseconds) > 0) { // bytes per millisecond e.TransferRateTotal = readBytesTotal/Convert.ToInt64(consumedTimeAllOver.TotalMilliseconds); // bits per millisecond == kbits per second e.TransferRateTotal *= 8; } else e.TransferRateTotal = -1; // check the max size if (MaxSize != -1) { if (readBytesTotal >= MaxSize) break; // check if we have to asjust the buffer size if (MaxSize - readBytesTotal < RealBufferSize) { RealBufferSize = Convert.ToInt32(MaxSize - readBytesTotal); } } // check if we have } while (readBytes > 0); return new StreamHelperResult { ResultCode = StreamHelperResultCodes.OK, TransferedBytes = readBytesTotal }; } public static MemoryStream ToStream(string data) { // create the memory stream var mStream = new MemoryStream(); // write the data into var sw = new StreamWriter(mStream); sw.Write(data); sw.Flush(); // reset position mStream.Position = 0; // go ahead return mStream; } public static TimeSpan CalculateOperationTransferTime(StreamHelperProgressEvent e) { // calc transfertime if (e.TransferRateTotal != -1 && e.TransferRateTotal > 0) { var bytesPerSecond = (e.TransferRateTotal/8)*1000; if (bytesPerSecond > 0) { var neededSeconds = (e.TotalLength - e.ReadBytesTotal)/bytesPerSecond; return new TimeSpan(neededSeconds*TimeSpan.TicksPerSecond); } return new TimeSpan(long.MaxValue); } return new TimeSpan(long.MaxValue); } } }