package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"github.com/hamcha/tg"
)
type SearchResult struct {
Name string
Description *string
Alternatives []string
None bool
}
type SearchResultData struct {
ItemListElement []struct {
Result struct {
Name []struct {
Value string `json:"@value"`
Lang string `json:"@language"`
} `json:"name,omitempty"`
Description []struct {
Value string `json:"@value"`
Lang string `json:"@language"`
} `json:"description,omitempty"`
DetailedDescription []struct {
Value string `json:"articleBody"`
Lang string `json:"inLanguage"`
} `json:"detailedDescription,omitempty"`
} `json:"result"`
} `json:"itemListElement"`
Error struct {
Code int `json:"code"`
Message string `json:"message"`
} `json:"error,omitempty"`
}
const MAX_SEARCH_ALTS = 2
func search_init() {
if strings.HasPrefix(*gapikey, "@") {
data, err := ioutil.ReadFile((*gapikey)[1:])
if err != nil {
panic(err)
}
*gapikey = strings.TrimSpace(string(data))
}
if *gapikey == "" {
panic(fmt.Errorf("Missing GAPI key for search module (provide it or --disable search)"))
}
}
func search_message(broker *tg.Broker, update tg.APIMessage) {
if isCommand(update, "search") {
parts := strings.SplitN(*(update.Text), " ", 2)
if len(parts) < 2 {
broker.SendTextMessage(update.Chat, "Non mi hai dato niente da cercare!", &update.MessageID)
return
}
broker.SendChatAction(update.Chat, tg.ActionTyping)
result, err := searchAPI(parts[1])
if err != nil {
log.Printf("[search] %s\n", err.Error())
broker.SendTextMessage(update.Chat, "ERRORE! @hamcha controlla la console!", &update.MessageID)
return
}
if result.None {
broker.SendTextMessage(update.Chat, "Non ho trovato nulla, mi spiace :(", &update.MessageID)
return
}
resulttxt := fmt.Sprintf("Ecco la prima cosa che ho trovato:\n%s", result.Name)
if result.Description != nil {
resulttxt += "\n" + *(result.Description)
}
if len(result.Alternatives) > 0 {
resulttxt += "\nAlternativamente:\n - " + strings.Join(result.Alternatives, "\n - ")
}
broker.SendTextMessage(update.Chat, resulttxt, &update.MessageID)
}
}
func searchAPI(term string) (SearchResult, error) {
resp, err := http.Get("https://kgsearch.googleapis.com/v1/entities:search?indent=true&languages=it&languages=en&query=" + url.QueryEscape(term) + "&key=" + *gapikey)
if err != nil {
return SearchResult{}, err
}
defer resp.Body.Close()
var res SearchResultData
err = json.NewDecoder(resp.Body).Decode(&res)
if err != nil {
return SearchResult{}, err
}
if res.Error.Message != "" {
return SearchResult{}, fmt.Errorf("Request error: %d %s", res.Error.Code, res.Error.Message)
}
if len(res.ItemListElement) < 1 {
return SearchResult{None: true}, nil
}
out := SearchResult{None: false}
for _, item := range res.ItemListElement {
// Skip elements without a name
if item.Result.Name == nil || len(item.Result.Name) == 0 {
continue
}
namestr := item.Result.Name[0].Value
// Check if it has a small description
if item.Result.Description != nil && len(item.Result.Description) > 0 {
namestr += " (" + item.Result.Description[0].Value + ")"
}
// If we already had an item, add it to alternatives and find others
if out.Name != "" {
out.Alternatives = append(out.Alternatives, namestr)
if len(out.Alternatives) > MAX_SEARCH_ALTS {
break
}
continue
}
out.Name = namestr
// Check for a description
if item.Result.DetailedDescription != nil || len(item.Result.DetailedDescription) > 0 {
out.Description = &(item.Result.DetailedDescription[0].Value)
}
}
return out, nil
}