move to a generic http requestor

This commit is contained in:
Aaron Bieber 2020-02-19 18:03:29 -07:00
parent d182ca2efb
commit df72df5e62
5 changed files with 119 additions and 81 deletions

View File

@ -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)))
}
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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)
}
}