gmessages/libgm/http.go

76 lines
1.9 KiB
Go

package libgm
import (
"bytes"
"fmt"
"io"
"mime"
"net/http"
"google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-gmessages/libgm/events"
"go.mau.fi/mautrix-gmessages/libgm/pblite"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
const ContentTypeProtobuf = "application/x-protobuf"
const ContentTypePBLite = "application/json+protobuf"
func (c *Client) makeProtobufHTTPRequest(url string, data proto.Message, contentType string) (*http.Response, error) {
var body []byte
var err error
switch contentType {
case ContentTypeProtobuf:
body, err = proto.Marshal(data)
case ContentTypePBLite:
body, err = pblite.Marshal(data)
default:
return nil, fmt.Errorf("unknown request content type %s", contentType)
}
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body))
if err != nil {
return nil, err
}
util.BuildRelayHeaders(req, contentType, "*/*")
res, reqErr := c.http.Do(req)
if reqErr != nil {
return res, reqErr
}
return res, nil
}
func typedHTTPResponse[T proto.Message](resp *http.Response, err error) (parsed T, retErr error) {
if err != nil {
retErr = err
return
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
retErr = events.HTTPError{Resp: resp}
return
}
body, err := io.ReadAll(resp.Body)
if err != nil {
retErr = fmt.Errorf("failed to read response body: %w", err)
return
}
contentType, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
retErr = fmt.Errorf("failed to parse content-type: %w", err)
return
}
parsed = parsed.ProtoReflect().New().Interface().(T)
switch contentType {
case ContentTypeProtobuf:
retErr = proto.Unmarshal(body, parsed)
case ContentTypePBLite:
retErr = pblite.Unmarshal(body, parsed)
default:
retErr = fmt.Errorf("unknown content type %s in response", contentType)
}
return
}