//go:build experimental // +build experimental package main import ( "bytes" "encoding/binary" "fmt" "time" ) var textResultsChan = make(chan []TextSearchResult) // Try other nodes is not defined for every type func tryOtherNodesForTextSearch(query, safe, lang string, page int) []TextSearchResult { for _, nodeTarget := range sockets { results, err := sendTextSearchRequestToNode(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 sendTextSearchRequestToNode(target, query, safe, lang string, page int) ([]TextSearchResult, error) { payload, err := encodeSearchTextParams(query, safe, lang, page) if err != nil { return nil, fmt.Errorf("encode error: %v", err) } msg := Message{ ID: generateMessageID(), // assume function returns uint32 Type: MsgTypeSearchTextRequest, Content: payload, Target: target, } err = sendMessage(msg) if err != nil { return nil, fmt.Errorf("failed to send search request to node %s: %v", target, err) } select { case res := <-textResultsChan: return res, nil case <-time.After(20 * time.Second): return nil, fmt.Errorf("timeout waiting for results from node %s", target) } } func handleTextResultsMessage(msg Message) { results, err := decodeTextResults([]byte(msg.Content)) if err != nil { printWarn("Error decoding text results: %v", err) return } printDebug("Received text results: %+v", results) go func() { textResultsChan <- results }() } func encodeTextResults(results []TextSearchResult) ([]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 := writeString(buf, r.Source); err != nil { return nil, err } } return buf.Bytes(), nil } func decodeTextResults(data []byte) ([]TextSearchResult, error) { buf := bytes.NewReader(data) var count uint16 if err := binary.Read(buf, binary.BigEndian, &count); err != nil { return nil, err } results := make([]TextSearchResult, 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 } description, err := readString(buf) if err != nil { return nil, err } source, err := readString(buf) if err != nil { return nil, err } results = append(results, TextSearchResult{ URL: url, Header: header, Description: description, Source: source, }) } return results, nil }