]> git.r.bdr.sh - rbdr/mobius/blobdiff - hotline/file_transfer.go
Clean up various linter warnings
[rbdr/mobius] / hotline / file_transfer.go
index c0c2f8700895443acb83cc42ff1bc4c13fe43cb5..194e8b9890e862ac0401e1e758ba3f37b3fc595b 100644 (file)
 package hotline
 
 import (
+       "crypto/rand"
        "encoding/binary"
        "fmt"
-       "strings"
+       "math"
+       "path/filepath"
+       "sync"
 )
 
 // File transfer types
 const (
-       FileDownload   = 0
-       FileUpload     = 1
-       FolderDownload = 2
-       FolderUpload   = 3
+       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
+       FileName         []byte
+       FilePath         []byte
+       ReferenceNumber  []byte
+       refNum           [4]byte
+       Type             int
+       TransferSize     []byte
+       FolderItemCount  []byte
+       fileResumeData   *FileResumeData
+       options          []byte
+       bytesSentCounter *WriteCounter
+       ClientConn       *ClientConn
 }
 
-func (ft *FileTransfer) String() string {
-       percentComplete := 10
-       out := fmt.Sprintf("%s\t %v", ft.FileName, percentComplete)
-
-       return out
+// WriteCounter counts the number of bytes written to it.
+type WriteCounter struct {
+       mux   sync.Mutex
+       Total int64 // Total # of bytes written
 }
 
-// 00 28 // DataSize
-// 00 00 // IsFolder
-// 00 02 // PathItemCount
+// Write implements the io.Writer interface.
 //
-// 00 00
-// 09
-// 73 75 62 66 6f 6c 64 65 72 // "subfolder"
-//
-// 00 00
-// 15
-// 73 75 62 66 6f 6c 64 65 72 2d 74 65 73 74 66 69 6c 65 2d 35 6b // "subfolder-testfile-5k"
-func readFolderUpload(buf []byte) folderUpload {
-       dataLen := binary.BigEndian.Uint16(buf[0:2])
-
-       fu := folderUpload{
-               DataSize:      [2]byte{buf[0], buf[1]}, // Size of this structure (not including data size element itself)
-               IsFolder:      [2]byte{buf[2], buf[3]},
-               PathItemCount: [2]byte{buf[4], buf[5]},
-               FileNamePath:  buf[6 : dataLen+2],
+// 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{},
        }
 
-       return fu
+       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 {
+       trunc := fmt.Sprintf("%.21s", ft.FileName)
+       return fmt.Sprintf("%-21s %.3s%%  %6s\n", trunc, ft.percentComplete(), ft.formattedTransferSize())
+}
+
+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 (fu *folderUpload) UnmarshalBinary(b []byte) error {
-       fu.DataSize = [2]byte{b[0], b[1]}
-       fu.IsFolder = [2]byte{b[2], b[3]}
-       fu.PathItemCount = [2]byte{b[4], b[5]}
+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)
+       }
+}
 
-       return nil
+func (ft *FileTransfer) ItemCount() int {
+       return int(binary.BigEndian.Uint16(ft.FolderItemCount))
 }
 
 type folderUpload struct {
@@ -78,11 +118,12 @@ func (fu *folderUpload) FormattedPath() string {
        var pathSegments []string
        pathData := fu.FileNamePath
 
+       // TODO: implement scanner interface instead?
        for i := uint16(0); i < pathItemLen; i++ {
                segLen := pathData[2]
                pathSegments = append(pathSegments, string(pathData[3:3+segLen]))
                pathData = pathData[3+segLen:]
        }
 
-       return strings.Join(pathSegments, pathSeparator)
+       return filepath.Join(pathSegments...)
 }