package fetch import ( "context" "fmt" "io/ioutil" "local1/logger" "net/http" "time" ) type Fetch struct { process func(string, []byte) error client *http.Client server *http.Server port string } func New(port string, process func(string, []byte) error) (*Fetch, error) { return &Fetch{ process: process, client: &http.Client{}, port: port, }, nil } func (fetcher *Fetch) FetchProcess(url string) error { req, err := http.NewRequest("GET", url, nil) if err != nil { return err } resp, err := fetcher.client.Do(req) if err != nil { return err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return err } if err := fetcher.process(url, b); err != nil { return err } return nil } func (fetcher *Fetch) listen() error { fetcher.server = &http.Server{ Addr: fetcher.port, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/fetchfeed" { http.NotFound(w, r) logger.Logf("bad path: %q", r.URL.Path) return } if r.Method != "POST" && r.Method != "PUT" { http.NotFound(w, r) logger.Logf("bad method: %q", r.Method) return } b, err := ioutil.ReadAll(r.Body) defer r.Body.Close() if err != nil || len(b) == 0 { logger.Log(len(b), err) w.WriteHeader(http.StatusBadRequest) return } if err := fetcher.FetchProcess(string(b)); err != nil { w.WriteHeader(http.StatusInternalServerError) return } }), } if err := fetcher.server.ListenAndServe(); err != http.ErrServerClosed && err != nil { return err } return nil } func (fetcher *Fetch) Start() error { errs := make(chan error) go func() { if err := fetcher.listen(); err != nil { select { case errs <- err: case <-time.After(time.Second * 10): panic(err) } } }() select { case err := <-errs: return fmt.Errorf("%s: %v", "fetcher server quit early", err) case <-time.After(time.Second * 10): } return nil } func (fetcher *Fetch) Close() error { return fetcher.Stop() } func (fetcher *Fetch) Stop() error { ctx, can := context.WithTimeout(context.Background(), time.Second*10) defer can() return fetcher.server.Shutdown(ctx) }