Skip to content

Instantly share code, notes, and snippets.

@nickvanw
Created August 23, 2014 01:52
Show Gist options
  • Save nickvanw/79b2f0f08e834738e9ef to your computer and use it in GitHub Desktop.
Save nickvanw/79b2f0f08e834738e9ef to your computer and use it in GitHub Desktop.
Parallel URL Fetcher
package main
import (
"encoding/csv"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"sync"
"github.com/codegangsta/negroni"
)
const BASE_URL = "http://example.com/"
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/example", asyncUrlHandler)
n := negroni.Classic()
n.UseHandler(mux)
n.Run(":3000")
}
func asyncUrlHandler(w http.ResponseWriter, req *http.Request) {
queryData := req.URL.Query()
format, ok := queryData["urls"]
if !ok {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("bad arguments"))
return
}
data := strings.NewReader(format[0])
r := csv.NewReader(data)
lines, err := r.Read()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("bad arguments"))
return
}
retChan := make(chan SiteOut)
doneChan := make(chan struct{})
var wg sync.WaitGroup
for _, v := range lines {
wg.Add(1)
go fetchUrl(v, retChan, &wg)
}
go func() {
wg.Wait()
doneChan <- struct{}{}
}()
var output []SiteOut
for {
select {
case v := <-retChan:
output = append(output, v)
case <-doneChan:
json.NewEncoder(w).Encode(output)
req.Body.Close()
return
}
}
}
func fetchUrl(url string, out chan SiteOut, wg *sync.WaitGroup) {
defer wg.Done()
newSite := SiteOut{Base: url}
fetchUrl := fmt.Sprintf("%s/%s", BASE_URL, url)
resp, err := http.Get(fetchUrl)
if err != nil {
newSite.Data = ""
out <- newSite
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
newSite.Data = ""
out <- newSite
return
}
newSite.Data = string(body)
out <- newSite
}
type SiteOut struct {
Data string `json:"data"`
Base string `json:"base"`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment