185 lines
4.1 KiB
Go
185 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/ergochat/irc-go/ircevent"
|
|
"github.com/ergochat/irc-go/ircmsg"
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
type empty struct{}
|
|
|
|
const (
|
|
concurrencyLimit = 128
|
|
|
|
IRCv3TimestampFormat = "2006-01-02T15:04:05.000Z"
|
|
|
|
defaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.81 Safari/537.36"
|
|
|
|
replyTagName = "+draft/reply"
|
|
)
|
|
|
|
type Bot struct {
|
|
ircevent.Connection
|
|
TwitterBearerToken string
|
|
Owner string
|
|
semaphore chan empty
|
|
userAgent string
|
|
}
|
|
|
|
func (b *Bot) tryAcquireSemaphore() bool {
|
|
select {
|
|
case b.semaphore <- empty{}:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (b *Bot) releaseSemaphore() {
|
|
<-b.semaphore
|
|
}
|
|
|
|
// func (irc *Bot) checkErr(err error, message string) (fatal bool) {
|
|
// if err != nil {
|
|
// irc.Log.Printf("%s: %v", message, err)
|
|
// return true
|
|
// }
|
|
// return false
|
|
// }
|
|
|
|
// Helper Functions
|
|
|
|
func (irc *Bot) handleOwnerCommand(target, command string) {
|
|
if !strings.HasPrefix(command, irc.Nick) {
|
|
return
|
|
}
|
|
command = strings.TrimPrefix(command, irc.Nick)
|
|
command = strings.TrimPrefix(command, ":")
|
|
f := strings.Fields(command)
|
|
if len(f) == 0 {
|
|
return
|
|
}
|
|
switch strings.ToLower(f[0]) {
|
|
case "abuse":
|
|
if len(f) > 1 {
|
|
irc.Privmsg(target, fmt.Sprintf("%s isn't a real programmer", f[1]))
|
|
}
|
|
case "quit":
|
|
irc.Quit()
|
|
}
|
|
}
|
|
|
|
func (irc *Bot) sendReplyNotice(target, msgid, text string) {
|
|
if msgid == "" {
|
|
irc.Notice(target, text)
|
|
} else {
|
|
irc.SendWithTags(map[string]string{replyTagName: msgid}, "NOTICE", target, text)
|
|
}
|
|
}
|
|
|
|
func ownerMatches(e ircmsg.Message, owner string) bool {
|
|
if owner == "" {
|
|
return false
|
|
}
|
|
if present, account := e.GetTag("account"); present && account == owner {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func newBot() *Bot {
|
|
err := godotenv.Load(".env")
|
|
if err != nil {
|
|
log.Fatalf("Some error occured. Err: %s", err)
|
|
}
|
|
// required:
|
|
nick := os.Getenv("WUTBOT_NICK")
|
|
server := os.Getenv("WUTBOT_SERVER")
|
|
// required (comma-delimited list of channels)
|
|
channels := os.Getenv("WUTBOT_CHANNELS")
|
|
// SASL is optional:
|
|
saslLogin := os.Getenv("WUTBOT_SASL_LOGIN")
|
|
saslPassword := os.Getenv("WUTBOT_SASL_PASSWORD")
|
|
// owner is optional (if unset, WUTBOT won't accept any owner commands)
|
|
owner := os.Getenv("WUTBOT_OWNER_ACCOUNT")
|
|
// more optional settings
|
|
version := os.Getenv("WUTBOT_VERSION")
|
|
if version == "" {
|
|
version = "github.com/ergochat/irc-go"
|
|
}
|
|
debug := os.Getenv("WUTBOT_DEBUG") != ""
|
|
insecure := os.Getenv("WUTBOT_INSECURE_SKIP_VERIFY") != ""
|
|
userAgent := os.Getenv("WUTBOT_USER_AGENT")
|
|
if userAgent == "" {
|
|
userAgent = defaultUserAgent
|
|
}
|
|
|
|
var tlsconf *tls.Config
|
|
if insecure {
|
|
tlsconf = &tls.Config{InsecureSkipVerify: true}
|
|
}
|
|
|
|
irc := &Bot{
|
|
Connection: ircevent.Connection{
|
|
Server: server,
|
|
Nick: nick,
|
|
UseTLS: true,
|
|
TLSConfig: tlsconf,
|
|
RequestCaps: []string{"server-time", "message-tags", "account-tag"},
|
|
SASLLogin: saslLogin, // SASL will be enabled automatically if these are set
|
|
SASLPassword: saslPassword,
|
|
QuitMessage: version,
|
|
Debug: debug,
|
|
},
|
|
Owner: owner,
|
|
userAgent: userAgent,
|
|
semaphore: make(chan empty, concurrencyLimit),
|
|
}
|
|
|
|
irc.AddConnectCallback(func(e ircmsg.Message) {
|
|
if botMode := irc.ISupport()["BOT"]; botMode != "" {
|
|
irc.Send("MODE", irc.CurrentNick(), "+"+botMode)
|
|
}
|
|
for _, channel := range strings.Split(channels, ",") {
|
|
irc.Join(strings.TrimSpace(channel))
|
|
}
|
|
})
|
|
irc.AddCallback("PRIVMSG", func(e ircmsg.Message) {
|
|
target, message := e.Params[0], e.Params[1]
|
|
_, msgid := e.GetTag("msgid")
|
|
fromOwner := ownerMatches(e, irc.Owner)
|
|
if !strings.HasPrefix(target, "#") && !fromOwner {
|
|
return
|
|
}
|
|
|
|
if fromOwner {
|
|
irc.handleOwnerCommand(e.Params[0], message)
|
|
} else if strings.HasPrefix(message, irc.Nick) {
|
|
irc.sendReplyNotice(e.Params[0], msgid, "don't @ me, mortal")
|
|
}
|
|
})
|
|
irc.AddCallback("INVITE", func(e ircmsg.Message) {
|
|
fromOwner := ownerMatches(e, irc.Owner)
|
|
if fromOwner {
|
|
irc.Join(e.Params[1])
|
|
}
|
|
})
|
|
|
|
return irc
|
|
}
|
|
|
|
func main() {
|
|
irc := newBot()
|
|
err := irc.Connect()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
irc.Loop()
|
|
}
|