From df72df5e629d77db8062d98f9070a2977e0c2884 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Wed, 19 Feb 2020 18:03:29 -0700 Subject: [PATCH] move to a generic http requestor --- plugins/beer.go | 49 ++++++++++++---------------------- plugins/beer_test.go | 17 ------------ plugins/federation.go | 46 +++++++++++--------------------- plugins/plugins.go | 58 +++++++++++++++++++++++++++++++++++++++++ plugins/plugins_test.go | 30 +++++++++++++++++++++ 5 files changed, 119 insertions(+), 81 deletions(-) delete mode 100644 plugins/beer_test.go diff --git a/plugins/beer.go b/plugins/beer.go index 9b071c8..72efffa 100644 --- a/plugins/beer.go +++ b/plugins/beer.go @@ -1,12 +1,9 @@ package plugins import ( - "encoding/json" "fmt" - "io/ioutil" "log" "math/rand" - "net/http" "net/url" "regexp" "time" @@ -95,30 +92,6 @@ func (h *Beer) Match(user, msg string) bool { return re.MatchString(msg) } -func (h *Beer) get(beer string) (*BeerResp, error) { - u := "https://data.opendatasoft.com/api/records/1.0/search?dataset=open-beer-database%40public-us&q=" - u = fmt.Sprintf("%s%s", u, url.PathEscape(beer)) - resp, err := http.Get(u) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - var beers = &BeerResp{} - err = json.Unmarshal([]byte(body), beers) - if err != nil { - return nil, err - } - - return beers, nil -} - func (h *Beer) pretty(b BeerResp, random bool) string { idx := 0 @@ -148,18 +121,28 @@ func (h *Beer) RespondText(c *gomatrix.Client, ev *gomatrix.Event, user, post st beer := h.fix(post) if beer != "" { log.Printf("%s: responding to '%s'", h.Name(), ev.Sender) - brr, err := h.get(beer) + var beers = &BeerResp{} + u := fmt.Sprintf("%s%s", + "https://data.opendatasoft.com/api/records/1.0/search?dataset=open-beer-database%40public-us&q=", + url.PathEscape(beer), + ) + req := HTTPRequest{ + Method: "GET", + ResBody: beers, + URL: u, + } + err := req.DoJSON() if err != nil { SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look for beer. (%s)", ev.Sender, err)) } switch { - case brr.Nhits == 0: + case beers.Nhits == 0: SendText(c, ev.RoomID, "¯\\_(ツ)_/¯") - case brr.Nhits == 1: - SendText(c, ev.RoomID, h.pretty(*brr, false)) - case brr.Nhits > 1: - SendText(c, ev.RoomID, fmt.Sprintf("Found %d beers, here is a random one:\n%s", brr.Nhits, h.pretty(*brr, true))) + case beers.Nhits == 1: + SendText(c, ev.RoomID, h.pretty(*beers, false)) + case beers.Nhits > 1: + SendText(c, ev.RoomID, fmt.Sprintf("Found %d beers, here is a random one:\n%s", beers.Nhits, h.pretty(*beers, true))) } } } diff --git a/plugins/beer_test.go b/plugins/beer_test.go deleted file mode 100644 index 1d37a47..0000000 --- a/plugins/beer_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package plugins - -import ( - "testing" -) - -func TestBeer(t *testing.T) { - beer := &Beer{} - b, err := beer.get("oskar blues") - if err != nil { - t.Errorf("%+v\n", err) - } - - if b.Nhits == 0 { - t.Errorf("Expected 7 results; got %d\n", b.Nhits) - } -} diff --git a/plugins/federation.go b/plugins/federation.go index 1dc8b27..6a84c24 100644 --- a/plugins/federation.go +++ b/plugins/federation.go @@ -1,11 +1,8 @@ package plugins import ( - "encoding/json" "fmt" - "io/ioutil" "log" - "net/http" "net/url" "regexp" "time" @@ -51,33 +48,6 @@ func (h *Feder) Match(user, msg string) bool { return re.MatchString(msg) } -func (h *Feder) get(hserver string) (*FedResp, error) { - u := "https://federationtester.matrix.org/api/report?server_name=" - u = fmt.Sprintf("%s%s", u, url.PathEscape(hserver)) - hClient := http.Client{ - Timeout: time.Duration(5 * time.Second), - } - resp, err := hClient.Get(u) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - var fresp = &FedResp{} - err = json.Unmarshal([]byte(body), fresp) - if err != nil { - return nil, err - } - - return fresp, nil -} - // SetStore we don't need a store here. func (h *Feder) SetStore(s PluginStore) {} @@ -94,7 +64,21 @@ func (h *Feder) RespondText(c *gomatrix.Client, ev *gomatrix.Event, user, post s homeServer = u.Hostname() log.Printf("%s: responding to '%s'", h.Name(), ev.Sender) - fed, err := h.get(homeServer) + + furl := fmt.Sprintf("%s%s", + "https://federationtester.matrix.org/api/report?server_name=", + url.PathEscape(homeServer), + ) + var fed = &FedResp{} + + var req = HTTPRequest{ + Timeout: 5 * time.Second, + URL: furl, + Method: "GET", + ResBody: fed, + } + err = req.DoJSON() + if err != nil { SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look up the federation status (%s)", ev.Sender, err)) return diff --git a/plugins/plugins.go b/plugins/plugins.go index f9b8dba..2b00cb5 100644 --- a/plugins/plugins.go +++ b/plugins/plugins.go @@ -1,8 +1,12 @@ package plugins import ( + "bytes" + "encoding/json" + "net/http" "regexp" "strings" + "time" "github.com/matrix-org/gomatrix" ) @@ -47,6 +51,60 @@ func ToMe(user, message string) bool { return strings.Contains(message, u) } +// HTTPRequest has the bits for making http requests +type HTTPRequest struct { + Client http.Client + Request *http.Request + Timeout time.Duration + URL string + Method string + ReqBody interface{} + ResBody interface{} +} + +// DoJSON is a general purpose http mechanic that can be used to get, post.. +// what evs. The response is always expected to be json +func (h *HTTPRequest) DoJSON() (err error) { + h.Client.Timeout = h.Timeout + + if h.Method == "" { + h.Method = "GET" + } + + if h.ReqBody != nil { + // We have a request to send to the server + buf := new(bytes.Buffer) + err = json.NewEncoder(buf).Encode(h.ReqBody) + if err != nil { + return err + } + h.Request, err = http.NewRequest(h.Method, h.URL, buf) + } else { + // Just gimme dem datas + h.Request, err = http.NewRequest(h.Method, h.URL, nil) + } + + if err != nil { + return err + } + + h.Request.Header.Set("Content-Type", "application/json") + + res, err := h.Client.Do(h.Request) + if res != nil { + defer res.Body.Close() + } + if err != nil { + return err + } + + if h.ResBody != nil && res.Body != nil { + return json.NewDecoder(res.Body).Decode(&h.ResBody) + } + + return nil +} + // SendText sends a text message to a given room. It pretends to be // "typing" by calling UserTyping for the caller. func SendText(c *gomatrix.Client, roomID, message string) error { diff --git a/plugins/plugins_test.go b/plugins/plugins_test.go index fd7e65d..46927ab 100644 --- a/plugins/plugins_test.go +++ b/plugins/plugins_test.go @@ -1,6 +1,9 @@ package plugins import ( + "fmt" + "net/http" + "net/http/httptest" "testing" ) @@ -16,3 +19,30 @@ func TestPluginsNameRE(t *testing.T) { t.Errorf("NameRE expected 'test'; got %q\n", n) } } + +type testResp struct { + Name string `json:"test"` +} + +func TestHTTPRequestDoJSON(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"test":"success"}`) + })) + defer ts.Close() + + var tr = &testResp{} + + req := HTTPRequest{ + ResBody: tr, + URL: ts.URL, + } + + err := req.DoJSON() + if err != nil { + t.Error(err) + } + + if tr.Name != "success" { + t.Errorf("Expected 'test'; got '%s'\n", tr.Name) + } +}