Browse Source

[protocol] added relative path logic to the FILE packet; [fsys] file relative path to its parent directory; [node&&FTU] CAN SEND DIRECTORIES RECURSIVELY

main
Unbewohnte 3 years ago
parent
commit
075c342dbd
  1. 25
      src/fsys/dir.go
  2. 8
      src/fsys/dir_test.go
  3. 25
      src/fsys/file.go
  4. 165
      src/node/node.go
  5. 8
      src/protocol/headers.go
  6. 7
      src/protocol/packetConstruct.go
  7. 27
      src/protocol/packetDecode.go
  8. 5
      src/protocol/protocol_test.go

25
src/fsys/dir.go

@ -8,12 +8,12 @@ import (
// A struct that represents the main information about a directory // A struct that represents the main information about a directory
type Directory struct { type Directory struct {
Name string Name string
Path string Path string
ParentPath string Size uint64
Size uint64 RelativeParentPath string // Relative path to the directory, where the highest point in the hierarchy is the upmost parent dir. Set manually
Files []*File Files []*File
Directories []*Directory Directories []*Directory
} }
var ErrorNotDirectory error = fmt.Errorf("not a directory") var ErrorNotDirectory error = fmt.Errorf("not a directory")
@ -37,7 +37,6 @@ func GetDir(path string, recursive bool) (*Directory, error) {
directory := Directory{ directory := Directory{
Name: stats.Name(), Name: stats.Name(),
Path: absPath, Path: absPath,
ParentPath: filepath.Dir(absPath),
Directories: nil, Directories: nil,
Files: nil, Files: nil,
} }
@ -66,9 +65,13 @@ func GetDir(path string, recursive bool) (*Directory, error) {
return nil, err return nil, err
} }
innerDirs = append(innerDirs, innerDir) for _, file := range innerDir.Files {
file.RelativeParentPath = filepath.Join(directory.Name, innerDir.Name, file.Name)
}
directory.Size += innerDir.Size directory.Size += innerDir.Size
innerDirs = append(innerDirs, innerDir)
} }
// if not - skip the directory and only work with the files // if not - skip the directory and only work with the files
@ -80,9 +83,11 @@ func GetDir(path string, recursive bool) (*Directory, error) {
return nil, err return nil, err
} }
innerFiles = append(innerFiles, innerFile) innerFile.RelativeParentPath = filepath.Join(directory.Name, innerFile.Name)
directory.Size += innerFile.Size directory.Size += innerFile.Size
innerFiles = append(innerFiles, innerFile)
} }
} }
@ -92,8 +97,6 @@ func GetDir(path string, recursive bool) (*Directory, error) {
return &directory, nil return &directory, nil
} }
var FILES []*File
// Returns every file in that directory // Returns every file in that directory
func (dir *Directory) GetAllFiles(recursively bool) []*File { func (dir *Directory) GetAllFiles(recursively bool) []*File {
var files []*File = dir.Files var files []*File = dir.Files

8
src/fsys/dir_test.go

@ -29,6 +29,14 @@ func Test_GetDirRecursive(t *testing.T) {
t.Fatalf("inner dir cannot have a bigger size (%d B) than its parent`s total size (%d B)", innerDir.Size, dir.Size) t.Fatalf("inner dir cannot have a bigger size (%d B) than its parent`s total size (%d B)", innerDir.Size, dir.Size)
} }
} }
// t.Errorf("[initialdir] %+v", dir.Files[0])
// for _, dir := range dir.Directories {
// for countf, file := range dir.Files {
// t.Errorf("[%d] %+v\n", countf, file)
// }
// }
} }
func Test_GetFiles(t *testing.T) { func Test_GetFiles(t *testing.T) {

25
src/fsys/file.go

@ -10,14 +10,14 @@ import (
// A struct that represents the necessary file information for transportation through node // A struct that represents the necessary file information for transportation through node
type File struct { type File struct {
ID uint64 // Set manually ID uint64 // Set manually
Name string Name string
Path string Path string
ParentPath string RelativeParentPath string // Relative path to the file, where the highest directory in the hierarchy is the upmost parent dir. Set manually
Size uint64 Size uint64
Checksum string Checksum string
Handler *os.File // Set when .Open() is called Handler *os.File // Set when .Open() is called
SentBytes uint64 // Set manually during transportation SentBytes uint64 // Set manually during transportation
} }
var ErrorNotFile error = fmt.Errorf("not a file") var ErrorNotFile error = fmt.Errorf("not a file")
@ -43,11 +43,10 @@ func GetFile(path string) (*File, error) {
} }
file := File{ file := File{
Name: stats.Name(), Name: stats.Name(),
Path: absPath, Path: absPath,
ParentPath: filepath.Dir(absPath), Size: uint64(stats.Size()),
Size: uint64(stats.Size()), Handler: nil,
Handler: nil,
} }
// get checksum // get checksum

165
src/node/node.go

@ -35,12 +35,12 @@ type netInfoInfo struct {
// Sending-side node information // Sending-side node information
type sending struct { type sending struct {
ServingPath string // path to the thing that will be sent ServingPath string // path to the thing that will be sent
IsDirectory bool // is ServingPath a directory IsDirectory bool // is ServingPath a directory
Recursive bool // recursively send directory Recursive bool // recursively send directory
CanSendBytes bool // is the other node ready to receive another piece CanSendBytes bool // is the other node ready to receive another piece
FilesToSend []*fsys.File FilesToSend []*fsys.File
CurrentFileID uint64 // an id of a file that is currently being transported CurrentFileIndex uint64 // an id of a file that is currently being transported
} }
// Receiving-side node information // Receiving-side node information
@ -209,9 +209,24 @@ func (node *Node) Start() {
} }
if dirToSend != nil { if dirToSend != nil {
fmt.Printf("Sending \"%s\" (%.2f MB) locally on %s:%d\n", dirToSend.Name, float32(dirToSend.Size)/1024/1024, localIP, node.netInfo.Port) size := float32(dirToSend.Size) / 1024 / 1024
sizeLevel := "MiB"
if size >= 1024 {
// GiB
size = size / 1024
sizeLevel = "GiB"
}
fmt.Printf("Sending \"%s\" (%.3f %s) locally on %s:%d\n", dirToSend.Name, size, sizeLevel, localIP, node.netInfo.Port)
} else { } else {
fmt.Printf("Sending \"%s\" (%.2f MB) locally on %s:%d\n", fileToSend.Name, float32(fileToSend.Size)/1024/1024, localIP, node.netInfo.Port) size := float32(dirToSend.Size) / 1024 / 1024
sizeLevel := "MiB"
if size >= 1024 {
// GiB
size = size / 1024
sizeLevel = "GiB"
}
fmt.Printf("Sending \"%s\" (%.3f %s) locally on %s:%d\n", fileToSend.Name, size, sizeLevel, localIP, node.netInfo.Port)
} }
@ -248,7 +263,7 @@ func (node *Node) Start() {
incomingPacket, ok := <-node.packetPipe incomingPacket, ok := <-node.packetPipe
if !ok { if !ok {
fmt.Printf("The connection has been closed unexpectedly\n") fmt.Printf("The connection has been closed unexpectedly\n")
break os.Exit(-1.)
} }
// if encryption key is set - decrypt packet on the spot // if encryption key is set - decrypt packet on the spot
@ -291,6 +306,9 @@ func (node *Node) Start() {
file.ID = uint64(counter) file.ID = uint64(counter)
node.transferInfo.Sending.FilesToSend = append(node.transferInfo.Sending.FilesToSend, file) node.transferInfo.Sending.FilesToSend = append(node.transferInfo.Sending.FilesToSend, file)
// set current file id to the first file
node.transferInfo.Sending.CurrentFileIndex = 0
filePacket, err := protocol.CreateFilePacket(file) filePacket, err := protocol.CreateFilePacket(file)
if err != nil { if err != nil {
panic(err) panic(err)
@ -311,14 +329,14 @@ func (node *Node) Start() {
} }
} }
// set current file id to the first file
node.transferInfo.Sending.CurrentFileID = 0
case false: case false:
// send a filepacket of a single file // send a filepacket of a single file
fileToSend.ID = 0 fileToSend.ID = 0
node.transferInfo.Sending.FilesToSend = append(node.transferInfo.Sending.FilesToSend, fileToSend) node.transferInfo.Sending.FilesToSend = append(node.transferInfo.Sending.FilesToSend, fileToSend)
// set current file index to the first and only file
node.transferInfo.Sending.CurrentFileIndex = 0
filePacket, err := protocol.CreateFilePacket(node.transferInfo.Sending.FilesToSend[0]) filePacket, err := protocol.CreateFilePacket(node.transferInfo.Sending.FilesToSend[0])
if err != nil { if err != nil {
panic(err) panic(err)
@ -338,14 +356,12 @@ func (node *Node) Start() {
panic(err) panic(err)
} }
// set current file id to the first and only file
node.transferInfo.Sending.CurrentFileID = 0
} }
case protocol.HeaderReject: case protocol.HeaderReject:
node.state.Stopped = true node.state.Stopped = true
fmt.Printf("Transfer rejected. Disconnecting...") fmt.Printf("Transfer rejected. Disconnecting...\n")
case protocol.HeaderDisconnecting: case protocol.HeaderDisconnecting:
node.state.Stopped = true node.state.Stopped = true
@ -354,30 +370,30 @@ func (node *Node) Start() {
// Transfer section // Transfer section
if len(node.transferInfo.Sending.FilesToSend) == 0 {
// if there`s nothing else to send - create and send DONE packet
protocol.SendPacket(node.netInfo.Conn, protocol.Packet{
Header: protocol.HeaderDone,
})
fmt.Printf("Transfer ended successfully\n")
node.state.Stopped = true
}
// if allowed to transfer and the other node is ready to receive packets - send one piece // if allowed to transfer and the other node is ready to receive packets - send one piece
// and wait for it to be ready again // and wait for it to be ready again
if node.state.AllowedToTransfer && node.transferInfo.Sending.CanSendBytes { if node.state.AllowedToTransfer && node.transferInfo.Sending.CanSendBytes {
if len(node.transferInfo.Sending.FilesToSend) == 0 {
// if there`s nothing else to send - create and send DONE packet
protocol.SendPacket(node.netInfo.Conn, protocol.Packet{
Header: protocol.HeaderDone,
})
fmt.Printf("Transfer ended successfully\n")
node.state.Stopped = true
}
// sending a piece of a single file // sending a piece of a single file
currentFileID := node.transferInfo.Sending.CurrentFileID currentFileIndex := node.transferInfo.Sending.CurrentFileIndex
err = protocol.SendPiece(node.transferInfo.Sending.FilesToSend[currentFileID], node.netInfo.Conn, node.netInfo.EncryptionKey) err = protocol.SendPiece(node.transferInfo.Sending.FilesToSend[currentFileIndex], node.netInfo.Conn, node.netInfo.EncryptionKey)
switch err { switch err {
case protocol.ErrorSentAll: case protocol.ErrorSentAll:
// the file has been sent fully // the file has been sent fully
fileIDBuff := new(bytes.Buffer) fileIDBuff := new(bytes.Buffer)
err = binary.Write(fileIDBuff, binary.BigEndian, node.transferInfo.Sending.FilesToSend[currentFileID].ID) err = binary.Write(fileIDBuff, binary.BigEndian, node.transferInfo.Sending.FilesToSend[currentFileIndex].ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -397,7 +413,7 @@ func (node *Node) Start() {
protocol.SendPacket(node.netInfo.Conn, endFilePacket) protocol.SendPacket(node.netInfo.Conn, endFilePacket)
// start sending the next file // start sending the next file
if uint64(len(node.transferInfo.Sending.FilesToSend)) == (node.transferInfo.Sending.CurrentFileID + 1) { if uint64(len(node.transferInfo.Sending.FilesToSend)) == (node.transferInfo.Sending.CurrentFileIndex + 1) {
// all files has been sent // all files has been sent
node.state.Stopped = true node.state.Stopped = true
@ -409,7 +425,7 @@ func (node *Node) Start() {
protocol.SendPacket(node.netInfo.Conn, donePacket) protocol.SendPacket(node.netInfo.Conn, donePacket)
} else { } else {
node.transferInfo.Sending.CurrentFileID++ node.transferInfo.Sending.CurrentFileIndex++
} }
case nil: case nil:
@ -418,8 +434,8 @@ func (node *Node) Start() {
default: default:
node.state.Stopped = true node.state.Stopped = true
currentFileID := node.transferInfo.Sending.CurrentFileID CurrentFileIndex := node.transferInfo.Sending.CurrentFileIndex
fmt.Printf("An error occured while sending a piece of \"%s\": %s\n", node.transferInfo.Sending.FilesToSend[currentFileID].Name, err) fmt.Printf("An error occured while sending a piece of \"%s\": %s\n", node.transferInfo.Sending.FilesToSend[CurrentFileIndex].Name, err)
panic(err) panic(err)
} }
@ -454,7 +470,7 @@ func (node *Node) Start() {
incomingPacket, ok := <-node.packetPipe incomingPacket, ok := <-node.packetPipe
if !ok { if !ok {
fmt.Printf("The connection has been closed unexpectedly\n") fmt.Printf("The connection has been closed unexpectedly\n")
break os.Exit(-1)
} }
// if encryption key is set - decrypt packet on the spot // if encryption key is set - decrypt packet on the spot
@ -477,9 +493,23 @@ func (node *Node) Start() {
} }
if file != nil { if file != nil {
fmt.Printf("\n| Filename: %s\n| Size: %.2f MB\n| Checksum: %s\n", file.Name, float32(file.Size)/1024/1024, file.Checksum) size := float32(file.Size) / 1024 / 1024
sizeLevel := "MiB"
if size >= 1024 {
// GiB
size = size / 1024
sizeLevel = "GiB"
}
fmt.Printf("\n| Filename: %s\n| Size: %.3f %s\n| Checksum: %s\n", file.Name, size, sizeLevel, file.Checksum)
} else if dir != nil { } else if dir != nil {
fmt.Printf("\n| Directory name: %s\n| Size: %.2f MB\n", dir.Name, float32(dir.Size)/1024/1024) size := float32(dir.Size) / 1024 / 1024
sizeLevel := "MiB"
if size >= 1024 {
// GiB
size = size / 1024
sizeLevel = "GiB"
}
fmt.Printf("\n| Directory name: %s\n| Size: %.3f %s\n", dir.Name, size, sizeLevel)
} }
var answer string var answer string
@ -490,18 +520,18 @@ func (node *Node) Start() {
if strings.EqualFold(answer, "y") || answer == "" { if strings.EqualFold(answer, "y") || answer == "" {
// yes // yes
// in case it`s a directory - create it now // // in case it`s a directory - create it now
if dir != nil { // if dir != nil {
err = os.MkdirAll(filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name), os.ModePerm) // err = os.MkdirAll(filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name), os.ModePerm)
if err != nil { // if err != nil {
// well, just download all files in the default downloads folder then // // well, just download all files in the default downloads folder then
fmt.Printf("[ERROR] could not create a directory\n") // fmt.Printf("[ERROR] could not create a directory\n")
} else { // } else {
// also download everything in a newly created directory // // also download everything in a newly created directory
node.transferInfo.Receiving.DownloadsPath = filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name) // node.transferInfo.Receiving.DownloadsPath = filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name)
} // }
} // }
// send aceptance packet // send aceptance packet
acceptancePacket := protocol.Packet{ acceptancePacket := protocol.Packet{
@ -547,44 +577,39 @@ func (node *Node) Start() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
fullFilePath := filepath.Join(node.transferInfo.Receiving.DownloadsPath, file.Name)
file.Path, err = filepath.Abs(filepath.Join(node.transferInfo.Receiving.DownloadsPath, file.RelativeParentPath))
if err != nil {
panic(err)
}
// create all underlying directories right ahead
err = os.MkdirAll(filepath.Dir(file.Path), os.ModePerm)
if err != nil {
panic(err)
}
// check if the file already exists; if yes - remove it and replace with a new one // check if the file already exists; if yes - remove it and replace with a new one
_, err = os.Stat(fullFilePath) _, err = os.Stat(file.Path)
if err == nil { if err == nil {
// exists // exists
// remove it // remove it
os.Remove(fullFilePath) os.Remove(file.Path)
} }
file.Path = fullFilePath
file.Open() file.Open()
node.mutex.Lock() node.mutex.Lock()
node.transferInfo.Receiving.AcceptedFiles = append(node.transferInfo.Receiving.AcceptedFiles, file) node.transferInfo.Receiving.AcceptedFiles = append(node.transferInfo.Receiving.AcceptedFiles, file)
node.mutex.Unlock() node.mutex.Unlock()
case protocol.HeaderDirectory:
// (TODO)
// directory
// dir, err := protocol.DecodeDirectoryPacket(incomingPacket)
// if err != nil {
// panic(err)
// }
// // add a new directory to downloads path
// node.transferInfo.Receiving.DownloadsPath = filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name)
// err = os.MkdirAll(node.transferInfo.Receiving.DownloadsPath, os.ModePerm)
// if err != nil {
// panic(err)
// }
case protocol.HeaderFileBytes: case protocol.HeaderFileBytes:
// check if this file has been accepted to receive // check if this file has been accepted to receive
fileIDReader := bytes.NewReader(incomingPacket.Body)
fileBytesBuffer := bytes.NewBuffer(incomingPacket.Body)
var fileID uint64 var fileID uint64
err := binary.Read(fileIDReader, binary.BigEndian, &fileID) err := binary.Read(fileBytesBuffer, binary.BigEndian, &fileID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -595,7 +620,7 @@ func (node *Node) Start() {
// append provided bytes to the file // append provided bytes to the file
fileBytes := incomingPacket.Body[8:] fileBytes := fileBytesBuffer.Bytes()
_, err = acceptedFile.Handler.Write(fileBytes) _, err = acceptedFile.Handler.Write(fileBytes)
if err != nil { if err != nil {
panic(err) panic(err)

8
src/protocol/headers.go

@ -65,7 +65,9 @@ const HeaderTransferOffer Header = "TRANSFEROFFER"
// FILE. // FILE.
// Sent by sender, indicating that the file is going to be sent. // Sent by sender, indicating that the file is going to be sent.
// The body structure must follow such structure: // The body structure must follow such structure:
// FILE~(id in binary)(filename length in binary)(filename)(filesize)(checksum length in binary)(checksum) // FILE~(id in binary)(filename length in binary)(filename)(filesize)(checksum length in binary)(checksum)(relative path to the upper directory size in binary if present)(relative path)
// relative path is not needed when the file is already in the root of the initial directory, but must be included when
// the whole directory is being sent recursively
const HeaderFile Header = "FILE" const HeaderFile Header = "FILE"
// FILEBYTES. // FILEBYTES.
@ -81,7 +83,7 @@ const HeaderFileBytes Header = "FILEBYTES"
const HeaderEndfile Header = "ENDFILE" const HeaderEndfile Header = "ENDFILE"
// DIRECTORY // DIRECTORY
// Sent by sender, indicates that a directory with current information // Sent by sender. Used in TRANSFEROFFER packet to tell the difference
// is going to be sent. The structure of the body must follow the example: // between a file and a directory.
// ie: DIRECTORY~(dirname size in binary)(dirname)(dirsize) // ie: DIRECTORY~(dirname size in binary)(dirname)(dirsize)
const HeaderDirectory Header = "DIRECTORY" const HeaderDirectory Header = "DIRECTORY"

7
src/protocol/packetConstruct.go

@ -16,7 +16,7 @@ func CreateFilePacket(file *fsys.File) (*Packet, error) {
} }
defer file.Handler.Close() defer file.Handler.Close()
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)(checksum) //(id in binary)(filename length in binary)(filename)(filesize)(checksum length in binary)(checksum)(relative path to the upper directory size in binary if present)(relative path)
filePacket := Packet{ filePacket := Packet{
Header: HeaderFile, Header: HeaderFile,
@ -39,6 +39,11 @@ func CreateFilePacket(file *fsys.File) (*Packet, error) {
binary.Write(fPacketBodyBuff, binary.BigEndian, &checksumLen) binary.Write(fPacketBodyBuff, binary.BigEndian, &checksumLen)
fPacketBodyBuff.Write([]byte(file.Checksum)) fPacketBodyBuff.Write([]byte(file.Checksum))
// relative path
relPathLen := uint64(len([]byte(file.RelativeParentPath)))
binary.Write(fPacketBodyBuff, binary.BigEndian, &relPathLen)
fPacketBodyBuff.Write([]byte(file.RelativeParentPath))
filePacket.Body = fPacketBodyBuff.Bytes() filePacket.Body = fPacketBodyBuff.Bytes()
// we do not check for packet size because there is no way that it`ll exceed current // we do not check for packet size because there is no way that it`ll exceed current

27
src/protocol/packetDecode.go

@ -16,7 +16,8 @@ func DecodeFilePacket(filePacket *Packet) (*fsys.File, error) {
if filePacket.Header != HeaderFile { if filePacket.Header != HeaderFile {
return nil, ErrorWrongPacket return nil, ErrorWrongPacket
} }
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)checksum
//(id in binary)(filename length in binary)(filename)(filesize)(checksum length in binary)(checksum)(relative path to the upper directory size in binary if present)(relative path)
// retrieve data from packet body // retrieve data from packet body
@ -64,12 +65,26 @@ func DecodeFilePacket(filePacket *Packet) (*fsys.File, error) {
} }
checksum := string(checksumBytes) checksum := string(checksumBytes)
// relative path
var relPathLength uint64
err = binary.Read(packetReader, binary.BigEndian, &relPathLength)
if err != nil {
return nil, err
}
relPathBytes := make([]byte, relPathLength)
_, err = packetReader.Read(relPathBytes)
if err != nil {
return nil, err
}
relPath := string(relPathBytes)
return &fsys.File{ return &fsys.File{
ID: fileID, ID: fileID,
Name: filename, Name: filename,
Size: filesize, Size: filesize,
Checksum: checksum, Checksum: checksum,
Handler: nil, RelativeParentPath: relPath,
Handler: nil,
}, nil }, nil
} }

5
src/protocol/protocol_test.go

@ -6,8 +6,7 @@ import (
"testing" "testing"
) )
// Practically tests the whole protocol func Test_WriteRead(t *testing.T) {
func TestTransfer(t *testing.T) {
packet := Packet{ packet := Packet{
Header: "randomheader", Header: "randomheader",
Body: []byte("fIlEnAmE.txt"), Body: []byte("fIlEnAmE.txt"),
@ -57,7 +56,7 @@ func TestTransfer(t *testing.T) {
} }
} }
func TestBytesToPacket(t *testing.T) { func Test_BytesToPacket(t *testing.T) {
packet := Packet{ packet := Packet{
Header: HeaderFileBytes, Header: HeaderFileBytes,
Body: []byte("fIlEnAmE.txt"), Body: []byte("fIlEnAmE.txt"),

Loading…
Cancel
Save