So I was trying to do this exercise from Tour of Go. I managed to get it working. I am not at all sure that it is correctly concurrent or idiomatic (I started learning Go, like, 4 hours ago).
I would really appreciate feedback about my solution. Here's the relevant meat of the code. Full code available below.
type urlToFetch struct {
Url string
Depth int
}
// Group stuff together, so that it's easier to pass around.
type fetchContext struct {
Queue chan urlToFetch
History map[string]int
Quit chan int
Fetcher Fetcher
}
func Crawl(url string, depth int, fetcher Fetcher) {
context := fetchContext{
Queue: make(chan urlToFetch, 500),
History: make(map[string]int),
Quit: make(chan int, 50),
Fetcher: fetcher,
}
go fetchOne(&context)
context.Queue <- urlToFetch{url, depth}
<-context.Quit
}
func fetchOne(ctx *fetchContext) {
timeout := time.After(2000 * time.Millisecond)
select {
case utf := <-ctx.Queue:
if utf.Depth > 0 {
body, urls, err := ctx.Fetcher.Fetch(utf.Url)
ctx.History[utf.Url] = 1
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", utf.Url, body)
for _, u := range urls {
go fetchOne(ctx)
if _, ok := ctx.History[u]; !ok {
ctx.Queue <- urlToFetch{u, utf.Depth - 1}
} else {
}
}
}
case <-timeout:
ctx.Quit <- 1
}
}
The full source is at: http://pastie.org/8443147