diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs index e11ef1f20..a716a0d58 100644 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs +++ b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Proton Technologies AG + * Copyright (c) 2023 Proton AG * * This file is part of ProtonVPN. * diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs index b9eb82eac..dd6683019 100644 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs +++ b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs @@ -85,12 +85,25 @@ private async Task CreateInternalAsync() int? appServerPort = _grpcServer?.Port; if (VpnController is not null && appServerPort is not null) { - Logger.Info($"Sending app gRPC server port {appServerPort.Value} to service."); + await RegisterStateConsumerAsync(appServerPort.Value); + } + } + + private async Task RegisterStateConsumerAsync(int appServerPort) + { + Logger.Info($"Sending the app gRPC server port {appServerPort} to service."); + try + { await VpnController.RegisterStateConsumer(new StateConsumerIpcEntity { - ServerPort = appServerPort.Value + ServerPort = appServerPort }); } + catch (Exception e) + { + Logger.Error($"An error occurred when " + + $"sending the app gRPC server port {appServerPort} to service.", e); + } } public async Task RecreateAsync() diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs index 1bdabd9f4..347f1ab95 100644 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs +++ b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Proton Technologies AG + * Copyright (c) 2023 Proton AG * * This file is part of ProtonVPN. * @@ -32,11 +32,33 @@ public static async Task OpenMainWindowAsync() int? appServerPort = appServerPortRegister.ReadOnce(); if (appServerPort.HasValue && GrpcChannelWrapperFactory.IsPortValid(appServerPort.Value)) { - GrpcChannelWrapper grpcChannelWrapper = new(appServerPort.Value); + await CreateGrpcChannelAndSendOpenWindowCommandAsync(appServerPort.Value); + } + } + + private static async Task CreateGrpcChannelAndSendOpenWindowCommandAsync(int appServerPort) + { + try + { + GrpcChannelWrapper grpcChannelWrapper = new(appServerPort); IAppController appController = grpcChannelWrapper.CreateService(); - await appController.OpenWindow(); + await SendOpenWindowCommandAsync(appController); await grpcChannelWrapper.ShutdownAsync(); } + catch + { + } + } + + private static async Task SendOpenWindowCommandAsync(IAppController appController) + { + try + { + await appController.OpenWindow(); + } + catch + { + } } } } \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/AppSettings.cs b/src/ProtonVPN.App/Core/AppSettings.cs index b8048445d..59ea05d25 100644 --- a/src/ProtonVPN.App/Core/AppSettings.cs +++ b/src/ProtonVPN.App/Core/AppSettings.cs @@ -28,6 +28,7 @@ using ProtonVPN.Announcements.Contracts; using ProtonVPN.Api.Contracts.ReportAnIssue; using ProtonVPN.Common; +using ProtonVPN.Common.Collections.Concurrent; using ProtonVPN.Common.Configuration; using ProtonVPN.Common.Extensions; using ProtonVPN.Common.KillSwitch; @@ -53,7 +54,7 @@ internal class AppSettings : IAppSettings, INotifyPropertyChanged, ILoggedInAwar private readonly ISettingsStorage _storage; private readonly UserSettings _userSettings; private readonly IConfiguration _config; - private readonly HashSet _accessedPerUserProperties = new(); + private readonly ConcurrentHashSet _accessedPerUserProperties = new(); public AppSettings(ILogger logger, ISettingsStorage storage, @@ -695,21 +696,21 @@ private void LogChange(string propertyName, T oldValue, T newValue) private T GetPerUser([CallerMemberName] string propertyName = null) { - _accessedPerUserProperties.Add(propertyName); + _accessedPerUserProperties.TryAdd(propertyName); return _userSettings.Get(propertyName); } private string GetPerUserDecrypted([CallerMemberName] string propertyName = null) { - _accessedPerUserProperties.Add(propertyName); + _accessedPerUserProperties.TryAdd(propertyName); return _userSettings.Get(propertyName)?.Decrypt(); } private void SetPerUserInner(T value, string propertyName) { - _accessedPerUserProperties.Add(propertyName); + _accessedPerUserProperties.TryAdd(propertyName); T oldValue = default; Type toType = UnwrapNullable(typeof(T)); diff --git a/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs b/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs index d9987dbf3..4a60fc8ac 100644 --- a/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs +++ b/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs @@ -20,6 +20,8 @@ using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using ProtonVPN.Common.Abstract; +using ProtonVPN.Common.Extensions; using ProtonVPN.Common.Logging; using ProtonVPN.Common.Logging.Categorization.Events.AppServiceLogs; using ProtonVPN.ProcessCommunication.Contracts; @@ -40,7 +42,7 @@ protected ServiceControllerCaller(ILogger logger, IAppGrpcClient grpcClient, Vpn _vpnSystemService = vpnSystemService; } - protected async Task Invoke(Func> serviceCall, + protected async Task> Invoke(Func> serviceCall, [CallerMemberName] string memberName = "") { int retryCount = 5; @@ -56,7 +58,7 @@ protected async Task Invoke(Func> serviceCall, await task; } - return result; + return Result.Ok(result); } catch (Exception e) { @@ -64,7 +66,7 @@ protected async Task Invoke(Func> serviceCall, if (retryCount <= 0) { LogError(e, memberName, isToRetry: false); - throw; + return Result.Fail(e.CombinedMessage()); } await _grpcClient.RecreateAsync(); diff --git a/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs b/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs index 299e7f2e5..77bd65661 100644 --- a/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs +++ b/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs @@ -28,8 +28,8 @@ namespace ProtonVPN.Core.Service.Update { public class UpdateServiceCaller : ServiceControllerCaller { - public UpdateServiceCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) : base( - logger, grpcClient, vpnSystemService) + public UpdateServiceCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) + : base(logger, grpcClient, vpnSystemService) { } diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnConnectionSpeed.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnConnectionSpeed.cs index 26ed953ed..6a28b1807 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnConnectionSpeed.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnConnectionSpeed.cs @@ -83,18 +83,7 @@ private async void UpdateSpeed(object sender, EventArgs e) InOutBytes total; using (await _lock.Lock()) { - try - { - total = await _vpnServiceManager.Total(); - } - catch (CommunicationException) - { - return; - } - catch (TimeoutException) - { - return; - } + total = await _vpnServiceManager.GetTrafficBytes(); } _speed = total - _total; diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs index 91c3cfbba..da9cd0cc0 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs @@ -80,9 +80,9 @@ await InvokeAction(async () => }); } - public async Task Total() + public async Task GetTrafficBytes() { - return await _decorated.Total(); + return await _decorated.GetTrafficBytes(); } public async Task RepeatState() diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs index 76ecc931e..2a1a8029e 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs @@ -18,6 +18,7 @@ */ using System.Threading.Tasks; +using ProtonVPN.Common.Abstract; using ProtonVPN.Common.Extensions; using ProtonVPN.Common.Logging; using ProtonVPN.ProcessCommunication.Contracts; @@ -31,8 +32,8 @@ namespace ProtonVPN.Core.Service.Vpn { public class VpnServiceCaller : ServiceControllerCaller { - public VpnServiceCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) : base( - logger, grpcClient, vpnSystemService) + public VpnServiceCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) + : base(logger, grpcClient, vpnSystemService) { } @@ -61,7 +62,7 @@ public Task RepeatState() return Invoke(c => c.RepeatState().Wrap()); } - public Task Total() + public Task> GetTrafficBytes() { return Invoke(c => c.GetTrafficBytes()); } @@ -71,7 +72,6 @@ public Task RequestNetShieldStats() return Invoke(c => c.RequestNetShieldStats().Wrap()); } - public Task RegisterVpnClient(int port) { return Invoke(c => c.RegisterStateConsumer(new StateConsumerIpcEntity { ServerPort = port }).Wrap()); diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs index 899126c5d..e1379589a 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs @@ -20,7 +20,7 @@ using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; -using System.Windows; +using ProtonVPN.Common.Abstract; using ProtonVPN.Common.Helpers; using ProtonVPN.Common.Logging; using ProtonVPN.Common.Logging.Categorization.Events.DisconnectLogs; @@ -118,9 +118,12 @@ public async Task UpdateAuthCertificate(string certificate) await _vpnServiceCaller.UpdateAuthCertificate(new AuthCertificateIpcEntity() { Certificate = certificate }); } - public async Task Total() + public async Task GetTrafficBytes() { - return _entityMapper.Map(await _vpnServiceCaller.Total()); + Result trafficBytes = await _vpnServiceCaller.GetTrafficBytes(); + return trafficBytes.Success + ? _entityMapper.Map(trafficBytes.Value) + : InOutBytes.Zero; } public async Task RepeatState() diff --git a/src/ProtonVPN.App/Windows/IOpenMainWindowAware.cs b/src/ProtonVPN.App/Windows/IOpenMainWindowAware.cs index 444d63b1a..5101aa7bc 100644 --- a/src/ProtonVPN.App/Windows/IOpenMainWindowAware.cs +++ b/src/ProtonVPN.App/Windows/IOpenMainWindowAware.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Proton Technologies AG + * Copyright (c) 2023 Proton AG * * This file is part of ProtonVPN. * diff --git a/src/ProtonVPN.Common/Collections/Concurrent/ConcurrentHashSet.cs b/src/ProtonVPN.Common/Collections/Concurrent/ConcurrentHashSet.cs new file mode 100644 index 000000000..9bdda04b4 --- /dev/null +++ b/src/ProtonVPN.Common/Collections/Concurrent/ConcurrentHashSet.cs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace ProtonVPN.Common.Collections.Concurrent +{ + public class ConcurrentHashSet + { + private readonly ConcurrentDictionary _dictionary = new(); + + public bool TryAdd(T item) + { + return _dictionary.TryAdd(item, true); + } + + public List ToList() + { + return _dictionary.Keys.ToList(); + } + + public void Clear() + { + _dictionary.Clear(); + } + } +} \ No newline at end of file diff --git a/src/ProtonVPN.Common/Logging/NullLogger.cs b/src/ProtonVPN.Common/Logging/NullLogger.cs index ff7dc2852..20c1b5760 100644 --- a/src/ProtonVPN.Common/Logging/NullLogger.cs +++ b/src/ProtonVPN.Common/Logging/NullLogger.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Proton Technologies AG + * Copyright (c) 2023 Proton AG * * This file is part of ProtonVPN. * diff --git a/src/ProtonVPN.Core/Vpn/IVpnServiceManager.cs b/src/ProtonVPN.Core/Vpn/IVpnServiceManager.cs index e03637b47..526954d6e 100644 --- a/src/ProtonVPN.Core/Vpn/IVpnServiceManager.cs +++ b/src/ProtonVPN.Core/Vpn/IVpnServiceManager.cs @@ -34,7 +34,7 @@ Task Disconnect(VpnError vpnError, [CallerFilePath] string sourceFilePath = "", [CallerMemberName] string sourceMemberName = "", [CallerLineNumber] int sourceLineNumber = 0); - Task Total(); + Task GetTrafficBytes(); Task RepeatState(); void RegisterVpnStateCallback(Action callback);