package main import ( "net/http" "log" "strings" "encoding/json" "io/ioutil" "regexp" ) var bangs = loadBangs() func main() { http.HandleFunc("/eval", func(w http.ResponseWriter, r *http.Request) { searchQuery := r.URL.Query().Get("query") searchEngine := r.URL.Query().Get("engine") if (searchQuery == "" || searchEngine == "") { http.Error(w, "400 Bad Request", http.StatusBadRequest) return } searchQuery, searchEngine = evaluateBang(searchQuery, searchEngine) searchURL := buildSearchURL(searchEngine, searchQuery) http.Redirect(w, r, searchURL, http.StatusSeeOther) }) log.Fatalf("Failed to start http server: %v", http.ListenAndServe(":8081", nil)) } func loadBangs() (bangs map[string]string) { data, err := ioutil.ReadFile("bangs.json") if err != nil { log.Fatalf("Failed to read bangs: %v", err) } err = json.Unmarshal(data, &bangs) if err != nil { log.Fatalf("Failed to decode bangs: %v", err) } return } func buildSearchURL(template string, query string) (searchUrl string) { return strings.Replace(template, "%s", query, 1) } func parseBang(searchQuery string) (bang string, query string) { regexStartBang, _ := regexp.Compile("\\!(.*) (.*)") regexEndBang, _ := regexp.Compile("(.*) \\!(.*)") startBang := regexStartBang.FindSubmatch([]byte(searchQuery)) endBang := regexEndBang.FindSubmatch([]byte(searchQuery)) if len(endBang) == 3 { return string(endBang[2]), string(endBang[1]) } else if len(startBang) == 3 { return string(startBang[1]), string(startBang[2]) } else { return "", searchQuery } } func evaluateBang(searchQuery string, searchEngine string) (query string, engine string) { bang, query := parseBang(searchQuery) if bang == "" { return query, searchEngine } else { return query, bangs[bang] } }