/****************** INDEX RELATED FUNCS ******************/ func fetchPage(payload *gabs.Container) error { //request the http url url := payload.Path("initial_input.url").Data().(string) payload.SetP(url, "return_value.url") //Example of forcing a halting condition and returning an error up to the bolt engine and api client //payload.SetP(boltsdk.HaltCallCommandName, "nextCommand") //payload.SetP("FAKE ERROR", "error") //return errors.New("FAKE ERROR") resp, err := http.Get(url) if err != nil { payload.SetP("Error getting url content: "+err.Error(), "error.fetchPage") return errors.New("Error getting url content: " + err.Error()) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { payload.SetP("Error getting url content: "+err.Error(), "error.fetchPage") return errors.New("Error getting url content: " + err.Error()) } payload.SetP(string(body), "return_value.html") return nil }
/****************** SEARCH RELATED FUNCS ******************/ func getBaseResults(payload *gabs.Container) error { //do some work/db queries, etc (in this case, 'query' the search index) stopAt := int(payload.Path("params.stopAt").Data().(float64)) results := doSearch(payload.Path("initial_input.searchtext").Data().(string), stopAt) _, err := payload.SetP(results, "return_value.results") return err }
func parseKeywords(payload *gabs.Container) error { //parse through html to extract unique 5+ letter a-zA-Z keywords html := "" if payload.Path("return_value.html").Data() != nil { html = payload.Path("return_value.html").Data().(string) } //super inefficient way to do this, a full app would parse the html tree //properly, treat certain elements differently, etc tmptokens := strings.Split(html, " ") //easy way to de-dupe keywords we'll be filling this map using the keys as the keyword //could also use it to up the # of occurences of the keyword to add weights keywords := make(map[string]int) for i := range tmptokens { //here we make sure to only include tokens that are alpha w/ no numerics or special chars matched, err := regexp.MatchString("^[a-zA-Z]+$", tmptokens[i]) if err == nil && len(tmptokens[i]) >= 5 && matched { keywords[strings.ToLower(tmptokens[i])] = 1 } } //fill a slice with the unique keywords kwarray := []string{} for kw := range keywords { kwarray = append(kwarray, kw) } //cheapo extract title of page without full html parse title := "(Unknown)" i := strings.Index(html, "<title>") e := strings.Index(html, "</title>") if i >= 0 && e >= 0 && i < e { title = html[i+7 : e] } //add to the payload payload.SetP(kwarray, "return_value.keywords") payload.SetP(title, "return_value.title") payload.SetP("", "return_value.html") //clear out the html, no need to send it to next workers return nil }
func saveToIndex(payload *gabs.Container) error { //loop through keywords, adding the url to keyword maps //(in a real application, this would be some sort of real datastore, of course) kw := payload.Path("return_value.keywords").Data().([]interface{}) url := payload.Path("return_value.url").Data().(string) title := payload.Path("return_value.title").Data().(string) //fmt.Println(kw, url, title) sites[url] = &ResultInfo{Title: title, URL: url, Meta: ""} //with multiple worker threads running, this might cause locking and need a mutex, but for example purpose its ok. //we look through all keywords, and store the association to the url for keywordi := range kw { keyword := kw[keywordi].(string) urls, ok := keywords[keyword] if ok { skip := false for u := range urls.C { if url == urls.C[u] { //site already in this keyword assoc skip = true } } if !skip { urls.C = append(urls.C, url) } } else { keywords[keyword] = &URLCollection{C: []string{url}} } } return nil }