-
Notifications
You must be signed in to change notification settings - Fork 5
/
irc-client.js
109 lines (88 loc) · 2.83 KB
/
irc-client.js
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
const LineBuffer = require('./line-buffer')
const EventStream = require('./event-stream')
const { PassThrough } = require('stream')
const EventEmitter = require('events');
const tls = require('tls')
const net = require('net')
class Client extends EventEmitter {
constructor (options) {
super()
if (options.dryRun) {
const serv = net.createServer().listen(11337)
serv.on('connection', s => s.on('data', (data) => console.log('SERVER', data)))
Object.assign(options, {host: 'localhost', port: 11337, tls: false})
}
if (options.tls) {
options.servername = options.host
this.socket = tls.connect(options)
} else {
this.socket = net.connect(options)
}
this.socket.setEncoding('utf8')
const debugLog = new PassThrough()
debugLog.on('data', (data) => {
if (options.debug)
console.log('DEBUG <', data.toString().trim())
})
// Raise events from socket messages
this.socket
.pipe(new LineBuffer())
.pipe(debugLog)
.pipe(EventStream([
[ /PING (\S+)/, ([, hostname]) => this.emit('ping', hostname) ],
[ /^(\S+) PRIVMSG (\S+) :(.+)/, ([, from, to, msg]) => this.emit('msg', {from, to, msg}) ],
[ /^\S+ 376/, () => this.emit('ready') ], // End of MOTD
[ /^\S+ 433/, () => this.emit('error', 'Nickname in use') ],
[ /^\S+ 451/, () => this.emit('error', 'Not registered') ],
[ /^\S+ 331 [^:]+:(.+)/, ([, topic]) => this.emit('topic', null) ],
[ /^\S+ 332 [^:]+:(.+)/, ([, topic]) => this.emit('topic', topic) ],
]))
// Handle the most important things automatically
this.socket.on('connect', () => this._identify(options.nick))
this.on('ping', (host) => this.send(`PONG ${host}`))
this.socket.on('error', (err) => {
console.error('Socket error:', err)
})
this.socket.on('close', (hadError) => {
if (hadError) {
console.log('Reconnecting after socket transmission error')
this.connect(options)
}
})
}
send (msg, cb) {
if (!this.socket.destroyed) {
this.socket.write(`${msg}\r\n`, cb)
console.log('DEBUG >', msg.trim())
}
}
msg (to, text) {
this.send(`PRIVMSG ${to} :${text}`)
}
notice (to, text) {
this.send(`NOTICE ${to} :${text}`)
}
// TODO: This currently only supports a single channel
set_topic (chan, new_topic, cb) {
this.send(`TOPIC #${chan} :${new_topic}`)
this.once('topic', (topic) => cb(null, topic))
}
get_topic (chan, cb) {
this.send(`TOPIC #${chan}`)
this.once('topic', (topic) => cb(null, topic))
}
join (chan) {
this.send(`JOIN ${chan}`)
}
nick (nick) {
this.send(`NICK ${nick}`)
}
quit (msg) {
this.send(`QUIT :${msg}`)
}
_identify (nick) {
this.send(`USER ${nick} * * :${nick}`)
this.nick(nick)
}
}
module.exports = Client