diff --git a/README.md b/README.md index b14737e..f864767 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Thus, with a connection and a way of communication, the sender will send some pa - **VERY** expensive on resources; somewhat FIXED - [x], no more **json manipulations**, only **raw bytes**`s wizardry ! - If `MAXFILEDATASIZE` is bigger than appr. 1024 - the packets on the other end will not be unmarshalled due to error ??; FIXED - [x], unnecessary, wrong, deprecated, **destroyed !!!** - Lack of proper error-handling; somewhat FIXED - [x] -- Lack of information about the process of transferring (ETA, lost packets, etc.); FIXED - [ ] +- Lack of information about the process of transferring; FIXED - [x] - No way to verify if the transferred file is not corrupted; FIXED via checksum- [x] - No encryption; FIXED via AES encryption of packets` body - [x] - Messy and hard to follow code && file structure; FIXED? - [x] diff --git a/protocol/constants.go b/protocol/constants.go index e58f4b8..b7620ec 100644 --- a/protocol/constants.go +++ b/protocol/constants.go @@ -4,7 +4,7 @@ package protocol // MAXPACKETSIZE. // How many bytes can contain one packet (header + body) at maximum // (packets with size bigger than MAXPACKETSIZE are invalid and will not be sent) -const MAXPACKETSIZE uint = 51200 // 50 kilobytes +const MAXPACKETSIZE uint = 512000 // 50 kilobytes // PACKETSIZEDELIMETER. // Character that delimits one and the other sides of the next incoming packet. diff --git a/receiver/file.go b/receiver/file.go index 2226f7e..5c13330 100644 --- a/receiver/file.go +++ b/receiver/file.go @@ -8,7 +8,7 @@ import ( ) // Receiver`s file struct. Used internally by receiver -type File struct { +type file struct { Filename string Filesize uint64 CheckSum checksum.CheckSum @@ -16,7 +16,7 @@ type File struct { // Goes through all files in the downloads directory and compares their // names with the name of the file that is about to be downloaded -func (r *Receiver) CheckIfFileAlreadyExists() (bool, error) { +func (r *Receiver) checkIfFileAlreadyExists() (bool, error) { contents, err := os.ReadDir(r.DownloadsFolder) if err != nil { return false, fmt.Errorf("could not get contents of the downloads` directory: %s", err) diff --git a/receiver/receiver.go b/receiver/receiver.go index 50c0af9..8396744 100644 --- a/receiver/receiver.go +++ b/receiver/receiver.go @@ -16,14 +16,14 @@ import ( // Representation of a receiver type Receiver struct { - DownloadsFolder string - Connection net.Conn - IncomingPackets chan protocol.Packet - FileToDownload *File - EncryptionKey []byte - ReadyToReceive bool - Stopped bool - FileBytesPacketCounter uint64 + DownloadsFolder string + Connection net.Conn + IncomingPackets chan protocol.Packet + FileToDownload *file + EncryptionKey []byte + ReadyToReceive bool + Stopped bool + TransferInfo *transferInfo } // Creates a new client with default fields @@ -40,7 +40,6 @@ func NewReceiver(downloadsFolder string) *Receiver { incomingPacketsChan := make(chan protocol.Packet, 5000) - var PacketCounter uint64 = 0 fmt.Println("Created a new receiver") return &Receiver{ DownloadsFolder: downloadsFolder, @@ -48,11 +47,14 @@ func NewReceiver(downloadsFolder string) *Receiver { IncomingPackets: incomingPacketsChan, Stopped: false, ReadyToReceive: false, - FileToDownload: &File{ + FileToDownload: &file{ Filename: "", Filesize: 0, }, - FileBytesPacketCounter: PacketCounter, + TransferInfo: &transferInfo{ + ReceivedFileBytesPackets: 0, + ApproximateNumberOfFilePackets: 0, + }, } } @@ -88,7 +90,6 @@ func (r *Receiver) Connect(addr string) error { // Handles the input from the user after the sender sent "DOYOUACCEPT?" packet. // The choice of acceptance is given to the user func (r *Receiver) HandleFileOffer() error { - // inform the user about the file fmt.Printf(` @@ -122,7 +123,7 @@ func (r *Receiver) HandleFileOffer() error { // accept the file // check if the file with the same name is present - doesExist, err := r.CheckIfFileAlreadyExists() + doesExist, err := r.checkIfFileAlreadyExists() if err != nil { return fmt.Errorf("could not check if the file with the same name alredy exists: %s", err) } @@ -154,6 +155,8 @@ func (r *Receiver) HandleFileOffer() error { return fmt.Errorf("could not send an acceptance packet: %s", err) } + r.TransferInfo.ApproximateNumberOfFilePackets = uint64(float32(r.FileToDownload.Filesize) / float32(protocol.MAXPACKETSIZE)) + return nil } @@ -171,11 +174,38 @@ func (r *Receiver) WritePieceOfFile(filePacket protocol.Packet) error { // just write the bytes file.Write(filePacket.Body) file.Close() - r.FileBytesPacketCounter++ + r.TransferInfo.ReceivedFileBytesPackets++ return nil } +// Prints a brief information about the state of the transfer +func (r *Receiver) PrintTransferInfo(pauseDuration time.Duration) { + next := time.Now().UTC() + for { + if r.TransferInfo.ReceivedFileBytesPackets == 0 { + time.Sleep(time.Second) + continue + } + + now := time.Now().UTC() + + if !now.After(next) { + continue + } + next = now.Add(pauseDuration) + + fmt.Printf(` + | Received packets/Approximate number of packets + | (%d|%d) (%.2f%%/100%%) +`, r.TransferInfo.ReceivedFileBytesPackets, + r.TransferInfo.ApproximateNumberOfFilePackets, + float32(r.TransferInfo.ReceivedFileBytesPackets)/float32(r.TransferInfo.ApproximateNumberOfFilePackets)*100) + + time.Sleep(pauseDuration) + } +} + // Listens in an endless loop; reads incoming packets, decrypts their BODY and puts into channel func (r *Receiver) ReceivePackets() { for { @@ -212,8 +242,7 @@ func (r *Receiver) ReceivePackets() { // in any order and react correspondingly func (r *Receiver) MainLoop() { go r.ReceivePackets() - - // r.Stop() + go r.PrintTransferInfo(time.Second * 3) for { if r.Stopped { @@ -291,8 +320,8 @@ func (r *Receiver) MainLoop() { // the sender has completed its mission, // checking hashes and exiting - fmt.Println("Got ", r.FileBytesPacketCounter, " file packets in total") - fmt.Println("Checking checksums...") + fmt.Println("Got ", r.TransferInfo.ReceivedFileBytesPackets, " file packets in total") + fmt.Println("Comparing checksums...") file, err := os.Open(filepath.Join(r.DownloadsFolder, r.FileToDownload.Filename)) if err != nil { diff --git a/receiver/transferinfo.go b/receiver/transferinfo.go new file mode 100644 index 0000000..6b75ffb --- /dev/null +++ b/receiver/transferinfo.go @@ -0,0 +1,6 @@ +package receiver + +type transferInfo struct { + ReceivedFileBytesPackets uint64 + ApproximateNumberOfFilePackets uint64 +} diff --git a/sender/file.go b/sender/file.go index 6b0943b..17a6d29 100644 --- a/sender/file.go +++ b/sender/file.go @@ -8,7 +8,7 @@ import ( ) // Struct that represents the served file. Used internally in the sender -type File struct { +type file struct { path string Filename string Filesize uint64 @@ -19,7 +19,7 @@ type File struct { } // Prepares a file for serving. Used for preparing info before sending a fileinfo packet by sender -func getFile(path string) (*File, error) { +func getFile(path string) (*file, error) { info, err := os.Stat(path) if err != nil { return nil, fmt.Errorf("could not get a fileinfo: %s", err) @@ -33,7 +33,7 @@ func getFile(path string) (*File, error) { return nil, fmt.Errorf("could not get a partial file checksum: %s", err) } - return &File{ + return &file{ path: path, Filename: info.Name(), Filesize: uint64(info.Size()), diff --git a/sender/sender.go b/sender/sender.go index 45afc12..db15114 100644 --- a/sender/sender.go +++ b/sender/sender.go @@ -5,6 +5,7 @@ import ( "net" "os" "strconv" + "time" "github.com/Unbewohnte/FTU/checksum" "github.com/Unbewohnte/FTU/encryption" @@ -13,16 +14,16 @@ import ( // The main sender struct type Sender struct { - Port int - FileToTransfer *File - Listener net.Listener - Connection net.Conn - IncomingPackets chan protocol.Packet - EncryptionKey []byte - SentFileBytesPackets uint64 - TransferAllowed bool - ReceiverIsReady bool - Stopped bool + Port int + FileToTransfer *file + Listener net.Listener + Connection net.Conn + IncomingPackets chan protocol.Packet + EncryptionKey []byte + TransferInfo *transferInfo + TransferAllowed bool + ReceiverIsReady bool + Stopped bool } // Creates a new sender with default|necessary fields @@ -49,21 +50,23 @@ func NewSender(port int, filepath string) *Sender { // !!! key := encryption.Generate32AESkey() - fmt.Printf("GENERATED ENCRYPTION KEY: %s\n", key) + fmt.Printf("Generated an encryption key: %s\n", key) - var filepacketCounter uint64 fmt.Printf("Created a new sender at %s:%d (remote)\n%s:%d (local)\n", remoteIP, port, localIP, port) return &Sender{ - Port: port, - FileToTransfer: fileToTransfer, - Listener: listener, - Connection: nil, - IncomingPackets: incomingPacketsChan, - SentFileBytesPackets: filepacketCounter, - EncryptionKey: key, - TransferAllowed: false, - ReceiverIsReady: false, - Stopped: false, + Port: port, + FileToTransfer: fileToTransfer, + Listener: listener, + Connection: nil, + IncomingPackets: incomingPacketsChan, + TransferInfo: &transferInfo{ + SentFileBytesPackets: 0, + ApproximateNumberOfFilePackets: uint64(float32(fileToTransfer.Filesize) / float32(protocol.MAXPACKETSIZE)), + }, + EncryptionKey: key, + TransferAllowed: false, + ReceiverIsReady: false, + Stopped: false, } } @@ -166,7 +169,7 @@ func (s *Sender) SendOffer() error { func (s *Sender) SendPiece() error { // if no data to send - exit if s.FileToTransfer.LeftBytes == 0 { - fmt.Printf("Done. Sent %d file packets\n", s.SentFileBytesPackets) + fmt.Printf("Done. Sent %d file packets\n", s.TransferInfo.SentFileBytesPackets) s.Stop() } @@ -198,14 +201,41 @@ func (s *Sender) SendPiece() error { return fmt.Errorf("could not send a file packet : %s", err) } - // doing a "logging" for the next time + // doing a "logging" for the next piece s.FileToTransfer.LeftBytes -= uint64(read) s.FileToTransfer.SentBytes += uint64(read) - s.SentFileBytesPackets++ + s.TransferInfo.SentFileBytesPackets++ return nil } +// Prints a brief information about the state of the transfer +func (s *Sender) PrintTransferInfo(pauseDuration time.Duration) { + next := time.Now().UTC() + for { + if !s.TransferAllowed { + time.Sleep(time.Second) + continue + } + + now := time.Now().UTC() + + if !now.After(next) { + continue + } + next = now.Add(pauseDuration) + + fmt.Printf(` + | Sent packets/Approximate number of packets + | (%d|%d) (%.2f%%/100%%) +`, s.TransferInfo.SentFileBytesPackets, + s.TransferInfo.ApproximateNumberOfFilePackets, + float32(s.TransferInfo.SentFileBytesPackets)/float32(s.TransferInfo.ApproximateNumberOfFilePackets)*100) + + time.Sleep(pauseDuration) + } +} + // Listens in an endless loop; reads incoming packets, decrypts their BODY and puts into channel func (s *Sender) ReceivePackets() { for { @@ -237,6 +267,7 @@ func (s *Sender) ReceivePackets() { func (s *Sender) MainLoop() { go s.ReceivePackets() + go s.PrintTransferInfo(time.Second * 3) // instantly sending an encryption key, following the protocol`s rule err := s.SendEncryptionKey() diff --git a/sender/transferinfo.go b/sender/transferinfo.go new file mode 100644 index 0000000..99f8867 --- /dev/null +++ b/sender/transferinfo.go @@ -0,0 +1,6 @@ +package sender + +type transferInfo struct { + SentFileBytesPackets uint64 + ApproximateNumberOfFilePackets uint64 +}