Adding basic Bot functionality
This commit is contained in:
parent
9101453bb7
commit
a2e793a6c3
|
@ -3,9 +3,11 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"git.1750studios.com/ToddShepard/DB640/internal/bot"
|
||||||
"git.1750studios.com/ToddShepard/DB640/internal/config"
|
"git.1750studios.com/ToddShepard/DB640/internal/config"
|
||||||
"git.1750studios.com/ToddShepard/DB640/internal/twitter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -15,18 +17,13 @@ func main() {
|
||||||
log.Fatalf("Config file must not be empty!")
|
log.Fatalf("Config file must not be empty!")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Hello World!")
|
|
||||||
|
|
||||||
config.LoadConfig(*cfg)
|
config.LoadConfig(*cfg)
|
||||||
twitter.Init()
|
bot.Init()
|
||||||
stream, err := twitter.GetStreamForTag("#NationalPuppyDay")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not establish twitter stream: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
twitter.StreamDemux(stream, showTweet)
|
c := make(chan os.Signal, 1)
|
||||||
}
|
signal.Notify(c, os.Interrupt)
|
||||||
|
<-c
|
||||||
|
|
||||||
func showTweet(tweet *twitter.Tweet) {
|
bot.DeInit()
|
||||||
log.Printf("%s\n", tweet.Text)
|
config.WriteConfig(*cfg)
|
||||||
}
|
}
|
||||||
|
|
83
internal/bot/bot.go
Normal file
83
internal/bot/bot.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package bot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.1750studios.com/ToddShepard/DB640/internal/config"
|
||||||
|
"git.1750studios.com/ToddShepard/DB640/internal/database"
|
||||||
|
"git.1750studios.com/ToddShepard/DB640/internal/twitter"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var stream *twitter.Stream
|
||||||
|
|
||||||
|
// Init initzializes the bot and subscribes the magic hashtag feed
|
||||||
|
func Init() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
err = database.Open(config.C.Database.Dialect, config.C.Database.Connection)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not establish database connection: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
twitter.Init()
|
||||||
|
stream, err = twitter.GetStreamForTag(config.C.Twitter.MagicHashtag)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not establish twitter stream: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
twitter.StreamDemux(stream, handleHashtagTweet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeInit stops the stream and deinitzializes the bot
|
||||||
|
func DeInit() {
|
||||||
|
stream.Stop()
|
||||||
|
database.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHashtagTweet(tweet *twitter.Tweet) {
|
||||||
|
msg, tags := twitter.GetTextAndHashtags(tweet)
|
||||||
|
// Ignore retweets
|
||||||
|
if tweet.RetweetedStatus != nil {
|
||||||
|
log.Printf("%s: %s - IGNORED (RT)\n", tweet.User.ScreenName, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Ignore replys
|
||||||
|
if tweet.InReplyToStatusID != 0 {
|
||||||
|
log.Printf("%s: %s - IGNORED (RPLY)\n", tweet.User.ScreenName, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Ignore if only magic hashtag is given
|
||||||
|
if len(tags) < 2 {
|
||||||
|
log.Printf("%s: %s - IGNORED (<2#)\n", tweet.User.ScreenName, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("%s: %s\n", tweet.User.ScreenName, msg)
|
||||||
|
go findCodes(tweet)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findCodes(tweet *twitter.Tweet) {
|
||||||
|
_, tags := twitter.GetTextAndHashtags(tweet)
|
||||||
|
var betriebsstellen []database.Betriebsstelle
|
||||||
|
for _, tag := range tags {
|
||||||
|
code := strings.ReplaceAll(tag.Text, "_", " ")
|
||||||
|
var bs database.Betriebsstelle
|
||||||
|
if database.Db.First(&bs, "code = ?", code).Error != gorm.ErrRecordNotFound {
|
||||||
|
betriebsstellen = append(betriebsstellen, bs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendReply(tweet, betriebsstellen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendReply(tweet *twitter.Tweet, betriebsstellen []database.Betriebsstelle) {
|
||||||
|
var reply string
|
||||||
|
for _, bs := range betriebsstellen {
|
||||||
|
reply = reply + bs.Code + ": " + bs.Name + "\n"
|
||||||
|
}
|
||||||
|
reply = reply[0 : len(reply)-1]
|
||||||
|
_, _, err := twitter.SendTweet(reply, tweet)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Cannot send reply, error: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,8 @@ import (
|
||||||
|
|
||||||
// Config main type
|
// Config main type
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Twitter Twitter
|
Twitter Twitter
|
||||||
|
Database Database
|
||||||
}
|
}
|
||||||
|
|
||||||
// Twitter related config
|
// Twitter related config
|
||||||
|
@ -21,6 +22,13 @@ type Twitter struct {
|
||||||
ConsumerSecret string
|
ConsumerSecret string
|
||||||
AccessKey string
|
AccessKey string
|
||||||
AccessSecret string
|
AccessSecret string
|
||||||
|
MagicHashtag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database related config
|
||||||
|
type Database struct {
|
||||||
|
Dialect string
|
||||||
|
Connection string
|
||||||
}
|
}
|
||||||
|
|
||||||
// C holds the loaded configuration
|
// C holds the loaded configuration
|
||||||
|
@ -32,6 +40,10 @@ func LoadDefaults() {
|
||||||
C.Twitter.AccessSecret = "ACCESSSECRET"
|
C.Twitter.AccessSecret = "ACCESSSECRET"
|
||||||
C.Twitter.ConsumerKey = "CONSUMERKEY"
|
C.Twitter.ConsumerKey = "CONSUMERKEY"
|
||||||
C.Twitter.ConsumerSecret = "CONSUMERSECRET"
|
C.Twitter.ConsumerSecret = "CONSUMERSECRET"
|
||||||
|
C.Twitter.MagicHashtag = "#DB640"
|
||||||
|
|
||||||
|
C.Database.Dialect = "sqlite3"
|
||||||
|
C.Database.Connection = ":memory:"
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads the configuration from given path
|
// LoadConfig loads the configuration from given path
|
||||||
|
|
|
@ -18,6 +18,9 @@ func TestWriteConfig(t *testing.T) {
|
||||||
C.Twitter.AccessSecret = "SuperNiceSecret"
|
C.Twitter.AccessSecret = "SuperNiceSecret"
|
||||||
C.Twitter.ConsumerKey = "ConsumeMe"
|
C.Twitter.ConsumerKey = "ConsumeMe"
|
||||||
C.Twitter.ConsumerSecret = "EatASecret"
|
C.Twitter.ConsumerSecret = "EatASecret"
|
||||||
|
C.Twitter.MagicHashtag = "#notsomagic"
|
||||||
|
C.Database.Dialect = "somedia"
|
||||||
|
C.Database.Connection = "conn"
|
||||||
err := WriteConfig(filepath.Join("..", "..", "test", "data", "doesnotexist.toml"))
|
err := WriteConfig(filepath.Join("..", "..", "test", "data", "doesnotexist.toml"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Could not write config, got error: %+v", err)
|
t.Errorf("Could not write config, got error: %+v", err)
|
||||||
|
@ -30,7 +33,13 @@ func TestLoadConfig(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Cannot read config, error: %+v", err)
|
t.Errorf("Cannot read config, error: %+v", err)
|
||||||
}
|
}
|
||||||
if C.Twitter.AccessKey != "§OneNiceKey" || C.Twitter.AccessSecret != "SuperNiceSecret" || C.Twitter.ConsumerKey != "ConsumeMe" || C.Twitter.ConsumerSecret != "EatASecret" {
|
if C.Twitter.AccessKey != "§OneNiceKey" ||
|
||||||
|
C.Twitter.AccessSecret != "SuperNiceSecret" ||
|
||||||
|
C.Twitter.ConsumerKey != "ConsumeMe" ||
|
||||||
|
C.Twitter.ConsumerSecret != "EatASecret" ||
|
||||||
|
C.Twitter.MagicHashtag != "#notsomagic" ||
|
||||||
|
C.Database.Dialect != "somedia" ||
|
||||||
|
C.Database.Connection != "conn" {
|
||||||
t.Errorf("Could not read config, entries wrong")
|
t.Errorf("Could not read config, entries wrong")
|
||||||
}
|
}
|
||||||
t.Cleanup(CleanupConfigTest)
|
t.Cleanup(CleanupConfigTest)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package twitter
|
package twitter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"git.1750studios.com/ToddShepard/DB640/internal/config"
|
"git.1750studios.com/ToddShepard/DB640/internal/config"
|
||||||
"github.com/dghubble/go-twitter/twitter"
|
"github.com/dghubble/go-twitter/twitter"
|
||||||
"github.com/dghubble/oauth1"
|
"github.com/dghubble/oauth1"
|
||||||
|
@ -12,6 +14,9 @@ var Client *twitter.Client
|
||||||
// Tweet as in twitter.Tweet
|
// Tweet as in twitter.Tweet
|
||||||
type Tweet = twitter.Tweet
|
type Tweet = twitter.Tweet
|
||||||
|
|
||||||
|
// Stream as in twitter.Stream
|
||||||
|
type Stream = twitter.Stream
|
||||||
|
|
||||||
// Init initzializes the twitter client
|
// Init initzializes the twitter client
|
||||||
func Init() {
|
func Init() {
|
||||||
conf := oauth1.NewConfig(config.C.Twitter.ConsumerKey, config.C.Twitter.ConsumerSecret)
|
conf := oauth1.NewConfig(config.C.Twitter.ConsumerKey, config.C.Twitter.ConsumerSecret)
|
||||||
|
@ -36,3 +41,24 @@ func StreamDemux(stream *twitter.Stream, cb func(*Tweet)) {
|
||||||
demux.Tweet = cb
|
demux.Tweet = cb
|
||||||
demux.HandleChan(stream.Messages)
|
demux.HandleChan(stream.Messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendTweet allows to send a string as tweet (optionally as reply to a specified tweet)
|
||||||
|
func SendTweet(msg string, replytweet *twitter.Tweet) (*twitter.Tweet, *http.Response, error) {
|
||||||
|
if replytweet == nil {
|
||||||
|
// not a reply
|
||||||
|
return Client.Statuses.Update(msg, nil)
|
||||||
|
}
|
||||||
|
// replying
|
||||||
|
p := twitter.StatusUpdateParams{
|
||||||
|
InReplyToStatusID: replytweet.ID,
|
||||||
|
}
|
||||||
|
return Client.Statuses.Update("@"+replytweet.User.ScreenName+" "+msg, &p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTextAndHashtags returns #tweet text and hashtags for short and extended tweets
|
||||||
|
func GetTextAndHashtags(tweet *twitter.Tweet) (string, []twitter.HashtagEntity) {
|
||||||
|
if tweet.ExtendedTweet == nil {
|
||||||
|
return tweet.Text, tweet.Entities.Hashtags
|
||||||
|
}
|
||||||
|
return tweet.ExtendedTweet.FullText, tweet.ExtendedTweet.Entities.Hashtags
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue