コード例 #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 async Task DownloadAndVerifyAsync(IDownloadManager downloadManager, string destination, CancellationToken token)
 {
     try
     {
         using var file = new FileStream(destination, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
         await downloadManager.DownloadAsync(Uri, file, status => _progress?.Invoke(status), token, Component, true);
     }
     catch (OperationCanceledException)
     {
         try
         {
             Logger.Trace($"Deleting potentially partially downloaded file '{destination}' generated as a result of operation cancellation.");
             File.Delete(destination);
         }
         catch (Exception e)
         {
             Logger.Trace($"Could not delete partially downloaded file '{destination}' due to exception: {e}");
         }
         throw;
     }
 }
コード例 #3
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);
        }
コード例 #4
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);
            }
        }
コード例 #5
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);
            }
        }
コード例 #6
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);
        }