private async Task ProcessGetSessionCmd() { var response = new ServerResponseWithData <Guid>(); try { var session = SessionStorage.Instance.GetNewSession(); session.BaseDir = _rootFolder; session.SyncDbDir = Path.Combine(session.BaseDir, ".sync"); if (!Directory.Exists(session.SyncDbDir)) { var dirInfo = Directory.CreateDirectory(session.SyncDbDir); dirInfo.Attributes = dirInfo.Attributes | FileAttributes.Hidden; } session.RemovedDir = Path.Combine(session.SyncDbDir, "rem"); PathHelpers.EnsureDirExists(session.RemovedDir); session.NewDir = Path.Combine(session.SyncDbDir, "new"); PathHelpers.EnsureDirExists(session.NewDir); var helper = new SessionFileHelper(session.NewDir, session.RemovedDir, session.BaseDir, new System.Text.StringBuilder()); session.FileHelper = helper; response.Data = session.Id; } catch (Exception e) { response.ErrorMsg = e.ToString(); } await CommandHelper.WriteCommandResponse(_networkStream, Commands.GetSessionCmd, response); }
public void FinishSession() { foreach (var f in NewFiles) { var oldFilePath = Path.Combine(_newDir, f); var newFilePath = Path.Combine(_baseDir, f); var newFileDir = Path.GetDirectoryName(newFilePath); _log.AppendFormat("Moving {0} to {1}", oldFilePath, newFilePath); if (File.Exists(newFilePath)) { File.Delete(newFilePath); _log.Append(" (with replace)"); } _log.AppendLine(); PathHelpers.EnsureDirExists(newFileDir); File.Move(oldFilePath, newFilePath); } foreach (var f in RemoveFiles) { var oldFilePath = Path.Combine(_toRemoveDir, f); _log.AppendFormat("Removing {0}", oldFilePath); _log.AppendLine(); File.Delete(oldFilePath); } }
private async Task ReceiveFileFromClient(CommandHeader cmdHeader) { var request = await NetworkHelper.Read <SendFileRequest>(_networkStream, cmdHeader.PayloadLength); var ret = new ServerResponse(); var session = SessionStorage.Instance.GetSession(request.SessionId); if (session == null) { ret.ErrorMsg = "Session does not exist"; } else if (session.Expired) { ret.ErrorMsg = "Session has expired"; Msg?.Invoke("Session has expired"); } await CommandHelper.WriteCommandResponse(_networkStream, request.Command, ret); if (!ret.HasError && session != null) { request.RelativeFilePath = PathHelpers.NormalizeRelative(request.RelativeFilePath); var filePath = Path.Combine(session.NewDir, request.RelativeFilePath); var fileDir = Path.GetDirectoryName(filePath); PathHelpers.EnsureDirExists(fileDir); Msg?.Invoke($"Receiving file '{request.RelativeFilePath}'"); var newHash = await NetworkHelper.ReadToFileAndHashAsync(_networkStream, filePath, request.FileLength); var hashString = newHash.ToHashString(); if (hashString != request.HashStr) { Msg?.Invoke("Receive failed, hash mismatch"); } var fileInfo = session.SyncDb.Files.FirstOrDefault(i => i.RelativePath == request.RelativeFilePath); if (fileInfo != null) { fileInfo.HashStr = hashString; fileInfo.State = SyncFileState.NotChanged; } else { session.SyncDb.AddFile(session.BaseDir, request.RelativeFilePath, hashString); } session.FileHelper.AddNew(request.RelativeFilePath); session.LastAccessTime = DateTime.Now; } }
private void FinishSession(Session session) { var filesToRemove = Directory.GetFiles(session.RemovedDir, "*", SearchOption.AllDirectories); foreach (var f in filesToRemove) { File.Delete(f); var ff = f.Replace(session.RemovedDir, null).TrimStart(Path.DirectorySeparatorChar); var fl = session.SyncDb.Files.FirstOrDefault(x => x.RelativePath == ff); if (fl != null) { session.SyncDb.Files.Remove(fl); } } var newFiles = Directory.GetFiles(session.NewDir, "*", SearchOption.AllDirectories); foreach (var f in newFiles) { var target = f.Replace(session.NewDir, session.BaseDir); if (File.Exists(target)) { File.Delete(target); } var targetDir = Path.GetDirectoryName(target); PathHelpers.EnsureDirExists(targetDir); File.Move(f, target); var relative = f.Replace(session.NewDir, null).TrimStart(Path.DirectorySeparatorChar); var fl = session.SyncDb.Files.FirstOrDefault(x => x.RelativePath == relative); if (fl == null) { Debugger.Break(); } } if (new DirectoryInfo(session.NewDir).EnumerateFiles("*", SearchOption.AllDirectories).Any()) { Debugger.Break(); // all files should be removed by now } if (new DirectoryInfo(session.RemovedDir).EnumerateFiles("*", SearchOption.AllDirectories).Any()) { Debugger.Break(); // all files should be removed by now } Directory.Delete(session.NewDir, true); Directory.Delete(session.RemovedDir, true); }
public void PrepareForRemove(string relativePath) { var filePath = Path.Combine(_baseDir, relativePath); var movedFilePath = Path.Combine(_toRemoveDir, relativePath); var movedFilePathDir = Path.GetDirectoryName(movedFilePath); if (movedFilePathDir == null) { throw new InvalidOperationException($"Unable to get '{movedFilePath}'s dir"); } PathHelpers.EnsureDirExists(movedFilePathDir); File.Move(filePath, movedFilePath); RemoveFiles.Add(relativePath); }
private async Task ProcessSendFileCmd(CommandHeader cmdHeader) { var data = await NetworkHelperSequential.Read <SendFileCommandData>(_networkStream, cmdHeader.PayloadLength); var ret = new ServerResponse(); var session = SessionStorage.Instance.GetSession(data.SessionId); if (session == null) { ret.ErrorMsg = "Session does not exist"; } else if (session.Expired) { ret.ErrorMsg = "Session has expired"; Msg?.Invoke("Session has expired"); } else { data.RelativeFilePath = PathHelpers.NormalizeRelative(data.RelativeFilePath); var filePath = Path.Combine(session.NewDir, data.RelativeFilePath); var fileDir = Path.GetDirectoryName(filePath); PathHelpers.EnsureDirExists(fileDir); Msg?.Invoke($"Receiving file '{data.RelativeFilePath}'"); var newHash = await NetworkHelperSequential.ReadToFileAndHashAsync(_networkStream, filePath, data.FileLength); var fileInfo = session.SyncDb.Files.FirstOrDefault(i => i.RelativePath == data.RelativeFilePath); if (fileInfo != null) { fileInfo.HashStr = newHash.ToHashString(); fileInfo.State = SyncFileState.NotChanged; } else { session.SyncDb.AddFile(session.BaseDir, data.RelativeFilePath, newHash.ToHashString()); } } }
private async Task ProcessGetSessionCmd(CommandHeader header) { var response = new ServerResponseWithData <Guid>(); try { var req = await NetworkHelper.Read <GetSessionRequest>(_networkStream, header.PayloadLength); var client = _config.Clients.Single(x => x.Id == req.ClientId); var folder = client.FolderEndpoints.Single(x => x.Id == req.EndpointId); var session = SessionStorage.Instance.GetNewSession(); session.BaseDir = folder.LocalPath; session.SyncDbDir = Path.Combine(folder.LocalPath, ".sync"); if (!Directory.Exists(session.SyncDbDir)) { var dirInfo = Directory.CreateDirectory(session.SyncDbDir); dirInfo.Attributes = dirInfo.Attributes | FileAttributes.Hidden; } session.RemovedDir = Path.Combine(session.SyncDbDir, "rem"); PathHelpers.EnsureDirExists(session.RemovedDir); session.NewDir = Path.Combine(session.SyncDbDir, "new"); PathHelpers.EnsureDirExists(session.NewDir); var helper = new SessionFileHelper(session.NewDir, session.RemovedDir, session.BaseDir, new StringBuilder()); session.FileHelper = helper; response.Data = session.Id; } catch (Exception e) { response.ErrorMsg = e.ToString(); } await CommandHelper.WriteCommandResponse(_networkStream, Commands.GetSessionCmd, response); }
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}"); } }