//go:build experimental // +build experimental package main import ( "bytes" "encoding/binary" "fmt" "time" ) // const ( // MessageTypeSearchImage uint8 = 11 // MessageTypeSearchImageThumb uint8 = 111 // MessageTypeSearchImageFull uint8 = 112 // MessageTypeSearchImageAllProxy uint8 = 113 // MessageTypeImageResults uint8 = 22 // ) var imageResultsChan = make(chan []ImageSearchResult) func sendImageSearchRequestToNode(target, query, safe, lang string, page int, mode uint8) ([]ImageSearchResult, error) { payload, err := encodeSearchTextParams(query, safe, lang, page) if err != nil { return nil, fmt.Errorf("encode error: %v", err) } msg := Message{ ID: generateMessageID(), Type: mode, // one of the image search types Content: payload, Target: target, } if err := sendMessage(msg); err != nil { return nil, fmt.Errorf("send error: %v", err) } select { case res := <-imageResultsChan: return res, nil case <-time.After(30 * time.Second): return nil, fmt.Errorf("timeout from %s", target) } } func handleImageResultsMessage(msg Message) { results, err := decodeImageResults([]byte(msg.Content)) if err != nil { printWarn("Error decoding image results: %v", err) return } printDebug("Received image results: %+v", results) go func() { imageResultsChan <- results }() } func encodeImageResults(results []ImageSearchResult) ([]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.ID); err != nil { return nil, err } if err := writeString(buf, r.Title); err != nil { return nil, err } if err := writeString(buf, r.Full); err != nil { return nil, err } if err := writeString(buf, r.Thumb); err != nil { return nil, err } if err := writeString(buf, r.ProxyFull); err != nil { return nil, err } if err := writeString(buf, r.ProxyThumb); err != nil { return nil, err } if err := writeString(buf, r.Source); err != nil { return nil, err } if err := binary.Write(buf, binary.BigEndian, int32(r.Width)); err != nil { return nil, err } if err := binary.Write(buf, binary.BigEndian, int32(r.Height)); err != nil { return nil, err } } return buf.Bytes(), nil } func decodeImageResults(data []byte) ([]ImageSearchResult, error) { buf := bytes.NewReader(data) var count uint16 if err := binary.Read(buf, binary.BigEndian, &count); err != nil { return nil, err } results := make([]ImageSearchResult, 0, count) for i := 0; i < int(count); i++ { id, _ := readString(buf) title, _ := readString(buf) full, _ := readString(buf) thumb, _ := readString(buf) proxyFull, _ := readString(buf) proxyThumb, _ := readString(buf) source, _ := readString(buf) var width, height int32 if err := binary.Read(buf, binary.BigEndian, &width); err != nil { return nil, err } if err := binary.Read(buf, binary.BigEndian, &height); err != nil { return nil, err } results = append(results, ImageSearchResult{ ID: id, Title: title, Full: full, Thumb: thumb, ProxyFull: proxyFull, ProxyThumb: proxyThumb, Source: source, Width: int(width), Height: int(height), }) } return results, nil } func prepareProxiedImages(results []ImageSearchResult, mode uint8) []ImageSearchResult { for i := range results { switch mode { case MsgTypeSearchImageThumbRequest: results[i].ProxyThumb = "/image/" + results[i].ID + "_thumb.webp" case MsgTypeSearchImageFullRequest: results[i].ProxyFull = "/image/" + results[i].ID + "_full.webp" case MsgTypeSearchImageAllRequest: results[i].ProxyThumb = "/image/" + results[i].ID + "_thumb.webp" results[i].ProxyFull = "/image/" + results[i].ID + "_full.webp" } } return results } // func handleSearchImageMessage(msg Message) { // query, safe, lang, page, err := decodeSearchTextParams([]byte(msg.Content)) // if err != nil { // printWarn("Error decoding image search parameters: %v", err) // return // } // results := fetchImageResults(query, safe, lang, page, true, true) // switch msg.Type { // case MsgTypeSearchImageRawRequest: // // No proxy URLs needed // case MsgTypeSearchImageThumbRequest: // results = prepareProxiedImages(results, MsgTypeSearchImageThumbRequest) // case MsgTypeSearchImageFullRequest: // results = prepareProxiedImages(results, MsgTypeSearchImageFullRequest) // case MsgTypeSearchImageAllRequest: // results = prepareProxiedImages(results, MsgTypeSearchImageAllRequest) // default: // printWarn("Unknown image request mode: %d", msg.Type) // return // } // payload, err := encodeImageResults(results) // if err != nil { // printWarn("Error encoding image search results: %v", err) // return // } // response := Message{ // ID: msg.ID, // Type: MsgTypeSearchImageResponse, // Content: string(payload), // Target: msg.Source, // Reply to sender // } // if err := sendMessage(response); err != nil { // printWarn("Error sending image search response: %v", err) // } // }