Exemple #1
0
        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);
            }
        }
Exemple #3
0
        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;
            }
        }
Exemple #4
0
        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);
        }
Exemple #6
0
        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());
                }
            }
        }
Exemple #7
0
        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);
        }
Exemple #8
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}");
            }
        }