Example #1
0
        public async Task Sync()
        {
            try
            {
                using (var client = new TcpClient())
                {
                    await client.ConnectAsync(IPAddress.Parse(_serverAddress), _serverPort);

                    using (var networkStream = client.GetStream())
                    {
                        var sessionId = await GetSession(networkStream);

                        if (sessionId.HasError)
                        {
                            Log?.Invoke($"Unable to create sync session. Server response was '{sessionId.ErrorMsg}'");
                            return;
                        }

                        _sessionId = sessionId.Data;

                        if (!Directory.Exists(_syncDbDir))
                        {
                            var dirInfo = Directory.CreateDirectory(_syncDbDir);
                            dirInfo.Attributes = dirInfo.Attributes | FileAttributes.Hidden;
                        }

                        var syncDb = GetLocalSyncDb(out var error);
                        if (syncDb == null)
                        {
                            Log?.Invoke(error);
                            return;
                        }

                        var syncList = await GetSyncList(networkStream, _sessionId, syncDb.Files);

                        if (syncList.HasError)
                        {
                            Log?.Invoke($"Unable to get sync list. Server response was '{syncList.ErrorMsg}'");
                            return;
                        }

                        PathHelpers.NormalizeRelative(syncList.Data.ToDownload, syncList.Data.ToUpload, syncList.Data.ToRemove);

                        PathHelpers.EnsureDirExists(_toRemoveDir);
                        PathHelpers.EnsureDirExists(_newDir);

                        foreach (var fileInfo in syncList.Data.ToRemove)
                        {
                            _sessionFileHelper.PrepareForRemove(fileInfo.RelativePath);

                            var fi = syncDb.Files.First(x => x.RelativePath == fileInfo.RelativePath);
                            syncDb.Files.Remove(fi);
                        }

                        if (syncList.Data.Conflicts.Count > 0)
                        {
                            Debugger.Break();
                        }

                        if (!await ReceiveFiles(networkStream, syncList.Data.ToDownload, syncDb))
                        {
                            return;
                        }

                        if (!await SendFiles(networkStream, syncList.Data.ToUpload, syncDb))
                        {
                            return;
                        }

                        var response = await FinishSession(networkStream, _sessionId);

                        if (response.HasError)
                        {
                            Log?.Invoke($"Error finishing session. Server response was '{response.ErrorMsg}'");

                            return;
                        }

                        _sessionFileHelper.FinishSession();

                        syncDb.Files.RemoveAll(x => x.State == SyncFileState.Deleted);
                        syncDb.Store(_syncDbDir);

                        File.WriteAllText(Path.Combine(_syncDbDir, $"sync-{DateTime.Now:dd-MM-yyyy_hh-mm-ss}.log"), _log.ToString());

                        if (new DirectoryInfo(_newDir).EnumerateFiles("*", SearchOption.AllDirectories).Any())
                        {
                            Debugger.Break(); // all files should be removed by now
                        }

                        if (new DirectoryInfo(_toRemoveDir).EnumerateFiles("*", SearchOption.AllDirectories).Any())
                        {
                            Debugger.Break(); // all files should be removed by now
                        }

                        Directory.Delete(_newDir, true);

                        Directory.Delete(_toRemoveDir, true);

                        await NetworkHelperSequential.WriteCommandHeader(networkStream, Commands.DisconnectCmd);
                    }
                }
            }
            catch (Exception e)
            {
                Log?.Invoke($"Error during sync {e}");
            }
        }
Example #2
0
        private async Task ReturnSyncList(CommandHeader cmdHeader)
        {
            var remoteData = await NetworkHelper.Read <GetSyncListRequest>(_networkStream, cmdHeader.PayloadLength);

            var ret = new ServerResponseWithData <SyncInfo>();

            var session = SessionStorage.Instance.GetSession(remoteData.SessionId);

            if (session == null)
            {
                ret.ErrorMsg = "Session does not exist";
            }
            else if (session.Expired)
            {
                ret.ErrorMsg = "Session has expired";
                _log.AppendLine("Session has expired");
                //return ret;
            }
            else
            {
                try
                {
                    Msg?.Invoke("Scanning local folder...");

                    var syncDb = GetSyncDb(session.BaseDir, session.SyncDbDir, out var error);
                    if (syncDb == null)
                    {
                        ret.ErrorMsg = error;
                        Msg?.Invoke($"Failed to get sync db: {error}");
                    }
                    else
                    {
                        var syncInfo = new SyncInfo();

                        PathHelpers.NormalizeRelative(remoteData.Files);

                        Msg?.Invoke("Preparing sync list...");

                        foreach (var localFileInfo in syncDb.Files)
                        {
                            var remoteFileInfo = remoteData.Files.FirstOrDefault(remoteFile =>
                                                                                 remoteFile.RelativePath == localFileInfo.RelativePath);
                            if (remoteFileInfo == null)
                            {
                                if (localFileInfo.State != SyncFileState.Deleted)
                                {
                                    syncInfo.ToDownload.Add(localFileInfo);
                                }
                            }
                            else
                            {
                                remoteData.Files.Remove(remoteFileInfo);

                                switch (remoteFileInfo.State)
                                {
                                case SyncFileState.Deleted:
                                    if (localFileInfo.State == SyncFileState.NotChanged ||
                                        localFileInfo.State == SyncFileState.Deleted)
                                    {
                                        session.FileHelper.PrepareForRemove(localFileInfo.RelativePath);
                                    }
                                    else if (localFileInfo.State == SyncFileState.New)
                                    {
                                        syncInfo.ToDownload.Add(localFileInfo);
                                    }
                                    else
                                    {
                                        var fileExt = Path.GetExtension(localFileInfo.RelativePath);
                                        var newPath = Path.GetFileNameWithoutExtension(localFileInfo.RelativePath) + "_FromServer" + fileExt;
                                        localFileInfo.NewRelativePath = newPath;
                                        session.FileHelper.AddRename(localFileInfo.RelativePath, newPath);
                                        syncInfo.ToDownload.Add(localFileInfo);
                                    }

                                    break;

                                case SyncFileState.New:
                                    if (localFileInfo.HashStr != remoteFileInfo.HashStr)
                                    {
                                        var fileExt = Path.GetExtension(remoteFileInfo.RelativePath);
                                        var newPath = Path.GetFileNameWithoutExtension(remoteFileInfo.RelativePath) + "_FromClient" + fileExt;
                                        remoteFileInfo.NewRelativePath = newPath;
                                        syncInfo.ToUpload.Add(remoteFileInfo);

                                        fileExt = Path.GetExtension(localFileInfo.RelativePath);
                                        newPath = Path.GetFileNameWithoutExtension(localFileInfo.RelativePath) + "_FromServer" + fileExt;
                                        localFileInfo.NewRelativePath = newPath;
                                        session.FileHelper.AddRename(localFileInfo.RelativePath, newPath);
                                        syncInfo.ToDownload.Add(localFileInfo);
                                    }

                                    break;

                                case SyncFileState.Modified:
                                    if (localFileInfo.State == SyncFileState.NotChanged)
                                    {
                                        syncInfo.ToUpload.Add(localFileInfo);
                                    }
                                    else if (localFileInfo.State == SyncFileState.Modified ||
                                             localFileInfo.State == SyncFileState.New)
                                    {
                                        var fileExt = Path.GetExtension(remoteFileInfo.RelativePath);
                                        var newPath = Path.GetFileNameWithoutExtension(remoteFileInfo.RelativePath) + "_FromClient" + fileExt;
                                        remoteFileInfo.NewRelativePath = newPath;
                                        syncInfo.ToUpload.Add(remoteFileInfo);

                                        fileExt = Path.GetExtension(localFileInfo.RelativePath);
                                        newPath = Path.GetFileNameWithoutExtension(localFileInfo.RelativePath) + "_FromServer" + fileExt;
                                        localFileInfo.NewRelativePath = newPath;
                                        session.FileHelper.AddRename(localFileInfo.RelativePath, newPath);
                                        syncInfo.ToDownload.Add(localFileInfo);
                                    }
                                    else if (localFileInfo.State == SyncFileState.Deleted)
                                    {
                                        var fileExt = Path.GetExtension(remoteFileInfo.RelativePath);
                                        var newPath = Path.GetFileNameWithoutExtension(remoteFileInfo.RelativePath) + "_FromClient" + fileExt;
                                        remoteFileInfo.NewRelativePath = newPath;
                                        syncInfo.ToUpload.Add(remoteFileInfo);
                                    }

                                    break;

                                case SyncFileState.NotChanged:
                                    if (localFileInfo.State == SyncFileState.Modified)
                                    {
                                        syncInfo.ToDownload.Add(localFileInfo);
                                    }
                                    else if (localFileInfo.State == SyncFileState.Deleted)
                                    {
                                        syncInfo.ToRemove.Add(remoteFileInfo);
                                    }
                                    else if (localFileInfo.State == SyncFileState.New)
                                    {
                                        if (localFileInfo.HashStr == remoteFileInfo.HashStr)
                                        {
                                            Msg?.Invoke("Skip identical file, client already has one");
                                            localFileInfo.State = SyncFileState.NotChanged;
                                        }
                                        else
                                        {
                                            Debugger.Break(); // not possible
                                            throw new InvalidOperationException("Invalid server state");
                                        }
                                    }

                                    break;
                                }
                            }
                        }

                        foreach (var remoteFileInfo in remoteData.Files.Where(x => x.State != SyncFileState.Deleted))
                        {
                            syncInfo.ToUpload.Add(remoteFileInfo);
                        }

                        ret.Data = syncInfo;

                        session.SyncDb         = syncDb;
                        session.LastAccessTime = DateTime.Now;
                    }
                }
                catch (Exception e)
                {
                    ret.ErrorMsg = e.Message;
                }
            }

            await CommandHelper.WriteCommandResponse(_networkStream, Commands.GetSyncListCmd, ret);
        }