Пример #1
0
        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;
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
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;
            }
        }
        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);
        }
Пример #6
0
        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);
        }
Пример #7
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());
                }
            }
        }
Пример #8
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);
        }
Пример #9
0
        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);
        }
Пример #10
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);
        }