]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/file_transfer.go
Fix broken io.Reader implementations
[rbdr/mobius] / hotline / file_transfer.go
index c7c1a62456e4c73162d99bbfdc8b4a2d4246ab43..7c24109e1dfb9e1f70f0938764d2614464ffb634 100644 (file)
@@ -3,36 +3,102 @@ package hotline
 import (
        "encoding/binary"
        "fmt"
+       "math"
+       "math/rand"
        "path/filepath"
+       "sync"
 )
 
 // File transfer types
 const (
-       FileDownload   = 0
-       FileUpload     = 1
-       FolderDownload = 2
-       FolderUpload   = 3
-       bannerDownload = 4
+       FileDownload = iota
+       FileUpload
+       FolderDownload
+       FolderUpload
+       bannerDownload
 )
 
 type FileTransfer struct {
-       FileName        []byte
-       FilePath        []byte
-       ReferenceNumber []byte
-       Type            int
-       TransferSize    []byte // total size of all items in the folder. Only used in FolderUpload action
-       FolderItemCount []byte
-       BytesSent       int
-       clientID        uint16
-       fileResumeData  *FileResumeData
-       options         []byte
+       FileName         []byte
+       FilePath         []byte
+       ReferenceNumber  []byte
+       refNum           [4]byte
+       Type             int
+       TransferSize     []byte
+       FolderItemCount  []byte
+       fileResumeData   *FileResumeData
+       options          []byte
+       bytesSentCounter *WriteCounter
+       ClientConn       *ClientConn
 }
 
+// WriteCounter counts the number of bytes written to it.
+type WriteCounter struct {
+       mux   sync.Mutex
+       Total int64 // Total # of bytes written
+}
+
+// Write implements the io.Writer interface.
+//
+// Always completes and never returns an error.
+func (wc *WriteCounter) Write(p []byte) (int, error) {
+       wc.mux.Lock()
+       defer wc.mux.Unlock()
+       n := len(p)
+       wc.Total += int64(n)
+       return n, nil
+}
+
+func (cc *ClientConn) newFileTransfer(transferType int, fileName, filePath, size []byte) *FileTransfer {
+       var transactionRef [4]byte
+       rand.Read(transactionRef[:])
+
+       ft := &FileTransfer{
+               FileName:         fileName,
+               FilePath:         filePath,
+               ReferenceNumber:  transactionRef[:],
+               refNum:           transactionRef,
+               Type:             transferType,
+               TransferSize:     size,
+               ClientConn:       cc,
+               bytesSentCounter: &WriteCounter{},
+       }
+
+       cc.transfersMU.Lock()
+       defer cc.transfersMU.Unlock()
+       cc.transfers[transferType][transactionRef] = ft
+
+       cc.Server.mux.Lock()
+       defer cc.Server.mux.Unlock()
+       cc.Server.fileTransfers[transactionRef] = ft
+
+       return ft
+}
+
+// String returns a string representation of a file transfer and its progress for display in the GetInfo window
+// Example:
+// MasterOfOrionII1.4.0. 0%   197.9M
 func (ft *FileTransfer) String() string {
-       percentComplete := 10
-       out := fmt.Sprintf("%s\t %v", ft.FileName, percentComplete)
+       trunc := fmt.Sprintf("%.21s", ft.FileName)
+       return fmt.Sprintf("%-21s %.3s%%  %6s\n", trunc, ft.percentComplete(), ft.formattedTransferSize())
+}
 
-       return out
+func (ft *FileTransfer) percentComplete() string {
+       ft.bytesSentCounter.mux.Lock()
+       defer ft.bytesSentCounter.mux.Unlock()
+       return fmt.Sprintf(
+               "%v",
+               math.RoundToEven(float64(ft.bytesSentCounter.Total)/float64(binary.BigEndian.Uint32(ft.TransferSize))*100),
+       )
+}
+
+func (ft *FileTransfer) formattedTransferSize() string {
+       sizeInKB := float32(binary.BigEndian.Uint32(ft.TransferSize)) / 1024
+       if sizeInKB > 1024 {
+               return fmt.Sprintf("%.1fM", sizeInKB/1024)
+       } else {
+               return fmt.Sprintf("%.0fK", sizeInKB)
+       }
 }
 
 func (ft *FileTransfer) ItemCount() int {