package main import ( "encoding/json" "fmt" "io" "net/http" "net/url" ) func handleSuggestions(w http.ResponseWriter, r *http.Request) { query := r.URL.Query().Get("q") if query == "" { w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `["",[]]`) return } // Define the fallback sequence with Google lower in the hierarchy suggestionSources := []func(string) []string{ fetchDuckDuckGoSuggestions, fetchEdgeSuggestions, fetchBraveSuggestions, fetchEcosiaSuggestions, fetchQwantSuggestions, fetchStartpageSuggestions, // fetchGoogleSuggestions, // I advise against it, but you can use it if you want to } var suggestions []string for _, fetchFunc := range suggestionSources { suggestions = fetchFunc(query) if len(suggestions) > 0 { printDebug("Suggestions found using %T", fetchFunc) break } else { printWarn("%T did not return any suggestions or failed.", fetchFunc) } } if len(suggestions) == 0 { printErr("All suggestion services failed. Returning empty response.") } // Return the final suggestions as JSON w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `["",%s]`, toJSONStringArray(suggestions)) } func fetchGoogleSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("http://suggestqueries.google.com/complete/search?client=firefox&q=%s", encodedQuery) printDebug("Fetching suggestions from Google: %s", url) return fetchSuggestionsFromURL(url) } func fetchDuckDuckGoSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("https://duckduckgo.com/ac/?q=%s&type=list", encodedQuery) printDebug("Fetching suggestions from DuckDuckGo: %s", url) return fetchSuggestionsFromURL(url) } func fetchEdgeSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("https://api.bing.com/osjson.aspx?query=%s", encodedQuery) printDebug("Fetching suggestions from Edge (Bing): %s", url) return fetchSuggestionsFromURL(url) } func fetchBraveSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("https://search.brave.com/api/suggest?q=%s", encodedQuery) printDebug("Fetching suggestions from Brave: %s", url) return fetchSuggestionsFromURL(url) } func fetchEcosiaSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("https://ac.ecosia.org/?q=%s&type=list", encodedQuery) printDebug("Fetching suggestions from Ecosia: %s", url) return fetchSuggestionsFromURL(url) } func fetchQwantSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("https://api.qwant.com/v3/suggest?q=%s", encodedQuery) printDebug("Fetching suggestions from Qwant: %s", url) return fetchSuggestionsFromURL(url) } func fetchStartpageSuggestions(query string) []string { encodedQuery := url.QueryEscape(query) url := fmt.Sprintf("https://startpage.com/suggestions?q=%s", encodedQuery) printDebug("Fetching suggestions from Startpage: %s", url) return fetchSuggestionsFromURL(url) } func fetchSuggestionsFromURL(url string) []string { resp, err := http.Get(url) if err != nil { printWarn("Error fetching suggestions from %s: %v", url, err) return []string{} } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { printWarn("Error reading response body from %s: %v", url, err) return []string{} } // Log the Content-Type for debugging contentType := resp.Header.Get("Content-Type") printDebug("Response Content-Type from %s: %s", url, contentType) // Check if the body is non-empty if len(body) == 0 { printWarn("Received empty response body from %s", url) return []string{} } // Attempt to parse the response as JSON regardless of Content-Type var parsedResponse []interface{} if err := json.Unmarshal(body, &parsedResponse); err != nil { printErr("Error parsing JSON from %s: %v", url, err) printDebug("Response body: %s", string(body)) return []string{} } // Ensure the response structure is as expected if len(parsedResponse) < 2 { printWarn("Unexpected response format from %v: %v", url, string(body)) return []string{} } suggestions := []string{} if items, ok := parsedResponse[1].([]interface{}); ok { for _, item := range items { if suggestion, ok := item.(string); ok { suggestions = append(suggestions, suggestion) } } } else { printErr("Unexpected suggestions format in response from: %v", url) } return suggestions } func toJSONStringArray(strings []string) string { result := "" for i, str := range strings { result += fmt.Sprintf(`"%s"`, str) if i < len(strings)-1 { result += "," } } return "[" + result + "]" }