This repository has been archived by the owner on May 23, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
twitter.go
114 lines (102 loc) · 2.9 KB
/
twitter.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
package main
import (
"context"
"net/http"
"net/url"
"time"
"golang.org/x/net/http2"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
"github.com/dghubble/go-twitter/twitter"
"github.com/dghubble/oauth1"
"github.com/dghubble/sling"
)
type Twitter struct {
client *sling.Sling
}
func NewAppModeTwitter(ck, cs string) *Twitter {
config := &clientcredentials.Config{
ClientID: ck,
ClientSecret: cs,
TokenURL: "https://api.twitter.com/oauth2/token",
}
ctx := context.WithValue(oauth2.NoContext, oauth2.HTTPClient, http.Client{
Transport: &http2.Transport{},
})
return NewTwitter(config.Client(ctx))
}
func NewUserModeTwitter(ck, cs, at, as string) *Twitter {
config := oauth1.NewConfig(ck, cs)
token := oauth1.NewToken(at, as)
ctx := context.WithValue(oauth1.NoContext, oauth1.HTTPClient, http.Client{
Transport: &http2.Transport{},
})
return NewTwitter(config.Client(ctx, token))
}
func NewTwitter(c *http.Client) *Twitter {
return &Twitter{sling.New().Client(c).Base("https://api.twitter.com/1.1/")}
}
func (t *Twitter) CheckRateLimit() (rl *twitter.RateLimit, err error) {
var apiError *twitter.APIError
for {
rl, apiError, err = t.checkRateLimit()
if err == nil && (apiError == nil || apiError.Empty()) {
return
}
if err == nil {
err = apiError
return
}
if urlError, ok := err.(*url.Error); ok && urlError.Err.Error() == "net/http: TLS handshake timeout" {
time.Sleep(500 * time.Millisecond)
continue
}
return
}
}
func (t *Twitter) checkRateLimit() (rl *twitter.RateLimit, apiError *twitter.APIError, err error) {
rl = new(twitter.RateLimit)
apiError = new(twitter.APIError)
_, err = t.client.New().Get("application/rate_limit_status.json").QueryStruct(&twitter.RateLimitParams{Resources: []string{"users"}}).Receive(rl, apiError)
return
}
func (t *Twitter) UserLookup(ctx context.Context, ids []int64) (us []twitter.User, err error) {
var apiError *twitter.APIError
for {
select {
case <-ctx.Done():
err = ctx.Err()
return
default:
us, apiError, err = t.userLookup(ctx, ids)
if err != nil {
if urlError, ok := err.(*url.Error); ok && urlError.Err.Error() == "net/http: TLS handshake timeout" {
time.Sleep(500 * time.Millisecond)
continue
}
return
}
if apiError == nil || apiError.Empty() || apiError.Errors[0].Code == 17 {
return
}
if apiError.Errors[0].Code == 88 {
// Rate limit exceeded
err = apiError
return
}
time.Sleep(1000 * time.Millisecond)
}
}
}
func (t *Twitter) userLookup(ctx context.Context, ids []int64) (us []twitter.User, apiError *twitter.APIError, err error) {
req, err := t.client.New().Get("users/lookup.json").QueryStruct(&twitter.UserLookupParams{UserID: ids}).Request()
if err != nil {
return
}
req = req.WithContext(ctx)
users := new([]twitter.User)
apiError = new(twitter.APIError)
_, err = t.client.Do(req, users, apiError)
us = *users
return
}