15 var defaultClient Client = Client{Client: http.DefaultClient}
17 func Lookup(id string) (*Activity, error) {
18 return defaultClient.Lookup(id)
21 func LookupActor(id string) (*Actor, error) {
22 return defaultClient.LookupActor(id)
31 func (c *Client) Lookup(id string) (*Activity, error) {
32 if !strings.HasPrefix(id, "http") {
33 return nil, fmt.Errorf("id is not a HTTP URL")
36 c.Client = http.DefaultClient
39 req, err := http.NewRequest(http.MethodGet, id, nil)
43 req.Header.Set("Accept", ContentType)
44 if c.Key != nil && c.Actor != nil {
45 if err := Sign(req, c.Key, c.Actor.PublicKey.ID); err != nil {
46 return nil, fmt.Errorf("sign http request: %w", err)
49 resp, err := c.Do(req)
53 defer resp.Body.Close()
54 if resp.StatusCode == http.StatusNotFound {
55 return nil, ErrNotExist
56 } else if resp.StatusCode >= 400 {
57 return nil, fmt.Errorf("non-ok response status %s", resp.Status)
59 return Decode(resp.Body)
62 func (c *Client) LookupActor(id string) (*Actor, error) {
63 activity, err := c.Lookup(id)
67 return activityToActor(activity), nil
70 func activityToActor(activity *Activity) *Actor {
72 AtContext: activity.AtContext,
76 Username: activity.Username,
77 Inbox: activity.Inbox,
78 Outbox: activity.Outbox,
79 Published: activity.Published,
80 Summary: activity.Summary,
84 func (c *Client) Send(inbox string, activity *Activity) (*Activity, error) {
85 b, err := json.Marshal(activity)
87 return nil, fmt.Errorf("encode outgoing activity: %w", err)
89 req, err := http.NewRequest(http.MethodPost, inbox, bytes.NewReader(b))
93 req.Header.Set("Content-Type", ContentType)
94 if err := Sign(req, c.Key, c.Actor.PublicKey.ID); err != nil {
95 return nil, fmt.Errorf("sign outgoing request: %w", err)
97 resp, err := c.Do(req)
101 switch resp.StatusCode {
103 if resp.ContentLength == 0 {
106 defer resp.Body.Close()
107 activity, err := Decode(resp.Body)
108 if errors.Is(err, io.EOF) {
112 case http.StatusAccepted, http.StatusNoContent:
114 case http.StatusNotFound:
115 return nil, fmt.Errorf("no such inbox %s", inbox)
117 io.Copy(os.Stderr, resp.Body)
119 return nil, fmt.Errorf("non-ok response status %s", resp.Status)