-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
137 lines (113 loc) · 3.04 KB
/
main.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
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"regexp"
"strings"
"time"
"github.com/dghubble/oauth1"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
)
// Tweet is a collection of important info in each Tweet
type Tweet struct {
Date string `json:"created_at"`
Text string `json:"text"`
ID string `json:"id_str"`
}
var config *oauth1.Config
var token *oauth1.Token
// API page limit
const pages = 18
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
// Load API credentials
config = oauth1.NewConfig(os.Getenv("APIKEY"), os.Getenv("APISECRET"))
token = oauth1.NewToken(os.Getenv("TOKEN"), os.Getenv("TOKENSECRET"))
s := &http.Server{
Addr: os.Getenv("PORT"),
Handler: makeMuxRouter(),
ReadTimeout: 20 * time.Second,
WriteTimeout: 120 * time.Second,
MaxHeaderBytes: 1 << 20,
}
if err := s.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
// makeMuxRouter defines and creates routes
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/{id}", handleGetTweets).Methods("GET")
return muxRouter
}
func respondWithError(err error, w http.ResponseWriter) {
log.Println(err)
w.WriteHeader(500)
w.Write([]byte(err.Error()))
}
func handleGetTweets(w http.ResponseWriter, r *http.Request) {
var maxIDQuery string
var tweets []Tweet
vars := mux.Vars(r)
userID := vars["id"]
// httpClient will automatically authorize http.Requests
httpClient := config.Client(oauth1.NoContext, token)
Outer:
for i := 0; i < pages; i++ {
// Twitter API request
// userID is the Twitter handle
// maxIDQuery is the last result on each page, so the API knows what the next page is
path := fmt.Sprintf("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=%v&include_rts=false&count=200%v", userID, maxIDQuery)
if strings.Contains(path, "favicon.ico") { // API returns this so skip it, not needed
break
}
resp, err := httpClient.Get(path)
if err != nil {
respondWithError(err, w)
break
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
respondWithError(err, w)
break
}
var gotTweets []Tweet
err = json.Unmarshal(body, &gotTweets)
if err != nil {
respondWithError(err, w)
break
}
// range through Tweets to clear out unneeded info
for i, t := range gotTweets {
if i == len(gotTweets)-1 {
// this is the logic to tell Twitter API where the pages are
if maxIDQuery == fmt.Sprintf("&max_id=%v", t.ID) {
break Outer
}
maxIDQuery = fmt.Sprintf("&max_id=%v", t.ID)
}
// remove @ mentions and links from returned Tweets
regAt := regexp.MustCompile(`@(\S+)`)
t.Text = regAt.ReplaceAllString(t.Text, "")
regHTTP := regexp.MustCompile(`http(\S+)`)
t.Text = regHTTP.ReplaceAllString(t.Text, "")
tweets = append(tweets, t)
}
}
var result []string
for _, t := range tweets {
result = append(result, t.Text)
}
stringResult := strings.Join(result, "\n")
w.WriteHeader(200)
w.Write([]byte(stringResult))
}