Files
core/webapi/Merge directory.go
2023-03-27 14:38:13 +01:00

130 lines
4.3 KiB
Go

package webapi
import (
"bytes"
"fmt"
"github.com/PeernetOfficial/core/blockchain"
"net/http"
"strconv"
)
// SearchResultMergedDirectory contains results for the merged directory.
type SearchResultMergedDirectory struct {
Status int `json:"status"` // Status: 0 = Success with results, 1 = No more results available, 2 = Search ID not found, 3 = No results yet available keep trying
Files [][]apiFile `json:"files"` // List of files found
Statistic interface{} `json:"statistic"` // Statistics of all results (independent from applied filters), if requested. Only set if files are returned (= if statistics changed). See SearchStatisticData.
}
func (api *WebapiInstance) apiMergeDirectory(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
offset, _ := strconv.Atoi(r.Form.Get("offset"))
limit, err := strconv.Atoi(r.Form.Get("limit"))
if err != nil {
limit = 100
}
// ID fields for results for a specific node ID.
NodeId, _ := DecodeBlake3Hash(r.Form.Get("node"))
hash, _ := DecodeBlake3Hash(r.Form.Get("hash"))
fileType, err := strconv.Atoi(r.Form.Get("type"))
if err != nil {
fileType = -1
}
result := api.ExploreFileSharedByNodeThatSharedSimilarFile(fileType, limit, offset, NodeId, hash, true)
EncodeJSON(api.Backend, w, r, result)
}
// ExploreFileSharedByNodeThatSharedSimilarFile lists files shared by a nodes which share the same file as a common point
// Currently this is a greedy search and requires work for optimization
func (api *WebapiInstance) ExploreFileSharedByNodeThatSharedSimilarFile(fileType int, limit, offset int, nodeID []byte, hash []byte, nodeIDState bool) *SearchResultMergedDirectory {
// lookup all NodeID blockchains which have the similar hash
// do a search to get all the node IDs sharing the particular file
NodeIDs, _ := api.Backend.SearchIndex.SearchNodeIDBasedOnHash(hash)
// Does a greedy search to find node serving similar files
api.GreedySearchMergeDirection(&NodeIDs, fileType, hash)
var result SearchResultMergedDirectory
for i := range NodeIDs {
resultFiles := api.queryRecentShared(api.Backend, fileType, uint64(limit*20/100), uint64(offset), uint64(limit), NodeIDs[i], nodeIDState)
var ApiFile []apiFile
// loop over results
for n := range resultFiles {
ApiFile = append(ApiFile, blockRecordFileToAPI(resultFiles[n]))
}
result.Files = append(result.Files, ApiFile)
}
result.Status = 1 // No more results to expect
return &result
}
// GreedySearchMergeDirection This function is implemented since the local index tables do not
// always consist of the required hashes of the NodeIDs.
func (api *WebapiInstance) GreedySearchMergeDirection(nodeID *[][]byte, fileType int, hash []byte) {
// 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 {
continue
}
var filesFromPeer uint64
// decode blocks from top down
for blockN := peer.BlockchainHeight - 1; blockN > 0; blockN-- {
blockDecoded, _, found, _ := api.Backend.ReadBlock(peer.PublicKey, peer.BlockchainVersion, blockN)
if !found {
continue
}
for _, record := range blockDecoded.RecordsDecoded {
if file, ok := record.(blockchain.BlockRecordFile); ok && isFileTypeMatchBlock(&file, fileType) {
// add the tags 'Shared By Count' and 'Shared By GeoIP'
file.Tags = append(file.Tags, blockchain.TagFromNumber(blockchain.TagSharedByCount, 1))
if latitude, longitude, valid := api.Peer2GeoIP(peer); valid {
sharedByGeoIP := fmt.Sprintf("%.4f", latitude) + "," + fmt.Sprintf("%.4f", longitude)
file.Tags = append(file.Tags, blockchain.TagFromText(blockchain.TagSharedByGeoIP, sharedByGeoIP))
}
// found a new file! append.
filesFromPeer++
// if both the hashes match
if bytes.Equal(file.Hash, hash) {
// set the Tags needed for the filter parameter
tags = file.Tags
}
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
}
}
}
}
}
}
}
}