owobot/internal/systems/plugins/builtins/fetch.go

119 lines
2.5 KiB
Go

package builtins
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/cookiejar"
"runtime/debug"
"strings"
"golang.org/x/net/publicsuffix"
)
// Options contains options for the JavaScript fetch function
type Options struct {
Method string
Body string
Headers map[string]any
HandleCookies *bool
}
// Response contains the response object for the JavaScript fetch function
type Response struct {
Status string
StatusCode int
Headers http.Header
body []byte
}
func (r Response) JSON() (v any, err error) {
err = json.Unmarshal(r.body, &v)
return v, err
}
func (r Response) String() string {
return string(r.body)
}
// FetchFunc is the fetch function signature
type FetchFunc = func(string, *Options) (*Response, error)
func fetch(pluginName, pluginVersion string) FetchFunc {
// cookiejar.New always returns a nil error
jar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
return func(url string, opts *Options) (*Response, error) {
if opts == nil {
t := true
opts = &Options{HandleCookies: &t}
}
if opts.HandleCookies == nil {
t := true
opts.HandleCookies = &t
}
if opts.Method == "" {
opts.Method = http.MethodGet
}
req, err := http.NewRequest(opts.Method, url, strings.NewReader(opts.Body))
if err != nil {
return nil, err
}
for key, value := range opts.Headers {
req.Header.Add(key, value.(string))
}
if req.Header.Get("User-Agent") == "" {
req.Header.Set("User-Agent", getUserAgent(pluginName, pluginVersion))
}
client := &http.Client{}
if *opts.HandleCookies {
client.Jar = jar
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return &Response{
Status: resp.Status,
StatusCode: resp.StatusCode,
Headers: resp.Header,
body: responseBody,
}, nil
}
}
// getUserAgent uses the built in vcs information to generate a user agent string
func getUserAgent(pluginName, pluginVersion string) string {
commit := "unknown"
modified := "unmodified"
if info, ok := debug.ReadBuildInfo(); ok {
for _, setting := range info.Settings {
switch setting.Key {
case "vcs.revision":
commit = setting.Value[:8]
case "vcs.modified":
if setting.Value == "true" {
modified = "modified"
}
}
}
}
return fmt.Sprintf("owobot/%s (%s; %s/%s)", commit, modified, pluginName, pluginVersion)
}