//go:build experimental // +build experimental package main import ( "bytes" "encoding/binary" "fmt" "time" ) var fileResultsChan = make(chan []TorrentResult) func tryOtherNodesForFileSearch(query, safe, lang string, page int) []TorrentResult { for _, nodeTarget := range sockets { results, err := sendFileSearchRequestToNode(nodeTarget, query, safe, lang, page) if err != nil { printWarn("Error contacting node %s: %v", nodeTarget, err) continue } if len(results) > 0 { return results } } return nil } func sendFileSearchRequestToNode(target, query, safe, lang string, page int) ([]TorrentResult, error) { payload, err := encodeSearchTextParams(query, safe, lang, page) if err != nil { return nil, fmt.Errorf("encode error: %v", err) } msg := Message{ ID: generateMessageID(), Type: MsgTypeSearchFileRequest, Content: payload, Target: target, } if err := sendMessage(msg); err != nil { return nil, fmt.Errorf("send error: %v", err) } select { case res := <-fileResultsChan: return res, nil case <-time.After(20 * time.Second): return nil, fmt.Errorf("timeout waiting for results from node %s", target) } } func handleFileResultsMessage(msg Message) { results, err := decodeFileResults([]byte(msg.Content)) if err != nil { printWarn("Error decoding file results: %v", err) return } printDebug("Received file results: %+v", results) go func() { fileResultsChan <- results }() } func encodeFileResults(results []TorrentResult) ([]byte, error) { buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, uint16(len(results))); err != nil { return nil, err } for _, r := range results { if err := writeString(buf, r.URL); err != nil { return nil, err } if err := binary.Write(buf, binary.BigEndian, uint32(r.Seeders)); err != nil { return nil, err } if err := binary.Write(buf, binary.BigEndian, uint32(r.Leechers)); err != nil { return nil, err } if err := writeString(buf, r.Magnet); err != nil { return nil, err } if err := binary.Write(buf, binary.BigEndian, uint32(r.Views)); err != nil { return nil, err } if err := writeString(buf, r.Size); err != nil { return nil, err } if err := writeString(buf, r.Title); err != nil { return nil, err } } return buf.Bytes(), nil } func decodeFileResults(data []byte) ([]TorrentResult, error) { buf := bytes.NewReader(data) var count uint16 if err := binary.Read(buf, binary.BigEndian, &count); err != nil { return nil, err } results := make([]TorrentResult, 0, count) for i := 0; i < int(count); i++ { url, err := readString(buf) if err != nil { return nil, err } var seeders, leechers, views uint32 if err := binary.Read(buf, binary.BigEndian, &seeders); err != nil { return nil, err } if err := binary.Read(buf, binary.BigEndian, &leechers); err != nil { return nil, err } magnet, err := readString(buf) if err != nil { return nil, err } if err := binary.Read(buf, binary.BigEndian, &views); err != nil { return nil, err } size, err := readString(buf) if err != nil { return nil, err } title, err := readString(buf) if err != nil { return nil, err } results = append(results, TorrentResult{ URL: url, Seeders: int(seeders), Leechers: int(leechers), Magnet: magnet, Views: int(views), Size: size, Title: title, }) } return results, nil }