Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ log.txt
test.*
# Ignore the IDE gitignore files
.idea/
# Test cases generate the following
data/
Config.yaml
107 changes: 107 additions & 0 deletions Abstrations/files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
File Name: abstractions.go
Copyright: 2021 Peernet s.r.o.
Authors: Peter Kleissner, Akilan Selvacoumar
*/
package Abstrations

import (
"encoding/hex"
"errors"
"github.com/PeernetOfficial/core"
"github.com/PeernetOfficial/core/blockchain"
"github.com/PeernetOfficial/core/protocol"
"github.com/PeernetOfficial/core/warehouse"
"github.com/PeernetOfficial/core/webapi"
"github.com/google/uuid"
"path/filepath"
"time"
)

/*
Library description
to about abstracted function to easily add and remove files.
*/

type TouchReturn struct {
BlockchainHeight uint64
BlockchainVersion uint64
}

// Touch abstracted function that creates a file
// and adds the file to the warehouse and
// blockchain
// returns blockchain version and height
func Touch(b *core.Backend, filePath string) (*TouchReturn, error) {
// Creates a File in the warehouse
hash, _, err := b.UserWarehouse.CreateFileFromPath(filePath)
if err != nil {
return nil, err
}

// Add the File to the local blockchain
var input webapi.ApiBlockAddFiles
var inputFiles []webapi.ApiFile
var inputFile webapi.ApiFile

// Write File information to the input File
inputFile.Date = time.Now()
// Folder and File name
dir, file := filepath.Split(filePath)
inputFile.Folder = dir
inputFile.Name = file
inputFile.ID = uuid.New()
inputFile.Hash = hash

// Get the public key of the current node
_, publicKey := b.ExportPrivateKey()
inputFile.NodeID = []byte(hex.EncodeToString(publicKey.SerializeCompressed()))

inputFiles = append(inputFiles, inputFile)

input.Files = inputFiles

var filesAdd []blockchain.BlockRecordFile

for _, File := range input.Files {
if len(File.Hash) != protocol.HashSize {
return nil, errors.New("bad request")
}
if File.ID == uuid.Nil { // if the ID is not provided by the caller, set it
File.ID = uuid.New()
}

// Verify that the File exists in the warehouse. Folders are exempt from this check as they are only virtual.
if !File.IsVirtualFolder() {
if _, err := warehouse.ValidateHash(File.Hash); err != nil {
return nil, errors.New("bad request when validating hash")
} else if _, fileInfo, status, _ := b.UserWarehouse.FileExists(File.Hash); status != warehouse.StatusOK {
//EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
return nil, errors.New("file not in warehouse")
} else {
File.Size = fileInfo
}
} else {
File.Hash = protocol.HashData(nil)
File.Size = 0
}

blockRecord := webapi.BlockRecordFileFromAPI(File)

// Set the merkle tree info as appropriate.
if !webapi.SetFileMerkleInfo(b, &blockRecord) {
return nil, errors.New("merkle information not set")
}

filesAdd = append(filesAdd, blockRecord)
}

newHeight, newVersion, _ := b.UserBlockchain.AddFiles(filesAdd)

// Creating object for custom return type
var touchReturn TouchReturn
touchReturn.BlockchainHeight = newHeight
touchReturn.BlockchainVersion = newVersion

return &touchReturn, nil
}
35 changes: 35 additions & 0 deletions Abstrations/files_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package Abstrations

import (
"fmt"
"github.com/PeernetOfficial/core"
"github.com/PeernetOfficial/core/webapi"
"github.com/google/uuid"
"testing"
"time"
)

func InitPeernet() *core.Backend {
backendInit, status, err := core.Init("Your application/1.0", "Config.yaml", nil, nil)
if status != core.ExitSuccess {
fmt.Printf("Error %d initializing config: %s\n", status, err.Error())
return nil
}

// start config api server
webapi.Start(backendInit, []string{"127.0.0.1:5125"}, false, "", "", 10*time.Second, 10*time.Second, uuid.Nil)

backendInit.Connect()

return backendInit
}

// Testing the touch function if the file is added or not
func TestBackend_Touch(t *testing.T) {
backend := InitPeernet()
touch, err := Touch(backend, "Config.yaml")
if err != nil {
t.Fail()
}
fmt.Printf("blockchain height: %v", touch.BlockchainHeight)
}
2 changes: 1 addition & 1 deletion webapi/Blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (api *WebapiInstance) apiBlockchainRead(w http.ResponseWriter, r *http.Requ
for _, record := range block.RecordsDecoded {
switch v := record.(type) {
case blockchain.BlockRecordFile:
result.RecordsDecoded = append(result.RecordsDecoded, blockRecordFileToAPI(v))
result.RecordsDecoded = append(result.RecordsDecoded, BlockRecordFileToAPI(v))

case blockchain.BlockRecordProfile:
result.RecordsDecoded = append(result.RecordsDecoded, blockRecordProfileToAPI(v))
Expand Down
4 changes: 2 additions & 2 deletions webapi/Download.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type apiResponseDownloadStatus struct {
APIStatus int `json:"apistatus"` // Status of the API call. See DownloadResponseX.
ID uuid.UUID `json:"id"` // Download ID. This can be used to query the latest status and take actions.
DownloadStatus int `json:"downloadstatus"` // Status of the download. See DownloadX.
File apiFile `json:"file"` // File information. Only available for status >= DownloadWaitSwarm.
File ApiFile `json:"file"` // File information. Only available for status >= DownloadWaitSwarm.
Progress struct {
TotalSize uint64 `json:"totalsize"` // Total size in bytes.
DownloadedSize uint64 `json:"downloadedsize"` // Count of bytes download so far.
Expand Down Expand Up @@ -189,7 +189,7 @@ type downloadInfo struct {
created time.Time // When the download was created.
ended time.Time // When the download was finished (only status = DownloadFinished).

file apiFile // File metadata (only status >= DownloadWaitSwarm)
file ApiFile // File metadata (only status >= DownloadWaitSwarm)

DiskFile struct { // Target file on disk to store downloaded data
Name string // File name
Expand Down
66 changes: 33 additions & 33 deletions webapi/File.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
"github.com/google/uuid"
)

// apiFileMetadata contains metadata information.
type apiFileMetadata struct {
// ApiFileMetadata contains metadata information.
type ApiFileMetadata struct {
Type uint16 `json:"type"` // See core.TagX constants.
Name string `json:"name"` // User friendly name of the metadata type. Use the Type fields to identify the metadata as this name may change.
// Depending on the exact type, one of the below fields is used for proper encoding:
Expand All @@ -29,8 +29,8 @@ type apiFileMetadata struct {
Number uint64 `json:"number"` // Number
}

// apiFile is the metadata of a file published on the blockchain
type apiFile struct {
// ApiFile is the metadata of a file published on the blockchain
type ApiFile struct {
ID uuid.UUID `json:"id"` // Unique ID.
Hash []byte `json:"hash"` // Blake3 hash of the file data
Type uint8 `json:"type"` // File Type. For example audio or document. See TypeX.
Expand All @@ -41,13 +41,13 @@ type apiFile struct {
Description string `json:"description"` // Description. This is expected to be multiline and contain hashtags!
Date time.Time `json:"date"` // Date shared
NodeID []byte `json:"nodeid"` // Node ID, owner of the file. Read only.
Metadata []apiFileMetadata `json:"metadata"` // Additional metadata.
Metadata []ApiFileMetadata `json:"metadata"` // Additional metadata.
}

// --- conversion from core to API data ---

func blockRecordFileToAPI(input blockchain.BlockRecordFile) (output apiFile) {
output = apiFile{ID: input.ID, Hash: input.Hash, NodeID: input.NodeID, Type: input.Type, Format: input.Format, Size: input.Size, Metadata: []apiFileMetadata{}}
func BlockRecordFileToAPI(input blockchain.BlockRecordFile) (output ApiFile) {
output = ApiFile{ID: input.ID, Hash: input.Hash, NodeID: input.NodeID, Type: input.Type, Format: input.Format, Size: input.Size, Metadata: []ApiFileMetadata{}}

for _, tag := range input.Tags {
switch tag.Type {
Expand All @@ -65,23 +65,23 @@ func blockRecordFileToAPI(input blockchain.BlockRecordFile) (output apiFile) {

case blockchain.TagDateCreated:
date, _ := tag.Date()
output.Metadata = append(output.Metadata, apiFileMetadata{Type: tag.Type, Name: "Date Created", Date: date})
output.Metadata = append(output.Metadata, ApiFileMetadata{Type: tag.Type, Name: "Date Created", Date: date})

case blockchain.TagSharedByCount:
output.Metadata = append(output.Metadata, apiFileMetadata{Type: tag.Type, Name: "Shared By Count", Number: tag.Number()})
output.Metadata = append(output.Metadata, ApiFileMetadata{Type: tag.Type, Name: "Shared By Count", Number: tag.Number()})

case blockchain.TagSharedByGeoIP:
output.Metadata = append(output.Metadata, apiFileMetadata{Type: tag.Type, Name: "Shared By GeoIP", Text: tag.Text()})
output.Metadata = append(output.Metadata, ApiFileMetadata{Type: tag.Type, Name: "Shared By GeoIP", Text: tag.Text()})

default:
output.Metadata = append(output.Metadata, apiFileMetadata{Type: tag.Type, Blob: tag.Data})
output.Metadata = append(output.Metadata, ApiFileMetadata{Type: tag.Type, Blob: tag.Data})
}
}

return output
}

func blockRecordFileFromAPI(input apiFile) (output blockchain.BlockRecordFile) {
func BlockRecordFileFromAPI(input ApiFile) (output blockchain.BlockRecordFile) {
output = blockchain.BlockRecordFile{ID: input.ID, Hash: input.Hash, Type: input.Type, Format: input.Format, Size: input.Size}

if input.Name != "" {
Expand Down Expand Up @@ -115,9 +115,9 @@ func blockRecordFileFromAPI(input apiFile) (output blockchain.BlockRecordFile) {

// --- File API ---

// apiBlockAddFiles contains a list of files from the blockchain
type apiBlockAddFiles struct {
Files []apiFile `json:"files"` // List of files
// ApiBlockAddFiles contains a list of files from the blockchain
type ApiBlockAddFiles struct {
Files []ApiFile `json:"files"` // List of files
Status int `json:"status"` // Status of the operation, only used when this structure is returned from the API.
}

Expand All @@ -128,12 +128,12 @@ If any file is not stored in the Warehouse, the function aborts with the status
If the block record encoding fails for any file, this function aborts with the status code StatusCorruptBlockRecord.
In case the function aborts, the blockchain remains unchanged.

Request: POST /blockchain/file/add with JSON structure apiBlockAddFiles
Request: POST /blockchain/file/add with JSON structure ApiBlockAddFiles
Response: 200 with JSON structure apiBlockchainBlockStatus
400 if invalid input
*/
func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.Request) {
var input apiBlockAddFiles
var input ApiBlockAddFiles
if err := DecodeJSON(w, r, &input); err != nil {
return
}
Expand Down Expand Up @@ -165,10 +165,10 @@ func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.R
file.Size = 0
}

blockRecord := blockRecordFileFromAPI(file)
blockRecord := BlockRecordFileFromAPI(file)

// Set the merkle tree info as appropriate.
if !setFileMerkleInfo(api.backend, &blockRecord) {
if !SetFileMerkleInfo(api.backend, &blockRecord) {
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
return
}
Expand All @@ -185,15 +185,15 @@ func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.R
apiBlockchainFileList lists all files stored on the blockchain.

Request: GET /blockchain/file/list
Response: 200 with JSON structure apiBlockAddFiles
Response: 200 with JSON structure ApiBlockAddFiles
*/
func (api *WebapiInstance) apiBlockchainFileList(w http.ResponseWriter, r *http.Request) {
files, status := api.backend.UserBlockchain.ListFiles()

var result apiBlockAddFiles
var result ApiBlockAddFiles

for _, file := range files {
result.Files = append(result.Files, blockRecordFileToAPI(file))
result.Files = append(result.Files, BlockRecordFileToAPI(file))
}

result.Status = status
Expand All @@ -205,11 +205,11 @@ func (api *WebapiInstance) apiBlockchainFileList(w http.ResponseWriter, r *http.
apiBlockchainFileDelete deletes files with the provided IDs. Other fields are ignored.
It will automatically delete the file in the Warehouse if there are no other references.

Request: POST /blockchain/file/delete with JSON structure apiBlockAddFiles
Request: POST /blockchain/file/delete with JSON structure ApiBlockAddFiles
Response: 200 with JSON structure apiBlockchainBlockStatus
*/
func (api *WebapiInstance) apiBlockchainFileDelete(w http.ResponseWriter, r *http.Request) {
var input apiBlockAddFiles
var input ApiBlockAddFiles
if err := DecodeJSON(w, r, &input); err != nil {
return
}
Expand Down Expand Up @@ -237,12 +237,12 @@ func (api *WebapiInstance) apiBlockchainFileDelete(w http.ResponseWriter, r *htt
/*
apiBlockchainSelfUpdateFile updates files that are already published on the blockchain.

Request: POST /blockchain/file/update with JSON structure apiBlockAddFiles
Request: POST /blockchain/file/update with JSON structure ApiBlockAddFiles
Response: 200 with JSON structure apiBlockchainBlockStatus
400 if invalid input
*/
func (api *WebapiInstance) apiBlockchainFileUpdate(w http.ResponseWriter, r *http.Request) {
var input apiBlockAddFiles
var input ApiBlockAddFiles
if err := DecodeJSON(w, r, &input); err != nil {
return
}
Expand Down Expand Up @@ -274,10 +274,10 @@ func (api *WebapiInstance) apiBlockchainFileUpdate(w http.ResponseWriter, r *htt
file.Size = 0
}

blockRecord := blockRecordFileFromAPI(file)
blockRecord := BlockRecordFileFromAPI(file)

// Set the merkle tree info as appropriate.
if !setFileMerkleInfo(api.backend, &blockRecord) {
if !SetFileMerkleInfo(api.backend, &blockRecord) {
EncodeJSON(api.backend, w, r, apiBlockchainBlockStatus{Status: blockchain.StatusNotInWarehouse})
return
}
Expand All @@ -293,7 +293,7 @@ func (api *WebapiInstance) apiBlockchainFileUpdate(w http.ResponseWriter, r *htt
// ---- metadata functions ----

// GetMetadata returns the specified metadata or nil if not available.
func (file *apiFile) GetMetadata(Type uint16) (info *apiFileMetadata) {
func (file *ApiFile) GetMetadata(Type uint16) (info *ApiFileMetadata) {
for n := range file.Metadata {
if file.Metadata[n].Type == Type {
return &file.Metadata[n]
Expand All @@ -304,7 +304,7 @@ func (file *apiFile) GetMetadata(Type uint16) (info *apiFileMetadata) {
}

// GetNumber returns the data as number. 0 if not available.
func (info *apiFileMetadata) GetNumber() uint64 {
func (info *ApiFileMetadata) GetNumber() uint64 {
if info == nil {
return 0
}
Expand All @@ -313,12 +313,12 @@ func (info *apiFileMetadata) GetNumber() uint64 {
}

// IsVirtualFolder returns true if the file is a virtual folder
func (file *apiFile) IsVirtualFolder() bool {
func (file *ApiFile) IsVirtualFolder() bool {
return file.Type == core.TypeFolder && file.Format == core.FormatFolder
}

// setFileMerkleInfo sets the merkle fields in the BlockRecordFile
func setFileMerkleInfo(backend *core.Backend, file *blockchain.BlockRecordFile) (valid bool) {
// SetFileMerkleInfo sets the merkle fields in the BlockRecordFile
func SetFileMerkleInfo(backend *core.Backend, file *blockchain.BlockRecordFile) (valid bool) {
if file.Size <= merkle.MinimumFragmentSize {
// If smaller or equal than the minimum fragment size, the merkle tree is not used.
file.MerkleRootHash = file.Hash
Expand Down
2 changes: 1 addition & 1 deletion webapi/Search Dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ resultLoop:
}

// new result
newFile := blockRecordFileToAPI(file)
newFile := BlockRecordFileToAPI(file)

job.Files = append(job.Files, &newFile)
job.AllFiles = append(job.AllFiles, &newFile)
Expand Down
Loading