//go:build experimental // +build experimental package main import ( "bytes" "encoding/binary" "fmt" "time" ) var forumResultsChan = make(chan []ForumSearchResult) func sendForumSearchRequestToNode(target, query, safe, lang string, page int, visitedNodes []string) ([]ForumSearchResult, error) { payload, err := encodeSearchTextParams(query, safe, lang, page) // reuse text param encoding if err != nil { return nil, fmt.Errorf("encode error: %v", err) } msg := Message{ ID: generateMessageID(), Type: MsgTypeSearchForumRequest, Content: payload, Target: target, } if err := sendMessage(msg); err != nil { return nil, fmt.Errorf("send error: %v", err) } select { case res := <-forumResultsChan: return res, nil case <-time.After(20 * time.Second): return nil, fmt.Errorf("timeout waiting for results from node %s", target) } } func handleForumResultsMessage(msg Message) { results, err := decodeForumResults([]byte(msg.Content)) if err != nil { printWarn("Error decoding forum results: %v", err) return } printDebug("Received forum results: %+v", results) go func() { forumResultsChan <- results }() } func encodeForumResults(results []ForumSearchResult) ([]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 := writeString(buf, r.Header); err != nil { return nil, err } if err := writeString(buf, r.Description); err != nil { return nil, err } if err := binary.Write(buf, binary.BigEndian, r.PublishedDate.Unix()); err != nil { return nil, err } if err := writeString(buf, r.ImgSrc); err != nil { return nil, err } if err := writeString(buf, r.ThumbnailSrc); err != nil { return nil, err } } return buf.Bytes(), nil } func decodeForumResults(data []byte) ([]ForumSearchResult, error) { buf := bytes.NewReader(data) var count uint16 if err := binary.Read(buf, binary.BigEndian, &count); err != nil { return nil, err } results := make([]ForumSearchResult, 0, count) for i := 0; i < int(count); i++ { url, err := readString(buf) if err != nil { return nil, err } header, err := readString(buf) if err != nil { return nil, err } desc, err := readString(buf) if err != nil { return nil, err } var unixTime int64 if err := binary.Read(buf, binary.BigEndian, &unixTime); err != nil { return nil, err } imgSrc, err := readString(buf) if err != nil { return nil, err } thumbSrc, err := readString(buf) if err != nil { return nil, err } results = append(results, ForumSearchResult{ URL: url, Header: header, Description: desc, PublishedDate: time.Unix(unixTime, 0), ImgSrc: imgSrc, ThumbnailSrc: thumbSrc, }) } return results, nil }