package main import ( "container/ring" "flag" "fmt" "log" "time" irc "github.com/fluffle/goirc/client" ) type bot struct { room string conn *irc.Conn notice chan string kick chan string last *ring.Ring } func New(name, node, room string, ssl bool) *bot { conf := irc.NewConfig(name) conf.Server = node conf.SSL = ssl conn := irc.Client(conf) return &bot{ room: room, conn: conn, notice: notify(conn, room), kick: kicker(conn, room), last: ring.New(10), } } func (b *bot) push(line *irc.Line) { b.last.Value = line b.last = b.last.Next() } func (b *bot) find(c chan string, nick string) { var msg string b.last.Do(func(v interface{}) { if v != nil { l := v.(*irc.Line) if l.Nick == nick { msg = l.Text() } } }) if msg != "" { c <- msg } } func (b *bot) lastMsgs(c chan string) { b.last.Do(func(v interface{}) { if v != nil { l := v.(*irc.Line) c <- fmt.Sprintf("%v <%v> %v", l.Time.UTC().Format(time.Kitchen), l.Nick, l.Text()) } }) } func notify(conn *irc.Conn, target string) chan string { const maxLen = 500 c := make(chan string, 1) go func() { for msg := range c { log.Println("send", msg) if len(msg) > maxLen { msg = msg[:maxLen] + "..." } conn.Notice(target, msg) } }() return c } func kicker(conn *irc.Conn, channel string) chan string { c := make(chan string, 1) go func() { for nick := range c { if nick != conn.Me().Nick { log.Println("kick", nick) conn.Kick(channel, nick) } } }() return c } func (b *bot) join() irc.HandlerFunc { return func(conn *irc.Conn, _ *irc.Line) { conn.Join(b.room) } } func discon(c chan struct{}) irc.HandlerFunc { return func(_ *irc.Conn, _ *irc.Line) { close(c) } } func (b *bot) privmsg() irc.HandlerFunc { l := links(b.notice) return func(conn *irc.Conn, line *irc.Line) { if isFlood(line.Text()) { b.kick <- line.Nick } switch line.Text() { case "last": c := notify(conn, line.Nick) defer close(c) b.lastMsgs(c) case "find": b.find(b.notice, line.Nick) default: b.push(line) } l <- line.Text() } } func main() { node := flag.String("node", "irc.freenode.org", "IRC Server") ssl := flag.Bool("ssl", false, "Use SSL") room := flag.String("room", "#lor", "IRC Channel") name := flag.String("name", "dim13", "Bots Name") flag.Parse() b := New(*name, *node, *room, *ssl) done := make(chan struct{}) go Watch(b.notice, Feeds) // TODO shall it be there? // setup event handler handler := []struct { ev string f irc.HandlerFunc }{ {irc.DISCONNECTED, discon(done)}, {irc.CONNECTED, b.join()}, {irc.KICK, b.join()}, {irc.PRIVMSG, b.privmsg()}, } for _, h := range handler { b.conn.HandleFunc(h.ev, h.f) } if err := b.conn.Connect(); err != nil { log.Fatal(err) } log.Println("Connected") <-done log.Println("Disconnected") }