Example #1
0
        private void SyncDatabaseDownloadEntries(int databaseId)
        {
            if (_databaseEntriesUploadRunning || _databaseEntriesDownloadRunning)
                return;

            _databaseEntriesDownloadRunning = true;

            // I think, but not entirely certain that this method needs a complete refactoring.....

            Task.Run(() =>
            {
                var database = GetDatabase(databaseId);
                var request = new GetDatabaseEntries { LinkIdentifier = database.Identifier };

                GetDatabaseEntries.ResponseParams response;
                try
                {
                    response = request.GetResponse(GetApiClient());
                    _requestErrors = 0;
                }
                catch (NetworkErrorException)
                {
                    _requestErrors++;
                    _databaseEntriesDownloadRunning = false;
                    return;
                }
                catch (RequestException)
                {
                    _databaseEntriesDownloadRunning = false;
                    return;
                }

                var serverEntriesToCreate = new List<GetDatabaseEntries.ResponseParamsItem>();

                foreach (var serverEntry in response.Entries)
                {
                    if (_stopSyncLoop)
                    {
                        _databaseEntriesDownloadRunning = false;
                        return;
                    }

                    var localEntry = Model.DatabasesEntries.Find(new DatabaseEntry
                    {
                        DatabaseId = databaseId,
                        Identifier = serverEntry.EntryIdentifier
                    }).FirstOrDefault();

                    if (serverEntry.Version < localEntry?.Version)
                    {
                        // Server is out of date. Force an update at next possible opportunity.
                        Model.DatabasesEntriesDataSync.Create(new DatabaseEntryDataSync { DatabaseEntryId = localEntry.Id });
                        continue;
                    }

                    if (localEntry == null)
                    {
                        serverEntriesToCreate.Add(serverEntry);
                        continue;
                    }

                    if (IsDatabaseEntryModified(localEntry.Id))
                    {
                        // It's conflict time!
                        // We're just going to bump the local version number to the same as the server version
                        // then force an update. This will cause the server entry to be overwritten, 
                        // but can be retrieved again through version history.
                        Model.DatabasesEntries.Update(localEntry.Id, new DatabaseEntry { Version = serverEntry.Version });
                        Model.DatabasesEntriesDataSync.Create(new DatabaseEntryDataSync { DatabaseEntryId = localEntry.Id });
                        continue;
                    }

                    if (serverEntry.Version == localEntry.Version)
                    {
                        // No changes required, as there are no local modifications nor any server updates.
                        continue;
                    }

                    // Update local to the latest server version.
                    var downloadedServerEntryData = DownloadDatabaseEntryData(database.Id, serverEntry.EntryIdentifier);
                    if (downloadedServerEntryData == null)
                        continue;
                    Model.DatabasesEntriesData.Update(localEntry.Id, downloadedServerEntryData);
                    Model.DatabasesEntries.Update(localEntry.Id, new DatabaseEntry
                    {
                        Version = serverEntry.Version
                    });

                    var localArchiveId = Model.DatabasesEntriesData.Create(downloadedServerEntryData);
                    Model.DatabasesEntriesDataVersions.Create(new DatabaseEntryDataVersion
                    {
                        DatabaseEntryId = localEntry.Id,
                        Version = serverEntry.Version,
                        DatabaseEntryDataId = localArchiveId
                    });
                }

                if (serverEntriesToCreate.Count == 0)
                {
                    _databaseEntriesDownloadRunning = false;
                    return;
                }

                // Split entries to download into chunks of 50
                var entriesToCreateSegments = serverEntriesToCreate.Select((x, i) => new { Index = i, Value = x })
                    .GroupBy(x => x.Index / 50)
                    .Select(x => x.Select(v => v.Value).ToList())
                    .ToList();

                var count = 0;
                foreach (var entriesToCreateSegment in entriesToCreateSegments)
                {
                    var downloadDataRequest = new GetDatabaseEntryData
                    {
                        LinkIdentifier = database.Identifier,
                        EntryIdentifiers = entriesToCreateSegment.Select(r => r.EntryIdentifier).ToList()
                    };

                    GetDatabaseEntryData.ResponseParams downloadDataResponse;
                    try
                    {
                        downloadDataResponse = downloadDataRequest.GetResponse(GetApiClient());
                    }
                    catch (RequestException)
                    {
                        _databaseEntriesDownloadRunning = false;
                        return;
                    }

                    foreach (var downloadEntryData in downloadDataResponse.EntriesData)
                    {
                        var serverEntry = serverEntriesToCreate[count];
                        var serverEntryData = DecryptServerDatabaseEntryData(downloadEntryData.Data);

                        count++;

                        var localGroup = Model.DatabasesGroups.Find(
                            new DatabaseGroup
                            {
                                DatabaseId = databaseId,
                                Identifier = serverEntry.GroupIdentifier
                            }).FirstOrDefault();

                        var entryDataId = Model.DatabasesEntriesData.Create(serverEntryData);

                        var newEntryId = Model.DatabasesEntries.Create(new DatabaseEntry
                        {
                            Identifier = serverEntry.EntryIdentifier,
                            DatabaseId = databaseId,
                            DatabaseGroupId = localGroup?.Id ?? 0,
                            DatabaseEntryDataId = entryDataId,
                            Version = serverEntry.Version
                        });

                        var archiveId = Model.DatabasesEntriesData.Create(serverEntryData);
                        Model.DatabasesEntriesDataVersions.Create(new DatabaseEntryDataVersion
                        {
                            DatabaseEntryId = newEntryId,
                            Version = serverEntry.Version,
                            DatabaseEntryDataId = archiveId
                        });
                    }
                }

                _databaseEntriesDownloadRunning = false;
            });
        }
Example #2
0
        private DatabaseEntryData DownloadDatabaseEntryData(int databaseId, string entryIdentifier)
        {
            var serverAccount = GetServerAccount();
            if (string.IsNullOrEmpty(serverAccount.BackupEncryptionPassword))
                return null;

            var database = GetDatabase(databaseId);
            var request = new GetDatabaseEntryData
            {
                LinkIdentifier = database.Identifier,
                EntryIdentifiers = new List<string> { entryIdentifier }
            };

            GetDatabaseEntryData.ResponseParams response;
            try
            {
                response = request.GetResponse(GetApiClient());
            }
            catch (RequestException)
            {
                return null;
            }

            var decryptedData = EncryptedDataWithPassword.DecryptDataAsBytes(
                response.EntriesData[0].Data, serverAccount.BackupEncryptionPassword);
            var dataJson = Util.DecompressData(decryptedData);

            var data = JsonConvert.DeserializeObject<DatabaseEntryData>(dataJson);
            data.RemoveId();
            
            return data;
        }