@sockethub/irc2as 4.0.0-alpha.4 → 4.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js CHANGED
@@ -1,265 +1,308 @@
1
- const events = require('events');
2
- const debug = require('debug')('irc2as');
3
- const ASEmitter = require('./as-emitter');
1
+ import events from "node:events";
2
+ import debug from "debug";
3
+ import { ASEmitter } from "./as-emitter.js";
4
4
 
5
- const EVENT_INCOMING = 'incoming',
6
- // EVENT_ERROR = 'error',
7
- EVENT_PONG = 'pong',
8
- EVENT_PING = 'ping',
9
- EVENT_UNPROCESSED = 'unprocessed';
5
+ const log = debug("irc2as");
10
6
 
11
- const ERR_BAD_NICK = "432",
12
- ERR_CHAN_PRIVS = "482",
13
- ERR_NICK_IN_USE = "433",
14
- ERR_TEMP_UNAVAIL = "437",
15
- ERR_NO_CHANNEL = "403",
16
- ERR_NOT_INVITED = "471",
17
- ERR_BADMODE= "472",
18
- ERR_INVITE_ONLY = "473",
19
- ERR_BANNED = "474",
20
- ERR_BADKEY = "475",
21
- ERR_BADMASK = "476",
22
- ERR_NOCHANMODES = "477",
23
- ERR_BANLISTFULL = "478",
24
- JOIN = "JOIN",
25
- MODE = "MODE",
26
- MOTD = "372",
27
- MOTD_END = "376",
28
- NAMES = "353",
29
- // NAMES_END = "366",
30
- NICK = "NICK",
31
- NOTICE = "NOTICE",
32
- PART = "PART",
33
- PING = "PING",
34
- PONG = "PONG",
35
- PRIVMSG = "PRIVMSG",
36
- QUIT = "QUIT",
37
- TOPIC_CHANGE = "TOPIC",
38
- TOPIC_IS = "332",
39
- TOPIC_SET_BY = "333",
40
- WHO = "352",
41
- WHO_OLD = "354";
42
- // WHO_END = "315";
7
+ const EVENT_INCOMING = "incoming";
8
+ // EVENT_ERROR = 'error',
9
+ const EVENT_PONG = "pong";
10
+ const EVENT_PING = "ping";
11
+ const EVENT_UNPROCESSED = "unprocessed";
12
+
13
+ const ERR_BAD_NICK = "432";
14
+ const ERR_CHAN_PRIVS = "482";
15
+ const ERR_NICK_IN_USE = "433";
16
+ const ERR_TEMP_UNAVAIL = "437";
17
+ const ERR_NO_CHANNEL = "403";
18
+ const ERR_NOT_INVITED = "471";
19
+ const ERR_BADMODE = "472";
20
+ const ERR_INVITE_ONLY = "473";
21
+ const ERR_BANNED = "474";
22
+ const ERR_BADKEY = "475";
23
+ const ERR_BADMASK = "476";
24
+ const ERR_NOCHANMODES = "477";
25
+ const ERR_BANLISTFULL = "478";
26
+ const JOIN = "JOIN";
27
+ const MODE = "MODE";
28
+ const MOTD = "372";
29
+ const MOTD_END = "376";
30
+ const NAMES = "353";
31
+ // NAMES_END = "366",
32
+ const NICK = "NICK";
33
+ const NOTICE = "NOTICE";
34
+ const PART = "PART";
35
+ const PING = "PING";
36
+ const PONG = "PONG";
37
+ const PRIVMSG = "PRIVMSG";
38
+ const QUIT = "QUIT";
39
+ const TOPIC_CHANGE = "TOPIC";
40
+ const TOPIC_IS = "332";
41
+ const TOPIC_SET_BY = "333";
42
+ const WHO = "352";
43
+ const WHO_OLD = "354";
44
+ // WHO_END = "315";
43
45
 
44
46
  const ROLE = {
45
- '@': 'owner',
46
- '%': 'admin',
47
- '*': 'participant'
47
+ "@": "owner",
48
+ "%": "admin",
49
+ "*": "participant",
48
50
  };
49
51
 
50
52
  const MODES = {
51
- 'o': 'owner',
52
- 'h': 'admin',
53
- 'v': 'participant'
53
+ o: "owner",
54
+ h: "admin",
55
+ v: "participant",
54
56
  };
55
57
 
56
58
  function getNickFromServer(server) {
57
- return server.split(/^:/)[1].split('!')[0];
59
+ return server.split(/^:/)[1].split("!")[0];
58
60
  }
59
61
 
60
- class IrcToActivityStreams {
61
- constructor(cfg) {
62
- const config = cfg || {};
63
- this.server = config.server;
64
- this.events = new events.EventEmitter();
65
- this.__buffer = {};
66
- this.__buffer[NAMES] = {};
67
- }
68
-
69
- input(incoming) {
70
- debug(incoming);
71
- if (typeof incoming !== 'string') {
72
- debug('unable to process incoming message as it was not a string.');
73
- return false;
74
- } else if (incoming.length < 3) {
75
- debug('unable to process incoming string, length smaller than 3.');
76
- return false;
62
+ export class IrcToActivityStreams {
63
+ constructor(cfg) {
64
+ const config = cfg || {};
65
+ this.server = config.server;
66
+ this.events = new events.EventEmitter();
67
+ this.__buffer = {};
68
+ this.__buffer[NAMES] = {};
77
69
  }
78
- incoming = incoming.trim();
79
- const [metadata, content] = incoming.split(' :');
80
- const [server, code, pos1, pos2, pos3, ...msg] = metadata.split(" ");
81
- const channel = ((typeof pos1 === "string") && (pos1.startsWith('#'))) ? pos1 :
82
- ((typeof pos2 === "string") && (pos2.startsWith('#'))) ? pos2 :
83
- ((typeof pos3 === "string") && (pos3.startsWith('#'))) ? pos3 : undefined;
84
- if (metadata === PING) {
85
- this.events.emit(EVENT_PING, `${Date.now()}`);
86
- return true;
70
+
71
+ input(payload) {
72
+ log(payload);
73
+ if (typeof payload !== "string") {
74
+ log("unable to process incoming message as it was not a string.");
75
+ return false;
76
+ }
77
+ if (payload.length < 3) {
78
+ log("unable to process incoming string, length smaller than 3.");
79
+ return false;
80
+ }
81
+ const incoming = payload.trim();
82
+ const [metadata, content] = incoming.split(" :");
83
+ const [server, code, pos1, pos2, pos3, ...msg] = metadata.split(" ");
84
+ const channel =
85
+ typeof pos1 === "string" && pos1.startsWith("#")
86
+ ? pos1
87
+ : typeof pos2 === "string" && pos2.startsWith("#")
88
+ ? pos2
89
+ : typeof pos3 === "string" && pos3.startsWith("#")
90
+ ? pos3
91
+ : undefined;
92
+ if (metadata === PING) {
93
+ this.events.emit(EVENT_PING, `${Date.now()}`);
94
+ return true;
95
+ }
96
+ log(
97
+ `[${code}] server: ${server} channel: ${channel} 1: ${pos1}, 2: ${pos2}, 3: ${pos3}. content: `,
98
+ content,
99
+ );
100
+ this.__processIRCCodes(
101
+ code,
102
+ server,
103
+ channel,
104
+ pos1,
105
+ pos2,
106
+ pos3,
107
+ content,
108
+ msg,
109
+ incoming,
110
+ );
87
111
  }
88
- debug(`[${code}] server: ${server} channel: ${channel} 1: ${pos1}, 2: ${pos2}, 3: ${pos3}.` +
89
- ` content: `, content);
90
- this.__processIRCCodes(code, server, channel, pos1, pos2, pos3, content, msg, incoming);
91
- }
92
112
 
93
- __processIRCCodes(code, server, channel, pos1, pos2, pos3, content, msg, incoming) {
94
- const ase = new ASEmitter(this.events, this.server);
95
- let nick, type, role;
96
- switch (code) {
97
- /** */
98
- case ERR_CHAN_PRIVS:
99
- case ERR_NOT_INVITED:
100
- case ERR_BADMODE:
101
- case ERR_INVITE_ONLY:
102
- case ERR_BANNED:
103
- case ERR_BADKEY:
104
- case ERR_BADMASK:
105
- case ERR_NOCHANMODES:
106
- case ERR_BANLISTFULL:
107
- ase.channelError(channel, pos1, content)
108
- break;
113
+ __processIRCCodes(
114
+ code,
115
+ server,
116
+ channel,
117
+ pos1,
118
+ pos2,
119
+ pos3,
120
+ content,
121
+ msg,
122
+ incoming,
123
+ ) {
124
+ const ase = new ASEmitter(this.events, this.server);
125
+ let nick;
126
+ let type;
127
+ let role;
109
128
 
110
- /** */
111
- case ERR_NICK_IN_USE: // nick conflict
112
- case ERR_BAD_NICK:
113
- ase.serviceError(pos2, content)
114
- break;
129
+ switch (code) {
130
+ /** */
131
+ case ERR_CHAN_PRIVS:
132
+ case ERR_NOT_INVITED:
133
+ case ERR_BADMODE:
134
+ case ERR_INVITE_ONLY:
135
+ case ERR_BANNED:
136
+ case ERR_BADKEY:
137
+ case ERR_BADMASK:
138
+ case ERR_NOCHANMODES:
139
+ case ERR_BANLISTFULL:
140
+ ase.channelError(channel, pos1, content);
141
+ break;
115
142
 
116
- /** */
117
- case ERR_NO_CHANNEL: // no such channel
118
- ase.joinError(pos2)
119
- break;
143
+ /** */
144
+ case ERR_NICK_IN_USE: // nick conflict
145
+ case ERR_BAD_NICK:
146
+ ase.serviceError(pos2, content);
147
+ break;
120
148
 
121
- /** */
122
- case ERR_TEMP_UNAVAIL: // nick conflict
123
- ase.nickError(pos2, content);
124
- break;
149
+ /** */
150
+ case ERR_NO_CHANNEL: // no such channel
151
+ ase.joinError(pos2);
152
+ break;
125
153
 
126
- /** */
127
- case JOIN: // room join
128
- ase.joinRoom(channel, getNickFromServer(server))
129
- break;
154
+ /** */
155
+ case ERR_TEMP_UNAVAIL: // nick conflict
156
+ ase.nickError(pos2, content);
157
+ break;
130
158
 
131
- case MODE: // custom event indicating a channel mode has been updated, used to re-query user or channel
132
- let user_mode = pos2 || content;
133
- if (! channel) { break; } // don't handle cases with no channel defined
134
- if (! pos3) { break; } // we need target user
135
- role = MODES[user_mode[1]] || 'member';
136
- type = 'add';
137
- if (user_mode[0] === '-') {
138
- type = 'remove';
139
- }
140
- ase.role(type, getNickFromServer(server), pos3, role, channel)
141
- break;
159
+ /** */
160
+ case JOIN: // room join
161
+ ase.joinRoom(channel, getNickFromServer(server));
162
+ break;
142
163
 
143
- /** */
144
- case MOTD: // MOTD
145
- if (! this.__buffer[MOTD]) {
146
- this.__buffer[MOTD] = {
147
- context: 'irc',
148
- type: 'update',
149
- actor: {
150
- type: 'service',
151
- id: this.server,
152
- name: this.server
153
- },
154
- object: {
155
- type: 'topic',
156
- content: content
164
+ // custom event indicating a channel mode has been updated, used to re-query user or channel
165
+ case MODE: {
166
+ const user_mode = pos2 || content;
167
+ if (!channel) {
168
+ break;
169
+ } // don't handle cases with no channel defined
170
+ if (!pos3) {
171
+ break;
172
+ } // we need target user
173
+ role = MODES[user_mode[1]] || "member";
174
+ type = "add";
175
+ if (user_mode[0] === "-") {
176
+ type = "remove";
157
177
  }
178
+ ase.role(type, getNickFromServer(server), pos3, role, channel);
179
+ break;
158
180
  }
159
- } else {
160
- this.__buffer[MOTD].object.content += " " + content;
161
- }
162
- break;
163
- case MOTD_END: // end of MOTD
164
- if (! this.__buffer[MOTD]) { break; }
165
- ase.emitEvent(EVENT_INCOMING, this.__buffer[MOTD]);
166
- delete this.__buffer[MOTD];
167
- break;
168
181
 
169
- /** */
170
- case NAMES: // user list
171
- for (let entry of content.split(' ')) {
172
- role = 'member';
173
- let username = entry;
174
- if (ROLE[entry[0]]) {
175
- username = entry.substr(1);
176
- role = ROLE[entry[0]];
177
- }
178
- ase.presence(username, role, channel);
179
- }
180
- break;
182
+ /** */
183
+ case MOTD: // MOTD
184
+ if (!this.__buffer[MOTD]) {
185
+ this.__buffer[MOTD] = {
186
+ context: "irc",
187
+ type: "update",
188
+ actor: {
189
+ type: "service",
190
+ id: this.server,
191
+ name: this.server,
192
+ },
193
+ object: {
194
+ type: "topic",
195
+ content: content,
196
+ },
197
+ };
198
+ } else {
199
+ this.__buffer[MOTD].object.content += ` ${content}`;
200
+ }
201
+ break;
202
+ case MOTD_END: // end of MOTD
203
+ if (!this.__buffer[MOTD]) {
204
+ break;
205
+ }
206
+ ase.emitEvent(EVENT_INCOMING, this.__buffer[MOTD]);
207
+ delete this.__buffer[MOTD];
208
+ break;
181
209
 
182
- /** */
183
- case NICK: // nick change
184
- // debug(`- 2 nick: ${nick} from content: ${content}`);
185
- ase.nickChange(getNickFromServer(server), content);
186
- break;
210
+ /** */
211
+ case NAMES: // user list
212
+ for (const entry of content.split(" ")) {
213
+ role = "member";
214
+ let username = entry;
215
+ if (ROLE[entry[0]]) {
216
+ username = entry.substr(1);
217
+ role = ROLE[entry[0]];
218
+ }
219
+ ase.presence(username, role, channel);
220
+ }
221
+ break;
187
222
 
188
- /** */
189
- case NOTICE: // notice
190
- ase.notice(pos1, content);
191
- break;
223
+ /** */
224
+ case NICK: // nick change
225
+ // log(`- 2 nick: ${nick} from content: ${content}`);
226
+ ase.nickChange(getNickFromServer(server), content);
227
+ break;
192
228
 
193
- /** */
194
- case PART: // leaving
195
- ase.userPart(channel, getNickFromServer(server));
196
- break;
229
+ /** */
230
+ case NOTICE: // notice
231
+ ase.notice(pos1, content);
232
+ break;
197
233
 
198
- /** */
199
- case PONG: // ping response received
200
- this.events.emit(EVENT_PONG, `${Date.now()}`);
201
- break;
234
+ /** */
235
+ case PART: // leaving
236
+ ase.userPart(channel, getNickFromServer(server));
237
+ break;
202
238
 
203
- /** */
204
- case PRIVMSG: // msg
205
- ase.privMsg(getNickFromServer(server), pos1, content);
206
- break;
239
+ /** */
240
+ case PONG: // ping response received
241
+ this.events.emit(EVENT_PONG, `${Date.now()}`);
242
+ break;
207
243
 
208
- /** */
209
- case QUIT: // quit user
210
- ase.userQuit(getNickFromServer(server))
211
- break;
244
+ /** */
245
+ case PRIVMSG: // msg
246
+ ase.privMsg(getNickFromServer(server), pos1, content);
247
+ break;
212
248
 
213
- /** */
214
- case TOPIC_CHANGE: // topic changed now
215
- ase.topicChange(channel, getNickFromServer(server), content);
216
- break;
249
+ /** */
250
+ case QUIT: // quit user
251
+ ase.userQuit(getNickFromServer(server));
252
+ break;
217
253
 
218
- /** */
219
- case TOPIC_IS: // topic currently set to
220
- this.__buffer[TOPIC_IS] = {
221
- context: 'irc',
222
- type: 'update',
223
- actor: undefined,
224
- target: {
225
- type: 'room',
226
- id: this.server + '/' + channel,
227
- name: channel
228
- },
229
- object: {
230
- type: 'topic',
231
- content: content
232
- }
233
- };
234
- break;
235
- case TOPIC_SET_BY: // current topic set by
236
- if (! this.__buffer[TOPIC_IS]) { break; }
237
- nick = pos3.split('!')[0];
238
- this.__buffer[TOPIC_IS].actor = {
239
- type: 'person',
240
- id: nick + '@' + this.server,
241
- name: nick
242
- };
243
- this.__buffer[TOPIC_IS].published = msg[0];
244
- ase.emitEvent(EVENT_INCOMING, this.__buffer[TOPIC_IS]);
245
- delete this.__buffer[TOPIC_IS];
246
- break;
254
+ /** */
255
+ case TOPIC_CHANGE: // topic changed now
256
+ ase.topicChange(channel, getNickFromServer(server), content);
257
+ break;
247
258
 
248
- /** */
249
- case WHO:
250
- case WHO_OLD:
251
- nick = (msg[3].length <= 2) ? msg[2] : msg[3];
252
- if (nick === 'undefined') { break; }
253
- role = MODES[pos2[1]] || 'member';
254
- ase.presence(nick, role, channel);
255
- break;
259
+ /** */
260
+ case TOPIC_IS: // topic currently set to
261
+ this.__buffer[TOPIC_IS] = {
262
+ context: "irc",
263
+ type: "update",
264
+ actor: undefined,
265
+ target: {
266
+ type: "room",
267
+ id: `${this.server}/${channel}`,
268
+ name: channel,
269
+ },
270
+ object: {
271
+ type: "topic",
272
+ content: content,
273
+ },
274
+ };
275
+ break;
276
+ case TOPIC_SET_BY: // current topic set by
277
+ if (!this.__buffer[TOPIC_IS]) {
278
+ break;
279
+ }
280
+ nick = pos3.split("!")[0];
281
+ this.__buffer[TOPIC_IS].actor = {
282
+ type: "person",
283
+ id: `${nick}@${this.server}`,
284
+ name: nick,
285
+ };
286
+ this.__buffer[TOPIC_IS].published = msg[0];
287
+ ase.emitEvent(EVENT_INCOMING, this.__buffer[TOPIC_IS]);
288
+ delete this.__buffer[TOPIC_IS];
289
+ break;
256
290
 
257
- /** */
258
- default:
259
- this.events.emit(EVENT_UNPROCESSED, incoming);
260
- break;
261
- }
262
- }
263
- };
291
+ /** */
292
+ case WHO:
293
+ case WHO_OLD:
294
+ nick = msg[3].length <= 2 ? msg[2] : msg[3];
295
+ if (nick === "undefined") {
296
+ break;
297
+ }
298
+ role = MODES[pos2[1]] || "member";
299
+ ase.presence(nick, role, channel);
300
+ break;
264
301
 
265
- module.exports = IrcToActivityStreams;
302
+ /** */
303
+ default:
304
+ this.events.emit(EVENT_UNPROCESSED, incoming);
305
+ break;
306
+ }
307
+ }
308
+ }