stillbox/pkg/sinks/relay.go

119 lines
2.2 KiB
Go
Raw Normal View History

2024-11-18 14:27:12 -05:00
package sinks
import (
"bytes"
"context"
"fmt"
"mime/multipart"
"net/http"
"net/url"
"dynatron.me/x/stillbox/internal/forms"
2024-11-18 18:31:17 -05:00
"dynatron.me/x/stillbox/internal/version"
2024-11-18 14:27:12 -05:00
"dynatron.me/x/stillbox/pkg/calls"
"dynatron.me/x/stillbox/pkg/config"
)
2024-11-18 18:31:17 -05:00
type RelayManager struct {
xp *http.Transport
client *http.Client
relays []*Relay
}
type Relay struct {
2024-11-18 14:27:12 -05:00
config.Relay
2024-11-18 18:31:17 -05:00
mgr *RelayManager
Name string
2024-11-18 14:27:12 -05:00
url *url.URL
}
2024-11-18 18:31:17 -05:00
func NewRelayManager(s Sinks, cfgs []config.Relay) (*RelayManager, error) {
xp := http.DefaultTransport.(*http.Transport).Clone()
xp.MaxIdleConnsPerHost = 10
client := &http.Client{
Transport: xp,
}
rm := &RelayManager{
xp: xp,
client: client,
relays: make([]*Relay, 0, len(cfgs)),
}
2024-11-18 14:27:12 -05:00
for i, cfg := range cfgs {
2024-11-19 09:10:55 -05:00
rs, err := rm.newRelay(i, cfg)
2024-11-18 14:27:12 -05:00
if err != nil {
2024-11-18 18:31:17 -05:00
return nil, err
2024-11-18 14:27:12 -05:00
}
2024-11-18 18:31:17 -05:00
rm.relays = append(rm.relays, rs)
2024-11-19 09:10:55 -05:00
s.Register(rs.Name, rs, cfg.Required)
2024-11-18 14:27:12 -05:00
}
2024-11-18 18:31:17 -05:00
return rm, nil
2024-11-18 14:27:12 -05:00
}
2024-11-19 09:10:55 -05:00
func (rs *RelayManager) newRelay(idx int, cfg config.Relay) (*Relay, error) {
2024-11-18 14:27:12 -05:00
u, err := url.Parse(cfg.URL)
if err != nil {
return nil, err
}
if u.Path != "" && u.Path != "/" {
return nil, fmt.Errorf("relay path in %s must be instance root", cfg.URL)
}
u = u.JoinPath("/api/call-upload")
2024-11-18 18:31:17 -05:00
return &Relay{
2024-11-19 09:10:55 -05:00
Name: fmt.Sprintf("relay%d:%s", idx, u.Host),
2024-11-18 14:27:12 -05:00
Relay: cfg,
url: u,
2024-11-18 18:31:17 -05:00
mgr: rs,
2024-11-18 14:27:12 -05:00
}, nil
}
2024-11-18 18:31:17 -05:00
func (s *Relay) Call(ctx context.Context, call *calls.Call) error {
2024-11-18 14:27:12 -05:00
var buf bytes.Buffer
body := multipart.NewWriter(&buf)
err := forms.Marshal(call, body)
if err != nil {
return fmt.Errorf("relay form parse: %w", err)
}
2024-11-18 18:31:17 -05:00
err = body.WriteField("key", s.APIKey)
if err != nil {
return fmt.Errorf("relay set API key: %w", err)
}
2024-11-18 14:27:12 -05:00
body.Close()
r, err := http.NewRequestWithContext(ctx, http.MethodPost, s.url.String(), &buf)
if err != nil {
return fmt.Errorf("relay newrequest: %w", err)
}
r.Header.Set("Content-Type", body.FormDataContentType())
2024-11-18 18:31:17 -05:00
r.Header.Set("User-Agent", version.HttpString("call-relay"))
2024-11-18 14:27:12 -05:00
2024-11-18 18:31:17 -05:00
resp, err := s.mgr.client.Do(r)
2024-11-18 14:27:12 -05:00
if err != nil {
2024-11-18 18:31:17 -05:00
return fmt.Errorf("relay %s: %w", s.Name, err)
2024-11-18 14:27:12 -05:00
}
if resp.StatusCode != http.StatusOK {
2024-11-18 18:31:17 -05:00
return fmt.Errorf("relay %s: received HTTP %d", s.Name, resp.StatusCode)
2024-11-18 14:27:12 -05:00
}
return nil
}
2024-11-18 18:31:17 -05:00
func (s *Relay) SinkType() string {
2024-11-18 14:27:12 -05:00
return "relay"
}