Files
core/webapi/Clone.go

131 lines
3.5 KiB
Go

/*
File Name: Download.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
package webapi
import (
"bytes"
"errors"
"github.com/PeernetOfficial/core/blockchain"
"net/http"
"time"
"github.com/google/uuid"
)
type hostInfo struct {
api *WebapiInstance
info *downloadInfo
filepath string
}
/*
apiCloneFile starts the download of a file, adds it the current warehouse and adds it
to your blockchain. The path is the full path on disk to store the file.
The hash parameter identifies the file to download. The node ID identifies the blockchain (i.e., the "owner" of the file).
The following is a prototype implementation
Request: GET /follow/file?path=[target path on disk]&hash=[file hash to download]&node=[node ID]
Result: 200 with JSON structure apiResponseDownloadStatus
*/
func (api *WebapiInstance) apiHostFile(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
// validate hashes, must be blake3
hash, valid1 := DecodeBlake3Hash(r.Form.Get("hash"))
nodeID, valid2 := DecodeBlake3Hash(r.Form.Get("node"))
if !valid1 || !valid2 {
http.Error(w, "node ID or hash not valid", http.StatusBadRequest)
return
}
filePath := r.Form.Get("path")
if filePath == "" {
http.Error(w, "file path provided is blank", http.StatusBadRequest)
return
}
info := &downloadInfo{backend: api.backend, api: api, id: uuid.New(), created: time.Now(), hash: hash, nodeID: nodeID}
// create the file immediately
if info.initDiskFile(filePath) != nil {
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseFileInvalid})
return
}
// add the download to the list
api.downloadAdd(info)
// Setting host information
var HostInfo hostInfo
HostInfo.api = api
HostInfo.info = info
HostInfo.filepath = filePath
// start the download!
go HostInfo.StartHostDownload()
EncodeJSON(api.backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseSuccess, ID: info.id, DownloadStatus: DownloadWaitMetadata})
}
// StartHostDownload Starts the download, adds the downloaded file to the warehouse and then the following file is added to the user blockchain
func (info *hostInfo) StartHostDownload() error {
// current user?
if bytes.Equal(info.info.nodeID, info.info.backend.SelfNodeID()) {
info.info.DownloadSelf()
return nil
}
for n := 0; n < 3 && info.info.peer == nil; n++ {
_, info.info.peer, _ = info.info.backend.FindNode(info.info.nodeID, time.Second*5)
if info.info.status == DownloadCanceled {
return errors.New("DownloadCanceled")
}
}
if info.info.peer != nil {
info.info.Download()
// Adding the following file the warehouse
if info.filepath == "" {
return errors.New("File Path empty. ")
}
hash, status, err := info.api.backend.UserWarehouse.CreateFileFromPath(info.filepath)
if err != nil {
info.api.backend.LogError("warehouse.CreateFile", "status %d error: %v", status, err)
}
// Adding file to the blockchain
var fileMetaData blockchain.BlockRecordFile
// Add the following file to the blockchain
fileMetaData.ID = uuid.New()
fileMetaData.Hash = hash
_, fileSize, _, _ := info.api.backend.UserWarehouse.FileExists(fileMetaData.Hash)
// setting file size
fileMetaData.Size = fileSize
// create block based on file information provided
block := blockRecordFileFromAPI(info.info.file)
var filesAdd []blockchain.BlockRecordFile
// appending the block to the file added
filesAdd = append(filesAdd, block)
info.api.backend.UserBlockchain.AddFiles(filesAdd)
} else {
info.info.status = DownloadCanceled
}
return nil
}