From c0fb632cfbda51bb3b54b13e7267496577b989e5 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Thu, 24 May 2018 01:08:18 +0200
Subject: [PATCH] Implement first working version

---
 glide.lock |  14 +++++
 glide.yaml |   4 ++
 main.go    | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 198 insertions(+), 1 deletion(-)
 create mode 100644 glide.lock

diff --git a/glide.lock b/glide.lock
new file mode 100644
index 0000000..9a55495
--- /dev/null
+++ b/glide.lock
@@ -0,0 +1,14 @@
+hash: 71071f00798b1f4ce22ab71a61bbaccc0a10c7cb9e0a9acd0ac8c868c843d46d
+updated: 2018-05-24T01:08:01.558664212+02:00
+imports:
+- name: github.com/lib/pq
+  version: 90697d60dd844d5ef6ff15135d0203f65d2f53b8
+  subpackages:
+  - oid
+- name: github.com/lrstanley/girc
+  version: 102f17f86306c2152a8c6188f9bb8b0e7288de31
+- name: golang.org/x/crypto
+  version: 75e913eb8a8e3d31a97b216de09de106a7b07681
+  subpackages:
+  - sha3
+testImports: []
diff --git a/glide.yaml b/glide.yaml
index 531c988..10bbc8a 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -1,3 +1,7 @@
 package: git.kuschku.de/justjanne/statsbot
 import:
 - package: github.com/lrstanley/girc
+- package: github.com/lib/pq
+- package: golang.org/x/crypto
+  subpackages:
+  - sha3
\ No newline at end of file
diff --git a/main.go b/main.go
index 17b6c08..42f47d3 100644
--- a/main.go
+++ b/main.go
@@ -1,5 +1,184 @@
-package statsbot
+package main
+
+import (
+	"github.com/lrstanley/girc"
+	"os"
+	"fmt"
+	"strings"
+	"log"
+	"time"
+	"golang.org/x/crypto/sha3"
+	_ "github.com/lib/pq"
+	"encoding/hex"
+	"database/sql"
+	"strconv"
+)
+
+type Config struct {
+	Database DatabaseConfig
+	Irc      IrcConfig
+}
+
+type IrcConfig struct {
+	Server       string
+	Port         int
+	Secure       bool
+	Nick         string
+	Ident        string
+	Realname     string
+	SaslAccount  string
+	SaslPassword string
+	SaslEnabled  bool
+}
+
+type DatabaseConfig struct {
+	Format string
+	Url    string
+}
+
+func NewConfigFromEnv() Config {
+	var err error
+	config := Config{}
+
+	config.Irc.Server = os.Getenv("KSTATS_IRC_SERVER")
+	config.Irc.Port, err = strconv.Atoi(os.Getenv("KSTATS_IRC_PORT"))
+	if err != nil {
+		panic(err)
+	}
+	config.Irc.Secure = os.Getenv("KSTATS_IRC_SECURE") == "true"
+	config.Irc.Nick = os.Getenv("KSTATS_IRC_NICK")
+	config.Irc.Ident = os.Getenv("KSTATS_IRC_IDENT")
+	config.Irc.Realname = os.Getenv("KSTATS_IRC_REALNAME")
+	config.Irc.SaslEnabled = os.Getenv("KSTATS_IRC_SASL_ENABLED") == "true"
+	config.Irc.SaslAccount = os.Getenv("KSTATS_IRC_SASL_ACCOUNT")
+	config.Irc.SaslPassword = os.Getenv("KSTATS_IRC_SASL_PASSWORD")
+
+	config.Database.Format = os.Getenv("KSTATS_DATABASE_TYPE")
+	config.Database.Url = os.Getenv("KSTATS_DATABASE_URL")
+
+	return config
+}
+
+type IrcMessage struct {
+	Time        time.Time
+	Channel     int
+	Sender      string
+	Words       int
+	Characters  int
+	Question    bool
+	Exclamation bool
+	Caps        bool
+	Aggression  bool
+	EmojiHappy  bool
+	EmojiSad    bool
+}
+
+func (m *IrcMessage) ToString() string {
+	var flags []string
+	if m.Question {
+		flags = append(flags, "Question")
+	}
+	if m.Exclamation {
+		flags = append(flags, "Exclamation")
+	}
+	if m.Caps {
+		flags = append(flags, "Caps")
+	}
+	if m.Aggression {
+		flags = append(flags, "Aggression")
+	}
+	if m.EmojiHappy {
+		flags = append(flags, "EmojiHappy")
+	}
+	if m.EmojiSad {
+		flags = append(flags, "EmojiSad")
+	}
+
+	return fmt.Sprintf("IrcMessage{time=%s,channel=%d,sender=%s,words=%d,characters=%d,flags=[%s]}", m.Time.Format(time.RFC3339), m.Channel, m.Sender, m.Words, m.Characters, strings.Join(flags, ","))
+}
 
 func main() {
+	config := NewConfigFromEnv()
+
+	db, err := sql.Open(config.Database.Format, config.Database.Url)
+	if err != nil {
+		panic(err)
+	}
+
+	ircConfig := girc.Config{
+		Server: config.Irc.Server,
+		Port:   config.Irc.Port,
+		SSL:    config.Irc.Secure,
+		Nick:   config.Irc.Nick,
+		User:   config.Irc.Ident,
+		Name:   config.Irc.Realname,
+		Debug:  os.Stdout,
+	}
+	if config.Irc.SaslEnabled {
+		ircConfig.SASL = &girc.SASLPlain{
+			User: config.Irc.SaslAccount,
+			Pass: config.Irc.SaslPassword,
+		}
+	}
+	client := girc.New(ircConfig)
+
+	channels := map[string]int{}
+	client.Handlers.Add(girc.CONNECTED, func(c *girc.Client, e girc.Event) {
+		result, err := db.Query("SELECT id, channel FROM channels")
+		if err != nil {
+			panic(err)
+		}
+		for result.Next() {
+			var id int
+			var name string
+			err := result.Scan(&id, &name)
+			if err != nil {
+				panic(err)
+			}
+			channels[name] = id
+		}
+		for name := range channels {
+			c.Cmd.Join(name)
+		}
+	})
+
+	client.Handlers.Add(girc.PRIVMSG, func(c *girc.Client, e girc.Event) {
+		if len(e.Params) == 1 {
+			channel := e.Params[0]
+			if id, ok := channels[channel]; ok {
+				name := hex.EncodeToString(sha3.New256().Sum([]byte(e.Source.Name)))
+				content := strings.TrimSpace(e.Trailing)
+				// Add referenced nick part here
+				// c.LookupChannel(channel).UserList
+				message := IrcMessage{
+					Time:        time.Now().UTC(),
+					Channel:     id,
+					Sender:      name,
+					Words:       len(strings.Split(content, " ")),
+					Characters:  len(content),
+					Question:    strings.HasSuffix(content, "?"),
+					Exclamation: strings.HasSuffix(content, "!"),
+					Caps:        content == strings.ToUpper(content),
+					Aggression:  false,
+					EmojiHappy:  strings.Contains(content, ":)"),
+					EmojiSad:    strings.Contains(content, ":("),
+				}
+				_, err := db.Exec("INSERT INTO messages (time, channel, sender, words, characters, question, exclamation, caps, aggression, emoji_happy, emoji_sad) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", message.Time, message.Channel, message.Sender, message.Words, message.Characters, message.Question, message.Exclamation, message.Caps, message.Aggression, message.EmojiHappy, message.EmojiSad)
+				if err != nil {
+					println(err.Error())
+				}
+			}
+		}
+	})
+
+	for {
+		if err := client.Connect(); err != nil {
+			log.Printf("error: %s", err)
 
+			log.Println("reconnecting in 30 seconds...")
+			time.Sleep(30 * time.Second)
+		} else {
+			return
+		}
+	}
 }
-- 
GitLab