Skip to content

Commit eb60f11

Browse files
authored
[TASK] Uptimizing Code
* Fix potential deadlock. A deadlock can occur when we have multiple hashes we are searching for and one of the searches fails * Better error handling with more context information * Use base 10 when parsing lastTweetIdValue * Close settings and lastTweetId files * Do not crash when lastTweetId file is not present (happens on first run)
2 parents 6c3a032 + 9209e17 commit eb60f11

File tree

1 file changed

+69
-24
lines changed

1 file changed

+69
-24
lines changed

tweetbot.go

+69-24
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"io/ioutil"
7+
"log"
78
"os"
89
"strconv"
910

@@ -25,9 +26,10 @@ type TwitterConf struct {
2526
Hash []string `yaml:"hash"`
2627
}
2728

28-
func check(e error) {
29-
if e != nil {
30-
panic(e)
29+
func closeFile(file *os.File) {
30+
err := file.Close()
31+
if err != nil {
32+
log.Printf("could not close file %s: %s", file.Name(), err)
3133
}
3234
}
3335

@@ -36,56 +38,93 @@ func check(e error) {
3638
func WriteToFile(filename string, data string) error {
3739
file, err := os.Create(filename)
3840
if err != nil {
39-
return err
41+
return fmt.Errorf("could not open file: %s", err)
4042
}
41-
defer file.Close()
43+
defer closeFile(file)
4244

4345
_, err = io.WriteString(file, data)
44-
check(err)
45-
return file.Sync()
46+
if err != nil {
47+
return fmt.Errorf("could not write string: %s", err)
48+
}
49+
return nil
50+
}
51+
52+
func getLastTweetID() (int64, error) {
53+
lastTweetIdFile, err := os.Open("lastTweetId")
54+
if err != nil {
55+
return 0, fmt.Errorf("could not open lastTweetId: %s", err)
56+
}
57+
defer closeFile(lastTweetIdFile)
58+
59+
lastTweetId, err := ioutil.ReadAll(lastTweetIdFile)
60+
if err != nil {
61+
return 0, fmt.Errorf("could not read lastTweetId content: %s", err)
62+
}
63+
64+
lastTweetIdValue, err := strconv.ParseInt(string(lastTweetId), 10, 64)
65+
if err != nil {
66+
return 0, fmt.Errorf("could not parse lastTweetId content as int64: %s", err)
67+
}
68+
69+
return lastTweetIdValue, nil
4670
}
4771

4872
func main() {
4973

5074
file, err := os.Open("settings.yaml")
5175
if err != nil {
52-
panic(err)
76+
log.Fatalf("could not open file: %s", err)
5377
}
78+
defer closeFile(file)
5479

5580
filecontent, err := ioutil.ReadAll(file)
56-
check(err)
81+
if err != nil {
82+
log.Fatalf("could not read settings.yaml content: %s", err)
83+
}
5784

5885
var conf Configuration
5986
err = yaml.Unmarshal(filecontent, &conf)
60-
check(err)
61-
62-
fileReference, err := os.Open("lastTweetId")
63-
check(err)
87+
if err != nil {
88+
log.Fatalf("could not unmarshal settings.yaml content: %s", err)
89+
}
6490

65-
lastTweetId, err := ioutil.ReadAll(fileReference)
66-
check(err)
91+
var lastTweetID int64
92+
if id, err := getLastTweetID(); err != nil {
93+
log.Printf("could not get last tweet id: %s", err)
94+
} else {
95+
lastTweetID = id
96+
}
6797

6898
config := oauth1.NewConfig(conf.Twitter.ConsumerKey, conf.Twitter.ConsumerSecret)
6999
token := oauth1.NewToken(conf.Twitter.OauthAccessToken, conf.Twitter.OauthAccessTokenSecret)
70100
httpClient := config.Client(oauth1.NoContext, token)
71101

72102
// Twitter client
73103
client := twitter.NewClient(httpClient)
74-
lastTweetIdValue, err := strconv.ParseInt(string(lastTweetId), 0, 64)
75-
check(err)
76104

77105
out := make(chan *twitter.Search)
78106

79107
for _, h := range conf.Twitter.Hash {
80108
go func(hash string) {
81109
// Search Tweets
82-
search, _, err := client.Search.Tweets(&twitter.SearchTweetParams{
110+
111+
params := &twitter.SearchTweetParams{
83112
Query: hash,
84113
Count: 5,
85114
ResultType: "recent",
86-
SinceID: lastTweetIdValue,
87-
})
88-
check(err)
115+
}
116+
117+
if lastTweetID != 0 {
118+
params.SinceID = lastTweetID
119+
}
120+
121+
search, _, err := client.Search.Tweets(params)
122+
if err != nil {
123+
log.Printf("could not search tweets for hash '%s': %s", hash, err)
124+
// a search did not execute properly, send an empty object so we don't deadlock
125+
out <- &twitter.Search{}
126+
return
127+
}
89128
out <- search
90129
}(h)
91130
}
@@ -103,15 +142,21 @@ func main() {
103142
fmt.Println(tweet.ID, tweet.Text)
104143

105144
var statusRetweetParam *twitter.StatusRetweetParams
106-
client.Statuses.Retweet(tweet.ID, statusRetweetParam)
107-
145+
_, _, err = client.Statuses.Retweet(tweet.ID, statusRetweetParam)
146+
if err != nil {
147+
log.Printf("could not retweet for hash '%s': %s", conf.Twitter.Hash[i], err)
148+
continue
149+
}
108150
}
109151
}
110152
close(out)
111153

112154
// Write latestTweetId to know where to start on next execution.
113155
if 0 < len(tweetIds) {
114156
latestTweetId := strconv.Itoa(ix.MaxSlice(tweetIds))
115-
WriteToFile("lastTweetId", latestTweetId)
157+
err := WriteToFile("lastTweetId", latestTweetId)
158+
if err != nil {
159+
log.Fatalf("could not write lastTweetId to file: %s", err)
160+
}
116161
}
117162
}

0 commit comments

Comments
 (0)