-
Notifications
You must be signed in to change notification settings - Fork 10.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IRC Federation: RFC2813 implementation (ngIRCd) (#10113)
* Initial progress * Direct messaging complete * Handle net-splits * Cleaned up logging * more cleanup, better log messages * Added support for IRC users to create rooms and invite RC users * Keep rooms in sync * IRC user can kick RC user * Working on transcription of coffescript to ecmascript code and fitting on the codebase. * Adds settings section for config the IRC Server bridge. * Working handles for direct messages * Working handles for direct messages * Working handles for direct messages * Working handles for direct messages * Working handles for direct messages * Working on RC server connection to a local IRC Network * first version, using a RFC2813 implementation * Fixing lint errors * Fixed partial username * Fixed problems with scope * removed parser name * Added a button to reset the IRC connection * Adjusted messages * Fixed IRC federation for new users * Ignore eslint about control character on regex * Adjusted settings strings
- Loading branch information
1 parent
3ebb78d
commit 17a63ec
Showing
37 changed files
with
2,500 additions
and
525 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
This directory and the files immediately inside it are automatically generated | ||
when you change this package's NPM dependencies. Commit the files in this | ||
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control | ||
so that others run the same versions of sub-dependencies. | ||
|
||
You should NOT check in the node_modules directory that Meteor automatically | ||
creates; if you are using git, the .gitignore file tells git to ignore it. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,22 @@ | ||
Package.describe({ | ||
name: 'rocketchat:irc', | ||
version: '0.0.2', | ||
summary: 'RocketChat libraries', | ||
version: '0.0.1', | ||
summary: 'RocketChat support for federating with IRC servers as a leaf node', | ||
git: '' | ||
}); | ||
|
||
Package.onUse(function(api) { | ||
api.use([ | ||
'ecmascript', | ||
'underscore', | ||
'rocketchat:lib' | ||
]); | ||
|
||
api.addFiles([ | ||
'server/settings.js', | ||
'server/server.js' | ||
], 'server'); | ||
api.addFiles('server/irc.js', 'server'); | ||
api.addFiles('server/methods/resetIrcConnection.js', 'server'); | ||
api.addFiles('server/irc-settings.js', 'server'); | ||
}); | ||
|
||
api.export(['Irc'], ['server']); | ||
Npm.depends({ | ||
'queue-fifo': '0.2.4' | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import Queue from 'queue-fifo'; | ||
import * as servers from '../servers'; | ||
import * as peerCommandHandlers from './peerHandlers'; | ||
import * as localCommandHandlers from './localHandlers'; | ||
|
||
class Bridge { | ||
constructor(config) { | ||
// General | ||
this.config = config; | ||
|
||
// Workaround for Rocket.Chat callbacks being called multiple times | ||
this.loggedInUsers = []; | ||
|
||
// Server | ||
const Server = servers[this.config.server.protocol]; | ||
|
||
this.server = new Server(this.config); | ||
|
||
this.setupPeerHandlers(); | ||
this.setupLocalHandlers(); | ||
|
||
// Command queue | ||
this.queue = new Queue(); | ||
this.queueTimeout = 5; | ||
} | ||
|
||
init() { | ||
this.loggedInUsers = []; | ||
this.server.register(); | ||
|
||
this.server.on('registered', () => { | ||
this.logQueue('Starting...'); | ||
|
||
this.runQueue(); | ||
}); | ||
} | ||
|
||
stop() { | ||
this.server.disconnect(); | ||
} | ||
|
||
/** | ||
* Log helper | ||
*/ | ||
log(message) { | ||
console.log(`[irc][bridge] ${ message }`); | ||
} | ||
|
||
logQueue(message) { | ||
console.log(`[irc][bridge][queue] ${ message }`); | ||
} | ||
|
||
/** | ||
* | ||
* | ||
* Queue | ||
* | ||
* | ||
*/ | ||
onMessageReceived(from, command, ...parameters) { | ||
this.queue.enqueue({ from, command, parameters }); | ||
} | ||
|
||
async runQueue() { | ||
// If it is empty, skip and keep the queue going | ||
if (this.queue.isEmpty()) { | ||
return setTimeout(this.runQueue.bind(this), this.queueTimeout); | ||
} | ||
|
||
// Get the command | ||
const item = this.queue.dequeue(); | ||
|
||
this.logQueue(`Processing "${ item.command }" command from "${ item.from }"`); | ||
|
||
// Handle the command accordingly | ||
switch (item.from) { | ||
case 'local': | ||
if (!localCommandHandlers[item.command]) { | ||
throw new Error(`Could not find handler for local:${ item.command }`); | ||
} | ||
|
||
await localCommandHandlers[item.command].apply(this, item.parameters); | ||
break; | ||
case 'peer': | ||
if (!peerCommandHandlers[item.command]) { | ||
throw new Error(`Could not find handler for peer:${ item.command }`); | ||
} | ||
|
||
await peerCommandHandlers[item.command].apply(this, item.parameters); | ||
break; | ||
} | ||
|
||
// Keep the queue going | ||
setTimeout(this.runQueue.bind(this), this.queueTimeout); | ||
} | ||
|
||
/** | ||
* | ||
* | ||
* Peer | ||
* | ||
* | ||
*/ | ||
setupPeerHandlers() { | ||
this.server.on('peerCommand', (cmd) => { | ||
this.onMessageReceived('peer', cmd.identifier, cmd.args); | ||
}); | ||
} | ||
|
||
/** | ||
* | ||
* | ||
* Local | ||
* | ||
* | ||
*/ | ||
setupLocalHandlers() { | ||
// Auth | ||
RocketChat.callbacks.add('afterValidateLogin', this.onMessageReceived.bind(this, 'local', 'onLogin'), RocketChat.callbacks.priority.LOW, 'irc-on-login'); | ||
RocketChat.callbacks.add('afterCreateUser', this.onMessageReceived.bind(this, 'local', 'onCreateUser'), RocketChat.callbacks.priority.LOW, 'irc-on-create-user'); | ||
// Joining rooms or channels | ||
RocketChat.callbacks.add('afterCreateChannel', this.onMessageReceived.bind(this, 'local', 'onCreateRoom'), RocketChat.callbacks.priority.LOW, 'irc-on-create-channel'); | ||
RocketChat.callbacks.add('afterCreateRoom', this.onMessageReceived.bind(this, 'local', 'onCreateRoom'), RocketChat.callbacks.priority.LOW, 'irc-on-create-room'); | ||
RocketChat.callbacks.add('afterJoinRoom', this.onMessageReceived.bind(this, 'local', 'onJoinRoom'), RocketChat.callbacks.priority.LOW, 'irc-on-join-room'); | ||
// Leaving rooms or channels | ||
RocketChat.callbacks.add('afterLeaveRoom', this.onMessageReceived.bind(this, 'local', 'onLeaveRoom'), RocketChat.callbacks.priority.LOW, 'irc-on-leave-room'); | ||
// Chatting | ||
RocketChat.callbacks.add('afterSaveMessage', this.onMessageReceived.bind(this, 'local', 'onSaveMessage'), RocketChat.callbacks.priority.LOW, 'irc-on-save-message'); | ||
// Leaving | ||
RocketChat.callbacks.add('afterLogoutCleanUp', this.onMessageReceived.bind(this, 'local', 'onLogout'), RocketChat.callbacks.priority.LOW, 'irc-on-logout'); | ||
} | ||
|
||
sendCommand(command, parameters) { | ||
this.server.emit('onReceiveFromLocal', command, parameters); | ||
} | ||
} | ||
|
||
export default Bridge; |
9 changes: 9 additions & 0 deletions
9
packages/rocketchat-irc/server/irc-bridge/localHandlers/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import onCreateRoom from './onCreateRoom'; | ||
import onJoinRoom from './onJoinRoom'; | ||
import onLeaveRoom from './onLeaveRoom'; | ||
import onLogin from './onLogin'; | ||
import onLogout from './onLogout'; | ||
import onSaveMessage from './onSaveMessage'; | ||
import onCreateUser from './onCreateUser'; | ||
|
||
export { onCreateRoom, onJoinRoom, onLeaveRoom, onLogin, onLogout, onSaveMessage, onCreateUser }; |
15 changes: 15 additions & 0 deletions
15
packages/rocketchat-irc/server/irc-bridge/localHandlers/onCreateRoom.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export default function handleOnCreateRoom(user, room) { | ||
if (!room.usernames) { | ||
return this.log(`Room ${ room.name } does not have a valid list of usernames`); | ||
} | ||
|
||
for (const username of room.usernames) { | ||
const user = RocketChat.models.Users.findOne({ username }); | ||
|
||
if (user.profile.irc.fromIRC) { | ||
this.sendCommand('joinChannel', { room, user }); | ||
} else { | ||
this.sendCommand('joinedChannel', { room, user }); | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
packages/rocketchat-irc/server/irc-bridge/localHandlers/onCreateUser.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export default function handleOnCreateUser(newUser) { | ||
if (!newUser) { | ||
return this.log('Invalid handleOnCreateUser call'); | ||
} | ||
if (!newUser.username) { | ||
return this.log('Invalid handleOnCreateUser call (Missing username)'); | ||
} | ||
if (this.loggedInUsers.indexOf(newUser._id) !== -1) { | ||
return this.log('Duplicate handleOnCreateUser call'); | ||
} | ||
|
||
this.loggedInUsers.push(newUser._id); | ||
|
||
Meteor.users.update({ _id: newUser._id }, { | ||
$set: { | ||
'profile.irc.fromIRC': false, | ||
'profile.irc.username': `${ newUser.username }-rkt`, | ||
'profile.irc.nick': `${ newUser.username }-rkt`, | ||
'profile.irc.hostname': 'rocket.chat' | ||
} | ||
}); | ||
|
||
const user = RocketChat.models.Users.findOne({ | ||
_id: newUser._id | ||
}); | ||
|
||
this.sendCommand('registerUser', user); | ||
|
||
const rooms = RocketChat.models.Rooms.findWithUsername(user.username).fetch(); | ||
|
||
rooms.forEach(room => this.sendCommand('joinedChannel', { room, user })); | ||
} |
3 changes: 3 additions & 0 deletions
3
packages/rocketchat-irc/server/irc-bridge/localHandlers/onJoinRoom.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function handleOnJoinRoom(user, room) { | ||
this.sendCommand('joinedChannel', { room, user }); | ||
} |
3 changes: 3 additions & 0 deletions
3
packages/rocketchat-irc/server/irc-bridge/localHandlers/onLeaveRoom.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function handleOnLeaveRoom(user, room) { | ||
this.sendCommand('leftChannel', { room, user }); | ||
} |
32 changes: 32 additions & 0 deletions
32
packages/rocketchat-irc/server/irc-bridge/localHandlers/onLogin.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export default function handleOnLogin(login) { | ||
if (login.user === null) { | ||
return this.log('Invalid handleOnLogin call'); | ||
} | ||
if (!login.user.username) { | ||
return this.log('Invalid handleOnLogin call (Missing username)'); | ||
} | ||
if (this.loggedInUsers.indexOf(login.user._id) !== -1) { | ||
return this.log('Duplicate handleOnLogin call'); | ||
} | ||
|
||
this.loggedInUsers.push(login.user._id); | ||
|
||
Meteor.users.update({ _id: login.user._id }, { | ||
$set: { | ||
'profile.irc.fromIRC': false, | ||
'profile.irc.username': `${ login.user.username }-rkt`, | ||
'profile.irc.nick': `${ login.user.username }-rkt`, | ||
'profile.irc.hostname': 'rocket.chat' | ||
} | ||
}); | ||
|
||
const user = RocketChat.models.Users.findOne({ | ||
_id: login.user._id | ||
}); | ||
|
||
this.sendCommand('registerUser', user); | ||
|
||
const rooms = RocketChat.models.Rooms.findWithUsername(user.username).fetch(); | ||
|
||
rooms.forEach(room => this.sendCommand('joinedChannel', { room, user })); | ||
} |
7 changes: 7 additions & 0 deletions
7
packages/rocketchat-irc/server/irc-bridge/localHandlers/onLogout.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import _ from 'underscore'; | ||
|
||
export default function handleOnLogout(user) { | ||
this.loggedInUsers = _.without(this.loggedInUsers, user._id); | ||
|
||
this.sendCommand('disconnected', { user }); | ||
} |
32 changes: 32 additions & 0 deletions
32
packages/rocketchat-irc/server/irc-bridge/localHandlers/onSaveMessage.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export default function handleOnSaveMessage(message, to) { | ||
let toIdentification = ''; | ||
// Direct message | ||
if (to.t === 'd') { | ||
const subscriptions = RocketChat.models.Subscriptions.findByRoomId(to._id); | ||
subscriptions.forEach((subscription) => { | ||
if (subscription.u.username !== to.username) { | ||
const userData = RocketChat.models.Users.findOne({ username: subscription.u.username }); | ||
if (userData) { | ||
if (userData.profile && userData.profile.irc && userData.profile.irc.nick) { | ||
toIdentification = userData.profile.irc.nick; | ||
} else { | ||
toIdentification = userData.username; | ||
} | ||
} else { | ||
toIdentification = subscription.u.username; | ||
} | ||
} | ||
}); | ||
|
||
if (!toIdentification) { | ||
console.error('[irc][server] Target user not found'); | ||
return; | ||
} | ||
} else { | ||
toIdentification = `#${ to.name }`; | ||
} | ||
|
||
const user = RocketChat.models.Users.findOne({ _id: message.u._id }); | ||
|
||
this.sendCommand('sentMessage', { to: toIdentification, user, message: message.msg }); | ||
} |
13 changes: 13 additions & 0 deletions
13
packages/rocketchat-irc/server/irc-bridge/peerHandlers/disconnected.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export default function handleQUIT(args) { | ||
const user = RocketChat.models.Users.findOne({ | ||
'profile.irc.nick': args.nick | ||
}); | ||
|
||
Meteor.users.update({ _id: user._id }, { | ||
$set: { | ||
status: 'offline' | ||
} | ||
}); | ||
|
||
RocketChat.models.Rooms.removeUsernameFromAll(user.username); | ||
} |
Oops, something went wrong.