diff --git a/node-handle-search.go b/node-handle-search.go index d489a08..d83f545 100644 --- a/node-handle-search.go +++ b/node-handle-search.go @@ -13,10 +13,11 @@ var ( func handleSearchTextMessage(msg Message) { var searchParams struct { - Query string `json:"query"` - Safe string `json:"safe"` - Lang string `json:"lang"` - Page int `json:"page"` + Query string `json:"query"` + Safe string `json:"safe"` + Lang string `json:"lang"` + Page int `json:"page"` + ResponseAddr string `json:"responseAddr"` } err := json.Unmarshal([]byte(msg.Content), &searchParams) if err != nil { @@ -24,6 +25,8 @@ func handleSearchTextMessage(msg Message) { return } + log.Printf("Received search-text request. ResponseAddr: %s", searchParams.ResponseAddr) + results := fetchTextResults(searchParams.Query, searchParams.Safe, searchParams.Lang, searchParams.Page) resultsJSON, err := json.Marshal(results) if err != nil { @@ -33,13 +36,21 @@ func handleSearchTextMessage(msg Message) { responseMsg := Message{ ID: hostID, - Type: "search-results", + Type: "text-results", Content: string(resultsJSON), } - err = sendMessage(msg.ID, responseMsg) + // Log the address to be used for sending the response + log.Printf("Sending text search results to %s", searchParams.ResponseAddr) + + if searchParams.ResponseAddr == "" { + log.Printf("Error: Response address is empty") + return + } + + err = sendMessage(searchParams.ResponseAddr, responseMsg) if err != nil { - log.Printf("Error sending search results to %s: %v", msg.ID, err) + log.Printf("Error sending text search results to %s: %v", searchParams.ResponseAddr, err) } } diff --git a/node.go b/node.go index 6f927d3..824577f 100644 --- a/node.go +++ b/node.go @@ -153,8 +153,8 @@ func interpretMessage(msg Message) { handleSearchForumMessage(msg) case "forum-results": handleForumResultsMessage(msg) - // case "text-results": - // handleTextResultsMessage(msg) // need to implement + case "text-results": + handleTextResultsMessage(msg) // need to implement case "image-results": handleImageResultsMessage(msg) // need to implement // case "video-results": diff --git a/text.go b/text.go index a6d67cc..a6c3283 100644 --- a/text.go +++ b/text.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "fmt" "html/template" "log" @@ -9,6 +10,7 @@ import ( ) var textSearchEngines []SearchEngine +var textResultsChan = make(chan []TextSearchResult) func init() { textSearchEngines = []SearchEngine{ @@ -26,16 +28,51 @@ func HandleTextSearch(w http.ResponseWriter, query, safe, lang string, page int) cacheKey := CacheKey{Query: query, Page: page, Safe: safe == "true", Lang: lang, Type: "text"} combinedResults := getTextResultsFromCacheOrFetch(cacheKey, query, safe, lang, page) - hasPrevPage := page > 1 - hasNextPage := len(combinedResults) > 0 + hasPrevPage := page > 1 // dupe - displayResults(w, combinedResults, query, lang, time.Since(startTime).Seconds(), page, hasPrevPage, hasNextPage) + //displayResults(w, combinedResults, query, lang, time.Since(startTime).Seconds(), page, hasPrevPage, hasNextPage) // Prefetch next and previous pages go prefetchPage(query, safe, lang, page+1) if hasPrevPage { go prefetchPage(query, safe, lang, page-1) } + + elapsedTime := time.Since(startTime) + tmpl, err := template.New("text.html").Funcs(funcs).ParseFiles("templates/text.html") + if err != nil { + log.Printf("Error parsing template: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + data := struct { + Results []TextSearchResult + 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 getTextResultsFromCacheOrFetch(cacheKey CacheKey, query, safe, lang string, page int) []TextSearchResult { @@ -109,6 +146,12 @@ func fetchTextResults(query, safe, lang string, page int) []TextSearchResult { } } + // If no results found after trying all engines + if len(results) == 0 { + log.Printf("No text results found for query: %s, trying other nodes", query) + results = tryOtherNodesForTextSearch(query, safe, lang, page) + } + return results } @@ -140,48 +183,71 @@ func wrapTextSearchFunc(f func(string, string, string, int) ([]TextSearchResult, } } -func displayResults(w http.ResponseWriter, results []TextSearchResult, query, lang string, elapsed float64, page int, hasPrevPage, hasNextPage bool) { - log.Printf("Displaying results for page %d", page) - log.Printf("Total results: %d", len(results)) - log.Printf("Has previous page: %t, Has next page: %t", hasPrevPage, hasNextPage) +func tryOtherNodesForTextSearch(query, safe, lang string, page int) []TextSearchResult { + for _, nodeAddr := range peers { + results, err := sendTextSearchRequestToNode(nodeAddr, query, safe, lang, page) + if err != nil { + log.Printf("Error contacting node %s: %v", nodeAddr, err) + continue + } + if len(results) > 0 { + return results + } + } + return nil +} - tmpl, err := template.New("text.html").Funcs(template.FuncMap{ - "sub": func(a, b int) int { - return a - b - }, - "add": func(a, b int) int { - return a + b - }, - }).ParseFiles("templates/text.html") +func sendTextSearchRequestToNode(nodeAddr, query, safe, lang string, page int) ([]TextSearchResult, error) { + searchParams := struct { + Query string `json:"query"` + Safe string `json:"safe"` + Lang string `json:"lang"` + Page int `json:"page"` + ResponseAddr string `json:"responseAddr"` + }{ + Query: query, + Safe: safe, + Lang: lang, + Page: page, + ResponseAddr: fmt.Sprintf("http://localhost:%d/node", config.Port), + } + + msgBytes, err := json.Marshal(searchParams) if err != nil { - http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return nil, fmt.Errorf("failed to marshal search parameters: %v", err) + } + + msg := Message{ + ID: hostID, + Type: "search-text", + Content: string(msgBytes), + } + + err = sendMessage(nodeAddr, msg) + if err != nil { + return nil, fmt.Errorf("failed to send search request to node %s: %v", nodeAddr, err) + } + + // Wait for results + select { + case res := <-textResultsChan: + return res, nil + case <-time.After(20 * time.Second): // Increased timeout duration + return nil, fmt.Errorf("timeout waiting for results from node %s", nodeAddr) + } +} + +func handleTextResultsMessage(msg Message) { + var results []TextSearchResult + err := json.Unmarshal([]byte(msg.Content), &results) + if err != nil { + log.Printf("Error unmarshalling text results: %v", err) return } - data := struct { - Results []TextSearchResult - Query string - Fetched string - Page int - HasPrevPage bool - HasNextPage bool - LanguageOptions []LanguageOption - CurrentLang string - NoResults bool - }{ - Results: results, - Query: query, - Fetched: fmt.Sprintf("%.2f seconds", elapsed), - Page: page, - HasPrevPage: hasPrevPage, - HasNextPage: hasNextPage, - LanguageOptions: languageOptions, - CurrentLang: lang, - NoResults: len(results) == 0, - } - - err = tmpl.Execute(w, data) - if err != nil { - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - } + log.Printf("Received text results: %+v", results) + // Send results to textResultsChan + go func() { + textResultsChan <- results + }() }