summaryrefslogtreecommitdiff
path: root/internal/client.go
blob: c0373a06e63b34bf02b020f71a8205e9eedcea12 (plain)
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
package irclogs

import (
	"bufio"
	"database/sql"
	"fmt"
	"log"
	"net"
	"net/textproto"
	"slices"
)

type IRCClient struct {
	dbid int

	Host string
	port int
	nick string
	pass string
	caps []string

	rooms []string

	conn net.Conn
}

func NewIRCClient(dbid int, host string, port int, nick string, pass string, capabilities []string) IRCClient {
	return IRCClient{
		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 {
		message, err := tp.ReadLine()
		if err != nil {
			log.Panicf("Failed to read a line: %v\n", err)
		}
		log.Printf("IRC message: %s\n", message)
	}
}

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(db *sql.DB) {
	for {
		rooms := []string{}
		rows, err := 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 })
			}
		}
	}
}