/// <summary> /// Reads an item from the storage. Order is Last-In-First-Out. /// When the Transmission is no longer needed (it was either sent or failed with a non-retriable error) it should be disposed. /// </summary> internal override StorageTransmission Peek() { IEnumerable <FileInfo> files = this.GetFiles("*.trn"); lock (this.peekLockObj) { foreach (FileInfo file in files) { try { // if a file was peeked before, skip it (wait until it is disposed). if (this.peekedTransmissions.ContainsKey(file.Name) == false && this.deletedFilesQueue.Contains(file.Name) == false) { // Load the transmission from disk. StorageTransmission storageTransmissionItem = LoadTransmissionFromFileAsync(file).ConfigureAwait(false).GetAwaiter().GetResult(); // when item is disposed it should be removed from the peeked list. storageTransmissionItem.Disposing = item => this.OnPeekedItemDisposed(file.Name); // add the transmission to the list. this.peekedTransmissions.Add(file.Name, file.FullName); return(storageTransmissionItem); } } catch (Exception e) { string msg = string.Format(CultureInfo.InvariantCulture, "Failed to load an item from the storage. file: {0} Exception: {1}", file, e); CoreEventSource.Log.LogVerbose(msg); } } } return(null); }
/// <summary> /// Sends a transmission and handle errors. /// </summary> /// <param name="transmission">The transmission to send.</param> /// <param name="nextSendInterval">When this value returns it will hold a recommendation for when to start the next sending iteration.</param> /// <returns>True, if there was sent error and we need to retry sending, otherwise false.</returns> protected virtual bool Send(StorageTransmission transmission, ref TimeSpan nextSendInterval) { try { if (transmission != null) { bool isConnected = NetworkInterface.GetIsNetworkAvailable(); // there is no internet connection available, return than. if (!isConnected) { CoreEventSource.Log.LogVerbose("Cannot send data to the HockeyApp server. Internet connection is not available"); return(true); } transmission.SendAsync().ConfigureAwait(false).GetAwaiter().GetResult(); // After a successful sending, try immeidiately to send another transmission. nextSendInterval = this.SendingInterval; } } catch (WebException e) { int?statusCode = GetStatusCode(e); nextSendInterval = this.CalculateNextInterval(statusCode, nextSendInterval, this.maxIntervalBetweenRetries); return(IsRetryable(statusCode, e.Status)); } catch (Exception e) { nextSendInterval = this.CalculateNextInterval(null, nextSendInterval, this.maxIntervalBetweenRetries); string msg = string.Format(CultureInfo.InvariantCulture, "Unknown exception during sending: {0}", e); CoreEventSource.Log.LogVerbose(msg); } return(false); }
private static async Task SaveTransmissionToFileAsync(Transmission transmission, string fileFullName) { try { using (Stream stream = File.OpenWrite(fileFullName)) { await StorageTransmission.SaveAsync(transmission, stream).ConfigureAwait(false); } } catch (UnauthorizedAccessException) { string message = string.Format("Failed to save transmission to file. UnauthorizedAccessException. File full path: {0}", fileFullName); CoreEventSource.Log.LogVerbose(message); throw; } }
/// <summary> /// Send transmissions in a loop. /// </summary> protected void SendLoop() { TimeSpan prevSendingInterval = TimeSpan.Zero; TimeSpan sendingInterval = this.sendingIntervalOnNoData; try { while (!this.stopped) { using (StorageTransmission transmission = this.storage.Peek()) { if (this.stopped) { // This second verfiication is required for cases where 'stopped' was set while peek was happening. // Once the actual sending starts the design is to wait until it finishes and deletes the transmission. // So no extra validation is required. break; } // If there is a transmission to send - send it. if (transmission != null) { bool shouldRetry = this.Send(transmission, ref sendingInterval); if (!shouldRetry) { // If retry is not required - delete the transmission. this.storage.Delete(transmission); } } else { sendingInterval = this.sendingIntervalOnNoData; } } LogInterval(prevSendingInterval, sendingInterval); this.DelayHandler.WaitOne(sendingInterval); prevSendingInterval = sendingInterval; } this.stoppedHandler.Set(); } catch (ObjectDisposedException) { } }
private static async Task <StorageTransmission> LoadTransmissionFromFileAsync(FileInfo file) { try { using (Stream stream = file.OpenRead()) { StorageTransmission storageTransmissionItem = await StorageTransmission.CreateFromStreamAsync(stream, file.FullName).ConfigureAwait(false); return(storageTransmissionItem); } } catch (Exception e) { string message = string.Format("Failed to load transmission from file. File full path: {0}, Exception: {1}", file.FullName, e); CoreEventSource.Log.LogVerbose(message); throw; } }
internal override void Delete(StorageTransmission item) { if (this.StorageFolder == null) { return; } try { File.Delete(item.FullFilePath); this.deletedFilesQueue.Enqueue(item.FileName); } catch (IOException e) { string msg = string.Format(CultureInfo.InvariantCulture, "Failed to delete a file. file: {0} Exception: {1}", item == null ? "null" : item.FullFilePath, e); CoreEventSource.Log.LogVerbose(msg); } catch (UnauthorizedAccessException e) { string msg = string.Format(CultureInfo.InvariantCulture, "Failed to delete a file. file: {0} Exception: {1}", item == null ? "null" : item.FullFilePath, e); CoreEventSource.Log.LogVerbose(msg); } }
internal override void Delete(StorageTransmission item) { if (this.StorageFolder == null) { return; } try { File.Delete(item.FullFilePath); this.deletedFilesQueue.Enqueue(item.FileName); } catch (IOException e) { string msg = string.Format(CultureInfo.InvariantCulture, "Failed to delete a file. file: {0} Exception: {1}", item == null ? "null" : item.FullFilePath, e); CoreEventSource.Log.LogVerbose(msg); } catch (UnauthorizedAccessException e) { string msg = string.Format(CultureInfo.InvariantCulture, "Failed to delete a file. file: {0} Exception: {1}", item == null ? "null" : item.FullFilePath, e); CoreEventSource.Log.LogVerbose(msg); } }
/// <summary> /// Sends a transmission and handle errors. /// </summary> /// <param name="transmission">The transmission to send.</param> /// <param name="nextSendInterval">When this value returns it will hold a recommendation for when to start the next sending iteration.</param> /// <returns>True, if there was sent error and we need to retry sending, otherwise false.</returns> protected virtual bool Send(StorageTransmission transmission, ref TimeSpan nextSendInterval) { try { if (transmission != null) { bool isConnected = NetworkInterface.GetIsNetworkAvailable(); // there is no internet connection available, return than. if (!isConnected) { CoreEventSource.Log.LogVerbose("Cannot send data to the HockeyApp server. Internet connection is not available"); return true; } transmission.SendAsync().ConfigureAwait(false).GetAwaiter().GetResult(); // After a successful sending, try immeidiately to send another transmission. nextSendInterval = this.SendingInterval; } } catch (WebException e) { int? statusCode = GetStatusCode(e); nextSendInterval = this.CalculateNextInterval(statusCode, nextSendInterval, this.maxIntervalBetweenRetries); return IsRetryable(statusCode, e.Status); } catch (Exception e) { nextSendInterval = this.CalculateNextInterval(null, nextSendInterval, this.maxIntervalBetweenRetries); string msg = string.Format(CultureInfo.InvariantCulture, "Unknown exception during sending: {0}", e); CoreEventSource.Log.LogVerbose(msg); } return false; }
internal override void Delete(StorageTransmission transmission) { storage.Remove(transmission); }