Commits

firefly committed 6d85f51

Refactored `BufferedSocket` to better match how `Socket` and the `net` module works.
Updated commands to match the new parallel-execution-friendly execution system. Various
minor source code adjustments.

  • Participants
  • Parent commits c3977e2

Comments (0)

Files changed (5)

File modules/core.coffee

 		exec.stdin.on 'data', (data) ->
 			exec.output data
 
+	"eval": (exec, expr) ->
+		exec.output eval expr
+
+	"reload": ->
+		bot.reloadModule module for module in bot.modules
+		@output "Done!"
+	
+	"commands": ->
+		@output cmd for cmd of bot.shell.commands
+
 	"rev":  @manual (exec) ->
 		outputBuffer = []
 
 			console.log "Outputting", outputBuffer
 			exec.end.apply exec, outputBuffer
 
-	"sel":  (exec, selector) ->
-		exec.stdin.on 'data', (data) ->
-			results = require('../deps/JSONSelect').match selector, data
-			exec.output result for result in results
-
 	"grep": (exec, pattern) ->
 		regex = new RegExp pattern
 
 		exec.stdin.on 'data', (data) ->
 			exec.output data.replace regex, replacement
 
-	"eval": (exec, expr) ->
-		exec.output eval expr
+	"sel":  (exec, selector) ->
+		exec.stdin.on 'data', (data) ->
+			results = require('../deps/JSONSelect').match selector, data
+			exec.output result for result in results
 
-	"addCommand": (name, argNames...) ->
-		functionBody = require('coffee-script').compile @input.join "\n"
-		bot.addCommand name, Function.apply null, argNames.concat [functionBody]
-		@output "Done!"
+	"addCommand": @manual (exec, name, argNames...) ->
+		buffer = []
+		
+		exec.stdin.on 'data', (data) ->
+			buffer.push data
+
+		exec.stdin.on 'end', ->
+			res = buffer.join "\n"
+			functionBody = require('coffee-script').compile res
+			bot.addCommand name, Function.apply null, argNames.concat [functionBody]
+			exec.end "Done!"
 	
-	"reload": ->
-		bot.reloadModule module for module in bot.modules
-		@output "Done!"
-
-	"g": @manual ->
-		query = encodeURIComponent Array::join.call arguments, " "
+	"g": @manual (exec, args...) ->
+		query = encodeURIComponent args.join " "
 
 		require('http').get {
 			host : 'ajax.googleapis.com'
 
 				if hits.length < 1
 					console.log "No results!"
-					@output "No result. :("
-					@done()
+					exec.end "No result. :("
 					return
 
 				{titleNoFormatting, url, content} = hits[0]
 				cont  = content[0..180] + (if content.length > 180 then " ..." else "")
 				cont  = cont.replace /<[^>]+>/g, ''
 
-				@output "[#{title}]: #{cont} <#{url}>"
-				@done()
+				exec.end "[#{title}]: #{cont} <#{url}>"
 

File src/bot.coffee

 fs      = require 'fs'
 vm      = require 'vm'
+net     = require 'net'
 
 irc     = require './irc'
 {Shell} = require './shell'
 
+#### Setup IRC connection ###########################################
 server = new irc.Server { hostname : "chat.freenode.net" }
 shell  = new Shell
 
 			server.connection.write "PRIVMSG", target, "Error: #{err.message}"
 			console.log err.stack
 
+#### Setup remote module server #####################################
+#moduleServer = net.createServer (socket) ->
+#	socket.on 'data', (data) ->
+#		o
+
 bot =
 	modules: []
+	shell: shell
 
 	addCommand: (name, func) ->
 		shell.commands[name] = func

File src/buffered-socket.coffee

-{EventEmitter} = require 'events'
-net  = require 'net'
-util = require 'util'
+events = require 'events'
+net    = require 'net'
+util   = require 'util'
 
 #### BufferedSocket #################################################
-BufferedSocket = (opts) ->
+BufferedSocket = (opts, socket = opts) ->
+	opts ?= {}
+	opts["separator"] ?= "\r\n"
+
+	@socket = socket
+	self = this
+
+	cache = ""
+	socket.on 'data', (chunk) ->
+		linesRaw = "" + cache + chunk
+
+		lines    = linesRaw.split opts["separator"]
+		cache    = lines.pop()
+
+		for line in lines
+			self.emit 'data', line
+	
+	socket.on 'connect', ->
+		self.emit 'connect'
+	
+	socket.on 'end', ->
+		self.emit 'end'
+
+	this
+
+util.inherits BufferedSocket, events.EventEmitter
+
+# delegate socket-related functions (e.g. write) to @socket.
+for key in Object.getOwnPropertyNames net.Socket.prototype
+	fn = net.Socket::[key]
+	continue if typeof fn != 'function'
+
+	do (key, fn) ->
+		BufferedSocket::[key] = ->
+			fn.apply @socket, arguments
+
+#### exports ########################################################
+exports.BufferedSocket = BufferedSocket
+exports.createSocket = (opts) ->
 	if not opts.hostname or not opts.port
 		throw new TypeError "Missing required option property: hostname or port."
 	
-	opts.separator ?= "\r\n"
-	
-	@options = opts
-	@
+	new BufferedSocket opts, new net.createConnection opts.port, opts.hostname
 
-exports.BufferedSocket = BufferedSocket
-util.inherits BufferedSocket, EventEmitter
-
-BufferedSocket::connect = ->
-	conn = this
-
-	socket = @socket = net.createConnection @options.port, @options.hostname
-	cache = ""
-
-	socket.on 'data', (chunk) =>
-		linesRaw = "" + cache + chunk
-
-		lines = linesRaw.split '\r\n'
-		cache = lines.pop()
-		
-		@emit 'data', line for line in lines
-
-	socket.on 'connect', =>
-		@emit 'connect'
-
-	socket.on 'end', =>
-		@emit 'end'
-
-BufferedSocket::write = (str) ->
-	@socket.write str
-
-exports.BufferedSocket = BufferedSocket
-

File src/irc.coffee

 util = require 'util'
 net  = require 'net'
 
-{BufferedSocket} = require './buffered-socket'
+bs   = require './buffered-socket'
 
 #### Helper functions ###############################################
 validateChannelName = (name) ->
 
 rawExpression = ///
 	^
-	(?: :([^\x20]+) \x20 |)         # : (user!ident@host)
-	([^:] [^\x20]*)                 # command
+	(?: :([^\x20]+) \x20 |)           # : (user!ident@host)
+	([^:] [^\x20]*)                   # command
 	((?: \x20 [^\x20:] [^\x20]* )*)   # parameters except last
 	\x20
-	(?: : (.*)                    # last parameter: either colon + rest of string
-		| ([^\x20]*))               # ...or multiple non-space characters (like other params)
+	(?: : (.*)                        # last parameter: either colon + rest of string
+		| ([^\x20]*))                 # ...or multiple non-space characters (like other params)
 	$
 ///
 
 #### Connection #####################################################
 Connection = (opts) ->
 	opts.port ?= 6667
+	@options = opts
 
-	@options = opts
-	@
+	this
 
 util.inherits Connection, EventEmitter
 
 	EventEmitter.call this
 
 	conn = this
-	socket = @socket = new BufferedSocket
+	socket = @socket = bs.createSocket
 		hostname  : @options.hostname
 		port      : @options.port
 		separator : "\r\n"
 	
-	socket.connect()
+	#socket.connect()
 
 	socket.on 'data', (lineRaw) ->
 		line = parseLine lineRaw.trimLeft()
 	conn.on '250', (sender, user, message) ->
 		console.log "[Statistics] #{message}"
 	
-	@
+	this
 
 #### exports ########################################################
 exports.Connection = Connection

File src/shell.coffee

 
 DEBUG_EXECUTIONS = false
 
-exports.Shell = Shell = (opts = {}) ->
-	@defaults =
-		input  : opts.input
-		output : opts.output or =>
-			Array::push.apply @outputBuffer, arguments
-
-	@outputBuffer = []
-	
-	@variables = opts.variables or {}
-	@commands  = opts.commands  or {}
-	
-	@commands["echo"] ?= -> @output.apply @, arguments
-	@commands["cat"]  ?= -> @output.apply @, @input
-	
-	@
-
+#### Lexer ##########################################################
 specialModesMap = {
 	"'" : 'str-single'
 	'"' : 'str-double'
 
 	res
 
+#### Shell ##########################################################
+exports.Shell = Shell = (opts = {}) ->
+	@defaults =
+		input  : opts.input
+		output : opts.output or =>
+			Array::push.apply @outputBuffer, arguments
+
+	@outputBuffer = []
+	
+	@variables = opts.variables or {}
+	@commands  = opts.commands  or {}
+	
+	@commands["echo"] ?= -> @output.apply @, arguments
+	@commands["cat"]  ?= -> @output.apply @, @input
+	
+	@
+
 Shell::createExecution = ->
 	res = {}
 
 	
 	res
 
+#### Shell#process ##################################################
 Shell::process = (tokens) ->
 	res = []
 	curr = @createExecution()
 	res.push curr
 	res
 
+#### Shell#exec ##################################################
 Shell::exec = (str, callback) ->
 	executions   = @process lex str
 	first        = executions[0]