コード例 #1
0
        protected override Message GetNextMessageImpl()
        {
            Message message = null;

            if (listSequenceSendable == null)
            {
                var tmp = new List <Item>();
                //因为3.5不支持协变,所以需要这个转化。
                GetChildren().ForEach(item => tmp.Add(item));
                listSequenceSendable                = new ListSequencable(ConversationID, tmp);
                listSequenceSendable.Name           = this.AbsolutePath;
                listSequenceSendable.PostCompleted += o => TransferState = TransferState.PostCompleted;
                listSequenceSendable.Errored       += o => TransferState = TransferState.Error;

                SendItemsMessage sendItemsMessage = new SendItemsMessage(tmp);
                //!!!!!!!!!注意:这里看起来很奇怪。原因是虽然添加到List中,但希望他们的Parent还是这个DirItem.
                //TODO 重构 如果让DirItem实现ListSequenceSendable呢?
                GetChildren().ForEach(item => {
                    item.Parent = this;
                    if (item is FileItem)
                    {
                        Conversation?.InternalWormHole(item);
                    }
                });
                sendItemsMessage.ParentItemID   = ID;
                sendItemsMessage.ConversationID = ConversationID;
                message = sendItemsMessage;
            }
            else
            {
                if (!createFolderMessageSent)
                {
                    FileDataMessage fm = new FileDataMessage()
                    {
                        ItemID = ID,
                        Length = 0,
                        Data   = new byte[0]
                    };
                    fm.ConversationID = ConversationID;
                    message           = fm;
                    //TODO 注意 如果这个文件夹是空的,这个会导致状态变化。只有长度为0,才能允许调用Progress。否则的话,会导致重复计算进度。
                    ((IProgressable)this).Progress(0);
                    createFolderMessageSent = true;
                }
                else
                {
                    //因为这个类监听了list的状态变化,当list状态变化时,这个类的状态也会变化。
                    message = listSequenceSendable.GetNextMessage();
                }
            }
            return(message);
        }
コード例 #2
0
        internal void CheckFileDataMessage(FileDataMessage message, FileItem fileItem)
        {
            var logger = Logger;

            if (message.Length < FileDataMessage.BUFFER_SIZE)
            {
                if (message.Length + fileItem.TransferredLength != fileItem.Length)
                {
                    var msg = "可能的接收文件错误。message.length=" + message.Length + " data.length=" + message.Data.Length + " file.length=" + fileItem.Length + " fileItem.TransferredLength=" + fileItem.TransferredLength + " file.name" + fileItem.Name;
                    //ShowMessage(msg);文件读取的时候,存不在在读取到的数据,在中间过程中,与给定长度不一致的时候?
                    logger.Debug(msg);
                }
            }
        }
コード例 #3
0
        protected IMessage ProcessData(Connection connection, BinaryReader reader)
        {
            IMessage result         = new NullMessage();
            IMessage currentMessage = MessageFactory.FromStream(reader);

            switch (currentMessage.MessageId)
            {
            case MessageIdentifier.FileChanged:
            {
                if (ClientHasBeenValidated == true)
                {
                    FileChangedMessage message   = currentMessage as FileChangedMessage;
                    string             filePath  = Path.Join(connection.LocalSyncPath, message.FileData.Path);
                    FileInfo           localFile = new FileInfo(filePath);

                    //we only need the file data when a file on the client was changed and that file is newer than our local copy
                    if (message.FileData.OperationType == WatcherChangeTypes.Changed || message.FileData.OperationType == WatcherChangeTypes.Created)
                    {
                        if (localFile.Exists == false || localFile.LastWriteTimeUtc < message.FileData.LastWriteTimeUtc)
                        {
                            FileMetaData = message.FileData;
                            result       = new FileRequestMessage(message.FileData);
                        }
                        else
                        {
                            result = new NullMessage();
                        }
                    }
                    else
                    {
                        if (message.FileData.OperationType == WatcherChangeTypes.Renamed)
                        {
                            string oldFilePath = Path.Join(connection.LocalSyncPath, message.FileData.OldPath);
                            if (File.Exists(oldFilePath))
                            {
                                File.Move(oldFilePath, filePath);
                            }
                        }
                        if (message.FileData.OperationType == WatcherChangeTypes.Deleted)
                        {
                            if (File.Exists(filePath))
                            {
                                File.Delete(filePath);
                            }
                        }
                        result = new NullMessage();
                    }
                }
                break;
            }

            case MessageIdentifier.FileData:
            {
                if (ClientHasBeenValidated == true && FileMetaData != null)
                {
                    FileDataMessage message = currentMessage as FileDataMessage;
                    message.FilePath = Path.Join(connection.LocalSyncPath, FileMetaData.Path);
                    ReceiveBegin(this, new ServerEventArgs()
                        {
                            FileData = FileMetaData, FullLocalPath = message.FilePath
                        });

                    try
                    {
                        message.FromBinaryStream(reader);

                        //change last write to match client file
                        File.SetLastWriteTimeUtc(message.FilePath, FileMetaData.LastWriteTimeUtc);
                        File.SetLastAccessTimeUtc(message.FilePath, FileMetaData.LastAccessTimeUtc);
                        File.SetCreationTimeUtc(message.FilePath, FileMetaData.CreateTimeUtc);
                        ReceiveEnd(this, new ServerEventArgs()
                            {
                                FileData = FileMetaData, FullLocalPath = message.FilePath, Success = true
                            });
                    }
                    catch (Exception ex)
                    {
                        Logger.Log(LogPriority.High, "Server #{0} error writing file: {1}", ServerId, message.FilePath);
                        ReceiveEnd(this, new ServerEventArgs()
                            {
                                FileData = FileMetaData, FullLocalPath = message.FilePath, Success = false
                            });
                    }
                }
                break;
            }


            case MessageIdentifier.Verification:
            {
                VerificationMessage message = currentMessage as VerificationMessage;
                if (message != null)
                {
                    if (message.Key == connection.LocalAccessKey)
                    {
                        result = new VerificationMessage(connection.RemoteAccessKey, NetworkResponse.Valid);

                        //store validation result for later use
                        ClientHasBeenValidated = true;
                    }
                }
                break;
            }
            }


            return(result);
        }
コード例 #4
0
        public ClientSendResult SendFile(FileMetaData data)
        {
            ClientSendResult args = new ClientSendResult();

            args.FileData = data;

            TcpClient client = new TcpClient(_connection.Address, _connection.Port);

#if DEBUG == false
            //timeouts don't work well when you're debugging
            client.SendTimeout = 5000;
#endif

            BufferedStream stream = new BufferedStream(client.GetStream());
            BinaryReader   reader = new BinaryReader(stream);
            BinaryWriter   writer = new BinaryWriter(stream);
            try
            {
                //introduce ourselves
                if (Handshake(reader, writer) == true)
                {
                    args.WasSuccessful = true;

                    //tell server that we would like to send them a file
                    IMessage message = new FileChangedMessage(data);
                    writer.Write(message.ToBytes());

                    //see if server wants the file
                    message = MessageFactory.FromStream(reader);

                    //server says they want the whole load
                    if (message.MessageId == MessageIdentifier.FileRequest)
                    {
                        message = new FileDataMessage();
                        writer.Write(message.ToBytes());

                        string basePath      = _connection.LocalSyncPath;
                        string localFilePath = Path.Join(basePath, data.Path);
                        if (File.Exists(localFilePath))
                        {
                            FileInfo toSend = new FileInfo(localFilePath);
                            using (var fileReader = new BinaryReader(File.OpenRead(localFilePath)))
                            {
                                byte[] buffer;
                                writer.Write(IPAddress.HostToNetworkOrder(toSend.Length));
                                while ((buffer = fileReader.ReadBytes(BUFFER_SIZE)).Length > 0)
                                {
                                    writer.Write(buffer);
                                }
                                writer.Flush();
                            }
                        }
                    }
                }
            }
            catch (EndOfStreamException ex)
            {
                //end of stream exception doesn't necessairly mean that the transfer was not successful so separate out
                //from generic exception
            }
            catch (Exception ex)
            {
                args.WasSuccessful = false;
                _logger.Log("Error: {0}", ex.Message);
            }
            finally
            {
                client.Close();
            }

            return(args);
        }
コード例 #5
0
        //TODO 在Send结束后,需要启动一个等待动作,等待对方回复确认消息。
        protected override Message GetNextMessageImpl()
        {
            Debug.Assert(TransferState != TransferState.Error, @"Item状态已经出错,为什么还到了这里呢?");

            //上次的包!=null, 而且已经PostComplted
            if (IsPostCompleted)
            {
                return(null);
            }
            FileDataMessage message = null;

            if (filestream == null)
            {
                try
                {
                    if (new FileInfo(AbsolutePath).Exists)
                    {
                        filestream = new FileStream(AbsolutePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                    }
                }
                catch (Exception ex)
                {
                    //下面检查filestream==null,会进入错误状态。
                }
            }

            if (filestream == null)
            {
                ErrorCode     = TransferErrorCode.NullFileStream;
                TransferState = TransferState.Error;
                return(null);
            }


            if (!createFileMessageSent)
            {
                message                = new FileDataMessage();
                message.Data           = new byte[0];
                message.Offset         = 0;
                message.Length         = 0;
                message.ItemID         = ID;
                message.ConversationID = ConversationID;
                createFileMessageSent  = true;
                ((IProgressable)this).Progress(0);
            }
            else
            {
                try
                {
                    filestream.Seek(TransferredLength, SeekOrigin.Begin);
                    byte[] buffer = new byte[FileDataMessage.BUFFER_SIZE];
                    int    count  = filestream.Read(buffer, 0, FileDataMessage.BUFFER_SIZE);

                    if (count > 0)
                    {
                        message = new FileDataMessage();
                        if (count == FileDataMessage.BUFFER_SIZE)
                        {
                            message.Data = buffer;
                        }
                        else
                        {
                            byte[] tmp = new byte[count];
                            Array.Copy(buffer, tmp, count);
                            message.Data = tmp;
                        }

                        message.Offset         = TransferredLength;
                        message.Length         = count;
                        message.ItemID         = ID;
                        message.ConversationID = ConversationID;
#if DEBUG
                        Env.Instance.CheckFileDataMessage(message, this);
#endif
                    }
                    else
                    {
                        ErrorCode     = TransferErrorCode.ReadFileDataFailed;
                        TransferState = TransferState.PostCompleted;
                    }
                }
                catch (Exception e)
                {
                    TransferState = TransferState.Error;
                    Env.Instance.Logger.Log(LogLevel.Error, e, "FileItemRead Exception");
                    message = null;
                }
            }


            if (message != null)
            {
                if (message.Length > 0)
                {
                    //注意:不是每个类型的GetNextMessage的Message.SendCompleted都适合触发Progress。
                    //如果把这个方法添加到基类(SequencableItem.GetNextMessage中),因为那个方法会被递归调用,例如,文件夹会调用File的GetNextMessage(通过SequencableItem) ,message.SendComplted会被处理一次
                    //然后外层的东西调用文件夹的GetNextMessage返回的时候,message.SendCompleted又被调用了一次。
                    message.SendCompleted += o => ((IProgressable)this).Progress((int)message.Length);
                }
                //写在这里是为了处理空文件的情况。空文件发第一个消息,就会进入这里。
            }
            if (message == null)
            {
                Debug.WriteLine("Get a null file message");
            }
            if (TransferredLength + (message == null ? 0 : message.Length) == Length)
            {
                TransferState = TransferState.PostCompleted;
                //SendCompeleted会在父类中处理
            }
            return(message);
        }