1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-04 17:43:17 +00:00

[PM-1576] Fix Race condition AccountsManager registration (#2434)

* PM-1576 Moved registration of AccountsManager to avoid race conditions with the app start. To do so, added ConditionedAwaiterManager so that it handles a task to be awaited or completed depending on the callers.

* PM-1576 Fix format

* PM-1576 Fix throw to preserve StackTrace
This commit is contained in:
Federico Maccaroni
2023-04-07 18:24:54 +01:00
committed by GitHub
parent e5ce1760a6
commit 1823efa0e5
7 changed files with 132 additions and 37 deletions

View File

@@ -0,0 +1,17 @@
using System;
using System.Threading.Tasks;
namespace Bit.Core.Abstractions
{
public enum AwaiterPrecondition
{
EnvironmentUrlsInited
}
public interface IConditionedAwaiterManager
{
Task GetAwaiterForPrecondition(AwaiterPrecondition awaiterPrecondition);
void SetAsCompleted(AwaiterPrecondition awaiterPrecondition);
void SetException(AwaiterPrecondition awaiterPrecondition, Exception ex);
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Abstractions;
namespace Bit.Core.Services
{
public class ConditionedAwaiterManager : IConditionedAwaiterManager
{
private readonly ConcurrentDictionary<AwaiterPrecondition, TaskCompletionSource<bool>> _preconditionsTasks = new ConcurrentDictionary<AwaiterPrecondition, TaskCompletionSource<bool>>
{
[AwaiterPrecondition.EnvironmentUrlsInited] = new TaskCompletionSource<bool>()
};
public Task GetAwaiterForPrecondition(AwaiterPrecondition awaiterPrecondition)
{
if (_preconditionsTasks.TryGetValue(awaiterPrecondition, out var tcs))
{
return tcs.Task;
}
return Task.CompletedTask;
}
public void SetAsCompleted(AwaiterPrecondition awaiterPrecondition)
{
if (_preconditionsTasks.TryGetValue(awaiterPrecondition, out var tcs))
{
tcs.TrySetResult(true);
}
}
public void SetException(AwaiterPrecondition awaiterPrecondition, Exception ex)
{
if (_preconditionsTasks.TryGetValue(awaiterPrecondition, out var tcs))
{
tcs.TrySetException(ex);
}
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Bit.Core.Abstractions;
using Bit.Core.Models.Data;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
namespace Bit.Core.Services
{
@@ -13,13 +14,16 @@ namespace Bit.Core.Services
private readonly IApiService _apiService;
private readonly IStateService _stateService;
private readonly IConditionedAwaiterManager _conditionedAwaiterManager;
public EnvironmentService(
IApiService apiService,
IStateService stateService)
IStateService stateService,
IConditionedAwaiterManager conditionedAwaiterManager)
{
_apiService = apiService;
_stateService = stateService;
_conditionedAwaiterManager = conditionedAwaiterManager;
}
public string BaseUrl { get; set; }
@@ -52,30 +56,44 @@ namespace Bit.Core.Services
public async Task SetUrlsFromStorageAsync()
{
var urls = await _stateService.GetEnvironmentUrlsAsync();
if (urls == null)
try
{
urls = await _stateService.GetPreAuthEnvironmentUrlsAsync();
}
if (urls == null)
{
urls = new EnvironmentUrlData();
}
var envUrls = new EnvironmentUrls();
if (!string.IsNullOrWhiteSpace(urls.Base))
{
BaseUrl = envUrls.Base = urls.Base;
var urls = await _stateService.GetEnvironmentUrlsAsync();
if (urls == null)
{
urls = await _stateService.GetPreAuthEnvironmentUrlsAsync();
}
if (urls == null)
{
urls = new EnvironmentUrlData();
}
var envUrls = new EnvironmentUrls();
if (!string.IsNullOrWhiteSpace(urls.Base))
{
BaseUrl = envUrls.Base = urls.Base;
_apiService.SetUrls(envUrls);
_conditionedAwaiterManager.SetAsCompleted(AwaiterPrecondition.EnvironmentUrlsInited);
return;
}
BaseUrl = urls.Base;
WebVaultUrl = urls.WebVault;
ApiUrl = envUrls.Api = urls.Api;
IdentityUrl = envUrls.Identity = urls.Identity;
IconsUrl = urls.Icons;
NotificationsUrl = urls.Notifications;
EventsUrl = envUrls.Events = urls.Events;
_apiService.SetUrls(envUrls);
return;
_conditionedAwaiterManager.SetAsCompleted(AwaiterPrecondition.EnvironmentUrlsInited);
}
BaseUrl = urls.Base;
WebVaultUrl = urls.WebVault;
ApiUrl = envUrls.Api = urls.Api;
IdentityUrl = envUrls.Identity = urls.Identity;
IconsUrl = urls.Icons;
NotificationsUrl = urls.Notifications;
EventsUrl = envUrls.Events = urls.Events;
_apiService.SetUrls(envUrls);
catch (System.Exception ex)
{
_conditionedAwaiterManager.SetException(AwaiterPrecondition.EnvironmentUrlsInited, ex);
throw;
}
}
public async Task<EnvironmentUrlData> SetUrlsAsync(EnvironmentUrlData urls)

View File

@@ -33,6 +33,7 @@ namespace Bit.Core.Utilities
SearchService searchService = null;
var conditionedRunner = new ConditionedAwaiterManager();
var tokenService = new TokenService(stateService);
var apiService = new ApiService(tokenService, platformUtilsService, (extras) =>
{
@@ -82,12 +83,13 @@ namespace Bit.Core.Utilities
keyConnectorService, passwordGenerationService);
var exportService = new ExportService(folderService, cipherService, cryptoService);
var auditService = new AuditService(cryptoFunctionService, apiService);
var environmentService = new EnvironmentService(apiService, stateService);
var environmentService = new EnvironmentService(apiService, stateService, conditionedRunner);
var eventService = new EventService(apiService, stateService, organizationService, cipherService);
var userVerificationService = new UserVerificationService(apiService, platformUtilsService, i18nService,
cryptoService);
var usernameGenerationService = new UsernameGenerationService(cryptoService, apiService, stateService);
Register<IConditionedAwaiterManager>(conditionedRunner);
Register<ITokenService>("tokenService", tokenService);
Register<IApiService>("apiService", apiService);
Register<IAppIdService>("appIdService", appIdService);