Beispiel #1
0
        private static async Task DownloadRoamingDataFromServerAsync(
            IRemoteStorageProvider remoteStorageProvider,
            IEnumerable <RemoteFileInfo> allOtherRoamingFiles,
            IEnumerable <StorageFile> allOtherLocalFiles,
            CancellationToken cancellationToken)
        {
            // Download the user data bundle file from the server.
            HandleDownloadResult(await remoteStorageProvider.DownloadFileAsync(Constants.UserDataBundleFileName, cancellationToken).ConfigureAwait(false));

            // Delete local data files that don't exist remotely
            foreach (StorageFile localFile in allOtherLocalFiles)
            {
                if (!allOtherRoamingFiles.Any(roamingFile
                                              => string.Equals(Path.GetFileName(roamingFile.FullPath), localFile.Name, StringComparison.Ordinal)))
                {
                    await localFile.DeleteAsync(StorageDeleteOption.PermanentDelete);
                }
            }

            // Download remote data files that don't exist locally
            foreach (RemoteFileInfo roamingFile in allOtherRoamingFiles)
            {
                if (!allOtherLocalFiles.Any(localFile
                                            => string.Equals(Path.GetFileName(roamingFile.FullPath), localFile.Name, StringComparison.Ordinal)))
                {
                    HandleDownloadResult(await remoteStorageProvider.DownloadFileAsync(roamingFile.FullPath, cancellationToken).ConfigureAwait(false));
                }
            }
        }
Beispiel #2
0
        private static async Task UploadLocalDataToServerAsync(
            IRemoteStorageProvider remoteStorageProvider,
            StorageFile localUserDataBundleFile,
            IEnumerable <RemoteFileInfo> allOtherRoamingFiles,
            IEnumerable <StorageFile> allOtherLocalFiles,
            CancellationToken cancellationToken)
        {
            // Upload the user data bundle file to the server.
            HandleUploadResult(await remoteStorageProvider.UploadFileAsync(localUserDataBundleFile, cancellationToken).ConfigureAwait(false));

            // Delete roaming data files that don't exist locally
            foreach (RemoteFileInfo roamingFile in allOtherRoamingFiles)
            {
                if (!allOtherLocalFiles.Any(localFile
                                            => string.Equals(Path.GetFileName(roamingFile.FullPath), localFile.Name, StringComparison.Ordinal)))
                {
                    await remoteStorageProvider.DeleteFileAsync(roamingFile.FullPath, cancellationToken).ConfigureAwait(false);
                }
            }

            // Upload local data files that don't exist remotely
            foreach (StorageFile localFile in allOtherLocalFiles)
            {
                if (!allOtherRoamingFiles.Any(roamingFile
                                              => string.Equals(Path.GetFileName(roamingFile.FullPath), localFile.Name, StringComparison.Ordinal)))
                {
                    HandleUploadResult(await remoteStorageProvider.UploadFileAsync(localFile, cancellationToken).ConfigureAwait(false));
                }
            }
        }
Beispiel #3
0
        private async Task SynchronizeAsync(CancellationToken cancellationToken)
        {
            // The semaphore acts like queue.
            using (await _sempahore.WaitAsync(cancellationToken).ConfigureAwait(false))
            {
                var synchronizationStarted = false;
                var succeeded = false;
                var requiresReloadLocalData = false;

                try
                {
                    if (!_settingsProvider.GetSetting(SettingsDefinitions.SyncDataWithCloud))
                    {
                        return;
                    }

                    string targetterProviderName = _settingsProvider.GetSetting(SettingsDefinitions.RemoteStorageProviderName);
                    IRemoteStorageProvider remoteStorageProvider = _remoteStorageProviders.SingleOrDefault(m => string.Equals(m.Metadata.ProviderName, targetterProviderName, StringComparison.Ordinal))?.Value;

                    if (remoteStorageProvider == null)
                    {
                        return;
                    }

                    if (!CoreHelper.IsInternetAccess())
                    {
                        return;
                    }

                    SynchronizationStarted?.Invoke(this, EventArgs.Empty);
                    synchronizationStarted = true;

                    if (!await remoteStorageProvider.SignInAsync(interactive: false, cancellationToken).ConfigureAwait(false))
                    {
                        // If fails to authenticate, disables synchronization and sign out.
                        _settingsProvider.SetSetting(SettingsDefinitions.SyncDataWithCloud, false);
                        await remoteStorageProvider.SignOutAsync().ConfigureAwait(false);

                        // TODO: Add a log to notify to let the user know it signed out and he should re-authenticate.

                        // returning here will still trigger the Finally block.
                        return;
                    }

                    // Retrieve the list of online files.
                    IReadOnlyList <RemoteFileInfo> roamingFiles =
                        await remoteStorageProvider.GetFilesAsync(Constants.DataFileCountLimit, cancellationToken).ConfigureAwait(false);

                    RemoteFileInfo roamingUserDataBundleFile = roamingFiles.FirstOrDefault(file
                                                                                           => string.Equals(Path.GetFileName(file.FullPath), Constants.UserDataBundleFileName, StringComparison.Ordinal));

                    IEnumerable <RemoteFileInfo> allOtherRoamingFiles = roamingFiles.Where(file
                                                                                           => !string.Equals(Path.GetFileName(file.FullPath), Constants.UserDataBundleFileName, StringComparison.Ordinal));

                    // Retrieve the list of local files.
                    var localUserDataFolder = await CoreHelper.GetOrCreateUserDataStorageFolderAsync().ConfigureAwait(false);

                    StorageFile localUserDataBundleFile = await localUserDataFolder.TryGetItemAsync(Constants.UserDataBundleFileName) as StorageFile;

                    IEnumerable <StorageFile> allOtherLocalFiles = (await localUserDataFolder.GetFilesAsync())
                                                                   .Where(file => !string.Equals(file.Name, Constants.UserDataBundleFileName, StringComparison.Ordinal));

                    if (localUserDataBundleFile == null && roamingUserDataBundleFile == RemoteFileInfo.Empty)
                    {
                        // Nothing locally and remotely?

                        succeeded = true;
                        return;
                    }

                    if (localUserDataBundleFile == null ||
                        (roamingUserDataBundleFile != RemoteFileInfo.Empty &&
                         roamingUserDataBundleFile.CreatedDateTime.ToUniversalTime()
                         > (await localUserDataBundleFile.GetBasicPropertiesAsync()).DateModified.ToUniversalTime()))
                    {
                        // If there is no local user data file, or that the file on the server is more recent than the local one,
                        // then we want to merge by taking the version from the server.

                        await DownloadRoamingDataFromServerAsync(
                            remoteStorageProvider,
                            allOtherRoamingFiles,
                            allOtherLocalFiles,
                            cancellationToken).ConfigureAwait(false);

                        // The local file changed, since we downloaded the one from the server, so let's indicate
                        // that we want to reload (and merge) the local data.
                        requiresReloadLocalData = true;
                    }
                    else
                    {
                        // Else, then it means the local file is more recent than the one on the server,
                        // or that there is simply no file on the server,
                        // so we want to merge by taking the version from the local file.

                        await UploadLocalDataToServerAsync(
                            remoteStorageProvider,
                            localUserDataBundleFile,
                            allOtherRoamingFiles,
                            allOtherLocalFiles,
                            cancellationToken).ConfigureAwait(false);
                    }

                    succeeded = true;
                }
                catch (OperationCanceledException)
                {
                    _logger.LogEvent(SynchronizeCanceledEvent, "The synchronization with the cloud has been canceled.");
                }
                catch (Exception ex)
                {
                    _logger.LogFault(SynchronizeFaultEvent, "Failed to synchronize the data with the cloud.", ex);
                }
                finally
                {
                    if (synchronizationStarted)
                    {
                        RaiseSynchronizationCompleted(succeeded, requiresReloadLocalData);
                    }
                }
            }
        }