private async Task SendFileToClient(CommandHeader cmdHeader) { var data = await NetworkHelper.Read <GetFileRequest>(_networkStream, cmdHeader.PayloadLength); var ret = new ServerResponseWithData <long>(); 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"; //Log?.Invoke("Session has expired"); //return ret; } else { data.RelativeFilePath = PathHelpers.NormalizeRelative(data.RelativeFilePath); Msg?.Invoke($"Sending '{data.RelativeFilePath}'"); var filePath = Path.Combine(session.BaseDir, data.RelativeFilePath); var fileLength = new FileInfo(filePath).Length; ret.Data = fileLength; await CommandHelper.WriteCommandResponse(_networkStream, data.Command, ret); await NetworkHelper.WriteFromFileAndHashAsync(_networkStream, filePath, (int)fileLength); session.LastAccessTime = DateTime.Now; } }
private async Task ProcessRegisterClientCmd(CommandHeader cmdHeader) { var clientIdBytes = await NetworkHelper.ReadBytes(_networkStream, cmdHeader.PayloadLength); var clientId = new Guid(clientIdBytes); var ret = new ServerResponseWithData <bool>(); var cl = _config.Clients.FirstOrDefault(x => x.Id == clientId); if (cl != null) { ret.Data = true; } else { _config.Clients.Add(new RegisteredClient { Id = clientId, }); _config.Store(); ret.Data = true; } await CommandHelper.WriteCommandResponse(_networkStream, Commands.RegisterClientCmd, ret); }
private async Task ProcessGetClientEndpointsCmd(CommandHeader cmdHeader) { var clientIdBytes = await NetworkHelper.ReadBytes(_networkStream, cmdHeader.PayloadLength); var clientId = new Guid(clientIdBytes); var ret = new ServerResponseWithData <List <ClientFolderEndpoint> >(); var cl = _config.Clients.FirstOrDefault(x => x.Id == clientId); if (cl == null) { ret.ErrorMsg = $"Client {clientId} is not registered"; } else { ret.Data = cl.FolderEndpoints .Select(x => new ClientFolderEndpoint { DisplayName = x.DisplayName, Id = x.Id }) .ToList(); } await CommandHelper.WriteCommandResponse(_networkStream, Commands.GetClientEndpointsCmd, ret); }
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; } }
public static async Task <CommandHeader> ReadCommandHeader(Stream stream, CancellationToken?token = null) { var commandHeaderBytes = await ReadBytes(stream, Commands.PreambleLength + Commands.CommandLength, token); var payloadLengthBytes = await ReadBytes(stream, sizeof(int), token); var payloadLength = BitConverter.ToInt32(payloadLengthBytes, 0); var ret = new CommandHeader(commandHeaderBytes[Commands.PreambleLength]) { PayloadLength = payloadLength, }; return(ret); }
private async Task FinishSession(CommandHeader cmdHeader) { var sessionId = await NetworkHelper.Read <Guid>(_networkStream, cmdHeader.PayloadLength); var response = new ServerResponseWithData <SyncInfo>(); var session = SessionStorage.Instance.GetSession(sessionId); if (session == null) { response.ErrorMsg = "Session does not exist"; } else if (session.Expired) { response.ErrorMsg = "Session has expired"; //Log?.Invoke("Session has expired"); //return ret; } else { try { session.FileHelper.FinishSession(); session.SyncDb.Files.RemoveAll(x => x.State == SyncFileState.Deleted); foreach (var f in session.SyncDb.Files.Where(x => !string.IsNullOrEmpty(x.NewRelativePath))) { f.RelativePath = f.NewRelativePath; f.NewRelativePath = null; } foreach (var f in session.SyncDb.Files) { f.State = SyncFileState.NotChanged; } } catch (Exception e) { response.ErrorMsg = e.ToString(); } session.SyncDb.Store(session.SyncDbDir); } await CommandHelper.WriteCommandResponse(_networkStream, Commands.FinishSessionCmd, response); }
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); }
private async Task ProcessGetSyncListCmd(CommandHeader cmdHeader) { var data = await NetworkHelperSequential.Read <GetSyncListCommandData>(_networkStream, cmdHeader.PayloadLength); var ret = new ServerResponseWithData <SyncInfo>(); 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"; //Log?.Invoke("Session has expired"); //return ret; } else { 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(data.Files); Msg?.Invoke("Preparing sync list..."); foreach (var localFileInfo in syncDb.Files) { var remoteFileInfo = data.Files.FirstOrDefault(remoteFile => remoteFile.RelativePath == localFileInfo.RelativePath); if (remoteFileInfo == null) { if (localFileInfo.State != SyncFileState.Deleted) { syncInfo.ToDownload.Add(localFileInfo); } } else { data.Files.Remove(remoteFileInfo); switch (remoteFileInfo.State) { case SyncFileState.Deleted: if (localFileInfo.State == SyncFileState.NotChanged || localFileInfo.State == SyncFileState.Deleted) { var filePath = Path.Combine(session.BaseDir, localFileInfo.RelativePath); if (File.Exists(filePath)) { var movedFilePath = Path.Combine(session.RemovedDir, localFileInfo.RelativePath); var movedFileDir = Path.GetDirectoryName(movedFilePath); if (movedFileDir == null) { throw new InvalidOperationException($"Unable to get '{movedFilePath}'s dir"); } if (!Directory.Exists(movedFileDir)) { Directory.CreateDirectory(movedFileDir); } File.Move(filePath, movedFilePath); } } else if (localFileInfo.State == SyncFileState.New) { syncInfo.ToDownload.Add(localFileInfo); } else { syncInfo.Conflicts.Add(localFileInfo); } break; case SyncFileState.New: syncInfo.Conflicts.Add(localFileInfo); break; case SyncFileState.Modified: if (localFileInfo.State == SyncFileState.NotChanged) { syncInfo.ToUpload.Add(localFileInfo); } else { syncInfo.Conflicts.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) { Debugger.Break(); // not possible } break; } } } foreach (var remoteFileInfo in data.Files.Where(x => x.State != SyncFileState.Deleted)) { syncInfo.ToUpload.Add(remoteFileInfo); } ret.Data = syncInfo; session.SyncDb = syncDb; } } await CommandHelper.WriteCommandResponse(_networkStream, Commands.GetSyncListCmd, ret); }
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); }