Permalink
Browse files

code import

  • Loading branch information...
deoxxa committed Nov 27, 2012
1 parent b99473b commit ec2bbc5db7b43a75499017442ebbb2f03c7b26a2
Showing with 329 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +26 −0 LICENSE.md
  3. +63 −0 README.md
  4. +2 −0 index.js
  5. +22 −0 package.json
  6. +163 −0 parser.js
  7. +21 −0 proxy.js
  8. +31 −0 serialiser.js
View
@@ -0,0 +1 @@
+/node_modules
View
@@ -0,0 +1,26 @@
+Copyright (c) 2012, Deoxxa Development
+======================================
+All rights reserved.
+--------------------
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of Deoxxa Development nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY DEOXXA DEVELOPMENT ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL DEOXXA DEVELOPMENT BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
@@ -0,0 +1,63 @@
+IRC-Protocol
+============
+
+Streaming parser and serialiser for IRC protocol data.
+
+Overview
+--------
+
+This module allows you to consume and produce IRC protocol messages. It doesn't
+contain any logic, leaving that up to the developer. Also everything is streams.
+
+Installation
+------------
+
+Available via [npm](http://npmjs.org/):
+
+> $ npm install irc-protocol
+
+Or via git:
+
+> $ git clone git://github.com/deoxxa/irc-protocol.git node_modules/irc-protocol
+
+Usage
+-----
+
+Also see [proxy.js](https://github.com/deoxxa/irc-protocol/blob/master/proxy.js).
+
+```javascript
+#!/usr/bin/env node
+
+var net = require("net"),
+ IRCProtocol = require("./index");
+
+var server = net.createServer(function(local) {
+ var local_parser = new IRCProtocol.Parser(),
+ remote_parser = new IRCProtocol.Parser(),
+ local_serialiser = new IRCProtocol.Serialiser(),
+ remote_serialiser = new IRCProtocol.Serialiser();
+
+ var remote = net.createConnection(6667, "127.0.0.1");
+
+ local.pipe(local_parser).pipe(local_serialiser).pipe(remote);
+ remote.pipe(remote_parser).pipe(remote_serialiser).pipe(local);
+
+ local_serialiser.on("data", function(data) { process.stdout.write(">> " + data); });
+ remote_serialiser.on("data", function(data) { process.stdout.write("<< " + data); });
+});
+
+server.listen(6668);
+```
+
+License
+-------
+
+3-clause BSD. A copy is included with the source.
+
+Contact
+-------
+
+* GitHub ([deoxxa](http://github.com/deoxxa))
+* Twitter ([@deoxxa](http://twitter.com/deoxxa))
+* ADN ([@deoxxa](https://alpha.app.net/deoxxa))
+* Email ([deoxxa@fknsrs.biz](mailto:deoxxa@fknsrs.biz))
View
@@ -0,0 +1,2 @@
+exports.Parser = require("./parser");
+exports.Serialiser = require("./serialiser");
View
@@ -0,0 +1,22 @@
+{
+ "name": "irc-protocol",
+ "version": "0.0.0",
+ "description": "Streaming parser and serialiser for IRC protocol data",
+ "main": "index.js",
+ "dependencies": {
+ "steez": "~0.4.2"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/deoxxa/irc-protocol.git"
+ },
+ "keywords": [
+ "irc",
+ "protocol",
+ "parser",
+ "serialiser",
+ "stream"
+ ],
+ "author": "Conrad Pankoff <deoxxa@fknsrs.biz> (http://www.fknsrs.biz/)",
+ "license": "BSD"
+}
View
163 parser.js
@@ -0,0 +1,163 @@
+var Steez = require("steez"),
+ util = require("util");
+
+var Parser = module.exports = function Parser() {
+ Steez.call(this);
+
+ this.buffer = "";
+};
+util.inherits(Parser, Steez);
+
+Parser.prototype.write = function write(data) {
+ data = data.toString();
+
+ this.buffer += data;
+
+ var parts = this.buffer.split(/\r\n/);
+
+ this.buffer = parts.pop();
+
+ parts.forEach(function(part) {
+ if (part.length > 510) {
+ this.emit("error", new Error("line length is too long"));
+ return;
+ }
+
+ try {
+ var message = this.parse(part);
+ this.emit("data", message);
+ } catch (e) {
+ this.emit("error", e);
+ }
+ }.bind(this));
+
+ if (this.buffer.length > 510) {
+ this.emit("error", new Error("line length is too long"));
+ }
+
+ return this.writable && !this.paused;
+};
+
+var RE_NICK = /^([a-z][a-z0-9\-\[\]\\`^\{\}]*)(?: |!|@)/i,
+ RE_USER = /^([^ \r\n@]+)/,
+ RE_SERVER = /^((?:[a-z][a-z0-9-]*\.)*(?:[a-z][a-z0-9-]*))/i,
+ RE_COMMAND = /^(\d{3}|[A-Z]+)/;
+
+Parser.prototype.parse = function parse(text, state) {
+ if (typeof state !== "object" || state === null) { state = {offset: 0}; }
+
+ var message = {};
+
+ if (text[state.offset] === ":") {
+ state.offset++;
+ message.prefix = this.parse_prefix(text, state);
+ }
+
+ message.command = this.parse_command(text, state);
+
+ message.parameters = this.parse_parameters(text, state);
+
+ return message;
+};
+
+Parser.prototype.parse_prefix = function parse_prefix(text, state) {
+ var prefix = {};
+
+ var nick;
+
+ if (nick = this.parse_nick(text, state)) {
+ prefix.nick = nick;
+
+ if (text[state.offset] === "!") {
+ state.offset++;
+ prefix.user = this.parse_user(text, state);
+ }
+
+ if (text[state.offset] === "@") {
+ state.offset++;
+ prefix.server = this.parse_server(text, state);
+ }
+ } else {
+ prefix.server = this.parse_server(text, state);
+ }
+
+ if (text[state.offset] !== " ") {
+ throw new Error("expected whitespace after prefix information");
+ }
+
+ while (text[state.offset] === " ") {
+ state.offset++;
+ }
+
+ return prefix;
+};
+
+Parser.prototype.parse_nick = function parse_nick(text, state) {
+ var nick = (RE_NICK.exec(text.substr(state.offset)) || {})[1];
+
+ if (nick) {
+ state.offset += nick.length;
+ }
+
+ return nick;
+};
+
+Parser.prototype.parse_user = function parse_user(text, state) {
+ var user = (RE_USER.exec(text.substr(state.offset)) || {})[1];
+
+ if (user) {
+ state.offset += user.length;
+ }
+
+ return user;
+};
+
+Parser.prototype.parse_server = function parse_server(text, state) {
+ var server = (RE_SERVER.exec(text.substr(state.offset)) || {})[1];
+
+ if (server) {
+ state.offset += server.length;
+ }
+
+ return server;
+};
+
+Parser.prototype.parse_command = function parse_command(text, state) {
+ var command = (RE_COMMAND.exec(text.substr(state.offset)) || {})[1];
+
+ if (command) {
+ state.offset += command.length;
+ }
+
+ while(text[state.offset] === " ") {
+ state.offset++;
+ }
+
+ return command;
+};
+
+Parser.prototype.parse_parameters = function parse_parameters(text, state) {
+ var parameters = [];
+
+ while (state.offset < text.length) {
+ var parameter = null;
+
+ if (text[state.offset] === ":") {
+ state.offset++;
+ parameter = text.substr(state.offset);
+ } else {
+ parameter = (text.substr(state.offset).match(/^(\S+)/) || {})[1];
+ }
+
+ if (typeof parameter === "string") {
+ parameters.push(parameter);
+ state.offset += parameter.length;
+ }
+
+ while (text[state.offset] === " ") {
+ state.offset++;
+ }
+ }
+
+ return parameters;
+};
View
@@ -0,0 +1,21 @@
+#!/usr/bin/env node
+
+var net = require("net"),
+ IRCProtocol = require("./index");
+
+var server = net.createServer(function(local) {
+ var local_parser = new IRCProtocol.Parser(),
+ remote_parser = new IRCProtocol.Parser(),
+ local_serialiser = new IRCProtocol.Serialiser(),
+ remote_serialiser = new IRCProtocol.Serialiser();
+
+ var remote = net.createConnection(6667, "127.0.0.1");
+
+ local.pipe(local_parser).pipe(local_serialiser).pipe(remote);
+ remote.pipe(remote_parser).pipe(remote_serialiser).pipe(local);
+
+ local_serialiser.on("data", function(data) { process.stdout.write(">> " + data); });
+ remote_serialiser.on("data", function(data) { process.stdout.write("<< " + data); });
+});
+
+server.listen(6668);
View
@@ -0,0 +1,31 @@
+var Steez = require("steez"),
+ util = require("util");
+
+var Serialiser = module.exports = function Serialiser() {
+ Steez.call(this);
+};
+util.inherits(Serialiser, Steez);
+
+Serialiser.prototype.write = function write(message) {
+ this.emit("data", this.format_message(message) + "\r\n");
+
+ return this.writable && !this.paused;
+};
+
+Serialiser.prototype.format_message = function format_message(message) {
+ return [(message.prefix ? ":" + this.format_prefix(message.prefix) + " " : ""), this.format_parameters([message.command].concat(message.parameters || []))].join("");
+};
+
+Serialiser.prototype.format_prefix = function format_prefix(prefix) {
+ if (prefix.nick && (prefix.user || prefix.server)) {
+ return prefix.nick + (prefix.user ? "!" + prefix.user : "") + (prefix.server ? "@" + prefix.server : "");
+ } else if (prefix.nick) {
+ return prefix.nick;
+ } else if (prefix.server) {
+ return prefix.server;
+ }
+};
+
+Serialiser.prototype.format_parameters = function format_parameters(parameters) {
+ return parameters.map(function(e) { return ((e.indexOf(" ") !== -1) ? ":" : "") + e; }).join(" ");
+};

0 comments on commit ec2bbc5

Please sign in to comment.