mirror of
https://github.com/PeernetOfficial/Abstraction.git
synced 2026-07-17 02:57:51 +01:00
added abstracted functions for download
This commit is contained in:
@@ -1,202 +1,202 @@
|
||||
/*
|
||||
File Name: Download Transfer.go
|
||||
Copyright: 2021 Peernet Foundation s.r.o.
|
||||
Author: Peter Kleissner
|
||||
|
||||
Temporary download code to provide dummy results for testing. To be replaced!
|
||||
*/
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/warehouse"
|
||||
)
|
||||
|
||||
// Starts the download.
|
||||
func (info *downloadInfo) Start() {
|
||||
// current user?
|
||||
if bytes.Equal(info.nodeID, info.backend.SelfNodeID()) {
|
||||
info.DownloadSelf()
|
||||
return
|
||||
}
|
||||
|
||||
for n := 0; n < 3 && info.peer == nil; n++ {
|
||||
_, info.peer, _ = info.backend.FindNode(info.nodeID, time.Second*5)
|
||||
|
||||
if info.status == DownloadCanceled {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if info.peer != nil {
|
||||
info.Download()
|
||||
} else {
|
||||
info.status = DownloadCanceled
|
||||
}
|
||||
}
|
||||
|
||||
func (info *downloadInfo) Download() {
|
||||
//fmt.Printf("Download start of %s\n", hex.EncodeToString(info.hash))
|
||||
|
||||
// try to download the entire file
|
||||
reader, fileSize, transferSize, err := FileStartReader(info.peer, info.hash, 0, 0, nil)
|
||||
if reader != nil {
|
||||
defer reader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
info.status = DownloadCanceled
|
||||
return
|
||||
} else if fileSize != transferSize {
|
||||
info.status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.file.Size = fileSize
|
||||
info.status = DownloadActive
|
||||
|
||||
// download in a loop
|
||||
var fileOffset, totalRead uint64
|
||||
dataRemaining := fileSize
|
||||
readSize := uint64(4096)
|
||||
|
||||
for dataRemaining > 0 {
|
||||
//fmt.Printf("data remaining: downloaded %d from total %d = %d %%\n", totalRead, fileSize, totalRead*100/fileSize)
|
||||
if dataRemaining < readSize {
|
||||
readSize = dataRemaining
|
||||
}
|
||||
|
||||
data := make([]byte, readSize)
|
||||
n, err := reader.Read(data)
|
||||
|
||||
totalRead += uint64(n)
|
||||
dataRemaining -= uint64(n)
|
||||
data = data[:n]
|
||||
|
||||
if err != nil {
|
||||
info.status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.storeDownloadData(data[:n], fileOffset)
|
||||
|
||||
fileOffset += uint64(n)
|
||||
}
|
||||
|
||||
//fmt.Printf("data finished: downloaded %d from total %d = %d %%\n", totalRead, fileSize, totalRead*100/fileSize)
|
||||
|
||||
info.Finish()
|
||||
info.DeleteDefer(time.Hour * 1) // cache the details for 1 hour before removing
|
||||
}
|
||||
|
||||
// Pause pauses the download. Status is DownloadResponseX.
|
||||
func (info *downloadInfo) Pause() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.status != DownloadActive { // The download must be active to be paused.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.status = DownloadPause
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// Resume resumes the download. Status is DownloadResponseX.
|
||||
func (info *downloadInfo) Resume() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.status != DownloadPause { // The download must be paused to resume.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.status = DownloadActive
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// Cancel cancels the download. Status is DownloadResponseX.
|
||||
func (info *downloadInfo) Cancel() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.status >= DownloadCanceled { // The download must not be already canceled or finished.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.status = DownloadCanceled
|
||||
info.DiskFile.Handle.Close()
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// Finish marks the download as finished.
|
||||
func (info *downloadInfo) Finish() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.status != DownloadActive { // The download must be active.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.status = DownloadFinished
|
||||
info.DiskFile.Handle.Close()
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// initDiskFile creates the target file
|
||||
func (info *downloadInfo) initDiskFile(path string) (err error) {
|
||||
info.DiskFile.Name = path
|
||||
info.DiskFile.Handle, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666) // 666 : All uses can read/write
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// storeDownloadData stores downloaded data. It does not change the download status.
|
||||
func (info *downloadInfo) storeDownloadData(data []byte, offset uint64) (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.status != DownloadActive { // The download must be active.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
if _, err := info.DiskFile.Handle.WriteAt(data, int64(offset)); err != nil {
|
||||
return DownloadResponseFileWrite
|
||||
}
|
||||
|
||||
info.DiskFile.StoredSize += uint64(len(data))
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
func (info *downloadInfo) DownloadSelf() {
|
||||
// Check if the file is available in the local warehouse.
|
||||
_, fileSize, status, _ := info.backend.UserWarehouse.FileExists(info.hash)
|
||||
if status != warehouse.StatusOK {
|
||||
info.status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.file.Size = fileSize
|
||||
info.status = DownloadActive
|
||||
|
||||
// read the file
|
||||
status, bytesRead, _ := info.backend.UserWarehouse.ReadFile(info.hash, 0, int64(info.file.Size), info.DiskFile.Handle)
|
||||
|
||||
info.DiskFile.StoredSize = uint64(bytesRead)
|
||||
|
||||
if status != warehouse.StatusOK {
|
||||
info.status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.Finish()
|
||||
info.DeleteDefer(time.Hour * 1) // cache the details for 1 hour before removing}
|
||||
}
|
||||
/*
|
||||
File Name: Download Transfer.go
|
||||
Copyright: 2021 Peernet Foundation s.r.o.
|
||||
Author: Peter Kleissner
|
||||
|
||||
Temporary download code to provide dummy results for testing. To be replaced!
|
||||
*/
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/PeernetOfficial/core/warehouse"
|
||||
)
|
||||
|
||||
// Starts the download.
|
||||
func (info *DownloadInfo) Start() {
|
||||
// current user?
|
||||
if bytes.Equal(info.NodeID, info.Backend.SelfNodeID()) {
|
||||
info.DownloadSelf()
|
||||
return
|
||||
}
|
||||
|
||||
for n := 0; n < 3 && info.Peer == nil; n++ {
|
||||
_, info.Peer, _ = info.Backend.FindNode(info.NodeID, time.Second*5)
|
||||
|
||||
if info.Status == DownloadCanceled {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if info.Peer != nil {
|
||||
info.Download()
|
||||
} else {
|
||||
info.Status = DownloadCanceled
|
||||
}
|
||||
}
|
||||
|
||||
func (info *DownloadInfo) Download() {
|
||||
//fmt.Printf("Download start of %s\n", hex.EncodeToString(info.Hash))
|
||||
|
||||
// try to download the entire File
|
||||
reader, fileSize, transferSize, err := FileStartReader(info.Peer, info.Hash, 0, 0, nil)
|
||||
if reader != nil {
|
||||
defer reader.Close()
|
||||
}
|
||||
if err != nil {
|
||||
info.Status = DownloadCanceled
|
||||
return
|
||||
} else if fileSize != transferSize {
|
||||
info.Status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.File.Size = fileSize
|
||||
info.Status = DownloadActive
|
||||
|
||||
// download in a loop
|
||||
var fileOffset, totalRead uint64
|
||||
dataRemaining := fileSize
|
||||
readSize := uint64(4096)
|
||||
|
||||
for dataRemaining > 0 {
|
||||
//fmt.Printf("data remaining: downloaded %d from total %d = %d %%\n", totalRead, fileSize, totalRead*100/fileSize)
|
||||
if dataRemaining < readSize {
|
||||
readSize = dataRemaining
|
||||
}
|
||||
|
||||
data := make([]byte, readSize)
|
||||
n, err := reader.Read(data)
|
||||
|
||||
totalRead += uint64(n)
|
||||
dataRemaining -= uint64(n)
|
||||
data = data[:n]
|
||||
|
||||
if err != nil {
|
||||
info.Status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.storeDownloadData(data[:n], fileOffset)
|
||||
|
||||
fileOffset += uint64(n)
|
||||
}
|
||||
|
||||
//fmt.Printf("data finished: downloaded %d from total %d = %d %%\n", totalRead, fileSize, totalRead*100/fileSize)
|
||||
|
||||
info.Finish()
|
||||
info.DeleteDefer(time.Hour * 1) // cache the details for 1 hour before removing
|
||||
}
|
||||
|
||||
// Pause pauses the download. Status is DownloadResponseX.
|
||||
func (info *DownloadInfo) Pause() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.Status != DownloadActive { // The download must be active to be paused.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.Status = DownloadPause
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// Resume resumes the download. Status is DownloadResponseX.
|
||||
func (info *DownloadInfo) Resume() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.Status != DownloadPause { // The download must be paused to resume.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.Status = DownloadActive
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// Cancel cancels the download. Status is DownloadResponseX.
|
||||
func (info *DownloadInfo) Cancel() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.Status >= DownloadCanceled { // The download must not be already canceled or finished.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.Status = DownloadCanceled
|
||||
info.DiskFile.Handle.Close()
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// Finish marks the download as finished.
|
||||
func (info *DownloadInfo) Finish() (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.Status != DownloadActive { // The download must be active.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
info.Status = DownloadFinished
|
||||
info.DiskFile.Handle.Close()
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
// InitDiskFile creates the target File
|
||||
func (info *DownloadInfo) InitDiskFile(path string) (err error) {
|
||||
info.DiskFile.Name = path
|
||||
info.DiskFile.Handle, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666) // 666 : All uses can read/write
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// storeDownloadData stores downloaded data. It does not change the download Status.
|
||||
func (info *DownloadInfo) storeDownloadData(data []byte, offset uint64) (status int) {
|
||||
info.Lock()
|
||||
defer info.Unlock()
|
||||
|
||||
if info.Status != DownloadActive { // The download must be active.
|
||||
return DownloadResponseActionInvalid
|
||||
}
|
||||
|
||||
if _, err := info.DiskFile.Handle.WriteAt(data, int64(offset)); err != nil {
|
||||
return DownloadResponseFileWrite
|
||||
}
|
||||
|
||||
info.DiskFile.StoredSize += uint64(len(data))
|
||||
|
||||
return DownloadResponseSuccess
|
||||
}
|
||||
|
||||
func (info *DownloadInfo) DownloadSelf() {
|
||||
// Check if the File is available in the local warehouse.
|
||||
_, fileSize, status, _ := info.Backend.UserWarehouse.FileExists(info.Hash)
|
||||
if status != warehouse.StatusOK {
|
||||
info.Status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.File.Size = fileSize
|
||||
info.Status = DownloadActive
|
||||
|
||||
// read the File
|
||||
status, bytesRead, _ := info.Backend.UserWarehouse.ReadFile(info.Hash, 0, int64(info.File.Size), info.DiskFile.Handle)
|
||||
|
||||
info.DiskFile.StoredSize = uint64(bytesRead)
|
||||
|
||||
if status != warehouse.StatusOK {
|
||||
info.Status = DownloadCanceled
|
||||
return
|
||||
}
|
||||
|
||||
info.Finish()
|
||||
info.DeleteDefer(time.Hour * 1) // cache the details for 1 hour before removing}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user