Permalink
Browse files

Attempt at "tell" plugin

  • Loading branch information...
Jonas Westerlund
Jonas Westerlund committed Mar 30, 2012
1 parent 71161a0 commit d90226805fd37ef5b5eae7bfb0757b9fa07912d4
Showing with 245 additions and 11 deletions.
  1. +4 −2 examples/bot.js
  2. +30 −9 plugins/seen.js
  3. +56 −0 plugins/shared.js
  4. +155 −0 plugins/tell.js
View
@@ -6,7 +6,8 @@ const path = require( "path" )
, lib = path.join( here, "..", "lib" )
, IRC = require( path.join( lib, "irc" ) ).IRC
, clr = require( path.join( lib, "color" ) )
- , lol = require( "../plugins/seen" )
+ , seen = require( "../plugins/seen" )
+ , tell = require( "../plugins/tell" )
// Get a path to your config file. If not provided, it will look for
// "config.json" in the current working directory.
@@ -96,4 +97,5 @@ bot.lookFor( fmt( "@?%s[: ]+(?:join|add) +([+!#&][^ ]+)(?: +([^ ]+))?", bot.user
})
})
-lol.register( bot )
+seen.register( bot )
+tell.register( bot )
View
@@ -6,13 +6,16 @@ const redis = require( "redis" )
, cnst = require( "../lib/constants" )
, obj = require( "../lib/objects" )
, parse = require( "../lib/parser" )
+ , log = require( "../lib/logger" )
+
+const logger = log.get( "ircjs" )
const TOKEN = "ff774f90da063a0dfa783172f16af4e3"
, HOST = "pike.redistogo.com"
, PORT = 9475
// Redis events
-const EVENT =
+const REDIS =
{ ERROR: "error"
}
@@ -26,24 +29,38 @@ const Seen = function( irc ) {
rclient.auth( TOKEN )
this.client = rclient
this.irc = irc
+
+ this.client.on( REDIS.ERROR, this.error.bind( this ) )
+}
+
+Seen.prototype.error = function( err ) {
+ logger.log( log.LEVEL.ERROR, "Seen Redis client error: %s", err )
}
-Seen.prototype.seen = function( msg, name ) {
+Seen.prototype.seen = function( msg, name, num ) {
const key = getKey( new obj.Person( name, null, null ).id ) // >_>
+ , ix = num || 0 // Bonus feature
if ( msg.prefix.nick === name )
return msg.reply( fmt( "%s, I see you right now, here in %s.", msg.prefix.nick
, this.irc.user.nick === msg.params[0] ? "our cozy private chat" : msg.params[0] ) )
if ( this.irc.user.nick === name )
return msg.reply( fmt( "%s, I am here with you in %s.", msg.prefix.nick
, this.irc.user.nick === msg.params[0] ? "our sexy private chat" : msg.params[0] ) )
- this.client.lindex( key, 0, this.reply.bind( this, msg, name ) )
+ this.client.lindex( key, ix, this.reply.bind( this, msg, name ) )
}
Seen.prototype.reply = function( msg, name, err, res ) {
- if ( err )
- return msg.reply( fmt( "%s, I went to see, but there was an error: %s", err ) )
- if ( ! res )
- return msg.reply( fmt( "%s, sorry, I have never seen %s.", msg.prefix.nick, name ) )
+ logger.log( log.LEVEL.DEBUG, "Replying to `seen` inquiry" )
+ if ( err ) {
+ msg.reply( fmt( "%s, I went to see, but there was an error: %s", err ) )
+ logger.log( log.LEVEL.DEBUG, "`seen` failed: %s", err )
+ return
+ }
+ if ( ! res ) {
+ msg.reply( fmt( "%s, sorry, I have never seen %s.", msg.prefix.nick, name ) )
+ logger.log( log.LEVEL.DEBUG, "Did not find any entries for %s", name )
+ return
+ }
const parts = res.match( /^(\d+)(.+)/ )
, date = new Date( Number( parts[1] ) )
, mesg = parse.message( parts[2] + "\r\n" )
@@ -84,18 +101,21 @@ Seen.prototype.reply = function( msg, name, err, res ) {
reply += fmt( " %s is here right now.", name )
msg.reply( reply )
+ logger.log( log.LEVEL.DEBUG, "Found stuff for %s, replied: %s", name, reply )
}
Seen.prototype.log = function( msg ) {
if ( ! ( msg.prefix instanceof obj.Person ) )
- return this
+ return
const now = Date.now()
, key = getKey( msg.prefix.id )
, val = now + msg
this.client.lpush( key, val )
+ logger.log( log.LEVEL.DEBUG, "Pushed message into Redis (maybe)" )
}
Seen.prototype.disconnect = function( msg ) {
+ logger.log( log.LEVEL.INFO, "Telling seen.js redis client to quit" )
this.client.quit()
}
@@ -123,7 +143,8 @@ const register = function( irc ) {
const s = new Seen( irc )
irc.observe( cnst.EVENT.ANY, s.log.bind( s ) )
irc.observe( cnst.EVENT.DISCONNECT, s.disconnect.bind( s ) )
- irc.lookFor( /\bseen +([-`_\{\}\[\]\^\|\\a-z0-9]+)/i, s.seen.bind( s ) )
+ irc.lookFor( /\bseen +([-`_\{\}\[\]\^\|\\a-z0-9]+)(?: +(\d+))?/i, s.seen.bind( s ) )
+ logger.log( log.LEVEL.INFO, "Registered Seen plugin" )
return "Hooray"
}
View
@@ -0,0 +1,56 @@
+const fmt = require( "util" ).format
+ , obj = require( "../lib/objects" )
+
+// Redis stuff
+const TOKEN = "ff774f90da063a0dfa783172f16af4e3"
+ , HOST = "pike.redistogo.com"
+ , PORT = 9475
+
+// Redis events
+const EVENT =
+ { ERROR: "error"
+ }
+
+const getKey = function( nick, prefix ) {
+ const id = nick instanceof obj.Person ? nick.id : new obj.Person( nick, null, null ).id
+ , p = prefix || "IRCJS"
+ return p + id
+}
+
+const timeAgo = function( t ) {
+ var diff = Math.round( ( Date.now() - t ) / 1000 )
+ const days = Math.floor( diff / 86400 )
+ , hours = Math.floor( ( diff -= days * 86400 ) / 3600 )
+ , mins = Math.floor( ( diff -= hours * 3600 ) / 60 )
+ , secs = Math.floor( ( diff -= mins * 60 ) )
+ , ago = []
+
+ if ( days )
+ ago.push( days === 1 ? "one day" : days + " days" )
+ if ( hours )
+ ago.push( hours === 1 ? "one hour" : hours + " hours" )
+ if ( mins )
+ ago.push( mins === 1 ? "one minute" : mins + " minutes" )
+ if ( secs )
+ ago.push( secs === 1 ? "one second" : secs + " seconds" )
+ ago.splice( 2 )
+ return ago.join( " and " )
+}
+
+const join = function( arr ) {
+ const last = arr.pop()
+ if ( arr.length === 0 )
+ return last
+ return fmt( "%s and %s", arr.join( ", " ), last )
+}
+
+exports.join = join
+exports.timeAgo = timeAgo
+
+exports.redis =
+ { EVENT: EVENT
+ , TOKEN: TOKEN
+ , HOST: HOST
+ , PORT: PORT
+ , key: getKey
+ }
View
@@ -0,0 +1,155 @@
+/** @module tell
+ * @todo Only add observers for people who have notes waiting for them.
+ * Then remove when list is empty.
+ */
+
+const redis = require( "redis" )
+ , fmt = require( "util" ).format
+ , cnst = require( "../lib/constants" )
+ , obj = require( "../lib/objects" )
+ , parse = require( "../lib/parser" )
+ , log = require( "../lib/logger" )
+ , shrd = require( "./shared" )
+
+const rds = shrd.redis
+
+const logger = log.get( "ircjs" )
+
+const RPREFIX = "TELL"
+
+const DELIM = String.fromCharCode( 0x7 )
+
+const Note = function( from, to, note ) {
+ this.date = Date.now()
+ this.from = from
+ this.to = rds.key( to, RPREFIX )
+ this.note = note
+ this.new = true
+}
+
+Note.prototype.toString = function() {
+ return [ this.new, this.date, this.from, this.to, this.note ].join( DELIM )
+}
+
+Note.fromString = function( s ) {
+ const parts = s.split( DELIM )
+ , note = new Note( parts[2], parts[3], parts[4] )
+ note.new = parts[0] === "true" ? true : false
+ note.date = Number( parts[1] )
+ return note
+}
+
+const Tell = function( irc ) {
+ const rclient = redis.createClient( rds.PORT, rds.HOST )
+ rclient.auth( rds.TOKEN )
+ this.client = rclient
+ this.irc = irc
+
+ this.client.on( rds.EVENT.ERROR, this.error.bind( this ) )
+}
+
+Tell.prototype.error = function( err ) {
+ logger.log( log.LEVEL.ERROR, "tell.js redis client error: %s", err )
+}
+
+Tell.prototype.tell = function( msg, num ) {
+ // Probably full of async-y bugs, how to update a bunch of items at once and get a callback?
+ const nick = msg.prefix.nick
+ , key = rds.key( msg.prefix, RPREFIX )
+ this.client.lrange( key, 0, -1, function( err, notes ) {
+ if ( err ) {
+ logger.log( log.LEVEL.ERROR, "Redis error in tell.js Tell.prototype.tell: %s", err )
+ return
+ }
+ if ( ! notes || 0 === notes.length )
+ return
+
+ var reply = null
+ , note = null
+ , new_ = []
+ , i = 0
+ , l = notes.length
+ for ( ; i < l ; ++i ) {
+ note = Note.fromString( notes[i] )
+ if ( ! note.new )
+ continue
+ new_.push( fmt( "%s (%s ago)", note.from, shrd.timeAgo( note.date ) ) )
+ note.new = false
+ logger.log( log.LEVEL.DEBUG, "Marking note from %s (%s) as not new", note.from, note )
+ this.client.lset( key, i, note.toString() )
+ }
+ l = new_.length
+ if ( 0 === l )
+ return
+ reply = fmt( "%s, you have %s, from %s. Tell me if you want to read %s (“read”)."
+ , nick, l === 1 ? "one new message" : l + " new messages"
+ , shrd.join( new_ ), l === 1 ? "it" : "them" )
+ msg.reply( reply )
+ }.bind( this ) )
+}
+
+Tell.prototype.read = function( msg ) {
+ const nick = msg.prefix.nick
+ , pm = msg.params[0] === this.irc.user.nick
+ , forMe = pm || -1 !== msg.params[1].indexOf( this.irc.user.nick )
+ , key = rds.key( msg.prefix, RPREFIX )
+
+ if ( ! forMe )
+ return
+
+ this.client.lrange( key, 0, -1, function( err, notes ) {
+ if ( err ) {
+ logger.log( log.LEVEL.ERROR, "Redis error in tell.js: %s", err )
+ return
+ }
+
+ if ( ! notes || 0 === notes.length ) {
+ msg.reply( fmt( "%sI have no messages for you.", pm ? "" : nick + ", " ) )
+ return
+ }
+ var l = notes.length
+ , note = null
+ while ( l-- ) {
+ note = Note.fromString( notes[l] )
+ msg.reply( fmt( "%s, from %s, %s ago: %s", pm ? "" : nick + ", ", note.from, shrd.timeAgo( note.date ), note.note ) )
+ }
+ this.client.del( key )
+ }.bind( this ) )
+}
+
+Tell.prototype.add = function( msg, name, note ) {
+ const forMe = -1 !== msg.params[1].indexOf( this.irc.user.nick )
+ , from = msg.prefix.nick
+ , key = rds.key( name, RPREFIX )
+ if ( ! forMe )
+ return
+ if ( key === rds.key( from, RPREFIX ) ) {
+ msg.reply( fmt( "%s, %s", from, note ) )
+ return
+ }
+ if ( key === rds.key( this.irc.user.nick, RPREFIX ) ) {
+ msg.reply( fmt( "%s, whatever you say…", from ) )
+ return
+ }
+ const rnote = new Note( from, key, note )
+ this.client.lpush( key, rnote.toString() )
+ msg.reply( fmt( "%s, OK, I will tell %s if I see them.", from, name ) )
+ logger.log( log.LEVEL.DEBUG, "Added note from %s to %s: %s", from, name, note )
+}
+
+Tell.prototype.disconnect = function( msg ) {
+ logger.log( log.LEVEL.INFO, "Telling tell.js Redis client to quit" )
+ this.client.quit()
+}
+
+const register = function( irc ) {
+ const tell = new Tell( irc )
+ irc.lookFor( /\btell +([-`_\{\}\[\]\^\|\\a-z0-9]+) +(.+)$/i, tell.add.bind( tell ) )
+ irc.lookFor( /\bread\b/i, tell.read.bind( tell ) )
+ irc.observe( cnst.COMMAND.PRIVMSG, tell.tell.bind( tell ) ) // tell tell, tell. also: tell
+ irc.observe( cnst.EVENT.DISCONNECT, tell.disconnect.bind( tell ) )
+ logger.log( log.LEVEL.INFO, "Registered Tell plugin" )
+ return "Yay"
+}
+
+exports.register = register

0 comments on commit d902268

Please sign in to comment.