This repository has been archived by the owner on Aug 13, 2023. It is now read-only.
/
reply.go
137 lines (121 loc) · 4.09 KB
/
reply.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (C) 2020 Michael J. Fromberger. All Rights Reserved.
package twitter
import (
"encoding/json"
"net/http"
"strconv"
"time"
"github.com/creachadair/twitter/jape"
"github.com/creachadair/twitter/types"
)
// A Reply is a wrapper for the reply object returned by successful calls to
// the Twitter API v2.
type Reply struct {
// The root reply object from a successful query.
Data json.RawMessage `json:"data,omitempty"`
// For expansions that generate attachments, a map of attachment type to
// JSON arrays of attachment objects.
Includes map[string]json.RawMessage `json:"includes,omitempty"`
// Server metadata reported with search replies.
Meta json.RawMessage `json:"meta,omitempty"`
// Error details reported with lookup or search replies.
Errors []*types.ErrorDetail `json:"errors,omitempty"`
// Rate limit metadata reported by the server. If the server did not return
// these data, this field will be nil.
RateLimit *RateLimit `json:"-"`
}
// IncludedMedia decodes any media objects in the includes of r.
// It returns nil without error if there are no media inclusions.
func (r *Reply) IncludedMedia() (types.Medias, error) {
media, ok := r.Includes["media"]
if !ok || len(media) == 0 {
return nil, nil
}
var out types.Medias
if err := json.Unmarshal(media, &out); err != nil {
return nil, &jape.Error{Data: media, Message: "decoding media", Err: err}
}
return out, nil
}
// IncludedTweets decodes any tweet objects in the includes of r.
// It returns nil without error if there are no tweet inclusions.
func (r *Reply) IncludedTweets() (types.Tweets, error) {
tweets, ok := r.Includes["tweets"]
if !ok || len(tweets) == 0 {
return nil, nil
}
var out types.Tweets
if err := json.Unmarshal(tweets, &out); err != nil {
return nil, &jape.Error{Data: tweets, Message: "decoding tweets", Err: err}
}
return out, nil
}
// IncludedUsers decodes any user objects in the includes of r.
// It returns nil without error if there are no user inclusions.
func (r *Reply) IncludedUsers() (types.Users, error) {
users, ok := r.Includes["users"]
if !ok || len(users) == 0 {
return nil, nil
}
var out types.Users
if err := json.Unmarshal(users, &out); err != nil {
return nil, &jape.Error{Data: users, Message: "decoding users", Err: err}
}
return out, nil
}
// IncludedPolls decodes any poll objects in the includes of r.
// It returns nil without error if there are no poll inclusions.
func (r *Reply) IncludedPolls() (types.Polls, error) {
polls, ok := r.Includes["polls"]
if !ok || len(polls) == 0 {
return nil, nil
}
var out types.Polls
if err := json.Unmarshal(polls, &out); err != nil {
return nil, &jape.Error{Data: polls, Message: "decoding polls", Err: err}
}
return out, nil
}
// IncludedPlaces decodes any place objects in the includes of r.
// It returns nil without error if there are no place inclusions.
func (r *Reply) IncludedPlaces() (types.Places, error) {
places, ok := r.Includes["places"]
if !ok || len(places) == 0 {
return nil, nil
}
var out types.Places
if err := json.Unmarshal(places, &out); err != nil {
return nil, &jape.Error{Data: places, Message: "decoding places", Err: err}
}
return out, nil
}
// RateLimit records metadata about API rate limits reported by the server.
type RateLimit struct {
Ceiling int // rate limit ceiling for this endpoint
Remaining int // requests remaining in the current window
Reset time.Time // time of next window reset
}
func decodeRateLimits(h http.Header) *RateLimit {
ceiling := h.Get("x-rate-limit-limit")
remaining := h.Get("x-rate-limit-remaining")
reset := h.Get("x-rate-limit-reset")
if ceiling == "" && remaining == "" && reset == "" {
return nil
}
out := new(RateLimit)
if v, err := strconv.Atoi(ceiling); err == nil {
out.Ceiling = v
}
if v, err := strconv.Atoi(remaining); err == nil {
out.Remaining = v
}
if v, err := strconv.ParseInt(reset, 10, 64); err == nil {
out.Reset = time.Unix(v, 0)
}
return out
}
// Pagination records metadata about pagination of results.
type Pagination struct {
ResultCount int `json:"result_count"`
NextToken string `json:"next_token"`
}