package irclogs import ( "bufio" "database/sql" "fmt" "log" "net" "net/textproto" "slices" "strings" ) type IRCClient struct { db *sql.DB dbid int Host string port int nick string pass string caps []string rooms []string conn net.Conn } func NewIRCClient(db *sql.DB, dbid int, host string, port int, nick string, pass string, capabilities []string) IRCClient { return IRCClient{ db: db, dbid: dbid, Host: host, port: port, nick: nick, pass: pass, caps: capabilities, } } func (c *IRCClient) Connect() (err error) { conn, err := net.Dial("tcp", net.JoinHostPort(c.Host, fmt.Sprintf("%d", c.port))) if err != nil { return } c.conn = conn c.authorize() for _, r := range c.rooms { c.SendRaw(fmt.Sprintf("JOIN %s", r)) } tp := textproto.NewReader(bufio.NewReader(c.conn)) for { raw, err := tp.ReadLine() if err != nil { log.Panicf("Failed to read a line: %v\n", err) } for _, line := range strings.Split(raw, "\r\n") { message := ParseIRCMessage(line) switch message.Command { case "PRIVMSG", "JOIN", "PART": message.Save(c.db, c.dbid) case "PING": c.SendRaw(fmt.Sprintf("PONG :%s", strings.Join(message.Params, " "))) } } } } func (c *IRCClient) authorize() { c.SendRaw(fmt.Sprintf("NICK %s", c.nick)) c.SendRaw(fmt.Sprintf("PASS %s", c.pass)) for _, cap := range c.caps { c.SendRaw(fmt.Sprintf("CAP REQ :%s", cap)) } } func (c *IRCClient) SendRaw(message string) { if c.conn != nil { fmt.Fprintf(c.conn, "%s\r\n", message) } } func (c *IRCClient) JoinChannels() { for { rooms := []string{} rows, err := c.db.Query("SELECT name FROM rooms WHERE server_id = ? AND departed_at IS NULL", c.dbid) if err != nil { log.Fatalf("Failed to get rooms: %v\n", err) continue } for rows.Next() { var room string if err = rows.Scan(&room); err != nil { log.Fatalf("Failed to scan rows: %v\n", err) continue } rooms = append(rooms, room) } rows.Close() for _, r := range rooms { if !slices.Contains(c.rooms, r) { log.Printf("[%s] Joining %s...", c.Host, r) c.SendRaw(fmt.Sprintf("JOIN %s", r)) c.rooms = append(c.rooms, r) } } for _, r := range c.rooms { if !slices.Contains(rooms, r) { log.Printf("[%s] Departing %s...", c.Host, r) c.SendRaw(fmt.Sprintf("PART %s", r)) c.rooms = slices.DeleteFunc(c.rooms, func(s string) bool { return s == r }) } } } }