Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183package worker
import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time"
"github.com/bluesky-social/indigo/atproto/atcrypto" "github.com/bluesky-social/indigo/atproto/auth" "github.com/bluesky-social/indigo/atproto/syntax")
type DeployContext struct { RepoDid string `json:"-"` OwnerDid string `json:"ownerDid"` Domain string `json:"domain"` Name string `json:"name"` Rkey string `json:"rkey"` Knot string `json:"knot"` Branch string `json:"branch"` Dir string `json:"dir"` IsIndex bool `json:"isIndex"`}
type Client struct { BaseURL string Issuer string Audience string Priv *atcrypto.PrivateKeyP256 HTTP *http.Client}
func New(baseURL, issuer, audience string, priv *atcrypto.PrivateKeyP256) *Client { return &Client{ BaseURL: baseURL, Issuer: issuer, Audience: audience, Priv: priv, HTTP: &http.Client{Timeout: 30 * time.Second}, }}
func (c *Client) mint(lxm string) (string, error) { nsid, err := syntax.ParseNSID(lxm) if err != nil { return "", fmt.Errorf("invalid lexicon method %q: %w", lxm, err) } return auth.SignServiceAuth(syntax.DID(c.Issuer), c.Audience, 5*time.Minute, &nsid, c.Priv)}
type Error struct { StatusCode int NSID string Name string Message string Body string}
func (e *Error) Error() string { if e.Name != "" { return fmt.Sprintf("worker %s: %s: %s", e.NSID, e.Name, e.Message) } return fmt.Sprintf("worker %s: HTTP %d: %s", e.NSID, e.StatusCode, strings.TrimSpace(e.Body))}
func (c *Client) do(ctx context.Context, method, path string, body any, out any) error { var buf bytes.Buffer if body != nil { if err := json.NewEncoder(&buf).Encode(body); err != nil { return err } }
full, err := url.Parse(strings.TrimRight(c.BaseURL, "/") + path) if err != nil { return err } nsid := full.Path[strings.LastIndex(full.Path, "/")+1:] token, err := c.mint(nsid) if err != nil { return err }
req, err := http.NewRequestWithContext(ctx, method, full.String(), &buf) if err != nil { return err } req.Header.Set("Authorization", "Bearer "+token) if body != nil { req.Header.Set("Content-Type", "application/json") }
resp, err := c.HTTP.Do(req) if err != nil { return err } defer resp.Body.Close() raw, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20)) if err != nil { return err }
if resp.StatusCode != http.StatusOK { xrpcErr := struct { Error string `json:"error"` Message string `json:"message"` }{} _ = json.Unmarshal(raw, &xrpcErr) return &Error{ StatusCode: resp.StatusCode, NSID: nsid, Name: xrpcErr.Error, Message: xrpcErr.Message, Body: string(raw), } }
if out != nil { decoder := json.NewDecoder(bytes.NewReader(raw)) decoder.DisallowUnknownFields() if err := decoder.Decode(out); err != nil { return fmt.Errorf("decoding worker response for %s: %w", nsid, err) } } return nil}
func (c *Client) GetDeployContext(ctx context.Context, repoDid string) (*DeployContext, error) { path := "/xrpc/org.tangled.temp.repo.getDeployContext?repoDid=" + url.QueryEscape(repoDid) var raw struct { OwnerDid string `json:"ownerDid"` Domain string `json:"domain"` Name string `json:"name"` Rkey string `json:"rkey"` Knot string `json:"knot"` Branch string `json:"branch"` Dir string `json:"dir"` IsIndex bool `json:"isIndex"` } if err := c.do(ctx, http.MethodGet, path, nil, &raw); err != nil { return nil, err } empty := raw.Rkey == "" && raw.OwnerDid == "" && raw.Domain == "" && raw.Name == "" && raw.Knot == "" && raw.Branch == "" && raw.Dir == "" if empty { return nil, nil } if raw.Rkey == "" || raw.OwnerDid == "" || raw.Domain == "" || raw.Name == "" || raw.Knot == "" || raw.Branch == "" || raw.Dir == "" { return nil, fmt.Errorf("incomplete deploy context from worker: %+v", raw) } return &DeployContext{ RepoDid: repoDid, OwnerDid: raw.OwnerDid, Domain: raw.Domain, Name: raw.Name, Rkey: raw.Rkey, Knot: raw.Knot, Branch: raw.Branch, Dir: raw.Dir, IsIndex: raw.IsIndex, }, nil}
func (c *Client) RecordDeploy(ctx context.Context, d *DeployContext, commitSha, status, trigger, errMsg string) error { body := map[string]string{ "repoDid": d.RepoDid, "branch": d.Branch, "dir": d.Dir, "commitSha": commitSha, "status": status, "trigger": trigger, "error": errMsg, } return c.do(ctx, http.MethodPost, "/xrpc/org.tangled.temp.repo.recordDeploy", body, nil)}