12 // File transfer types
21 type FileTransfer struct {
24 ReferenceNumber []byte
28 FolderItemCount []byte
29 fileResumeData *FileResumeData
31 bytesSentCounter *WriteCounter
32 ClientConn *ClientConn
35 // WriteCounter counts the number of bytes written to it.
36 type WriteCounter struct {
38 Total int64 // Total # of bytes written
41 // Write implements the io.Writer interface.
43 // Always completes and never returns an error.
44 func (wc *WriteCounter) Write(p []byte) (int, error) {
52 func (cc *ClientConn) newFileTransfer(transferType int, fileName, filePath, size []byte) *FileTransfer {
53 var transactionRef [4]byte
54 _, _ = rand.Read(transactionRef[:])
59 ReferenceNumber: transactionRef[:],
60 refNum: transactionRef,
64 bytesSentCounter: &WriteCounter{},
68 defer cc.transfersMU.Unlock()
69 cc.transfers[transferType][transactionRef] = ft
72 defer cc.Server.mux.Unlock()
73 cc.Server.fileTransfers[transactionRef] = ft
78 // String returns a string representation of a file transfer and its progress for display in the GetInfo window
80 // MasterOfOrionII1.4.0. 0% 197.9M
81 func (ft *FileTransfer) String() string {
82 trunc := fmt.Sprintf("%.21s", ft.FileName)
83 return fmt.Sprintf("%-21s %.3s%% %6s\n", trunc, ft.percentComplete(), ft.formattedTransferSize())
86 func (ft *FileTransfer) percentComplete() string {
87 ft.bytesSentCounter.mux.Lock()
88 defer ft.bytesSentCounter.mux.Unlock()
91 math.RoundToEven(float64(ft.bytesSentCounter.Total)/float64(binary.BigEndian.Uint32(ft.TransferSize))*100),
95 func (ft *FileTransfer) formattedTransferSize() string {
96 sizeInKB := float32(binary.BigEndian.Uint32(ft.TransferSize)) / 1024
98 return fmt.Sprintf("%.1fM", sizeInKB/1024)
100 return fmt.Sprintf("%.0fK", sizeInKB)
104 func (ft *FileTransfer) ItemCount() int {
105 return int(binary.BigEndian.Uint16(ft.FolderItemCount))
108 type folderUpload struct {
111 PathItemCount [2]byte
115 func (fu *folderUpload) FormattedPath() string {
116 pathItemLen := binary.BigEndian.Uint16(fu.PathItemCount[:])
118 var pathSegments []string
119 pathData := fu.FileNamePath
121 // TODO: implement scanner interface instead?
122 for i := uint16(0); i < pathItemLen; i++ {
123 segLen := pathData[2]
124 pathSegments = append(pathSegments, string(pathData[3:3+segLen]))
125 pathData = pathData[3+segLen:]
128 return filepath.Join(pathSegments...)