mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-17 02:47:51 +01:00
250 lines
6.6 KiB
Go
250 lines
6.6 KiB
Go
/*
|
|
File Name: Search Temp.go
|
|
Copyright: 2021 Peernet Foundation s.r.o.
|
|
Author: Peter Kleissner
|
|
|
|
Temporary search code to provide dummy results for testing. To be replaced!
|
|
*/
|
|
|
|
package webapi
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"math/rand"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/PeernetOfficial/core"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func dispatchSearch(input SearchRequest) (job *SearchJob) {
|
|
job = &SearchJob{id: uuid.New(), timeout: time.Duration(input.Timeout) * time.Second, maxResult: input.MaxResults, sortOrder: input.Sort, fileType: -1, fileFormat: -1}
|
|
|
|
allJobsMutex.Lock()
|
|
allJobs[job.id] = job
|
|
allJobsMutex.Unlock()
|
|
|
|
// Create test data
|
|
// * Between 0-100 results
|
|
// * Delay of first result is 0-5 seconds
|
|
// * File name, type, format, ID and hash are randomized
|
|
go func(job *SearchJob) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
waitTime := time.Duration(rand.Intn(5)) * time.Second
|
|
countResults := rand.Intn(100)
|
|
|
|
time.Sleep(waitTime)
|
|
job.ResultSync.Lock()
|
|
|
|
for n := 0; n < countResults; n++ {
|
|
newFile := createTestResult()
|
|
job.filesCurrent = append(job.filesCurrent, &newFile)
|
|
}
|
|
|
|
job.ResultSync.Unlock()
|
|
|
|
}(job)
|
|
|
|
job.RemoveDefer(job.timeout + time.Second*20)
|
|
|
|
return job
|
|
}
|
|
|
|
// ---- job list management ----
|
|
|
|
// SearchJob is a collection of search jobs
|
|
type SearchJob struct {
|
|
// input settings
|
|
id uuid.UUID // The job id
|
|
timeout time.Duration // timeout set for all searches
|
|
maxResult int // max results user-facing.
|
|
sortOrder int // 0 = No sorting, 1 = Relevance ASC, 2 = Relevance DESC, 3 = Date ASC, 4 = Date DESC
|
|
|
|
// additional optional filters
|
|
isDates bool // whether the from/to dates are valid, both are required.
|
|
dateFrom time.Time // optional date from
|
|
dateTo time.Time // optional date to
|
|
fileType int // File type such as binary, text document etc. See core.TypeX. -1 not used.
|
|
fileFormat int // File format such as PDF, Word, Ebook, etc. See core.FormatX. -1 not used.
|
|
|
|
// runtime data
|
|
//clients []*SearchClient // all search clients
|
|
//clientsMutex sync.Mutex // mutex for manipulating client list
|
|
|
|
filesCurrent []*core.BlockRecordFile // Current result list of files, not yet fetched by caller.
|
|
FilesAll []*core.BlockRecordFile // List of all files. This list only gets expanded.
|
|
ResultSync sync.Mutex // ResultSync ensures unique access to the file results
|
|
}
|
|
|
|
// job list management
|
|
var (
|
|
allJobs map[uuid.UUID]*SearchJob = make(map[uuid.UUID]*SearchJob)
|
|
allJobsMutex sync.RWMutex
|
|
)
|
|
|
|
// Remove removes the structure from the list. Terminate should be called before. Unless the search is manually removed, it stays forever in the list.
|
|
func (job *SearchJob) Remove() {
|
|
allJobsMutex.Lock()
|
|
delete(allJobs, job.id) // delete is safe to call multiple times, so auto-removal and manual one are fine and need no syncing
|
|
allJobsMutex.Unlock()
|
|
}
|
|
|
|
// RemoveDefer removes the search job after a given time after all searches are terminated. This can be used for automated time delayed removal. Do not create additional search clients after deferal removing.
|
|
func (job *SearchJob) RemoveDefer(Duration time.Duration) {
|
|
go func() {
|
|
// for _, client := range job.clients {
|
|
// <-client.TerminateSignal
|
|
// }
|
|
|
|
<-time.After(Duration)
|
|
job.Remove()
|
|
}()
|
|
}
|
|
|
|
// JobLookup looks up a job. Returns nil if not found.
|
|
func JobLookup(id uuid.UUID) (job *SearchJob) {
|
|
allJobsMutex.RLock()
|
|
job = allJobs[id]
|
|
allJobsMutex.RUnlock()
|
|
|
|
return job
|
|
}
|
|
|
|
// Terminate terminates all searches
|
|
func (job *SearchJob) Terminate() {
|
|
//job.clientsMutex.Lock()
|
|
//defer job.clientsMutex.Unlock()
|
|
|
|
// for n := range job.clients {
|
|
// if !job.clients[n].IsTerminated {
|
|
// job.clients[n].Terminate(true)
|
|
// }
|
|
// }
|
|
}
|
|
|
|
// ReturnResult returns the selected results.
|
|
func (job *SearchJob) ReturnResult(Limit int) (Result []*core.BlockRecordFile) {
|
|
if Limit == 0 {
|
|
return Result
|
|
}
|
|
|
|
job.ResultSync.Lock()
|
|
defer job.ResultSync.Unlock()
|
|
|
|
if len(job.filesCurrent) == 0 {
|
|
return Result
|
|
} else if Limit > len(job.filesCurrent) {
|
|
Limit = len(job.filesCurrent)
|
|
}
|
|
|
|
Result = job.filesCurrent[:Limit]
|
|
job.filesCurrent = job.filesCurrent[Limit:]
|
|
|
|
return Result
|
|
}
|
|
|
|
// ReturnNext returns the next results. Call must be serialized.
|
|
func (job *SearchJob) ReturnNext(Limit int) (Result []*core.BlockRecordFile) {
|
|
return job.ReturnResult(Limit)
|
|
}
|
|
|
|
// createTestResult creates a test file
|
|
func createTestResult() (file core.BlockRecordFile) {
|
|
randomData := make([]byte, 10)
|
|
rand.Read(randomData)
|
|
|
|
file.Hash = core.Data2Hash(randomData)
|
|
file.Format = uint16(rand.Intn(core.FormatCSV))
|
|
file.ID = uuid.New()
|
|
file.Size = uint64(len(randomData))
|
|
|
|
switch file.Format {
|
|
case core.FormatCSV, core.FormatEmail, core.FormatText, core.FormatHTML:
|
|
file.Type = core.TypeText
|
|
|
|
case core.FormatDatabase:
|
|
file.Type = core.TypeBinary
|
|
|
|
case core.FormatCompressed:
|
|
file.Type = core.TypeCompressed
|
|
|
|
case core.FormatContainer:
|
|
file.Type = core.TypeContainer
|
|
|
|
case core.FormatEbook:
|
|
file.Type = core.TypeEbook
|
|
|
|
case core.FormatVideo:
|
|
file.Type = core.TypeVideo
|
|
|
|
case core.FormatAudio:
|
|
file.Type = core.TypeAudio
|
|
|
|
case core.FormatPicture:
|
|
file.Type = core.TypePicture
|
|
|
|
case core.FormatPowerpoint, core.FormatExcel, core.FormatWord, core.FormatPDF:
|
|
file.Type = core.TypeDocument
|
|
|
|
case core.FormatFolder:
|
|
file.Type = core.TypeFolder
|
|
|
|
default:
|
|
file.Type = core.TypeBinary
|
|
|
|
}
|
|
|
|
var extension string
|
|
switch file.Type {
|
|
case core.TypeBinary:
|
|
extension = "bin"
|
|
|
|
case core.TypeText:
|
|
extension = "txt"
|
|
|
|
case core.TypePicture:
|
|
extension = "jpg"
|
|
|
|
case core.TypeVideo:
|
|
extension = "mp4"
|
|
|
|
case core.TypeAudio:
|
|
extension = "mp3"
|
|
|
|
case core.TypeDocument:
|
|
extension = "pdf"
|
|
|
|
case core.TypeExecutable:
|
|
extension = "exe"
|
|
|
|
case core.TypeContainer:
|
|
extension = "zip"
|
|
|
|
case core.TypeCompressed:
|
|
extension = "gz"
|
|
|
|
case core.TypeFolder:
|
|
extension = ""
|
|
|
|
case core.TypeEbook:
|
|
extension = ""
|
|
|
|
default:
|
|
extension = ".bin"
|
|
}
|
|
|
|
file.TagsDecoded = append(file.TagsDecoded, core.FileTagName{Name: TempFileName("", extension)})
|
|
//file.TagsDecoded = append(file.TagsDecoded, core.FileTagFolder{Name: "not set"})
|
|
file.TagsDecoded = append(file.TagsDecoded, core.FileTagDateShared{Date: time.Now().UTC()})
|
|
|
|
return
|
|
}
|
|
|
|
// TempFileName generates a temporary filename for use in testing or whatever
|
|
func TempFileName(prefix, suffix string) string {
|
|
randBytes := make([]byte, 16)
|
|
rand.Read(randBytes)
|
|
return prefix + hex.EncodeToString(randBytes) + "." + suffix
|
|
}
|