M jisho/jisho.go => jisho/jisho.go +9 -2
@@ 35,7 35,7 @@ type Senses struct {
}
type Client struct {
- HttpClient http.Client
+ HTTPClient *http.Client
}
func (c *Client) Query(ctx context.Context, query string) (*Response, error) {
@@ 44,7 44,7 @@ func (c *Client) Query(ctx context.Context, query string) (*Response, error) {
q.Set("keyword", query)
req.URL.RawQuery = q.Encode()
- resp, err := c.HttpClient.Do(req)
+ resp, err := c.httpClient().Do(req)
if err != nil {
return nil, err
}
@@ 56,3 56,10 @@ func (c *Client) Query(ctx context.Context, query string) (*Response, error) {
}
return &res, nil
}
+
+func (c *Client) httpClient() *http.Client {
+ if c.HTTPClient != nil {
+ return c.HTTPClient
+ }
+ return http.DefaultClient
+}
M main.go => main.go +30 -3
@@ 5,6 5,7 @@ import (
"flag"
"io"
"log"
+ "net/http"
"net/url"
"os"
"strings"
@@ 25,9 26,22 @@ import (
const BotName = "handlebot"
const BotVersion = "0.0.6"
const ForgeLink = "https://sr.ht/~handlerug/handlebot"
+const UserAgent = BotName + "/" + BotVersion
var urlRegexp = xurls.Strict()
+type userAgentTransport struct {
+ inner http.RoundTripper
+ userAgent string
+}
+
+func (u *userAgentTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+ if req.Header.Get("User-Agent") == "" {
+ req.Header.Set("User-Agent", u.userAgent)
+ }
+ return u.inner.RoundTrip(req)
+}
+
func main() {
cfgPath := flag.String("config", "/etc/wormy.json", "path to the config file")
flag.Parse()
@@ 62,20 76,33 @@ func main() {
waClient *wolframalpha.Client
ytClient *youtube.Client
)
- previewer = &urlpreview.Previewer{}
+ httpClient := &http.Client{
+ Transport: &userAgentTransport{
+ inner: http.DefaultTransport,
+ userAgent: UserAgent,
+ },
+ }
+ previewer = &urlpreview.Previewer{HTTPClient: httpClient}
if cfg.APIKeys.OpenWeatherMap != "" && cfg.APIKeys.MapQuest != "" {
forecaster = &weather.Forecaster{
Credentials: weather.APICredentials{
OpenWeatherMap: cfg.APIKeys.OpenWeatherMap,
MapQuest: cfg.APIKeys.MapQuest,
},
+ HTTPClient: httpClient,
}
}
if cfg.APIKeys.WolframAlpha != "" {
- waClient = &wolframalpha.Client{AppID: cfg.APIKeys.WolframAlpha}
+ waClient = &wolframalpha.Client{
+ AppID: cfg.APIKeys.WolframAlpha,
+ HTTPClient: httpClient,
+ }
}
if cfg.APIKeys.YouTube != "" {
- ytClient = &youtube.Client{APIKey: cfg.APIKeys.YouTube}
+ ytClient = &youtube.Client{
+ APIKey: cfg.APIKeys.YouTube,
+ HTTPClient: httpClient,
+ }
}
client := girc.New(girc.Config{
M urlpreview/gemini.go => urlpreview/gemini.go +1 -1
@@ 20,7 20,7 @@ var errTooManyRedirects = errors.New("Too many redirects")
func (p *Previewer) gemini(ctx context.Context, u *url.URL) (string, error) {
req := &gemini.Request{URL: u, Host: "", Certificate: nil}
- resp, err := doGemini(ctx, &p.GeminiClient, req, nil)
+ resp, err := doGemini(ctx, p.geminiClient(), req, nil)
if err != nil {
return "", err
}
M urlpreview/generic.go => urlpreview/generic.go +1 -1
@@ 20,7 20,7 @@ import (
func (p *Previewer) generic(ctx context.Context, u *url.URL) (string, error) {
req, _ := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
- resp, err := p.HttpClient.Do(req)
+ resp, err := p.httpClient().Do(req)
if err != nil {
return "", err
}
M urlpreview/jisho.go => urlpreview/jisho.go +1 -1
@@ 25,7 25,7 @@ func (p *Previewer) jisho(ctx context.Context, u *url.URL) (string, error) {
return "", err
}
- client := &jisho.Client{p.HttpClient}
+ client := &jisho.Client{p.httpClient()}
result, err := client.Query(ctx, lastSegment)
if err != nil {
return "", err
M urlpreview/urlpreview.go => urlpreview/urlpreview.go +18 -2
@@ 9,9 9,11 @@ import (
"git.sr.ht/~adnano/go-gemini"
)
+var geminiDefaultClient = &gemini.Client{}
+
type Previewer struct {
- HttpClient http.Client
- GeminiClient gemini.Client
+ HTTPClient *http.Client
+ GeminiClient *gemini.Client
}
func (p *Previewer) Preview(ctx context.Context, u *url.URL) (string, error) {
@@ 44,3 46,17 @@ func (p *Previewer) Preview(ctx context.Context, u *url.URL) (string, error) {
}
return res, err
}
+
+func (p *Previewer) httpClient() *http.Client {
+ if p.HTTPClient != nil {
+ return p.HTTPClient
+ }
+ return http.DefaultClient
+}
+
+func (p *Previewer) geminiClient() *gemini.Client {
+ if p.GeminiClient != nil {
+ return p.GeminiClient
+ }
+ return geminiDefaultClient
+}
M weather/weather.go => weather/weather.go +10 -3
@@ 15,7 15,7 @@ var ErrQuota = errors.New("Sorry, the API key seems to have reached its max quot
type Forecaster struct {
Credentials APICredentials
- HttpClient http.Client
+ HTTPClient *http.Client
}
type APICredentials struct {
@@ 89,7 89,7 @@ func (f *Forecaster) Weather(ctx context.Context, lat float64, lng float64) (*We
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.openweathermap.org/data/2.5/onecall", nil)
req.URL.RawQuery = q.Encode()
- resp, err := f.HttpClient.Do(req)
+ resp, err := f.httpClient().Do(req)
if err != nil {
return nil, err
}
@@ 119,7 119,7 @@ func (f *Forecaster) Geocode(ctx context.Context, query string) (
req, _ := http.NewRequestWithContext(ctx, "GET", "https://www.mapquestapi.com/geocoding/v1/address", nil)
req.URL.RawQuery = q.Encode()
- resp, err := f.HttpClient.Do(req)
+ resp, err := f.httpClient().Do(req)
if err != nil {
return
}
@@ 171,3 171,10 @@ func (f *Forecaster) Geocode(ctx context.Context, query string) (
err = nil
return
}
+
+func (f *Forecaster) httpClient() *http.Client {
+ if f.HTTPClient != nil {
+ return f.HTTPClient
+ }
+ return http.DefaultClient
+}
M wolframalpha/wolframalpha.go => wolframalpha/wolframalpha.go +9 -2
@@ 78,7 78,7 @@ type Subpod struct {
type Client struct {
AppID string
- HttpClient http.Client
+ HTTPClient *http.Client
}
func (c *Client) Query(ctx context.Context, input string) (*Result, error) {
@@ 95,7 95,7 @@ func (c *Client) Query(ctx context.Context, input string) (*Result, error) {
req, _ := http.NewRequestWithContext(ctx, "GET", "http://api.wolframalpha.com/v2/query", nil)
req.URL.RawQuery = q.Encode()
- resp, err := c.HttpClient.Do(req)
+ resp, err := c.httpClient().Do(req)
if err != nil {
if err.(*url.Error).Timeout() {
return nil, &TimeoutError{}
@@ 119,3 119,10 @@ func (c *Client) Query(ctx context.Context, input string) (*Result, error) {
}
return &apiResp.Result, nil
}
+
+func (c *Client) httpClient() *http.Client {
+ if c.HTTPClient != nil {
+ return c.HTTPClient
+ }
+ return http.DefaultClient
+}
M youtube/youtube.go => youtube/youtube.go +9 -2
@@ 11,7 11,7 @@ import (
type Client struct {
APIKey string
- HttpClient http.Client
+ HTTPClient *http.Client
}
type Response struct {
@@ 125,7 125,7 @@ func (c *Client) GetVideo(ctx context.Context, id string) (*Video, error) {
q.Set("id", id)
req.URL.RawQuery = q.Encode()
- resp, err := c.HttpClient.Do(req)
+ resp, err := c.httpClient().Do(req)
if err != nil {
return nil, err
}
@@ 146,3 146,10 @@ func (c *Client) GetVideo(ctx context.Context, id string) (*Video, error) {
return res.Items[0], nil
}
+
+func (c *Client) httpClient() *http.Client {
+ if c.HTTPClient != nil {
+ return c.HTTPClient
+ }
+ return http.DefaultClient
+}