UNPKG

@thaunknown/web-irc

Version:

A TypeScript port of irc-framework's WebIRC client, without the bloat of unnceessary packages.

182 lines 6.86 kB
import { Duplex } from 'streamx'; import { partial, filter, find, each, pull, extend } from './util'; export default class IrcChannel { ircClient; name; say; notice; part; join; mode; banlist; ban; unban; users; constructor(ircClient, channelName, key) { this.ircClient = ircClient; this.name = channelName; // TODO: Proxy channel related events from irc_bot to this instance this.say = partial(ircClient.say.bind(ircClient), channelName); this.notice = partial(ircClient.notice.bind(ircClient), channelName); // this.action = partial(irc_client.action.bind(irc_client), channel_name); this.part = partial(ircClient.part.bind(ircClient), channelName); this.join = partial(ircClient.join.bind(ircClient), channelName); this.mode = partial(ircClient.mode.bind(ircClient), channelName); this.banlist = partial(ircClient.banlist.bind(ircClient), channelName); this.ban = partial(ircClient.ban.bind(ircClient), channelName); this.unban = partial(ircClient.unban.bind(ircClient), channelName); this.users = []; ircClient.on('userlist', (event) => { if (ircClient.caseCompare(event.channel, this.name)) { this.users = event.users; } }); ircClient.on('join', (event) => { if (ircClient.caseCompare(event.channel, this.name)) { this.users.push(event); } }); ircClient.on('part', (event) => { if (ircClient.caseCompare(event.channel, this.name)) { this.users = filter(this.users, function (o) { return !ircClient.caseCompare(event.nick, o.nick); }); } }); ircClient.on('kick', (event) => { if (ircClient.caseCompare(event.channel, this.name)) { this.users = filter(this.users, function (o) { return !ircClient.caseCompare(event.kicked, o.nick); }); } }); ircClient.on('quit', (event) => { this.users = filter(this.users, function (o) { return !ircClient.caseCompare(event.nick, o.nick); }); }); ircClient.on('nick', (event) => { find(this.users, function (o) { if (ircClient.caseCompare(event.nick, o.nick)) { o.nick = event.new_nick; return true; } }); }); ircClient.on('mode', (event) => { /* event will be something like: { target: '#prawnsalad', nick: 'ChanServ', modes: [ { mode: '+o', param: 'prawnsalad' } ], time: undefined } */ if (!ircClient.caseCompare(event.target, this.name)) { return; } // There can be multiple modes set at once, loop through each(event.modes, mode => { // If this mode has a user prefix then we need to update the user object // eg. +o +h +v const userPrefix = ircClient.network.options.PREFIX.find(pref => { return pref.mode === mode.mode; }); if (!userPrefix) { // TODO : manage channel mode changes } else { // It's a user mode // Find the user affected const user = find(this.users, u => ircClient.caseCompare(u.nick, mode.param)); if (!user) { return; } if (mode.mode[0] === '+') { user.modes = user.modes || []; user.modes.push(mode.mode[1]); } else { pull(user.modes, mode.mode[1]); } } }); }); this.join(key); } /** * Relay messages between this channel to another * @param {IrcChannel|String} targetChan Target channel * @param {Object} opts Extra options * * opts may contain the following properties: * one_way (false) Only relay messages to target_chan, not the reverse * replay_nicks (true) Include the sending nick as part of the relayed message */ relay(targetChan, opts) { opts = extend({ one_way: false, replay_nicks: true }, opts); if (typeof targetChan === 'string') { targetChan = this.ircClient.channel(targetChan); } const thisStream = this.stream(opts); const otherStream = targetChan.stream(opts); thisStream.pipe(otherStream); if (!opts.one_way) { otherStream.pipe(thisStream); } } stream(streamOpts) { const readQueue = []; let isReading = false; const stream = new Duplex({ objectMode: true, write: (chunk, encoding, next) => { // Support piping from one irc buffer to another if (typeof chunk === 'object' && typeof chunk.message === 'string') { if (streamOpts.replay_nicks) { chunk = '<' + chunk.nick + '> ' + chunk.message; } else { chunk = chunk.message; } } this.say(chunk.toString()); next(); }, read: () => { isReading = true; while (readQueue.length > 0) { const message = readQueue.shift(); if (stream.push(message) === false) { isReading = false; break; } } } }); this.ircClient.on('privmsg', (event) => { if (this.ircClient.caseCompare(event.target, this.name)) { readQueue.push(event); if (isReading) { stream._read(); } } }); return stream; } updateUsers(cb) { const updateUserList = (event) => { if (this.ircClient.caseCompare(event.channel, this.name)) { this.ircClient.removeListener('userlist', updateUserList); if (typeof cb === 'function') { cb(this); } } }; this.ircClient.on('userlist', updateUserList); this.ircClient.raw('NAMES', this.name); } } //# sourceMappingURL=channel.js.map