-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.go
121 lines (106 loc) · 2.43 KB
/
bot.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
package miniporte
import (
"log"
"github.com/cenkalti/backoff"
irc "github.com/fluffle/goirc/client"
"github.com/oz/miniporte/epistoli"
link "github.com/oz/miniporte/link"
)
// Bot stores the state of our bot, and its configuration.
type Bot struct {
Chans []string
Config *irc.Config
Client *irc.Conn
Ctl (chan string)
}
// New initializes a new Bot, ready to connect to IRC.
func New(server, nick, name, ident string, chans []string) *Bot {
cfg := irc.NewConfig(nick)
cfg.SSL = true
cfg.Me.Name = name
cfg.Me.Ident = ident
cfg.Server = server
cfg.NewNick = func(n string) string { return n + "_" }
return &Bot{
Chans: chans,
Config: cfg,
Client: irc.Client(cfg),
Ctl: make(chan string),
}
}
func (b *Bot) joinChannels() {
log.Println("Joining channels", b.Chans)
for _, c := range b.Chans {
b.Client.Join(c)
}
}
func (b *Bot) Run() {
b.initializeHandlers()
go b.Connect()
b.commandLoop()
log.Println("Bot quitting...")
}
func (b *Bot) onMessage(msg *irc.Line) {
// Ignore non-public messages
if !msg.Public() {
return
}
l := link.New(epistoli.New())
if err := l.MustExtract(msg.Text()); err != nil {
// No links.
return
}
l.Tags = append(l.Tags, msg.Nick, msg.Target())
go func() {
if err := l.Save(); err != nil {
if l.Pub {
b.Client.Privmsg(msg.Target(), "Oops! "+err.Error())
}
return
}
if l.Pub {
b.Client.Privmsg(msg.Target(), "Saved!")
}
}()
}
func (b *Bot) initializeHandlers() {
// Connected
b.Client.HandleFunc("connected", func(conn *irc.Conn, line *irc.Line) {
log.Println("Connected!")
b.joinChannels()
})
// Disconnected
b.Client.HandleFunc("disconnected", func(conn *irc.Conn, line *irc.Line) {
log.Println("Disconnected")
b.Ctl <- "disconnected"
})
// PRIVMSG
b.Client.HandleFunc("PRIVMSG", func(conn *irc.Conn, line *irc.Line) {
b.onMessage(line)
})
}
// Connect connect the bot to an IRC server.
func (b *Bot) Connect() error {
log.Println("Connecting to", b.Config.Server)
return b.Client.Connect()
}
func (b *Bot) connect() {
if err := backoff.Retry(b.Connect, backoff.NewExponentialBackOff()); err != nil {
log.Printf("Connection error: %s\n", err)
b.Ctl <- "connection-error"
}
}
// Connection loop
func (b *Bot) commandLoop() {
for {
for cmd := range b.Ctl {
switch cmd {
case "disconnected", "connection-error":
log.Println("Disconnected:", cmd)
go b.connect()
default:
log.Println("Ignoring command", cmd)
}
}
}
}