package notify
import (
"context"
"encoding/json"
"fmt"
"net/url"
)
// PushResult is how one triggered push went, as notify recorded it on
// the push message: Status is notify's word (sent, error, skipped) and
// Error its text, which names each device that refused and why. Found
// is false until the push step has run.
type PushResult struct {
Found bool
Status string
Error string
}
// PushOutcome reads the push message notify wrote for one trigger,
// found by its transaction id: the notification first, then its
// messages. notify's domain types carry no json tags, so the keys are
// the Go field names (ID, Channel, Status, ErrorText).
func (c *Client) PushOutcome(ctx context.Context, subscriber, txn string) (PushResult, error) {
if c == nil || c.base == "" || txn == "" {
return PushResult{}, nil
}
q := url.Values{"transactionId": {txn}, "limit": {"1"}}
if subscriber != "" {
q.Set("subscriberId", subscriber)
}
status, body, err := c.do(ctx, "GET", "/v1/notifications?"+q.Encode(), nil)
if err != nil {
return PushResult{}, fmt.Errorf("notify: push outcome: %w", err)
}
if status >= 300 {
return PushResult{}, fmt.Errorf("notify: push outcome: status %d", status)
}
var list struct {
Items []struct {
ID string `json:"ID"`
} `json:"items"`
}
if err := json.Unmarshal(body, &list); err != nil {
return PushResult{}, fmt.Errorf("notify: push outcome: %w", err)
}
if len(list.Items) == 0 || list.Items[0].ID == "" {
return PushResult{}, nil
}
status, body, err = c.do(ctx, "GET", "/v1/notifications/"+url.PathEscape(list.Items[0].ID)+"/messages", nil)
if err != nil {
return PushResult{}, fmt.Errorf("notify: push outcome: %w", err)
}
if status >= 300 {
return PushResult{}, fmt.Errorf("notify: push outcome: status %d", status)
}
var msgs []struct {
Channel string `json:"Channel"`
Status string `json:"Status"`
ErrorText string `json:"ErrorText"`
}
if err := json.Unmarshal(body, &msgs); err != nil {
return PushResult{}, fmt.Errorf("notify: push outcome: %w", err)
}
for _, m := range msgs {
if m.Channel == "push" {
return PushResult{Found: true, Status: m.Status, Error: m.ErrorText}, nil
}
}
return PushResult{}, nil
}