Permalink
Browse files

More robust joining with proper error handling

  • Loading branch information...
1 parent 6632d6b commit e35e1cdc1e89b3e1c2a09b48fec4898d484c9b0e Jonas Westerlund committed Mar 28, 2012
Showing with 391 additions and 174 deletions.
  1. +14 −8 examples/basic/bot.js
  2. +21 −6 lib/constants.js
  3. +29 −17 lib/irc.js
  4. +7 −8 lib/map.js
  5. +90 −16 lib/objects.js
  6. +13 −3 lib/observable.js
  7. +73 −33 lib/observers.js
  8. +4 −0 spec/helpers.js
  9. +36 −43 spec/lib/irc.spec.js
  10. +88 −32 spec/lib/objects.spec.js
  11. +4 −4 spec/lib/observable.spec.js
  12. +12 −4 spec/mockstream.js
View
@@ -65,22 +65,28 @@ bot.lookFor( fmt( "@?%s[: ]+(?:quit|shutdown|die|disconnect) ?(.+)?", bot.user.n
bot.lookFor( fmt( "@?%s[: ]+(?:part|leave|gtfo)(?: +([+!#&][^ ]+))?(?: (.+))?", bot.user.nick )
, function( msg, name, txt ) {
const chan = bot.channels.get( name || msg.params[0] )
+ , from = msg.prefix.nick
if ( ! chan )
- return msg.reply( fmt( "I’m not in %s.", name ) )
- chan.part( txt ? txt.trim() : fmt( "%s told me to leave. Bye!", msg.prefix.nick ) )
+ return msg.reply( fmt( "%s, I’m not in %s.", from, name ) )
+ chan.part( txt ? txt.trim() : fmt( "%s told me to leave. Bye!", from ) )
if ( chan.name !== msg.params[0] )
- msg.reply( fmt( "I have left %s.", chan.name ) )
+ msg.reply( fmt( "%s, I have left %s.", from, chan.name ) )
})
bot.lookFor( fmt( "@?%s[: ]+(?:join|add) +([+!#&][^ ]+)(?: +([^ ]+))?", bot.user.nick )
, function( msg, name, key ) {
const chan = bot.channels.get( name )
+ , from = msg.prefix.nick
if ( chan && chan.name === msg.params[0] )
- return msg.reply( fmt( "I am already here, %s.", msg.prefix.nick ) )
+ return msg.reply( fmt( "%s, I am already here!", from ) )
else if ( chan )
- return msg.reply( fmt( "I am already in %s, and I can prove it. The topic is as follows. %s"
- , name, chan.topic || "Hmm, appears to be empty." ) )
- bot.channels.add( name, key, function( chan ) {
- msg.reply( fmt( "I am now in %s%s", name, key ? fmt( ", I used “%s” to get in.", key ) : "." ) )
+ return msg.reply( fmt( "%s, I am already in %s, and I can prove it. The topic is as follows. %s"
+ , from, name, chan.topic || "Hmm, appears to be empty." ) )
+ bot.channels.add( name, key, function( chan, err ) {
+ if ( err ) {
+ msg.reply( fmt( "%s, there was an error when I tried to join %s. Server said “%s”.", from, name, err.message ) )
+ return
+ }
+ msg.reply( fmt( "%s: I am now in %s%s", from, name, key ? fmt( ", I used “%s” to get in.", key ) : "." ) )
})
})
View
@@ -7,6 +7,17 @@ const EVENT =
, ERROR: "3"
}
+// Stuff used in Node socket
+const SOCKET =
+ { CLOSE: "close"
+ , CONNECT: "connect"
+ , DATA: "data"
+ , DRAIN: "drain"
+ , END: "end"
+ , ERROR: "error"
+ , TIMEOUT: "timeout"
+ }
+
// IRC protocol commands and codes
// Generated from data @ http://www.networksorcery.com/enp/protocol/irc.htm
// Additional modes found @ http://freenode.net/using_the_network.shtml
@@ -194,6 +205,8 @@ const ERROR =
, YOUREBANNEDCREEP: "465"
, YOUWILLBEBANNED: "466"
, KEYSET: "467"
+ // 470 Found here http://freenode.net/using_the_network.shtml
+ , NOINVITEFORWARD: "470"
, CHANNELISFULL: "471"
, UNKNOWNMODE: "472"
, INVITEONLYCHAN: "473"
@@ -291,13 +304,14 @@ const USERCHAR =
, 'Z': USERMODE.SECURE
}
-Object.keys( CHANCHAR ).forEach( function( k ) {
- CHANCHAR[CHANCHAR[k]] = k
-} )
+var k, v
+for ( k in CHANCHAR )
+ v = CHANCHAR[k]
+ , CHANCHAR[v] = k
-Object.keys( USERCHAR ).forEach( function( k ) {
- USERCHAR[USERCHAR[k]] = k
-} )
+for ( k in USERCHAR )
+ v = USERCHAR[k]
+ , USERCHAR[v] = k
const MODE =
{ CHANNEL: CHANMODE
@@ -313,3 +327,4 @@ exports.COMMAND = COMMAND
exports.ERROR = ERROR
exports.MODE = MODE
exports.REPLY = REPLY
+exports.SOCKET = SOCKET
View
@@ -30,6 +30,7 @@ const events = require( "events" )
const Channel = objects.Channel
, IRCMap = map.IRCMap
, Message = objects.Message
+ , Observable= observe.Observable
, Person = objects.Person
, Server = objects.Server
// Factory functions
@@ -46,6 +47,7 @@ const Channel = objects.Channel
, MODE = constants.MODE
, REPLY = constants.REPLY
, STATUS = observe.STATUS
+ , SOCKET = constants.SOCKET
// Level is (re)set later, when config is read
const logger = log.get( "ircjs", LEVEL.ALL )
@@ -62,6 +64,8 @@ const getConfig = function( conf ) {
// Maximum message length, not counting the "\r\n" terminating sequence
const MAXLEN = 510
+const queue = []
+
/** IRC!
* The star of the show.
*
@@ -71,6 +75,7 @@ const MAXLEN = 510
*/
const IRC = function( conf ) {
const config = getConfig( conf )
+ , server = config.server
, internal =
{ buffer: []
, connected: false
@@ -81,11 +86,13 @@ const IRC = function( conf ) {
logger.level = LEVEL.fromString( config["log"] )
- this.user = new Person( config["nick"], null, null )
this.config = config
+ this.server = new Server( server.address, server.port )
+ this.user = new Person( config["nick"], null, null )
+
this.channels = IRCMap.of( Channel ).for( this )
- this.observers = new observe.Observable().for( this )
+ this.observers = Observable.of( this ).for( this )
// Priviliged methods
this.connect = connect.bind( this, internal )
@@ -94,10 +101,6 @@ const IRC = function( conf ) {
// Add all default observers
observers.register( this )
-
- // :(
- if ( TEST )
- this._internal = internal
}
/** @private
@@ -164,7 +167,6 @@ const onData = function( internal, data ) {
internal.buffer.push( last )
// Emit!
- l = buffer.length
for ( i = 0, l = buffer.length; i < l; ++i ) {
logger.log( LEVEL.INFO, "[RECV] %s", buffer[i] )
@@ -177,8 +179,8 @@ const onData = function( internal, data ) {
// Give superpowers
message.for( this )
- this.observers.notify( EVENT.ANY, message )
this.observers.notify( message.command, message )
+ this.observers.notify( EVENT.ANY, message )
}
}
@@ -197,24 +199,30 @@ const connect = function( internal, callback ) {
return this
}
- internal.socket = connect( this.config.server.port, this.config.server.address )
+ internal.socket = connect( this.server.port, this.server.name )
internal.socket.setEncoding( this.config.encoding )
internal.socket.setTimeout( 0 )
- internal.socket.addListener( "connect", onConnect.bind( this, internal ) )
- internal.socket.addListener( "data", onData.bind( this, internal ) )
- internal.socket.addListener( "timeout", this.disconnect )
+ internal.socket.addListener( SOCKET.CONNECT, onConnect.bind( this, internal ) )
+ internal.socket.addListener( SOCKET.DATA, onData.bind( this, internal ) )
+ internal.socket.addListener( SOCKET.TIMEOUT, this.disconnect )
+
+ this.observe( REPLY.MYINFO, function( msg ) {
+ const name = msg.params[1]
+ logger.log( LEVEL.DEBUG, "[DEBUG] Updating server name from %s to %s", this.server.name, name )
+ this.server.name = name
+ return STATUS.SUCCESS | STATUS.REMOVE
+ }.bind( this ) )
if ( 2 === arguments.length ) // Do all servers send a 001 ?
this.observe( REPLY.WELCOME
, function( _ ) {
- callback()
- return STATUS.SUCCESS | STATUS.REMOVE } )
+ callback( this )
+ return STATUS.SUCCESS | STATUS.REMOVE }.bind( this ) )
// Forward network errors
- internal.socket.addListener( "error", function( er ) {
- this.observers.notify( EVENT.ERROR, er )
- })
+ internal.socket.addListener( SOCKET.ERROR
+ , this.observers.notify.bind( this.observers, EVENT.ERROR ) )
return this
}
@@ -336,6 +344,10 @@ IRC.prototype.setMode = function( mode ) {
return this.send( message( COMMAND.MODE, [ this.user.nick, mode ] ) )
}
+const Success = function( message ) {
+ this.message = message || ""
+}
+
exports.IRC = IRC
// Re-exports
View
@@ -127,21 +127,20 @@ const removeChannel = function( channel ) {
* @return {Person}
*/
const addPerson = function( prsn ) {
+
const exists = this.get( prsn )
, nick = prsn instanceof Person ? prsn.nick : prsn
, nkey = key( nick )
, cached = _people[nkey]
if ( exists )
return exists
- if ( ! cached )
- this[nkey] = _people[nkey]
- = prsn instanceof Person ? prsn
- : new Person( nick, null, null )
- return this[nkey]
+ if ( cached )
+ return this[nkey] = _people[nkey]
+ return this[nkey] = _people[nkey] =
+ prsn instanceof Person ? prsn : new Person( nick, null, null )
}
const getPerson = function( p ) {
- if ( p instanceof Person && p.nick === undefined ) throw Error(p)
const k = key( p instanceof Person ? p.nick : p )
return this[k] || null
}
@@ -167,10 +166,10 @@ const charMap =
}
const chars = function( c ) { return charMap[c] }
-const re = /[|{}^]/g
+ , regex = /[|{}^]/g
const key = function( s ) {
- return s.toUpperCase().replace( re, chars )
+ return "$" + s.toUpperCase().replace( regex, chars )
}
exports.IRCMap = IRCMap
Oops, something went wrong.

0 comments on commit e35e1cd

Please sign in to comment.