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
type Directory struct {
Name string
Path string
ParentPath string
Size uint64
Files []*File
Directories []*Directory
Name string
Path string
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
Directories []*Directory
}
var ErrorNotDirectory error = fmt.Errorf("not a directory")
@ -37,7 +37,6 @@ func GetDir(path string, recursive bool) (*Directory, error) {
directory := Directory{
Name: stats.Name(),
Path: absPath,
ParentPath: filepath.Dir(absPath),
Directories: nil,
Files: nil,
}
@ -66,9 +65,13 @@ func GetDir(path string, recursive bool) (*Directory, error) {
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
innerDirs = append(innerDirs, innerDir)
}
// 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
}
innerFiles = append(innerFiles, innerFile)
innerFile.RelativeParentPath = filepath.Join(directory.Name, innerFile.Name)
directory.Size += innerFile.Size
innerFiles = append(innerFiles, innerFile)
}
}
@ -92,8 +97,6 @@ func GetDir(path string, recursive bool) (*Directory, error) {
return &directory, nil
}
var FILES []*File
// Returns every file in that directory
func (dir *Directory) GetAllFiles(recursively bool) []*File {
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.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) {

25
src/fsys/file.go

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

165
src/node/node.go

@ -35,12 +35,12 @@ type netInfoInfo struct {
// Sending-side node information
type sending struct {
ServingPath string // path to the thing that will be sent
IsDirectory bool // is ServingPath a directory
Recursive bool // recursively send directory
CanSendBytes bool // is the other node ready to receive another piece
FilesToSend []*fsys.File
CurrentFileID uint64 // an id of a file that is currently being transported
ServingPath string // path to the thing that will be sent
IsDirectory bool // is ServingPath a directory
Recursive bool // recursively send directory
CanSendBytes bool // is the other node ready to receive another piece
FilesToSend []*fsys.File
CurrentFileIndex uint64 // an id of a file that is currently being transported
}
// Receiving-side node information
@ -209,9 +209,24 @@ func (node *Node) Start() {
}
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 {
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
if !ok {
fmt.Printf("The connection has been closed unexpectedly\n")
break
os.Exit(-1.)
}
// if encryption key is set - decrypt packet on the spot
@ -291,6 +306,9 @@ func (node *Node) Start() {
file.ID = uint64(counter)
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)
if err != nil {
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:
// send a filepacket of a single file
fileToSend.ID = 0
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])
if err != nil {
panic(err)
@ -338,14 +356,12 @@ func (node *Node) Start() {
panic(err)
}
// set current file id to the first and only file
node.transferInfo.Sending.CurrentFileID = 0
}
case protocol.HeaderReject:
node.state.Stopped = true
fmt.Printf("Transfer rejected. Disconnecting...")
fmt.Printf("Transfer rejected. Disconnecting...\n")
case protocol.HeaderDisconnecting:
node.state.Stopped = true
@ -354,30 +370,30 @@ func (node *Node) Start() {
// 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
// and wait for it to be ready again
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
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 {
case protocol.ErrorSentAll:
// the file has been sent fully
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 {
panic(err)
}
@ -397,7 +413,7 @@ func (node *Node) Start() {
protocol.SendPacket(node.netInfo.Conn, endFilePacket)
// 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
node.state.Stopped = true
@ -409,7 +425,7 @@ func (node *Node) Start() {
protocol.SendPacket(node.netInfo.Conn, donePacket)
} else {
node.transferInfo.Sending.CurrentFileID++
node.transferInfo.Sending.CurrentFileIndex++
}
case nil:
@ -418,8 +434,8 @@ func (node *Node) Start() {
default:
node.state.Stopped = true
currentFileID := node.transferInfo.Sending.CurrentFileID
fmt.Printf("An error occured while sending a piece of \"%s\": %s\n", node.transferInfo.Sending.FilesToSend[currentFileID].Name, err)
CurrentFileIndex := node.transferInfo.Sending.CurrentFileIndex
fmt.Printf("An error occured while sending a piece of \"%s\": %s\n", node.transferInfo.Sending.FilesToSend[CurrentFileIndex].Name, err)
panic(err)
}
@ -454,7 +470,7 @@ func (node *Node) Start() {
incomingPacket, ok := <-node.packetPipe
if !ok {
fmt.Printf("The connection has been closed unexpectedly\n")
break
os.Exit(-1)
}
// if encryption key is set - decrypt packet on the spot
@ -477,9 +493,23 @@ func (node *Node) Start() {
}
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 {
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
@ -490,18 +520,18 @@ func (node *Node) Start() {
if strings.EqualFold(answer, "y") || answer == "" {
// yes
// in case it`s a directory - create it now
if dir != nil {
err = os.MkdirAll(filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name), os.ModePerm)
if err != nil {
// well, just download all files in the default downloads folder then
fmt.Printf("[ERROR] could not create a directory\n")
} else {
// also download everything in a newly created directory
node.transferInfo.Receiving.DownloadsPath = filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name)
}
// // in case it`s a directory - create it now
// if dir != nil {
// err = os.MkdirAll(filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name), os.ModePerm)
// if err != nil {
// // well, just download all files in the default downloads folder then
// fmt.Printf("[ERROR] could not create a directory\n")
// } else {
// // also download everything in a newly created directory
// node.transferInfo.Receiving.DownloadsPath = filepath.Join(node.transferInfo.Receiving.DownloadsPath, dir.Name)
// }
}
// }
// send aceptance packet
acceptancePacket := protocol.Packet{
@ -547,44 +577,39 @@ func (node *Node) Start() {
if err != nil {
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
_, err = os.Stat(fullFilePath)
_, err = os.Stat(file.Path)
if err == nil {
// exists
// remove it
os.Remove(fullFilePath)
os.Remove(file.Path)
}
file.Path = fullFilePath
file.Open()
node.mutex.Lock()
node.transferInfo.Receiving.AcceptedFiles = append(node.transferInfo.Receiving.AcceptedFiles, file)
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:
// check if this file has been accepted to receive
fileIDReader := bytes.NewReader(incomingPacket.Body)
fileBytesBuffer := bytes.NewBuffer(incomingPacket.Body)
var fileID uint64
err := binary.Read(fileIDReader, binary.BigEndian, &fileID)
err := binary.Read(fileBytesBuffer, binary.BigEndian, &fileID)
if err != nil {
panic(err)
}
@ -595,7 +620,7 @@ func (node *Node) Start() {
// append provided bytes to the file
fileBytes := incomingPacket.Body[8:]
fileBytes := fileBytesBuffer.Bytes()
_, err = acceptedFile.Handler.Write(fileBytes)
if err != nil {
panic(err)

8
src/protocol/headers.go

@ -65,7 +65,9 @@ const HeaderTransferOffer Header = "TRANSFEROFFER"
// FILE.
// Sent by sender, indicating that the file is going to be sent.
// 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"
// FILEBYTES.
@ -81,7 +83,7 @@ const HeaderFileBytes Header = "FILEBYTES"
const HeaderEndfile Header = "ENDFILE"
// DIRECTORY
// Sent by sender, indicates that a directory with current information
// is going to be sent. The structure of the body must follow the example:
// Sent by sender. Used in TRANSFEROFFER packet to tell the difference
// between a file and a directory.
// ie: DIRECTORY~(dirname size in binary)(dirname)(dirsize)
const HeaderDirectory Header = "DIRECTORY"

7
src/protocol/packetConstruct.go

@ -16,7 +16,7 @@ func CreateFilePacket(file *fsys.File) (*Packet, error) {
}
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{
Header: HeaderFile,
@ -39,6 +39,11 @@ func CreateFilePacket(file *fsys.File) (*Packet, error) {
binary.Write(fPacketBodyBuff, binary.BigEndian, &checksumLen)
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()
// 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 {
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
@ -64,12 +65,26 @@ func DecodeFilePacket(filePacket *Packet) (*fsys.File, error) {
}
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{
ID: fileID,
Name: filename,
Size: filesize,
Checksum: checksum,
Handler: nil,
ID: fileID,
Name: filename,
Size: filesize,
Checksum: checksum,
RelativeParentPath: relPath,
Handler: nil,
}, nil
}

5
src/protocol/protocol_test.go

@ -6,8 +6,7 @@ import (
"testing"
)
// Practically tests the whole protocol
func TestTransfer(t *testing.T) {
func Test_WriteRead(t *testing.T) {
packet := Packet{
Header: "randomheader",
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{
Header: HeaderFileBytes,
Body: []byte("fIlEnAmE.txt"),

Loading…
Cancel
Save