Skip to content

Commit

Permalink
Merge pull request #5 from groupme/magnificrogue/go-twitter-bot
Browse files Browse the repository at this point in the history
Add go based twitter bot example
  • Loading branch information
MagnificRogue committed Aug 3, 2021
2 parents a4349eb + 3fd3c66 commit 8624ffd
Show file tree
Hide file tree
Showing 10 changed files with 685 additions and 0 deletions.
1 change: 1 addition & 0 deletions go/twitterbot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin
15 changes: 15 additions & 0 deletions go/twitterbot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM golang:1.16-alpine as base
WORKDIR /app
RUN apk add --no-cache make

FROM base as builder
COPY . ./
RUN go mod download
RUN make build
RUN chmod +x /app/bin/main

FROM base as runtime

COPY --from=builder /app/bin/main .

CMD /app/main -tweet-query=${TWEET_QUERY} -groupme-bot-id=${GROUPME_BOT_ID} -twitter-app-key=${TWITTER_APP_KEY} -twitter-app-secret=${TWITTER_APP_SECRET}
8 changes: 8 additions & 0 deletions go/twitterbot/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build:
go build -o bin/main cmd/main.go

run:
go run cmd/main.go -tweet-query=${TWEET_QUERY} -groupme-bot-id=${GROUPME_BOT_ID} -twitter-app-key=${TWITTER_APP_KEY} -twitter-app-secret=${TWITTER_APP_SECRET}

container:
docker build -t groupme/twitterbot .
19 changes: 19 additions & 0 deletions go/twitterbot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# What is it

It is a simple bot that attempts to read tweets from twitter, specified by the tweet-query passed, and write it to a given group by using a bot user.


# How to use it
To use this bot in either a docker container or locally, you'll need the following:

1) A query for tweets set in an environment variable TWEET_QUERY
2) A groupMe bot ID set in GROUPME_BOT_ID
3) A twitter app key and secret, set in TWITTER_APP_KEY and TWITTER_APP_SECRET respectively

## Locally
1. Have go/make installed.
2. $ make run # Run in your terminal

## In a container
1. Ensure the environment variables above are set
2. Run /app/main -tweet-query=${TWEET_QUERY} -groupme-bot-id=${GROUPME_BOT_ID} -twitter-app-key=${TWITTER_APP_KEY} -twitter-app-secret=${TWITTER_APP_SECRET}
63 changes: 63 additions & 0 deletions go/twitterbot/bot_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package twitterbot

import (
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"

"github.com/Azure/go-autorest/autorest"
)

// BotClient is a simple wrapper for writing messages on GroupMe
type BotClient struct {
botID string
}

// NewBotClient returns a configured BotClient suitable for use
func NewBotClient(botID string) (*BotClient, error) {
if botID == "" {
return nil, errors.New("Can't instantiate a bot client with no botID")
} else {
return &BotClient{
botID: botID,
}, nil
}
}

// botMessage is a simplified message body for some text sent on behalf of a bot.
type botMessage struct {
BotID string `json:"bot_id"`
Text string `json:"text"`
}

// SendMessage posts a message on behalf of a bot. If the message is empty, an error will be returned
func (bc *BotClient) SendMessage(message string) error {
req, err := autorest.Prepare(&http.Request{},
autorest.WithBaseURL("https://api.groupme.com/v3/bots/post"),
autorest.WithMethod("POST"),
autorest.WithHeader("Content-Type", "application/json"),
autorest.WithJSON(botMessage{
BotID: bc.botID,
Text: message,
}),
)
if err != nil {
return fmt.Errorf("Unable to construct request to send message on behalf of bot: %w", err)
}

resp, err := autorest.Send(req)
if err != nil {
return fmt.Errorf("Error sending request to create a message: %w", err)
}

if resp.StatusCode != http.StatusAccepted {
bytes, _ := ioutil.ReadAll(resp.Body)
log.Fatal("Bad response code from GroupMe:", string(bytes))
err := fmt.Errorf("Unexpected HTTP status code when creating message: %d", resp.StatusCode)
return err
}

return nil
}
42 changes: 42 additions & 0 deletions go/twitterbot/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"context"
"flag"
"os"
"os/signal"
"strings"
"time"

twitterbot "github.com/groupme/BotExamples/go/twitter-bot"
)

var (
flagTweetQuery = flag.String("tweet-query", "groupme,cats,burrito", "What tags to filter on. Passed as a single comma seperated string")
flagGroupMeBotID = flag.String("groupme-bot-id", "", "Identifier for your bot on GroupMe")
flagTwitterAppKey = flag.String("twitter-app-key", "", "Developer Key associated with your twitter project")
flagTwitterAppSecret = flag.String("twitter-app-secret", "", "Developer secret associated with your twitter project")
)

func main() {
flag.Parse()

// setup signal aware context.
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
defer cancel()

twitterClient, _ := twitterbot.NewTwitterClient(*flagTwitterAppKey, *flagTwitterAppSecret)
botClient, _ := twitterbot.NewBotClient(*flagGroupMeBotID)

poster, err := twitterbot.NewTwitterPoster(twitterClient, botClient, strings.Split(*flagTweetQuery, ",")...)
if err != nil {
panic(err)
}

// Default rate limit is 450 requests in an hour, so fetch new tweets every 10 seconds
go poster.StartListening(time.Second * 10)

<-ctx.Done()

poster.StopListening()
}
10 changes: 10 additions & 0 deletions go/twitterbot/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/groupme/BotExamples/go/twitter-bot

go 1.16

require (
github.com/Azure/go-autorest/autorest v0.11.19 // indirect
github.com/dghubble/go-twitter v0.0.0-20210609183100-2fdbf421508e // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 // indirect
)
Loading

0 comments on commit 8624ffd

Please sign in to comment.