Initial commit of utilities

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld
2021-05-27 12:17:12 +02:00
commit b52ec14d2d
20 changed files with 3764 additions and 0 deletions

177
cmd/ircmirror/ircwriters.go Normal file
View File

@@ -0,0 +1,177 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2021 Jason A. Donenfeld. All Rights Reserved.
*/
package main
import (
"bufio"
"container/list"
"log"
"math/rand"
"net"
"os"
"regexp"
"strconv"
"strings"
"sync"
"time"
"golang.zx2c4.com/irc/hbot"
)
var words []string
func init() {
f, err := os.Open("/usr/share/dict/words")
if err != nil {
log.Fatalf("Unable to open dictionary: %v", err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
matcher := regexp.MustCompile(`^[a-zA-Z0-9_-]{3,}$`)
for scanner.Scan() {
word := scanner.Text()
if !matcher.MatchString(word) {
continue
}
words = append(words, word)
}
if len(words) == 0 {
log.Fatalln("Did not find any words in dictionary")
}
}
func randomNick() string {
return words[rand.Intn(len(words))] + words[rand.Intn(len(words))] + strconv.Itoa(rand.Intn(10000))
}
type ircWriter struct {
mu sync.Mutex
bot *hbot.Bot
nick string
mungedNick string
usageElem *list.Element
name string
}
type ircWriters struct {
mu sync.Mutex
byNick map[string]*ircWriter
byUsage list.List
server string
channel string
}
func (writers *ircWriters) runWriter(name string, dialer func(network, address string) (net.Conn, error)) {
writer := &ircWriter{name: name}
startNick := randomNick()
logf := func(format string, args ...interface{}) {
log.Printf("[DST %s] "+format, append([]interface{}{name}, args...)...)
}
writer.bot = hbot.NewBot(&hbot.Config{
Host: writers.server,
Nick: startNick,
User: hbot.CommonBotUserPrefix + startNick,
Channels: []string{writers.channel},
Dial: dialer,
Logger: hbot.Logger{Verbosef: logf, Errorf: logf},
})
go func() {
<-writer.bot.Joined()
writers.mu.Lock()
defer writers.mu.Unlock()
writer.mu.Lock()
defer writer.mu.Unlock()
writer.usageElem = writers.byUsage.PushBack(writer)
}()
writer.bot.AddTrigger(hbot.Trigger{
Condition: func(bot *hbot.Bot, m *hbot.Message) bool {
return (m.Command == "436" || m.Command == "433") && len(writer.nick) > 0
},
Action: func(bot *hbot.Bot, m *hbot.Message) {
logf("Failed with nick %q, trying %q\n", writer.mungedNick, writer.mungedNick+"_")
writer.mungedNick += "_"
if len(writer.mungedNick) > 16 {
usidx := strings.IndexByte(writer.mungedNick, '_')
uslen := len(writer.mungedNick[usidx:])
if uslen >= 16 {
writer.mungedNick = writer.nick + "-"
if len(writer.mungedNick) > 16 {
writer.mungedNick = writer.nick[:15] + "-"
}
} else {
writer.mungedNick = writer.mungedNick[:16-uslen] + writer.mungedNick[usidx:]
}
}
bot.SetNick(writer.mungedNick)
},
})
writer.bot.Run()
writers.mu.Lock()
writer.mu.Lock()
if writer.usageElem != nil {
writers.byUsage.Remove(writer.usageElem)
delete(writers.byNick, writer.nick)
}
writer.mu.Unlock()
writers.mu.Unlock()
}
func (writers *ircWriters) getWriter(nick string) *ircWriter {
writers.mu.Lock()
if writer, ok := writers.byNick[nick]; ok {
writer.mu.Lock()
if writer.nick == nick {
writers.byUsage.MoveToFront(writer.usageElem)
writers.mu.Unlock()
if writer.bot.Nick() != writer.mungedNick {
log.Printf("[DST %s] Changing nick to %q\n", writer.name, nick)
writer.bot.SetNick(writer.mungedNick)
}
return writer
}
writer.mu.Unlock()
}
if writers.byUsage.Len() == 0 {
writers.mu.Unlock()
return nil
}
writer := writers.byUsage.Back().Value.(*ircWriter)
writer.mu.Lock()
delete(writers.byNick, writer.nick)
writer.nick = nick
writer.mungedNick = nick + "-"
if len(writer.mungedNick) > 16 {
writer.mungedNick = nick[:15] + "-"
}
writers.byNick[nick] = writer
writers.byUsage.MoveToFront(writer.usageElem)
writers.mu.Unlock()
log.Printf("[DST %s] Changing nick to %q\n", writer.name, nick)
writer.bot.SetNick(writer.mungedNick)
return writer
}
func (writers *ircWriters) queueMessage(from, message string) {
writer := writers.getWriter(from)
if writer == nil {
time.AfterFunc(time.Second*3, func() {
writers.queueMessage(from, message)
})
return
}
log.Printf("[DST %s] Queueing message from %q\n", writer.name, from)
writer.bot.Msg(writers.channel, message)
writer.mu.Unlock()
}
func newIrcWriterGroup(server, channel string) *ircWriters {
return &ircWriters{
mu: sync.Mutex{},
byNick: make(map[string]*ircWriter, 400),
server: server,
channel: channel,
}
}