New features (#110)

* added upload status

* added changes for progress bar with more logs and bug fixes, Documentation yet to be added

* huge changes that need more doucmenting

* added possibility to get profile using NodeID

* added fix profile listing user profile information

* removed profile image from the explore reult struct

* saving current changes

* added filter to search based on NodeID

* Monday bug fixing

* updates to the profile

* changes for tracing the blockchain profile image not shown

* added condition to ensure TAG is not sent and removed debug prints

* updated webapi docs
This commit is contained in:
Akilan Selvacoumar
2023-06-28 00:38:17 +01:00
committed by GitHub
parent 97c3001596
commit ae5f1d2fd7
91 changed files with 483 additions and 196 deletions

View File

@@ -1,5 +1,5 @@
/*
File Name: Blockchain Cache Global.go
File Username: Blockchain Cache Global.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Blockchain User.go
File Username: Blockchain User.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Bootstrap.go
File Username: Bootstrap.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Command Traverse.go
File Username: Command Traverse.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Commands.go
File Username: Commands.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Settings.go
File Username: Settings.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Connection.go
File Username: Connection.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/
@@ -357,7 +357,7 @@ func (c *Connection) send(packet *protocol.PacketRaw, receiverPublicKey *btcec.P
// Send Traverse message if the peer is behind a NAT or firewall and this is the first message. Only for Announcement.
if err == nil && isFirstPacket && (c.IsBehindNAT() || c.Firewall) && c.traversePeer != nil && packet.Command == protocol.CommandAnnouncement {
c.traversePeer.sendTraverse(packet, receiverPublicKey)
err = c.traversePeer.sendTraverse(packet, receiverPublicKey)
}
return err

View File

@@ -1,5 +1,5 @@
/*
File Name: DHT Store.go
File Username: DHT Store.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Exit.go
File Username: Exit.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: File Formats.go
File Username: File Formats.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -25,25 +25,26 @@ const (
// File formats. New ones may be added to the list as required.
const (
FormatBinary = iota // Binary/unspecified
FormatPDF // PDF document
FormatWord // Word document
FormatExcel // Excel
FormatPowerpoint // Powerpoint
FormatPicture // Pictures (including GIF, excluding icons)
FormatAudio // Audio files
FormatVideo // Video files
FormatContainer // Compressed files including ZIP, RAR, TAR and others
FormatHTML // HTML file
FormatText // Text file
FormatEbook // Ebook file
FormatCompressed // Compressed file
FormatDatabase // Database file
FormatEmail // Single email
FormatCSV // CSV file
FormatFolder // Virtual folder
FormatExecutable // Executable file
FormatInstaller // Installer
FormatAPK // APK
FormatISO // ISO
FormatBinary = iota // Binary/unspecified
FormatPDF // PDF document
FormatWord // Word document
FormatExcel // Excel
FormatPowerpoint // Powerpoint
FormatPicture // Pictures (including GIF, excluding icons)
FormatAudio // Audio files
FormatVideo // Video files
FormatContainer // Compressed files including ZIP, RAR, TAR and others
FormatHTML // HTML file
FormatText // Text file
FormatEbook // Ebook file
FormatCompressed // Compressed file
FormatDatabase // Database file
FormatEmail // Single email
FormatCSV // CSV file
FormatFolder // Virtual folder
FormatExecutable // Executable file
FormatInstaller // Installer
FormatAPK // APK
FormatISO // ISO
FormatPeernetSearch // Peernet Search
)

View File

@@ -1,5 +1,5 @@
/*
File Name: Filter.go
File Username: Filter.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Kademlia.go
File Username: Kademlia.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Send.go
File Username: Message Send.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Network Detection.go
File Username: Network Detection.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Network IPv4 Broadcast.go
File Username: Network IPv4 Broadcast.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Network IPv6 Multicast.go
File Username: Network IPv6 Multicast.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -63,7 +63,7 @@ func (network *Network) MulticastIPv6Join() (err error) {
joinMulticastGroup := func(iface *net.Interface) (err error) {
pc := ipv6.NewPacketConn(network.multicastSocket)
if err := pc.JoinGroup(iface, &net.UDPAddr{IP: network.multicastIP}); err != nil {
//LogError("MulticastIPv6Join", "join multicast group iface '%s' multicast IP '%s' listen on IP '%s' port '%d': %v\n", iface.Name, network.multicastIP.String(), network.address.IP.String(), ipv6MulticastPort, err)
//LogError("MulticastIPv6Join", "join multicast group iface '%s' multicast IP '%s' listen on IP '%s' port '%d': %v\n", iface.Username, network.multicastIP.String(), network.address.IP.String(), ipv6MulticastPort, err)
return err
}

View File

@@ -1,5 +1,5 @@
/*
File Name: Network Init.go
File Username: Network Init.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Network UPnP.go
File Username: Network UPnP.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Network.go
File Username: Network.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Networks.go
File Username: Networks.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Peer ID.go
File Username: Peer ID.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Peernet.go
File Username: Peernet.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/
@@ -19,7 +19,7 @@ import (
)
// Init initializes the client. If the config file does not exist or is empty, a default one will be created.
// The User Agent must be provided in the form "Application Name/1.0".
// The User Agent must be provided in the form "Application Username/1.0".
// The returned status is of type ExitX. Anything other than ExitSuccess indicates a fatal failure.
func Init(UserAgent string, ConfigFilename string, Filters *Filters, ConfigOut interface{}) (backend *Backend, status int, err error) {
if UserAgent == "" {

View File

@@ -1,5 +1,5 @@
/*
File Name: Ping.go
File Username: Ping.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Transfer Block.go
File Username: Transfer Block.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Transfer UDT.go
File Username: Transfer UDT.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Transfer Virtual Connection.go
File Username: Transfer Virtual Connection.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Warehouse.go
File Username: Warehouse.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Block Record File.go
File Username: Block Record File.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -48,6 +48,7 @@ type BlockRecordFile struct {
Size uint64 // Size of the file data
NodeID []byte // Node ID, owner of the file
Tags []BlockRecordFileTag // Tags provide additional metadata
Username string // Username of the User who uploaded the file
}
// BlockRecordFileTag provides metadata about the file.

View File

@@ -1,5 +1,5 @@
/*
File Name: Block Record Profile.go
File Username: Block Record Profile.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -24,8 +24,8 @@ type BlockRecordProfile struct {
Data []byte // Data
}
// decodeBlockRecordProfile decodes only profile records. Other records are ignored.
func decodeBlockRecordProfile(recordsRaw []BlockRecordRaw) (fields []BlockRecordProfile, err error) {
// DecodeBlockRecordProfile decodes only profile records. Other records are ignored.
func DecodeBlockRecordProfile(recordsRaw []BlockRecordRaw) (fields []BlockRecordProfile, err error) {
fieldMap := make(map[uint16][]byte)
for _, record := range recordsRaw {

View File

@@ -1,5 +1,5 @@
/*
File Name: Block Record.go
File Username: Block Record.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -45,7 +45,7 @@ func decodeBlockRecords(block *Block) (decoded *BlockDecoded, err error) {
decoded.RecordsDecoded = append(decoded.RecordsDecoded, file)
}
if profileFields, err := decodeBlockRecordProfile(block.RecordsRaw); err != nil {
if profileFields, err := DecodeBlockRecordProfile(block.RecordsRaw); err != nil {
return nil, err
} else if len(profileFields) > 0 {
decoded.RecordsDecoded = append(decoded.RecordsDecoded, profileFields)

View File

@@ -1,5 +1,5 @@
/*
File Name: Block.go
File Username: Block.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Blockchain.go
File Username: Blockchain.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: File Tag.go
File Username: File Tag.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -16,7 +16,7 @@ import (
// List of defined file tags. Virtual tags are generated at runtime and are read-only. They cannot be stored on the blockchain.
const (
TagName = 0 // Name of file.
TagName = 0 // Username of file.
TagFolder = 1 // Folder name.
TagDescription = 2 // Arbitrary description of the file. May contain hashtags.
TagDateShared = 3 // When the file was published on the blockchain. Virtual.

View File

@@ -1,5 +1,5 @@
/*
File Name: File.go
File Username: File.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Multi.go
File Username: Multi.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
@@ -16,6 +16,7 @@ package blockchain
import (
"encoding/binary"
"errors"
"fmt"
"time"
"github.com/PeernetOfficial/core/btcec"
@@ -277,7 +278,11 @@ func (multi *MultiStore) IngestBlock(header *MultiBlockchainHeader, blockNumber
}
// store the transferred block in the cache
multi.WriteBlock(header.PublicKey, header.Version, blockNumber, raw)
err = multi.WriteBlock(header.PublicKey, header.Version, blockNumber, raw)
if err != nil {
fmt.Println(err)
}
header.ListBlocks = append(header.ListBlocks, blockNumber)
// update blockchain header stats if records were decoded

View File

@@ -1,5 +1,5 @@
/*
File Name: Profile Data.go
File Username: Profile Data.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Profile.go
File Username: Profile.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/
@@ -11,7 +11,7 @@ func (blockchain *Blockchain) ProfileReadField(index uint16) (data []byte, statu
found := false
status = blockchain.Iterate(func(block *Block) (statusI int) {
fields, err := decodeBlockRecordProfile(block.RecordsRaw)
fields, err := DecodeBlockRecordProfile(block.RecordsRaw)
if err != nil {
return StatusCorruptBlockRecord
} else if len(fields) == 0 {
@@ -43,7 +43,7 @@ func (blockchain *Blockchain) ProfileList() (fields []BlockRecordProfile, status
uniqueFields := make(map[uint16][]byte)
status = blockchain.Iterate(func(block *Block) (statusI int) {
fields, err := decodeBlockRecordProfile(block.RecordsRaw)
fields, err := DecodeBlockRecordProfile(block.RecordsRaw)
if err != nil {
return StatusCorruptBlockRecord
}
@@ -103,7 +103,7 @@ func (blockchain *Blockchain) ProfileDelete(fields []uint16) (newHeight, newVers
return 0 // no action
}
existingFields, err := decodeBlockRecordProfile([]BlockRecordRaw{*record})
existingFields, err := DecodeBlockRecordProfile([]BlockRecordRaw{*record})
if err != nil || len(existingFields) != 1 {
return 3 // error blockchain corrupt
}

View File

@@ -167,7 +167,7 @@ func printFile(file BlockRecordFile) {
for _, tag := range file.Tags {
switch tag.Type {
case TagName:
fmt.Printf(" Name %s\n", tag.Text())
fmt.Printf(" Username %s\n", tag.Text())
case TagFolder:
fmt.Printf(" Folder %s\n", tag.Text())
case TagDescription:

View File

@@ -1,5 +1,5 @@
/*
File Name: DHT Lite.go
File Username: DHT Lite.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Hash Table.go
File Username: Hash Table.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Information Request.go
File Username: Information Request.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Node.go
File Username: Node.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Search Client.go
File Username: Search Client.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Fragment.go
File Username: Fragment.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Merkle Tree.go
File Username: Merkle Tree.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Command.go
File Username: Command.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: File Transfer.go
File Username: File Transfer.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Hash.go
File Username: Hash.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Encoding Announcement.go
File Username: Message Encoding Announcement.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Encoding Get Block.go
File Username: Message Encoding Get Block.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Encoding Response.go
File Username: Message Encoding Response.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Encoding Transfer.go
File Username: Message Encoding Transfer.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Encoding Traverse.go
File Username: Message Encoding Traverse.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Message Encoding.go
File Username: Message Encoding.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Packet Encoding.go
File Username: Packet Encoding.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Packet Lite.go
File Username: Packet Lite.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Sequence.go
File Username: Sequence.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Sanitize.go
File Username: Sanitize.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Normalizing.go
File name: Normalizing.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Search Index.go
File name: Search Index.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Search Term.go
File name: Search Term.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Text 2 Hash.go
File name: Text 2 Hash.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Memory.go
File name: Memory.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Pebble.go
File name: Pebble.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Pogreb.go
File Username: Pogreb.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Store.go
File Username: Store.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Execute.go
File Username: Execute.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Read Package.go
File Username: Read Package.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: UPnP.go
File Username: UPnP.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Merkle.go
File Username: Merkle.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: Store.go
File Username: Store.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -38,7 +38,7 @@ const (
// CreateFile creates a new file in the warehouse
// If fileSize is provided, creating the merkle tree is significantly faster as it will be created on the fly. If the file size is unknown, set the size to 0.
func (wh *Warehouse) CreateFile(data io.Reader, fileSize uint64) (hash []byte, status int, err error) {
func (wh *Warehouse) CreateFile(data io.Reader, fileSize uint64, uploadStatus io.Writer) (hash []byte, status int, err error) {
// create a temporary file to hold the body content
tmpFile, err := wh.tempFile()
if err != nil {
@@ -55,8 +55,14 @@ func (wh *Warehouse) CreateFile(data io.Reader, fileSize uint64) (hash []byte, s
// create the hash-writer
hashWriter := blake3.New(hashSize, nil)
// the multi-writer writes to the temp-file and the hash simultaneously
mw := io.MultiWriter(tmpFile, hashWriter)
var mw io.Writer
if uploadStatus != nil {
// the multi-writer writes to the temp-file and the hash simultaneously
mw = io.MultiWriter(tmpFile, hashWriter, uploadStatus)
} else {
mw = io.MultiWriter(tmpFile, hashWriter)
}
// copy into the multiwriter
if _, err = io.Copy(mw, data); err != nil {
@@ -132,7 +138,7 @@ func (wh *Warehouse) CreateFileFromPath(file string) (hash []byte, status int, e
}
// create the file using the opened file
return wh.CreateFile(fileHandle, fileSize)
return wh.CreateFile(fileHandle, fileSize, nil)
}
// ReadFile reads a file from the warehouse and outputs it to the writer

View File

@@ -1,5 +1,5 @@
/*
File Name: Warehouse.go
File Username: Warehouse.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -93,7 +93,7 @@ func (wh *Warehouse) IterateFiles(Callback func(Hash []byte, Size int64) (Contin
name1 := file.Name()
_, err = hex.DecodeString(name1)
// we are only looking for directories. Name has to be "XXXX" hex chars only.
// we are only looking for directories. Username has to be "XXXX" hex chars only.
if !file.IsDir() || len(name1) != 4 || err != nil {
continue
}
@@ -108,7 +108,7 @@ func (wh *Warehouse) IterateFiles(Callback func(Hash []byte, Size int64) (Contin
name2 := file2.Name()
_, err = hex.DecodeString(name2)
// we are only looking for directories. Name has to be "XXXX" hex chars only.
// we are only looking for directories. Username has to be "XXXX" hex chars only.
if !file2.IsDir() || len(name2) != 4 || err != nil {
continue
}

View File

@@ -1,5 +1,5 @@
/*
File Name: API.go
File Username: API.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -36,6 +36,17 @@ type WebapiInstance struct {
// download info
downloads map[uuid.UUID]*downloadInfo
downloadsMutex sync.RWMutex
// upload info
uploads map[uuid.UUID]*UploadStatus
uploadsMutex sync.RWMutex
}
// API error
// This follows the same format as the logger
type errorResponse struct {
function string
error string
}
// WSUpgrader is used for websocket functionality. It allows all requests.
@@ -62,6 +73,7 @@ func Start(Backend *core.Backend, ListenAddresses []string, UseSSL bool, Certifi
AllowKeyInParam: []string{"/file/read", "/file/view"},
allJobs: make(map[uuid.UUID]*SearchJob),
downloads: make(map[uuid.UUID]*downloadInfo),
uploads: make(map[uuid.UUID]*UploadStatus),
}
if APIKey != uuid.Nil {
@@ -96,7 +108,9 @@ func Start(Backend *core.Backend, ListenAddresses []string, UseSSL bool, Certifi
api.Router.HandleFunc("/download/start", api.apiDownloadStart).Methods("GET")
api.Router.HandleFunc("/download/status", api.apiDownloadStatus).Methods("GET")
api.Router.HandleFunc("/download/action", api.apiDownloadAction).Methods("GET")
api.Router.HandleFunc("/warehouse/create", api.apiWarehouseCreateFile).Methods("POST")
api.Router.HandleFunc("/warehouse/create", api.ApiWarehouseCreateFile).Methods("POST")
api.Router.HandleFunc("/warehouse/create/uploadID", api.apiUploadID).Methods("GET")
api.Router.HandleFunc("/warehouse/create/track/uploadID", api.apiUploadInfo).Methods("GET")
api.Router.HandleFunc("/warehouse/create/path", api.apiWarehouseCreateFilePath).Methods("GET")
api.Router.HandleFunc("/warehouse/read", api.apiWarehouseReadFile).Methods("GET")
api.Router.HandleFunc("/warehouse/read/path", api.apiWarehouseReadFilePath).Methods("GET")

View File

@@ -1,5 +1,5 @@
/*
File Name: Blockchain.go
File Username: Blockchain.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -8,10 +8,9 @@ package webapi
import (
"encoding/hex"
"github.com/PeernetOfficial/core/blockchain"
"net/http"
"strconv"
"github.com/PeernetOfficial/core/blockchain"
)
type apiBlockchainHeader struct {

View File

@@ -1,5 +1,5 @@
/*
File Name: Download Transfer.go
File Username: Download Transfer.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: Download.go
File Username: Download.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -78,6 +78,8 @@ func (api *WebapiInstance) apiDownloadStart(w http.ResponseWriter, r *http.Reque
info := &downloadInfo{backend: api.Backend, api: api, id: uuid.New(), created: time.Now(), hash: hash, nodeID: nodeID}
api.Backend.LogError("Download.DownloadStart", "output %v", 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})
@@ -90,6 +92,8 @@ func (api *WebapiInstance) apiDownloadStart(w http.ResponseWriter, r *http.Reque
// start the download!
go info.Start()
api.Backend.LogError("Download.DownloadStart", "output %v", apiResponseDownloadStatus{APIStatus: DownloadResponseSuccess, ID: info.id, DownloadStatus: DownloadWaitMetadata})
EncodeJSON(api.Backend, w, r, apiResponseDownloadStatus{APIStatus: DownloadResponseSuccess, ID: info.id, DownloadStatus: DownloadWaitMetadata})
}
@@ -132,6 +136,8 @@ func (api *WebapiInstance) apiDownloadStatus(w http.ResponseWriter, r *http.Requ
info.RUnlock()
api.Backend.LogError("Download.DownloadStatus", "output %v", response)
EncodeJSON(api.Backend, w, r, response)
}

View File

@@ -1,5 +1,5 @@
/*
File Name: File Detection.go
File: File Detection.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -94,6 +94,9 @@ func FileTranslateExtension(extension string) (fileType, fileFormat uint16) {
case "iso":
return core.TypeContainer, core.FormatISO
case "pnsearch":
return core.TypeText, core.FormatPeernetSearch
default:
return core.TypeBinary, core.FormatBinary
}

View File

@@ -1,5 +1,5 @@
/*
File Name: File IO.go
File Username: File IO.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/

View File

@@ -1,5 +1,5 @@
/*
File Name: File.go
File Username: File.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -8,6 +8,7 @@ package webapi
import (
"net/http"
"strconv"
"time"
"github.com/PeernetOfficial/core"
@@ -42,14 +43,18 @@ type apiFile struct {
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.
Username string `json:"username"` // Username of the user who uploaded the file
}
// --- 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{}}
output = apiFile{ID: input.ID, Hash: input.Hash, NodeID: input.NodeID, Type: input.Type, Format: input.Format, Size: input.Size, Username: input.Username, Metadata: []apiFileMetadata{}}
for _, tag := range input.Tags {
if tag.Type == blockchain.TagSharedByCount && tag.Number() == 0 {
return apiFile{}
}
switch tag.Type {
case blockchain.TagName:
output.Name = tag.Text()
@@ -69,6 +74,10 @@ func blockRecordFileToAPI(input blockchain.BlockRecordFile) (output apiFile) {
case blockchain.TagSharedByCount:
output.Metadata = append(output.Metadata, apiFileMetadata{Type: tag.Type, Name: "Shared By Count", Number: tag.Number()})
// if a file has 0 peers sharing then do not add it to the list.
if tag.Number() == 0 {
return apiFile{}
}
case blockchain.TagSharedByGeoIP:
output.Metadata = append(output.Metadata, apiFileMetadata{Type: tag.Type, Name: "Shared By GeoIP", Text: tag.Text()})
@@ -136,6 +145,7 @@ Response: 200 with JSON structure apiBlockchainBlockStatus
func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.Request) {
var input apiBlockAddFiles
if err := DecodeJSON(w, r, &input); err != nil {
api.Backend.LogError("blockchain.AddFile", "error: %v", "error decoding JSON")
return
}
@@ -143,6 +153,8 @@ func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.R
for _, file := range input.Files {
if len(file.Hash) != protocol.HashSize {
api.Backend.LogError("blockchain.AddFile", "error: %v", "file length is not the same length as "+
"the protocol hash size.")
http.Error(w, "", http.StatusBadRequest)
return
}
@@ -153,6 +165,7 @@ func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.R
// 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 {
api.Backend.LogError("blockchain.AddFile", "error: %v", err)
http.Error(w, "", http.StatusBadRequest)
return
} else if _, fileSize, status, _ := api.Backend.UserWarehouse.FileExists(file.Hash); status != warehouse.StatusOK {
@@ -179,22 +192,37 @@ func (api *WebapiInstance) apiBlockchainFileAdd(w http.ResponseWriter, r *http.R
newHeight, newVersion, status := api.Backend.UserBlockchain.AddFiles(filesAdd)
// Temporary log to check the output for warehouse API
api.Backend.LogError("blockchain.AddFile", "output %v", apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
EncodeJSON(api.Backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
}
/*
apiBlockchainFileList lists all files stored on the blockchain.
Request: GET /blockchain/file/list
Request: GET /blockchain/file/list?fileFormat=<file format>
Response: 200 with JSON structure apiBlockAddFiles
*/
func (api *WebapiInstance) apiBlockchainFileList(w http.ResponseWriter, r *http.Request) {
files, status := api.Backend.UserBlockchain.ListFiles()
r.ParseForm()
// filter based on file type
fileType, err := strconv.Atoi(r.Form.Get("fileFormat"))
var result apiBlockAddFiles
for _, file := range files {
result.Files = append(result.Files, blockRecordFileToAPI(file))
ApiFile := blockRecordFileToAPI(file)
if ApiFile.NodeID == nil {
continue
}
if ApiFile.Format == uint16(fileType) {
result.Files = append(result.Files, ApiFile)
} else if err != nil {
result.Files = append(result.Files, ApiFile)
}
}
result.Status = status

View File

@@ -1,5 +1,5 @@
/*
File Name: GeoIP.go
File Username: GeoIP.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner

View File

@@ -1,5 +1,5 @@
/*
File Name: HTTP Range.go
File Username: HTTP Range.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/

View File

@@ -69,7 +69,11 @@ func (api *WebapiInstance) ExploreFileSharedByNodeThatSharedSimilarFile(fileType
// loop over results
for n := range resultFiles {
result.Files = append(result.Files, blockRecordFileToAPI(resultFiles[n]))
ApiFile := blockRecordFileToAPI(resultFiles[n])
if ApiFile.NodeID == nil {
continue
}
result.Files = append(result.Files, ApiFile)
}
}
@@ -86,8 +90,6 @@ func (api *WebapiInstance) GreedySearchMergeDirection(nodeID *[][]byte, fileType
// get all NodeIDs
peerList := api.Backend.PeerlistGet()
//var tags []blockchain.BlockRecordFileTag
// search with AllNodes which have a match of the NodeID.
for _, peer := range peerList {
if peer.BlockchainHeight == 0 {
@@ -112,28 +114,18 @@ func (api *WebapiInstance) GreedySearchMergeDirection(nodeID *[][]byte, fileType
file.Tags = append(file.Tags, blockchain.TagFromText(blockchain.TagSharedByGeoIP, sharedByGeoIP))
}
// found a new file! append.
filesFromPeer++
//file.Username = Name
// if both the hashes match
if bytes.Equal(file.Hash, hash) {
// set the Tags needed for the filter parameter
//tags = file.Tags
// found a new file! append.
filesFromPeer++
*nodeID = append(*nodeID, file.NodeID)
}
//for _, tag := range file.Tags {
// // checks if any of tags from
// // the NodeID provided matches
// // Requires better search parameters
// // So that it's more narrow
// for i := range tags {
// if tag.Text() == tags[i].Text() {
// *nodeID = append(*nodeID, file.NodeID)
// break
// }
// }
//}
}
}

View File

@@ -1,5 +1,5 @@
/*
File Name: Profile.go
File Username: Profile.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -7,8 +7,10 @@ Author: Peter Kleissner
package webapi
import (
"bytes"
"net/http"
"strconv"
"time"
"github.com/PeernetOfficial/core/blockchain"
)
@@ -31,15 +33,50 @@ type apiBlockRecordProfile struct {
/*
apiProfileList lists all users profile fields.
Request: GET /profile/list
Request: GET /profile/list?node=[nodeid]
Response: 200 with JSON structure apiProfileData
*/
func (api *WebapiInstance) apiProfileList(w http.ResponseWriter, r *http.Request) {
fields, status := api.Backend.UserBlockchain.ProfileList()
NodeID, valid := DecodeBlake3Hash(r.URL.Query().Get("node"))
var fields []blockchain.BlockRecordProfile
var status int
result := apiProfileData{Status: status}
for n := range fields {
result.Fields = append(result.Fields, blockRecordProfileToAPI(fields[n]))
if valid && !bytes.Equal(NodeID, api.Backend.SelfNodeID()) {
//_, node, _ := api.Backend.FindNode(NodeID, 100)
_, peers, _ := api.Backend.FindNode(NodeID, time.Second*5)
// First iteration of the entire blockchain to search for the profile
// image and Username of the user
for blockN1 := peers.BlockchainHeight; blockN1 > 0; blockN1-- {
blockDecoded, _, found, _ := api.Backend.ReadBlock(peers.PublicKey, peers.BlockchainVersion, blockN1)
if !found {
continue
}
profile, _ := blockchain.DecodeBlockRecordProfile(blockDecoded.Block.RecordsRaw)
// Adding profile image and Username to the output
for raw, _ := range profile {
if profile[raw].Type == blockchain.ProfileName {
result.Fields = append(result.Fields, blockRecordProfileToAPI(blockchain.BlockRecordProfile{Type: profile[raw].Type, Data: profile[raw].Data[:]}))
}
if profile[raw].Type == blockchain.ProfilePicture {
result.Fields = append(result.Fields, blockRecordProfileToAPI(blockchain.BlockRecordProfile{Type: profile[raw].Type, Data: profile[raw].Data[:]}))
}
}
}
} else {
fields, status = api.Backend.UserBlockchain.ProfileList()
result.Status = status
for n := range fields {
result.Fields = append(result.Fields, blockRecordProfileToAPI(fields[n]))
}
}
EncodeJSON(api.Backend, w, r, result)
@@ -48,12 +85,13 @@ func (api *WebapiInstance) apiProfileList(w http.ResponseWriter, r *http.Request
/*
apiProfileRead reads a specific users profile field. See core.ProfileX for recognized fields.
Request: GET /profile/read?field=[index]
Request: GET /profile/read?field=[index]&node=[nodeid]
Response: 200 with JSON structure apiProfileData
*/
func (api *WebapiInstance) apiProfileRead(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fieldN, err1 := strconv.Atoi(r.Form.Get("field"))
fieldN, err1 := strconv.Atoi(r.URL.Query().Get("field"))
NodeID, valid := DecodeBlake3Hash(r.URL.Query().Get("node"))
if err1 != nil || fieldN < 0 {
http.Error(w, "", http.StatusBadRequest)
@@ -61,10 +99,19 @@ func (api *WebapiInstance) apiProfileRead(w http.ResponseWriter, r *http.Request
}
var result apiProfileData
var data []byte
if data, result.Status = api.Backend.UserBlockchain.ProfileReadField(uint16(fieldN)); result.Status == blockchain.StatusOK {
result.Fields = append(result.Fields, blockRecordProfileToAPI(blockchain.BlockRecordProfile{Type: uint16(fieldN), Data: data}))
if !valid {
_, node, _ := api.Backend.FindNode(NodeID, 100)
if data, result.Status = node.Backend.UserBlockchain.ProfileReadField(uint16(fieldN)); result.Status == blockchain.StatusOK {
result.Fields = append(result.Fields, blockRecordProfileToAPI(blockchain.BlockRecordProfile{Type: uint16(fieldN), Data: data}))
}
} else {
if api.Backend.NodelistLookup(NodeID) != nil {
if data, result.Status = api.Backend.NodelistLookup(NodeID).Backend.UserBlockchain.ProfileReadField(uint16(fieldN)); result.Status == blockchain.StatusOK {
result.Fields = append(result.Fields, blockRecordProfileToAPI(blockchain.BlockRecordProfile{Type: uint16(fieldN), Data: data}))
}
}
}
EncodeJSON(api.Backend, w, r, result)
@@ -90,6 +137,8 @@ func (api *WebapiInstance) apiProfileWrite(w http.ResponseWriter, r *http.Reques
newHeight, newVersion, status := api.Backend.UserBlockchain.ProfileWrite(fields)
api.Backend.LogError("apiProfileWrite", "Height: %v, Version %v", newHeight, newVersion)
EncodeJSON(api.Backend, w, r, apiBlockchainBlockStatus{Status: status, Height: newHeight, Version: newVersion})
}

View File

@@ -1,5 +1,5 @@
/*
File Name: Search Dispatch.go
File Username: Search Dispatch.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -9,6 +9,7 @@ package webapi
import (
"bytes"
"fmt"
"github.com/PeernetOfficial/core/protocol"
"time"
"github.com/PeernetOfficial/core/blockchain"
@@ -43,6 +44,12 @@ func (job *SearchJob) localSearch(api *WebapiInstance, term string) {
resultLoop:
for _, result := range results {
// check if the NodeID filter is provided
if job.filtersStart.NodeID != nil && !(bytes.Equal(job.filtersStart.NodeID, protocol.PublicKey2NodeID(result.PublicKey))) {
continue
}
file, _, found, err := api.Backend.ReadFile(result.PublicKey, result.BlockchainVersion, result.BlockNumber, result.FileID)
if err != nil || !found {
continue

View File

@@ -1,5 +1,5 @@
/*
File Name: Search Job.go
File Username: Search Job.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -25,6 +25,7 @@ type SearchFilter struct {
Sort int // Sort order. See SortX.
SizeMin int // Min file size in bytes. -1 = not used.
SizeMax int // Max file size in bytes. -1 = not used.
NodeID []byte // Filter based on a NodeID provided
}
// SearchJob is a collection of search jobs
@@ -257,7 +258,7 @@ func (job *SearchJob) isFileFiltered(file *apiFile) bool {
return true
}
// SortFiles sorts a list of files. It returns a sorted list. 0 = no sorting, 1 = Relevance ASC, 2 = Relevance DESC, 3 = Date ASC, 4 = Date DESC, 5 = Name ASC, 6 = Name DESC
// SortFiles sorts a list of files. It returns a sorted list. 0 = no sorting, 1 = Relevance ASC, 2 = Relevance DESC, 3 = Date ASC, 4 = Date DESC, 5 = Username ASC, 6 = Username DESC
func SortFiles(files []*apiFile, Sort int) (sorted []*apiFile) {
switch Sort {
case SortRelevanceAsc:

View File

@@ -1,5 +1,5 @@
/*
File Name: Search.go
File Username: Search.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
@@ -156,6 +156,7 @@ func (api *WebapiInstance) apiSearchResult(w http.ResponseWriter, r *http.Reques
sort, _ := strconv.Atoi(r.Form.Get("sort"))
sizeMin, _ := strconv.Atoi(r.Form.Get("sizemin"))
sizeMax, _ := strconv.Atoi(r.Form.Get("sizemax"))
//nodeID, _ := DecodeBlake3Hash(r.Form.Get("node"))
filter := inputToSearchFilter(sort, fileType, fileFormat, dateFrom, dateTo, sizeMin, sizeMax)
@@ -353,23 +354,30 @@ func (api *WebapiInstance) apiSearchStatistic(w http.ResponseWriter, r *http.Req
apiExplore returns recently shared files in Peernet. Results are returned in real-time. The file type is an optional filter. See TypeX.
Special type -2 = Binary, Compressed, Container, Executable. This special type includes everything except Documents, Video, Audio, Ebooks, Picture, Text.
Request: GET /explore?limit=[max records]&type=[file type]&offset=[offset]
Request: GET /explore?limit=[max records]&type=[file type]&offset=[offset]&node=[nodeID]
Result: 200 with JSON structure SearchResult. Check the field status.
*/
func (api *WebapiInstance) apiExplore(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
offset, _ := strconv.Atoi(r.Form.Get("offset"))
limit, err := strconv.Atoi(r.Form.Get("limit"))
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
limit, err := strconv.Atoi(r.URL.Query().Get("limit"))
if err != nil {
limit = 100
}
fileType, err := strconv.Atoi(r.Form.Get("type"))
fileType, err := strconv.Atoi(r.URL.Query().Get("type"))
if err != nil {
fileType = -1
}
result := api.ExploreHelper(fileType, limit, offset, []byte{}, false)
var result *SearchResult
NodeId, valid := DecodeBlake3Hash(r.URL.Query().Get("node"))
if valid {
result = api.ExploreHelper(fileType, limit, offset, NodeId, true)
} else {
result = api.ExploreHelper(fileType, limit, offset, []byte{}, false)
}
EncodeJSON(api.Backend, w, r, result)
}
@@ -383,7 +391,11 @@ func (api *WebapiInstance) ExploreHelper(fileType int, limit, offset int, nodeID
// loop over results
for n := range resultFiles {
result.Files = append(result.Files, blockRecordFileToAPI(resultFiles[n]))
ApiFile := blockRecordFileToAPI(resultFiles[n])
if ApiFile.NodeID == nil {
continue
}
result.Files = append(result.Files, ApiFile)
}
if len(result.Files) == 0 {
@@ -407,6 +419,7 @@ func (input *SearchRequest) Parse() (Timeout time.Duration) {
// ToSearchFilter converts the user input to a valid search filter
func (input *SearchRequest) ToSearchFilter() (output SearchFilter) {
//hash, _ := DecodeBlake3Hash(input.NodeID)
return inputToSearchFilter(input.Sort, input.FileType, input.FileFormat, input.DateFrom, input.DateTo, input.SizeMin, input.SizeMax)
}

View File

@@ -1,5 +1,5 @@
/*
File Name: Shared Recent.go
File Username: Shared Recent.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -18,7 +18,6 @@ func (api *WebapiInstance) queryRecentShared(backend *core.Backend, fileType int
if limitPeer == 0 {
limitPeer = 1
}
// Assign peer list as an empty array
var peerList []*core.PeerInfo
@@ -44,11 +43,31 @@ func (api *WebapiInstance) queryRecentShared(backend *core.Backend, fileType int
}
var filesFromPeer uint64
var Name string
ProfileNameFound := false
// First iteration of the entire blockchain to search for the profile
// image and Username of the user
for blockN1 := peer.BlockchainHeight - 1; blockN1 > 0; blockN1-- {
blockDecoded, _, found, _ := backend.ReadBlock(peer.PublicKey, peer.BlockchainVersion, blockN1)
if !found {
continue
}
// Adding profile image and Username to the output
for raw := range blockDecoded.Block.RecordsRaw {
if blockDecoded.Block.RecordsRaw[raw].Type == blockchain.ProfileName && !ProfileNameFound {
Name = string(blockDecoded.Block.RecordsRaw[raw].Data[:])
ProfileNameFound = true
}
}
}
// decode blocks from top down
blockLoop:
for blockN := peer.BlockchainHeight - 1; blockN > 0; blockN-- {
blockDecoded, _, found, _ := backend.ReadBlock(peer.PublicKey, peer.BlockchainVersion, blockN)
if !found {
continue
}
@@ -62,6 +81,8 @@ func (api *WebapiInstance) queryRecentShared(backend *core.Backend, fileType int
file.Tags = append(file.Tags, blockchain.TagFromText(blockchain.TagSharedByGeoIP, sharedByGeoIP))
}
file.Username = Name
// found a new file! append.
if filesFromPeer < limitPeer {
filesFromPeer++

View File

@@ -1,5 +1,5 @@
/*
File Name: Status.go
File Username: Status.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/

86
webapi/Upload.go Normal file
View File

@@ -0,0 +1,86 @@
package webapi
import (
"github.com/google/uuid"
"math"
"net/http"
"sync"
)
type UploadStatus 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.
sync.RWMutex // Mutext for changing the status
UploadStatus int `json:"uploadstatus"` // Status of the download. See DownloadX.
Progress struct {
TotalSize uint64 `json:"totalsize"` // Total size in bytes.
UploadedSize uint64 `json:"uploadedsize"` // Count of bytes download so far.
Percentage float64 `json:"percentage"` // Percentage downloaded. Rounded to 2 decimal points. Between 0.00 and 100.00.
} `json:"progress"` // Progress of the download. Only valid for status >= DownloadWaitSwarm.
}
func (api *WebapiInstance) uploadAdd(info *UploadStatus) {
api.uploadsMutex.Lock()
api.uploads[info.ID] = info
api.uploadsMutex.Unlock()
}
func (api *WebapiInstance) uploadDelete(id uuid.UUID) {
api.uploadsMutex.Lock()
delete(api.uploads, id)
api.uploadsMutex.Unlock()
}
func (api *WebapiInstance) uploadLookup(id uuid.UUID) (info *UploadStatus) {
api.uploadsMutex.Lock()
info = api.uploads[id]
api.uploadsMutex.Unlock()
return info
}
// UploadID API to set a Status ID to track the upload
func (api *WebapiInstance) apiUploadID(w http.ResponseWriter, r *http.Request) {
var info UploadStatus
info.ID = uuid.New()
// Create a upload ID for adding the upload
// metadata later one
api.uploadAdd(&info)
EncodeJSON(api.Backend, w, r, info)
}
// Write is used to satisfy the io.Writer interface.
// Instead of writing somewhere, it simply aggregates
// the total bytes on each read
func (uploadStatus *UploadStatus) Write(p []byte) (n int, err error) {
n = len(p)
uploadStatus.Progress.UploadedSize += uint64(n)
uploadStatus.Progress.Percentage = math.Round(float64(uploadStatus.Progress.UploadedSize)/float64(uploadStatus.Progress.TotalSize)*100*100) / 100
return
}
// Get information about upload file status
func (api *WebapiInstance) apiUploadInfo(w http.ResponseWriter, r *http.Request) {
ID := r.URL.Query().Get("id")
if ID == "" {
api.Backend.LogError("upload.UploadInformation", "error: %v", "ID parameter not passed")
http.Error(w, "", http.StatusBadRequest)
return
}
IDUUID, err := uuid.Parse(ID)
if err != nil {
api.Backend.LogError("upload.UploadInformation", "error: %v", err)
return
}
info := api.uploadLookup(IDUUID)
if info == nil {
EncodeJSON(api.Backend, w, r, UploadStatus{APIStatus: DownloadResponseIDNotFound})
return
}
EncodeJSON(api.Backend, w, r, info)
}

View File

@@ -1,5 +1,5 @@
/*
File Name: Warehouse.go
File Username: Warehouse.go
Copyright: 2021 Peernet Foundation s.r.o.
Author: Peter Kleissner
*/
@@ -7,6 +7,7 @@ Author: Peter Kleissner
package webapi
import (
"github.com/google/uuid"
"net/http"
"strconv"
@@ -20,18 +21,63 @@ type WarehouseResult struct {
}
/*
apiWarehouseCreateFile creates a file in the warehouse.
ApiWarehouseCreateFile creates a file in the warehouse.
Request: POST /warehouse/create with raw data to create as new file
Response: 200 with JSON structure WarehouseResult
*/
func (api *WebapiInstance) apiWarehouseCreateFile(w http.ResponseWriter, r *http.Request) {
hash, status, err := api.Backend.UserWarehouse.CreateFile(r.Body, 0)
func (api *WebapiInstance) ApiWarehouseCreateFile(w http.ResponseWriter, r *http.Request) {
// changing parameter to take ID as a parameter for upload and file itself
ID := r.FormValue("id")
file, handler, err := r.FormFile("File")
if err != nil {
api.Backend.LogError("warehouse.CreateFile", "error: %v", err)
EncodeJSON(api.Backend, w, r, errorResponse{function: "warehouse.CreateFile", error: err.Error()})
return
}
var hash []byte
var status int
// checks if there is a new upload and then
if ID != "" {
IDUUID, err := uuid.Parse(ID)
if err != nil {
api.Backend.LogError("warehouse.CreateFile", "error: %v", err)
EncodeJSON(api.Backend, w, r, errorResponse{function: "warehouse.CreateFile", error: err.Error()})
return
}
info := api.uploadLookup(IDUUID)
if info == nil {
var newInfo UploadStatus
newInfo.ID = IDUUID
newInfo.Progress.TotalSize = uint64(handler.Size)
api.Backend.LogError("warehouse.CreateFile", "%v", newInfo)
api.uploadAdd(&newInfo)
hash, status, err = api.Backend.UserWarehouse.CreateFile(file, uint64(handler.Size), &newInfo)
} else {
info.Progress.TotalSize = uint64(handler.Size)
api.Backend.LogError("warehouse.CreateFile", "%v", info)
hash, status, err = api.Backend.UserWarehouse.CreateFile(file, uint64(handler.Size), info)
}
api.Backend.LogError("warehouse.CreateFile", "outside Create file: %v", info)
} else {
// File := r.
hash, status, err = api.Backend.UserWarehouse.CreateFile(file, uint64(handler.Size), nil)
}
if err != nil {
api.Backend.LogError("warehouse.CreateFile", "status %d error: %v", status, err)
EncodeJSON(api.Backend, w, r, errorResponse{function: "warehouse.CreateFile", error: err.Error()})
return
}
// Temporary log to check the output for warehouse API
api.Backend.LogError("warehouse.CreateFile", "output %v", WarehouseResult{Status: status, Hash: hash})
EncodeJSON(api.Backend, w, r, WarehouseResult{Status: status, Hash: hash})
}

View File

@@ -75,6 +75,11 @@ These are the functions provided by the API:
/merge/directory List all recent files shared by peers based
on the similar file shared
/warehouse/create/uploadID Generates a UUID to track upload status
/warehouse/create/track/uploadID Tracks upload status when a upload is
ongoing to the warehaouse (Triggers after
the route "/warehouse/create" is called).
```
# API Documentation
@@ -277,29 +282,30 @@ The file type is an indication what type of content the file's data is:
The file format is a more granular indicator about the content of a file:
| Type | Constant | Info |
| ---- | ---------------- | --------------------------------------------------- |
| 0 | FormatBinary | Binary/unspecified |
| 1 | FormatPDF | PDF document |
| 2 | FormatWord | Word document |
| 3 | FormatExcel | Excel |
| 4 | FormatPowerpoint | Powerpoint |
| 5 | FormatPicture | Pictures (including GIF, excluding icons) |
| 6 | FormatAudio | Audio files |
| 7 | FormatVideo | Video files |
| Type | Constant | Info |
|------| ---------------- |----------------------------------------------------|
| 0 | FormatBinary | Binary/unspecified |
| 1 | FormatPDF | PDF document |
| 2 | FormatWord | Word document |
| 3 | FormatExcel | Excel |
| 4 | FormatPowerpoint | Powerpoint |
| 5 | FormatPicture | Pictures (including GIF, excluding icons) |
| 6 | FormatAudio | Audio files |
| 7 | FormatVideo | Video files |
| 8 | FormatContainer | Compressed files including ZIP, RAR, TAR and others |
| 9 | FormatHTML | HTML file |
| 10 | FormatText | Text file |
| 11 | FormatEbook | Ebook file |
| 12 | FormatCompressed | Compressed file |
| 13 | FormatDatabase | Database file |
| 14 | FormatEmail | Single email |
| 15 | FormatCSV | CSV file |
| 16 | FormatFolder | Virtual folder |
| 17 | FormatExecutable | Executable file |
| 18 | FormatInstaller | Installer |
| 19 | FormatAPK | APK |
| 20 | FormatISO | ISO |
| 9 | FormatHTML | HTML file |
| 10 | FormatText | Text file |
| 11 | FormatEbook | Ebook file |
| 12 | FormatCompressed | Compressed file |
| 13 | FormatDatabase | Database file |
| 14 | FormatEmail | Single email |
| 15 | FormatCSV | CSV file |
| 16 | FormatFolder | Virtual folder |
| 17 | FormatExecutable | Executable file |
| 18 | FormatInstaller | Installer |
| 19 | FormatAPK | APK |
| 20 | FormatISO | ISO |
| 21 | FormatPeernetSearch | File type to store peernet search history |
### Add File
@@ -496,7 +502,7 @@ Below is the list of well known profile information. Clients may define addition
This lists all profile fields.
```
Request: GET /profile/list
Request: GET /profile/list&node=[node id<optional>]
Response: 200 with JSON structure apiProfileData
```
@@ -538,7 +544,7 @@ Example response:
This reads a specific profile field. See ProfileX for recognized fields.
```
Request: GET /profile/read?field=[index]
Request: GET /profile/read?field=[index]&node=[node id<optional>]
Response: 200 with JSON structure apiProfileData
```
@@ -617,7 +623,7 @@ Filters and sort order may be applied when starting the search at `/search`, or
These are the available sort options:
| Sort | Constant | Info |
| ---- | --------------------- | ----------------------------------------------------------------------------------- |
|------|-----------------------|-------------------------------------------------------------------------------------|
| 0 | SortNone | No sorting. Results are returned as they come in. |
| 1 | SortRelevanceAsc | Least relevant results first. |
| 2 | SortRelevanceDec | Most relevant results first. |
@@ -630,6 +636,7 @@ These are the available sort options:
| 9 | SortSharedByCountAsc | Shared by count ascending. Files that are shared by the least count of peers first. |
| 10 | SortSharedByCountDesc | Shared by count descending. Files that are shared by the most count of peers first. |
The following filters are supported:
* Filter by date from and to. Both dates are required. The inclusion check for the 'from date' is >= and 'to date' <.
@@ -658,6 +665,7 @@ type SearchRequest struct {
FileFormat int `json:"fileformat"` // File format such as PDF, Word, Ebook, etc. See core.FormatX. -1 = not used.
SizeMin int `json:"sizemin"` // Min file size in bytes. -1 = not used.
SizeMax int `json:"sizemax"` // Max file size in bytes. -1 = not used.
NodeID string `json:"node"` // Filter based on the NodeID provided
}
type SearchRequestResponse struct {
@@ -1028,7 +1036,8 @@ type WarehouseResult struct {
Example POST request to `http://127.0.0.1:112/warehouse/create`:
```
Test file.
--form 'id="<uuid>"' \
--form 'File=@"<file path>"'
```
Example response: