2018-01-06 06:57:26 +03:00
|
|
|
package fetchers
|
2018-01-06 08:55:04 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Fetcher interface {
|
|
|
|
Fetch(url string) (string, error)
|
|
|
|
GetName() string
|
|
|
|
}
|
|
|
|
|
|
|
|
type GoogleFetcher struct {
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GoogleFetcher) Fetch(url string) (string, error) {
|
2018-01-06 08:58:45 +03:00
|
|
|
time.Sleep(time.Second * 1)
|
2018-01-06 08:55:04 +03:00
|
|
|
return fmt.Sprintf("%s is fetching %s", g.Name, url), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GoogleFetcher) GetName() string {
|
|
|
|
return g.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGoogleFetcher(name string) *GoogleFetcher {
|
|
|
|
return &GoogleFetcher{Name: name}
|
|
|
|
}
|
|
|
|
|
|
|
|
type BingFetcher struct {
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BingFetcher) Fetch(url string) (string, error) {
|
2018-01-06 09:55:59 +03:00
|
|
|
time.Sleep(time.Second * 10)
|
2018-01-06 08:55:04 +03:00
|
|
|
return fmt.Sprintf("%s is fetching %s", b.Name, url), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *BingFetcher) GetName() string {
|
|
|
|
return b.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewBingFetcher(name string) *BingFetcher {
|
|
|
|
return &BingFetcher{Name: name}
|
|
|
|
}
|
|
|
|
|
|
|
|
type DuckDuckGoFetcher struct {
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DuckDuckGoFetcher) Fetch(url string) (string, error) {
|
2018-01-06 09:55:59 +03:00
|
|
|
time.Sleep(time.Second * 10)
|
2018-01-06 08:55:04 +03:00
|
|
|
return fmt.Sprintf("%s is fetching %s", d.Name, url), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DuckDuckGoFetcher) GetName() string {
|
|
|
|
return d.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewDuckDuckGoFetcherFetcher(name string) *DuckDuckGoFetcher {
|
|
|
|
return &DuckDuckGoFetcher{Name: name}
|
|
|
|
}
|
|
|
|
func FetchResults(url string, fetchers []Fetcher, timeout time.Duration) ([]string, []error) {
|
2018-01-06 08:58:45 +03:00
|
|
|
chStr := make(chan string, len(fetchers))
|
|
|
|
chErr := make(chan error, len(fetchers))
|
2018-01-06 08:55:04 +03:00
|
|
|
for _, f := range fetchers {
|
|
|
|
go func(f Fetcher) {
|
2018-01-06 09:55:59 +03:00
|
|
|
ch := make(chan string, 1)
|
|
|
|
eCh := make(chan error, 1)
|
|
|
|
go func() {
|
|
|
|
s, err := f.Fetch(url)
|
|
|
|
if err != nil {
|
|
|
|
eCh <- err
|
|
|
|
} else {
|
|
|
|
ch <- s
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
select {
|
|
|
|
case r := <-ch:
|
|
|
|
chStr <- r
|
|
|
|
case err := <-eCh:
|
2018-01-06 08:55:04 +03:00
|
|
|
chErr <- err
|
2018-01-06 09:55:59 +03:00
|
|
|
case <-time.After(timeout):
|
|
|
|
chErr <- fmt.Errorf("%s timeout after %v on %v", f.GetName(), timeout, url)
|
2018-01-06 08:55:04 +03:00
|
|
|
}
|
|
|
|
}(f)
|
|
|
|
}
|
2018-01-06 08:58:45 +03:00
|
|
|
stringResults := make([]string, 0, len(fetchers))
|
|
|
|
errorResults := make([]error, 0, len(fetchers))
|
2018-01-06 08:55:04 +03:00
|
|
|
for range fetchers {
|
|
|
|
select {
|
|
|
|
case s := <-chStr:
|
|
|
|
stringResults = append(stringResults, s)
|
|
|
|
case e := <-chErr:
|
|
|
|
errorResults = append(errorResults, e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return stringResults, errorResults
|
|
|
|
}
|
|
|
|
|
|
|
|
func RunFetchers() {
|
2018-01-06 09:55:59 +03:00
|
|
|
fetchers := []Fetcher{NewGoogleFetcher("Google"), NewBingFetcher("Bing"), NewDuckDuckGoFetcherFetcher("Duck Duck Go")}
|
|
|
|
r, e := FetchResults("http://www.abc.com", fetchers, time.Second*2)
|
2018-01-06 08:55:04 +03:00
|
|
|
spew.Dump(r, e)
|
|
|
|
}
|