package main import ( "fmt" "html/template" "log" "net/http" "time" ) var imageSearchEngines []SearchEngine func init() { imageSearchEngines = []SearchEngine{ {Name: "Qwant", Func: wrapImageSearchFunc(PerformQwantImageSearch), Weight: 1}, {Name: "Imgur", Func: wrapImageSearchFunc(PerformImgurImageSearch), Weight: 2}, } } func handleImageSearch(w http.ResponseWriter, query, safe, lang string, page int) { startTime := time.Now() cacheKey := CacheKey{Query: query, Page: page, Safe: safe == "true", Lang: lang, Type: "image"} combinedResults := getImageResultsFromCacheOrFetch(cacheKey, query, safe, lang, page) elapsedTime := time.Since(startTime) tmpl, err := template.New("images.html").Funcs(funcs).ParseFiles("templates/images.html") if err != nil { log.Printf("Error parsing template: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } data := struct { Results []ImageSearchResult Query string Page int Fetched string LanguageOptions []LanguageOption CurrentLang string HasPrevPage bool HasNextPage bool NoResults bool }{ Results: combinedResults, Query: query, Page: page, Fetched: fmt.Sprintf("%.2f seconds", elapsedTime.Seconds()), LanguageOptions: languageOptions, CurrentLang: lang, HasPrevPage: page > 1, HasNextPage: len(combinedResults) >= 50, NoResults: len(combinedResults) == 0, } err = tmpl.Execute(w, data) if err != nil { log.Printf("Error executing template: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } func getImageResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []ImageSearchResult { cacheChan := make(chan []SearchResult) var combinedResults []ImageSearchResult go func() { results, exists := resultsCache.Get(cacheKey) if exists { log.Println("Cache hit") cacheChan <- results } else { log.Println("Cache miss") cacheChan <- nil } }() select { case results := <-cacheChan: if results == nil { combinedResults = fetchImageResults(query, safe, lang, page) if len(combinedResults) > 0 { resultsCache.Set(cacheKey, convertToSearchResults(combinedResults)) } } else { _, _, imageResults := convertToSpecificResults(results) combinedResults = imageResults } case <-time.After(2 * time.Second): log.Println("Cache check timeout") combinedResults = fetchImageResults(query, safe, lang, page) if len(combinedResults) > 0 { resultsCache.Set(cacheKey, convertToSearchResults(combinedResults)) } } return combinedResults } func fetchImageResults(query, safe, lang string, page int) []ImageSearchResult { var results []ImageSearchResult for _, engine := range imageSearchEngines { log.Printf("Using image search engine: %s", engine.Name) searchResults, duration, err := engine.Func(query, safe, lang, page) updateEngineMetrics(&engine, duration, err == nil) if err != nil { log.Printf("Error performing image search with %s: %v", engine.Name, err) continue } for _, result := range searchResults { results = append(results, result.(ImageSearchResult)) } // If results are found, break out of the loop if len(results) > 0 { break } } // If no results found after trying all engines if len(results) == 0 { log.Printf("No image results found for query: %s, trying other nodes", query) results = tryOtherNodesForImageSearch(query, safe, lang, page, []string{hostID}) } return results } func wrapImageSearchFunc(f func(string, string, string, int) ([]ImageSearchResult, time.Duration, error)) func(string, string, string, int) ([]SearchResult, time.Duration, error) { return func(query, safe, lang string, page int) ([]SearchResult, time.Duration, error) { imageResults, duration, err := f(query, safe, lang, page) if err != nil { return nil, duration, err } searchResults := make([]SearchResult, len(imageResults)) for i, result := range imageResults { searchResults[i] = result } return searchResults, duration, nil } }