コード例 #1
0
        public static long CopyFileToStream(string filePath, Stream outStream, ProgressUpdateCallback progress, CancellationToken cancellationToken)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException(nameof(filePath));
            }
            var downloadSize = 0L;
            var array        = new byte[32768];

            using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var readSize = fileStream.Read(array, 0, array.Length);
                cancellationToken.ThrowIfCancellationRequested();
                if (readSize <= 0)
                {
                    break;
                }
                outStream.Write(array, 0, readSize);
                downloadSize += readSize;
                progress?.Invoke(new ProgressUpdateStatus(downloadSize, fileStream.Length, 0.0));
            }
            if (downloadSize != fileStream.Length)
            {
                throw new IOException("Internal error copying streams. Total read bytes does not match stream Length.");
            }
            return(downloadSize);
        }
コード例 #2
0
 private static void RegisterProgressUpdateCallback(Action <double> whatToDo)
 {
     // Many thanks to http://www.codeproject.com/Tips/318140/How-to-make-a-callback-to-Csharp-from-C-Cplusplus
     // for providing a solution that worked, in terms of what calling convention to use.
     // I tried a few things before that - there is a lot of other (incorrect?) information
     // that did not work (probably my bad, still).
     callback = null;
     callback = new ProgressUpdateCallback(whatToDo);
     RegisterProgressUpdateCallbackNative(callback);
 }
コード例 #3
0
        public static List<uint> ByteArrayFindAll(byte[] InputBuffer, byte[] ToSearch, ProgressUpdateCallback ProgressCallback)
        {
            List<uint> Found = new List<uint>();

            for (int i = 0; i < InputBuffer.Length - ToSearch.Length; i++)
            {
                if (ProgressCallback != null)
                {
                    ProgressCallback((int)Math.Round(((double)i / (double)InputBuffer.Length) * 100));
                }

                if (BComp(InputBuffer, i, ToSearch))
                {
                    Found.Add((uint)i);
                }
            }

            return Found;
        }
コード例 #4
0
        public Task <DownloadSummary> DownloadAsync(Uri uri, Stream outputStream, ProgressUpdateCallback progress, CancellationToken cancellationToken,
                                                    IComponent?component = default, bool verify = false)
        {
            Logger.Trace($"Download requested: {uri.AbsoluteUri}");
            if (outputStream == null)
            {
                throw new ArgumentNullException(nameof(outputStream));
            }
            if (!outputStream.CanWrite)
            {
                throw new InvalidOperationException("Input stream must be writable.");
            }
            if (!uri.IsFile && !uri.IsUnc)
            {
                if (!string.Equals(uri.Scheme, "http", StringComparison.OrdinalIgnoreCase) && !string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase) && !string.Equals(uri.Scheme, "ftp", StringComparison.OrdinalIgnoreCase))
                {
                    var argumentException = new ArgumentException($"Uri scheme '{uri.Scheme}' is not supported.");
                    Logger?.Trace($"Uri scheme '{uri.Scheme}' is not supported. {argumentException.Message}");
                    throw argumentException;
                }
                if (uri.AbsoluteUri.Length < 7)
                {
                    var argumentException = new ArgumentException($"Invalid Uri: {uri.AbsoluteUri}.");
                    Logger?.Trace($"The Uri is too short: {uri.AbsoluteUri}; {argumentException.Message}");
                    throw argumentException;
                }
            }

            try
            {
                var engines = GetSuitableEngines(_defaultEngines, uri);
                return(Task.Factory.StartNew(() => DownloadWithRetry(engines, uri, outputStream, progress,
                                                                     cancellationToken, component, verify), cancellationToken,
                                             TaskCreationOptions.LongRunning, TaskScheduler.Default));
            }
            catch (Exception ex)
            {
                Logger.Trace($"Unable to get download engine: {ex.Message}");
                throw;
            }
        }
コード例 #5
0
        private DownloadSummary DownloadWithBitRate(Uri uri, Stream outputStream, ProgressUpdateCallback progress, CancellationToken cancellationToken, IComponent?component)
        {
            var now = DateTime.Now;
            var lastProgressUpdate = now;
            ProgressUpdateCallback wrappedProgress = null;

            if (progress != null)
            {
                wrappedProgress = p =>
                {
                    var now2     = DateTime.Now;
                    var timeSpan = now2 - lastProgressUpdate;
                    var bitRate  = 8.0 * p.BytesRead / timeSpan.TotalSeconds;
                    progress(new ProgressUpdateStatus(p.BytesRead, p.TotalBytes, bitRate));
                    lastProgressUpdate = now2;
                }
            }
            ;
            var downloadSummary = DownloadCore(uri, outputStream, wrappedProgress, cancellationToken, component);

            downloadSummary.DownloadTime = DateTime.Now - now;
            downloadSummary.BitRate      = 8.0 * downloadSummary.DownloadedSize / downloadSummary.DownloadTime.TotalSeconds;
            return(downloadSummary);
        }
コード例 #6
0
 protected override DownloadSummary DownloadCore(Uri uri, Stream outputStream, ProgressUpdateCallback progress,
                                                 CancellationToken cancellationToken, IComponent?component)
 {
     if (!uri.IsFile && !uri.IsUnc)
     {
         throw new ArgumentException("Expected file or UNC path", nameof(uri));
     }
     return(new DownloadSummary
     {
         DownloadedSize = UpdaterUtilities.CopyFileToStream(uri.LocalPath, outputStream, progress, cancellationToken)
     });
 }
コード例 #7
0
        private DownloadSummary DownloadWithRetry(IDownloadEngine[] engines, Uri uri, Stream outputStream, ProgressUpdateCallback progress, CancellationToken cancellationToken, IComponent?component = null, bool verify = false)
        {
            var failureList = new List <DownloadFailureInformation>();

            foreach (var engine in engines)
            {
                var position = outputStream.Position;
                var length   = outputStream.Length;
                try
                {
                    Logger.Trace($"Attempting download '{uri.AbsoluteUri}' using engine '{engine.Name}'");
                    var engineSummary = engine.Download(uri, outputStream, status =>
                    {
                        progress?.Invoke(new ProgressUpdateStatus(engine.Name, status.BytesRead, status.TotalBytes, status.BitRate));
                    }, cancellationToken,
                                                        component);
                    if (outputStream.Length == 0 && !UpdateConfiguration.Instance.AllowEmptyFileDownload)
                    {
                        var exception = new UpdaterException($"Empty file downloaded on '{uri}'.");
                        Logger?.Error(exception, exception.Message);
                        throw exception;
                    }

                    if (verify && outputStream.Length != 0)
                    {
                        if (component is null)
                        {
                            if (UpdateConfiguration.Instance.ValidationPolicy == ValidationPolicy.Enforce)
                            {
                                throw new ValidationFailedException(DownloadResult.MissingOrInvalidValidationContext,
                                                                    "Unable to get necessary validation data because download context is null.");
                            }
                        }
                        else
                        {
                            var componentValidationContext = component.OriginInfo?.ValidationContext;
                            var valid = componentValidationContext?.Verify();

                            if ((!valid.HasValue || !valid.Value) && UpdateConfiguration.Instance.ValidationPolicy == ValidationPolicy.Enforce)
                            {
                                throw new ValidationFailedException(DownloadResult.MissingOrInvalidValidationContext,
                                                                    $"Component '{component.Name}' is missing or has an invalid ValidationInfo");
                            }

                            if (valid.HasValue && valid.Value)
                            {
                                var validationResult = HashVerifier.Verify(outputStream, componentValidationContext);
                                engineSummary.ValidationResult = validationResult;
                                if (validationResult == ValidationResult.HashMismatch)
                                {
                                    var exception = new ValidationFailedException(DownloadResult.HashMismatch,
                                                                                  $"Hash on downloaded file '{uri.AbsoluteUri}' does not match expected value.");
                                    Logger?.Error(exception, exception.Message);
                                    throw exception;
                                }
                            }
                            else
                            {
                                Logger.Trace($"Skipping validation because validation context of Component {component.Name} is not valid.");
                            }
                        }
                    }

                    Logger?.Info($"Download of '{uri.AbsoluteUri}' succeeded using engine '{engine.Name}'");
                    PreferredDownloadEngines.Instance.LastSuccessfulEngineName = engine.Name;
                    engineSummary.DownloadEngine = engine.Name;
                    return(engineSummary);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    failureList.Add(new DownloadFailureInformation(ex, engine.Name));
                    Logger.Trace($"Download failed using {engine.Name} engine. {ex}");

                    if (engine.Equals(engines.LastOrDefault()))
                    {
                        throw new DownloadFailureException(failureList);
                    }

                    cancellationToken.ThrowIfCancellationRequested();
                    outputStream.SetLength(length);
                    outputStream.Seek(position, SeekOrigin.Begin);
                    var millisecondsTimeout = SleepDurationBetweenRetries;
                    if (millisecondsTimeout < 0)
                    {
                        millisecondsTimeout = 0;
                    }
                    Logger.Trace($"Sleeping {millisecondsTimeout} before retrying download.");
                    Thread.Sleep(millisecondsTimeout);
                }
            }
            return(null);
        }
コード例 #8
0
ファイル: MeComG2Cmd.cs プロジェクト: intvenlab/AutoDefrost
        /// <summary>
        /// Writes an array of FLOAT32, INT32, DOUBLE64 or ASCII (char) values to the device.
        /// The data length is given by the value parameter.
        /// This method does only return when all data is downloaded.
        /// The data is being written in an loop with several sub queries.
        /// During this command is working, it is possible to use other commands with an different thread.
        /// </summary>
        /// <param name="address">Device Address. Use null to use the DefaultDeviceAddress defined on MeComQuerySet.</param>
        /// <param name="parameterId">Device Parameter ID.</param>
        /// <param name="instance">Parameter Instance. (usually 1)</param>
        /// <param name="type">Specifies the type of the value to be written.</param>
        /// <param name="values">Data to be written (can be float[], int[], double[] or string.</param>
        /// <param name="callback">Is called every time when the progress has changed.</param>
        /// <exception cref="ComCommandException">when the command fails. Check the inner exception for details.</exception>
        public void SetBigData(byte?address, UInt16 parameterId, byte instance, MeParType type, dynamic values, ProgressUpdateCallback callback)
        {
            int maxDataSize            = meQuerySet.MaxTxPayloadSize - 22; //-xx Bytes used for commands
            int nrOfElementsPerPackage = 0;

            switch (type)
            {
            case MeParType.FLOAT32:
                nrOfElementsPerPackage = maxDataSize / 8;
                break;

            case MeParType.INT32:
                nrOfElementsPerPackage = maxDataSize / 8;
                break;

            case MeParType.DOUBLE64:
                nrOfElementsPerPackage = maxDataSize / 16;
                break;

            case MeParType.LATIN1:
                values += (char)0;     //Add zero terminator
                nrOfElementsPerPackage = maxDataSize / 2;
                break;

            case MeParType.BYTE:
                nrOfElementsPerPackage = maxDataSize / 2;
                break;

            default:
                throw new ArgumentOutOfRangeException("Unknown EParType: " + type);
            }
            int nrOfPackages = (values.Length - 1) / nrOfElementsPerPackage + 1;

            try
            {
                int          totalSentElements = 0;
                MemoryStream totalStream       = new MemoryStream();

                for (int packageNr = 0; packageNr < nrOfPackages; packageNr++)
                {
                    bool lastPackage = (packageNr + 1) == nrOfPackages;
                    int  nrOfElementsInThisPackage = values.Length - totalSentElements;
                    if (nrOfElementsInThisPackage > nrOfElementsPerPackage)
                    {
                        nrOfElementsInThisPackage = nrOfElementsPerPackage;
                    }

                    MeComPacket txFrame = new MeComPacket('#', address);
                    MeComVarConvert.AddString(txFrame.Payload, "VB");
                    MeComVarConvert.AddUint16(txFrame.Payload, parameterId);
                    MeComVarConvert.AddUint8(txFrame.Payload, instance);
                    MeComVarConvert.AddUint32(txFrame.Payload, (uint)totalSentElements); //write start position
                    MeComVarConvert.AddUint16(txFrame.Payload, (ushort)nrOfElementsInThisPackage);
                    if (lastPackage)
                    {
                        MeComVarConvert.AddUint8(txFrame.Payload, 1);
                    }
                    else
                    {
                        MeComVarConvert.AddUint8(txFrame.Payload, 0);
                    }

                    switch (type)
                    {
                    case MeParType.FLOAT32:
                        for (int i = 0; i < nrOfElementsInThisPackage; i++)
                        {
                            MeComVarConvert.AddFloat32(txFrame.Payload, values[totalSentElements + i]);
                        }
                        break;

                    case MeParType.INT32:
                        for (int i = 0; i < nrOfElementsInThisPackage; i++)
                        {
                            MeComVarConvert.AddUint32(txFrame.Payload, values[totalSentElements + i]);
                        }
                        break;

                    case MeParType.DOUBLE64:
                        for (int i = 0; i < nrOfElementsInThisPackage; i++)
                        {
                            MeComVarConvert.AddDouble64(txFrame.Payload, values[totalSentElements + i]);
                        }
                        break;

                    case MeParType.LATIN1:
                        MeComVarConvert.AddEncodedString(txFrame.Payload, values.Substring(totalSentElements, nrOfElementsInThisPackage));
                        break;

                    case MeParType.BYTE:
                        for (int i = 0; i < nrOfElementsInThisPackage; i++)
                        {
                            MeComVarConvert.AddUint8(txFrame.Payload, values[totalSentElements + i]);
                        }
                        break;
                    }
                    int timeout = 0;
                    while (timeout < 50) //Manage device busy
                    {
                        timeout++;
                        try
                        {
                            meQuerySet.Set(txFrame);
                            break;
                        }
                        catch (ServerException ex)
                        {
                            if (ex.ServerErrorCode != 2)
                            {
                                throw;
                            }
                            TraceLog.Verbose("Device busy detected. Timeout {0}", timeout);
                            Thread.Sleep(10);
                        }
                    }

                    totalSentElements += nrOfElementsInThisPackage;
                    callback?.Invoke(100.0 / nrOfPackages * (packageNr + 1));
                }
            }
            catch (Exception Ex)
            {
                throw new ComCommandException(String.Format("Set Value failed: Address: {0}; ID: {1}; Inst: {2}; Detail: {3}", address, parameterId, instance, Ex.Message), Ex);
            }
        }
コード例 #9
0
ファイル: MeComG2Cmd.cs プロジェクト: intvenlab/AutoDefrost
        /// <summary>
        /// Reads an array of FLOAT32, INT32, DOUBLE64 or ASCII (char) values form the device.
        /// The data length is given by the device.
        /// This method does only return when the device tells the host, that all data is read.
        /// The data is read in an loop with several sub queries.
        /// During this command is working, it is possible to use other commands with an different thread.
        /// </summary>
        /// <param name="address">Device Address. Use null to use the DefaultDeviceAddress defined on MeComQuerySet.</param>
        /// <param name="parameterId">Device Parameter ID.</param>
        /// <param name="instance">Parameter Instance. (usually 1)</param>
        /// <param name="type">Specifies the type of the value to be read.</param>
        /// <param name="callback">Is called every time when the progress has changed.</param>
        /// <param name="expectedNrOfElements">Defines the expected number of elements to calculate the progress for the callback function.</param>
        /// <returns>Returned value.</returns>
        /// <exception cref="ComCommandException">when the command fails. Check the inner exception for details.</exception>
        public dynamic GetBigData(byte?address, UInt16 parameterId, byte instance, MeParType type, ProgressUpdateCallback callback = null, int expectedNrOfElements = 0)
        {
            dynamic value;

            try
            {
                ushort       rcvElements;
                bool         hasMoreData;
                uint         totalReadElements = 0;
                MemoryStream totalStream       = new MemoryStream();

                do
                {
                    MeComPacket txFrame = new MeComPacket('#', address);
                    MeComVarConvert.AddString(txFrame.Payload, "?VB");
                    MeComVarConvert.AddUint16(txFrame.Payload, parameterId);
                    MeComVarConvert.AddUint8(txFrame.Payload, instance);
                    MeComVarConvert.AddUint32(txFrame.Payload, totalReadElements); //Read start position
                    MeComVarConvert.AddUint16(txFrame.Payload, UInt16.MaxValue);   //Maximum Elements to read per call.

                    MeComPacket rxFrame = meQuerySet.Query(txFrame);
                    rcvElements        = MeComVarConvert.ReadUint16(rxFrame.Payload);
                    hasMoreData        = MeComVarConvert.ReadUint8(rxFrame.Payload) == 1;
                    totalReadElements += rcvElements;
                    if (rcvElements > 0)
                    {
                        rxFrame.Payload.CopyTo(totalStream);
                    }

                    callback?.Invoke(100.0 / expectedNrOfElements * totalReadElements);
                } while (hasMoreData);

                totalStream.Position = 0;

                callback?.Invoke(100);

                switch (type)
                {
                case MeParType.FLOAT32:
                    value = new float[totalReadElements];
                    break;

                case MeParType.INT32:
                    value = new int[totalReadElements];
                    break;

                case MeParType.DOUBLE64:
                    value = new double[totalReadElements];
                    break;

                case MeParType.LATIN1:
                    value = "";
                    break;

                case MeParType.BYTE:
                    value = new byte[totalReadElements];
                    break;

                default:
                    throw new ArgumentOutOfRangeException("Unknown EParType: " + type);
                }

                for (int i = 0; i < totalReadElements; i++)
                {
                    switch (type)
                    {
                    case MeParType.FLOAT32:
                        value[i] = MeComVarConvert.ReadFloat32(totalStream);
                        break;

                    case MeParType.INT32:
                        value[i] = MeComVarConvert.ReadInt32(totalStream);
                        break;

                    case MeParType.DOUBLE64:
                        value[i] = MeComVarConvert.ReadDouble64(totalStream);
                        break;

                    case MeParType.LATIN1:
                        value = MeComVarConvert.ReadEncodedString(totalStream, (int)totalReadElements);
                        return(value);

                    case MeParType.BYTE:
                        value[i] = MeComVarConvert.ReadUint8(totalStream);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("Unknown EParType: " + type);
                    }
                }
                return(value);
            }
            catch (Exception Ex)
            {
                throw new ComCommandException(String.Format("Get Value failed: Address: {0}; ID: {1}; Inst: {2}; Detail: {3}", address, parameterId, instance, Ex.Message), Ex);
            }
        }
コード例 #10
0
        protected override DownloadSummary DownloadCore(Uri uri, Stream outputStream, ProgressUpdateCallback progress,
                                                        CancellationToken cancellationToken, IComponent?component)
        {
            var summary = new DownloadSummary();

            using var webResponse = GetWebResponse(uri, ref summary, out var webRequest, cancellationToken);
            if (webResponse != null)
            {
                var registration1 = cancellationToken.Register(() => webResponse.Close());
                try
                {
                    using var responseStream = webResponse.GetResponseStream();
                    var header = webResponse.Headers["Content-Length"];
                    if (string.IsNullOrEmpty(header))
                    {
                        throw new IOException("Error: Content-Length is missing from response header.");
                    }
                    var totalStreamLength = (long)Convert.ToInt32(header);
                    if (totalStreamLength.Equals(0L))
                    {
                        throw new IOException("Error: Response stream length is 0.");
                    }
                    var streamReadError = false;
                    var totalBytesRead  = 0L;
                    var array           = new byte[Math.Max(1024L, Math.Min(totalStreamLength, 32768L))];
                    var registration2   = cancellationToken.Register(() => webRequest.Abort());
                    try
                    {
                        while (true)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            var bytesRead = responseStream.Read(array, 0, array.Length);
                            streamReadError = bytesRead < 0;
                            if (bytesRead <= 0)
                            {
                                break;
                            }
                            totalBytesRead += bytesRead;
                            outputStream.Write(array, 0, bytesRead);
                            if (totalStreamLength < totalBytesRead)
                            {
                                totalStreamLength = totalBytesRead;
                            }
                            progress?.Invoke(new ProgressUpdateStatus(totalBytesRead, totalStreamLength, 0));
                        }
                    }
                    finally
                    {
                        registration2.Dispose();
                    }
                    cancellationToken.ThrowIfCancellationRequested();
                    if (streamReadError)
                    {
                        throw new IOException("Internal error while downloading the stream.");
                    }
                    summary.DownloadedSize = totalBytesRead;
                    return(summary);
                }
                catch (WebException ex)
                {
                    var message = cancellationToken.IsCancellationRequested
                        ? "DownloadCore failed along with a cancellation request."
                        : "DownloadCore failed";
                    if (cancellationToken.IsCancellationRequested)
                    {
                        Logger.Trace("WebClient error '" + ex.Status + "' with '" + uri.AbsoluteUri + "' - " +
                                     message);
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                    else
                    {
                        Logger.Trace("WebClient error '" + ex.Status + "' with '" + uri.AbsoluteUri + "'.");
                        throw;
                    }
                }
                finally
                {
                    registration1.Dispose();
                }
            }

            return(summary);
        }
コード例 #11
0
        public static List <uint> ByteArrayFindAll(byte[] InputBuffer, byte[] ToSearch, ProgressUpdateCallback ProgressCallback)
        {
            List <uint> Found = new List <uint>();

            for (int i = 0; i < InputBuffer.Length - ToSearch.Length; i++)
            {
                if (ProgressCallback != null)
                {
                    ProgressCallback((int)Math.Round((i / (double)InputBuffer.Length) * 100));
                }

                if (BComp(InputBuffer, i, ToSearch))
                {
                    Found.Add((uint)i);
                }
            }

            return(Found);
        }
コード例 #12
0
 protected abstract DownloadSummary DownloadCore(Uri uri, Stream outputStream, ProgressUpdateCallback progress,
                                                 CancellationToken cancellationToken, IComponent?component);
コード例 #13
0
 public DownloadSummary Download(Uri uri, Stream outputStream, ProgressUpdateCallback progress,
                                 CancellationToken cancellationToken, IComponent?component)
 {
     return(DownloadWithBitRate(uri, outputStream, progress, cancellationToken, component));
 }
コード例 #14
0
 public static extern void RegisterProgressUpdateCallbackNative([MarshalAs(UnmanagedType.FunctionPtr)] ProgressUpdateCallback call);