Give Ajax IM a proper web framework with Express.js (bug 17)

Start bugs 17, 12, 13

* Begin integration of Express.js grammar into Ajax IM server (bug 17)
* Add basic framework for various chat object (User, Message, Room,
  Notification) (bug 12)
* Begin bringing Ajax IM up to speed with Node.js (assisted by bug 17) (bug 13)
Esse commit está contido em:
Joshua Gross
2010-06-20 18:58:40 -07:00
commit 833883928a
14 arquivos alterados com 479 adições e 1611 exclusões
+2
Ver Arquivo
@@ -0,0 +1,2 @@
local/*
*.local.*
+25 -2
Ver Arquivo
@@ -1,2 +1,25 @@
# What is Ajax IM?
**Ajax IM ("Ajax Instant Messenger") is a browser-centric instant messaging framework.** It uses AJAX to create a real-time (or near real-time) IM environment that can be used in conjunction with existing community and commercial software, or simply as a stand-alone product.
# Ajax IM
Ajax IM ("Ajax Instant Messenger") is a browser-centric instant messaging framework.
## What is Ajax IM?
It uses AJAX to create a real-time (or near real-time) IM environment that can be used in conjunction with existing community and commercial software, or simply as a stand-alone product.
## Installation
Install `Node.js`:
wget http://nodejs.org/dist/node-v0.1.98.tar.gz
tar xzf node-v0.1.98.tar.gz
cd node-v0.1.98
./configure
make
make install
Install Node Package Manager (`npm`):
See instructions at [isaacs' npm git repo](http://github.com/isaacs/npm).
Install `Express.js`:
npm install express
-93
Ver Arquivo
@@ -1,93 +0,0 @@
Node Server Memcached Protocol
for logging users in and out of the server.
-------------------------------------------
add <username> <!ignore flags> <!ignore exptime> <bytes> [!ignore noreply]\r\n
- <username> is the username of the new user
- <flags> and <exptime> are ignored.
- <bytes> is the number of bytes in the data block to follow, *not*
including the delimiting \r\n. <bytes> may *not* be zero.
After this line, the client sends the JSON-encoded data block:
<data block>\r\n
- <data block> is JSON-encoded information about the user, having a length
of <bytes> bytes.
After sending the command line and the data block, the client awaits
the reply, which may be:
- "STORED\r\n", to indicate that the user is or has been logged in.
- "NOT_STORED\r\n", to indicate that there was a problem storing the
new user data.
Retrieval command:
------------------
The retrieval commands "get" and "gets" operates like this:
get <type/identifier>\r\n
gets <type/identifier> <type/identifier> <...>\r\n
- <type/identifier> is one of:
- session/<session_id> where <session_id> is the session of an
existing user.
> returns information about the user
- username/<username> where <username> is the (properly formatted)
username of a logged in user.
> returns information about the user
- list/
> returns a list of all online users
- online/
> returns an integer value of the online user count
After this command, the client expects zero or more items, each of
which is received as a text line followed by a data block. After all
the items have been transmitted, the server sends the string
"END\r\n"
to indicate the end of response.
Each item sent by the server looks like this:
VALUE <key> <flags> <bytes>\r\n
<data block>\r\n
- <key> is the key for the item being sent
- <flags> is set to 0
- <bytes> is the length of the data block to follow, *not* including
its delimiting \r\n
- <data block> is the data for this response, usually in JSON format (exception: online/).
If some of the keys appearing in a retrieval request are not sent back
by the server in the item list this means that the server does not
hold items with such keys (because they were never stored, or stored
but deleted to make space for more items, or expired, or explicitly
deleted by a client).
Logging out
--------
The command "delete" allows for explicit logging out of users:
delete <username>\r\n
- <username> is the username of the user the client wishes the server
to log out.
The response line to this command can be one of:
- "DELETED\r\n" to indicate success
- "NOT_FOUND\r\n" to indicate that the user with this username was not
found.
+30
Ver Arquivo
@@ -0,0 +1,30 @@
setInterval X000ms
|
|
V
Online user list --> JSON --> list.txt
getOnlineUserList --> list.txt
|
|
V
Output
-------------------------------------------
AjaxIM.init({
...
statusButton: true/false,
onlineUserList: true/false,
friendsList: true/false,
registration: true/false,
login: true/false
});
.- All Users
| .- Register/Login || Set Status
| |
V V
_____________________________________________________
| | Friends | ◊ | • |
—————————————————————————————————————————————————————
Arquivo executável
+51
Ver Arquivo
@@ -0,0 +1,51 @@
#!/bin/sh
# Ajax IM build script
# Automatically exports, minifies, and packages Ajax IM
# Path to checked-out repository
AJAXIM=$HOME/Sites/AjaxIM
AJAXIMBUILD=$HOME/Sites/AjaxIMBuild
YUIC=$HOME/Sites/yuicompressor-2.4.2.jar
echo "Ajax IM, (c) 2005-2010 Joshua Gross"
cd $AJAXIM/..
echo "Cleaning up any old folders... \c"
rm -rf AjaxIMBuild
mkdir AjaxIMBuild
echo "Done."
cd $AJAXIM
echo "Checking out repository for Development and Minified versions... \c"
git checkout-index -a -f $AJAXIMBUILD/AjaxIMDevelopment/
git checkout-index -a -f $AJAXIMBUILD/AjaxIMMinified/
echo "Done."
echo "Building Development .tar.gz file... \c"
cd $AJAXIMBUILD/AjaxIMDevelopment
tar -cf AjaxIM_v$1.tar *
gzip -9 AjaxIM_v$1.tar
mv AjaxIM_v$1.tar.gz $AJAXIM/build
cd ..
rm -rf AjaxIMDevelopment
echo "Done."
echo "Compacting Minified copy with YUI Compressor... \c"
cd AjaxIMMinified
java -jar $YUIC -o js/im.min.js js/im.js
mv im.min.js im.js
java -jar $YUIC -o js/im.load.min.js js/im.load.js
mv im.load.min.js im.load.js
java -jar $YUIC -o js/jquery.md5.min.js js/jquery.md5.js
mv jquery.md5.min.js jquery.md5.js
echo "Done."
echo "Building Minified .tar.gz file... \c"
cd AjaxIMMinified
tar -cf AjaxIM_v$1_min.tar *
gzip -9 AjaxIM_v$1_min.tar
mv AjaxIM_v$1_min.tar.gz ..
cd ..
rm -rf AjaxIMMinified
echo "Done."
BIN
Ver Arquivo
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.1 KiB

+177
Ver Arquivo
@@ -0,0 +1,177 @@
// = Ajax IM =
//
// **Copyright &copy; 2005 &ndash; 2010 Joshua Gross**\\
// //MIT Licensed//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// == Node.js Server ==
//
var sys = require('sys');
require.paths.unshift('express/lib');
require('express');
require('express/plugins');
Object.merge(global, require('ext'));
Object.merge(global, require('./session.js')); // Ugly.
require('settings.js');
configure('development', function() {
use(Logger);
use(Static);
});
configure(function() {
use(MethodOverride);
use(Cookie);
use(Session.IM, {lifetime: (15).minutes,
reapInterval: (1).minute,
authentication:
require('libs/authenticate/' + AUTH_LIBRARY)
});
set('root', __dirname);
});
var AjaxIM = new Class({
// === {{{ AjaxIM.constructor() }}} ===
//
// Initializes the frontend webserver and the backend Memcache server, which provides
// and easy-to-use API for controlling the server from other scripts.
constructor: function() {
if(typeof this.config.port != 'number')
throw new TypeError();
get('/listen', function() {
// Do nothing.
});
post('/send', function() {
this.send()
});
get('/status', this.status);
run(PORT, HOST);
}
// === {{{ AjaxIM.send() }}} ===
//
// Send a message to the user specified in the query and return a
// result declaring whether or not the message was sent. Messages
// are only sent if the user has an active session.
this.send = function() {
var sent = false;
var user = self._session(this.request, 'object');
var to = this.request.uri.params['to'] || '';
if(!user) {
self._d('An unknown user tried to send a message to [' + to + '] without being authenticated.');
return this.response.reply(200, {'r': 'error', 'e': 'no session found'});
}
if(user.username && to &&
to in self.users &&
self.users[to].callback
) {
var time = Math.round(Date.now() / 1000);
self.users[to].callback({
t: 'm',
s: user.username,
r: to,
m: this.request.uri.params.message
});
sent = true;
}
self._d('User [' + user.username + '] sent a message to [' + to + '] ' + (sent ? 'successfully.' : 'UNSUCCESSFULLY.'));
self.users[user.username].active();
self.sessions[user.session_id].active();
this.response.reply(200, {'sent': sent});
};
// === {{{ AjaxIM.status() }}} ===
//
// Update a user's status based on the query parameters; this includes
// both their status code and any custom status message associated with
// that code. If the status update is successful, send an update to the
// user's friends.
this.status = function() {
var status_updated = false;
var user = self._session(this.request, 'object');
if(!user) {
self._d('An unknown user tried to change their status without being authenticated.');
return this.response.reply(200, {'r': 'error', 'e': 'no session found'});
}
var status = this.request.uri.params.status;
var statusMsg = status + ':' + this.request.uri.params.message;
user.friends.forEach(function(f) {
if(f.u in self.users) {
var group = null;
for(var i=0; i < self.users[f.u]['friends'].length; i++) {
if(self.users[f.u]['friends'][i].u == user.username) {
self.users[f.u]['friends'][i].s = status;
group = self.users[f.u]['friends'][i].g;
break;
}
}
self.users[f.u].callback({t: 's', s: user.username, r: f.u, m: statusMsg, g: group});
}
});
self._d('User [' + user.username + '] set his/her status to [' + statusMsg + ']. Friends notified.');
self.users[user.username].status = {s: status, m: this.request.uri.params.message};
self.users[user.username].active();
self.sessions[user.session_id].active();
this.response.reply(200, {status_updated: status_updated});
};
// === {{{ AjaxIM.online() }}} ===
//
// Return a list of currently signed in users and their statuses
// sans the status messages.
this.online = function() {
var user = self._session(this.request, 'object');
if(!user) {
self._d('An unknown user tried to retrieve a list of online users without being authenticated.');
return this.response.reply(200, {'r': 'error', 'e': 'no session found'});
}
this.response.reply(200, this.onlineList);
};
// === {{{ AjaxIM.onlineTotal() }}} ===
//
// Return a count of the number of online users.
this.onlineTotal = function() {
this.response.reply(200, {count: self.onlineCount});
};
};
var im = new AjaxIM(config);
im.init();
+10
Ver Arquivo
@@ -0,0 +1,10 @@
var utils = require('express/utils');
exports.Message = new Class({
});
exports.Notification = new Class({
});
exports.Room = new Class({
});
-41
Ver Arquivo
@@ -1,41 +0,0 @@
// == Node.js Server Configuration ==
//
// This is the configuration file for the Node.js Ajax IM server. Here, you
// can set which ports will be used for the public and internal servers,
// as well as other settings such as the session cookie name and expiration.
// === {{{ ports }}} ===
//
// Define the ports and hosts that Ajax IM will run on. {{{public}}} is the
// public-facing API, while {{{private}}} is the memcache-compatible API
// intended for server-side use.
//
// The first item of each array is the port, the second is the host name. If
// you do not want to specify a host, set it to {{{null}}}.
exports.ports = {
public: [8000, 'localhost'],
private: [11998, 'localhost']
};
// === API Key ===
//
// This is the **private** API key that is used for any REST calls to the
// server. Please change this key to something long and random. You should
// never use this key on the client side!
exports.api_key = 'FG34tbNW$n5aw4E6Y&U&6inBFDs';
// === {{{ cookie }}} ===
//
// Define the cookie name and how long a session will be stored on the server.
// If you change the cookie name here, you will also need to change it in the
// PHP login script/configuration; if you fail to do this, the Node.js server
// will be looking for a cookie that does not exist.
//
// **Note:** The period for the session should be as long or longer than the
// cookie itself is set to be stored. If it is less, the user won't be logged
// back in automatically, as their cookie will have been deleted.
exports.cookie = {
name: 'ajaxim_session',
period: 8760,
domain: '.localdomain'
};
+12
Ver Arquivo
@@ -0,0 +1,12 @@
exports.cookie = 'ajaxim_session';
exports.authenticate = function(request) {
// Verify user based on request.
// On failure, redirect user to auth form
return {
username: 'username',
displayname: 'John Smith',
otherinfo: 'any other relevant key/values'
};
};
-379
Ver Arquivo
@@ -1,379 +0,0 @@
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
exports.hex_md5 = function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
exports.b64_md5 = function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
exports.any_md5 = function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
exports.hex_hmac_md5 = function hex_hmac_md5(k, d)
{ return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
exports.b64_hmac_md5 = function b64_hmac_md5(k, d)
{ return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
exports.any_hmac_md5 = function any_hmac_md5(k, d, e)
{ return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
/*
* Perform a simple self-test to see if the VM is working
*/
function md5_vm_test()
{
return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
}
/*
* Calculate the MD5 of a raw string
*/
function rstr_md5(s)
{
return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}
/*
* Calculate the HMAC-MD5, of a key and some data (raw strings)
*/
function rstr_hmac_md5(key, data)
{
var bkey = rstr2binl(key);
if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}
/*
* Convert a raw string to a hex string
*/
function rstr2hex(input)
{
try { hexcase } catch(e) { hexcase=0; }
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var output = "";
var x;
for(var i = 0; i < input.length; i++)
{
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F)
+ hex_tab.charAt( x & 0x0F);
}
return output;
}
/*
* Convert a raw string to a base-64 string
*/
function rstr2b64(input)
{
try { b64pad } catch(e) { b64pad=''; }
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var output = "";
var len = input.length;
for(var i = 0; i < len; i += 3)
{
var triplet = (input.charCodeAt(i) << 16)
| (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
| (i + 2 < len ? input.charCodeAt(i+2) : 0);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > input.length * 8) output += b64pad;
else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
}
}
return output;
}
/*
* Convert a raw string to an arbitrary string encoding
*/
function rstr2any(input, encoding)
{
var divisor = encoding.length;
var i, j, q, x, quotient;
/* Convert to an array of 16-bit big-endian values, forming the dividend */
var dividend = Array(Math.ceil(input.length / 2));
for(i = 0; i < dividend.length; i++)
{
dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
}
/*
* Repeatedly perform a long division. The binary array forms the dividend,
* the length of the encoding is the divisor. Once computed, the quotient
* forms the dividend for the next step. All remainders are stored for later
* use.
*/
var full_length = Math.ceil(input.length * 8 /
(Math.log(encoding.length) / Math.log(2)));
var remainders = Array(full_length);
for(j = 0; j < full_length; j++)
{
quotient = Array();
x = 0;
for(i = 0; i < dividend.length; i++)
{
x = (x << 16) + dividend[i];
q = Math.floor(x / divisor);
x -= q * divisor;
if(quotient.length > 0 || q > 0)
quotient[quotient.length] = q;
}
remainders[j] = x;
dividend = quotient;
}
/* Convert the remainders to the output string */
var output = "";
for(i = remainders.length - 1; i >= 0; i--)
output += encoding.charAt(remainders[i]);
return output;
}
/*
* Encode a string as utf-8.
* For efficiency, this assumes the input is valid utf-16.
*/
function str2rstr_utf8(input)
{
var output = "";
var i = -1;
var x, y;
while(++i < input.length)
{
/* Decode utf-16 surrogate pairs */
x = input.charCodeAt(i);
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
{
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
i++;
}
/* Encode output as utf-8 */
if(x <= 0x7F)
output += String.fromCharCode(x);
else if(x <= 0x7FF)
output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
0x80 | ( x & 0x3F));
else if(x <= 0xFFFF)
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
else if(x <= 0x1FFFFF)
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
}
return output;
}
/*
* Encode a string as utf-16
*/
function str2rstr_utf16le(input)
{
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
(input.charCodeAt(i) >>> 8) & 0xFF);
return output;
}
function str2rstr_utf16be(input)
{
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
input.charCodeAt(i) & 0xFF);
return output;
}
/*
* Convert a raw string to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
function rstr2binl(input)
{
var output = Array(input.length >> 2);
for(var i = 0; i < output.length; i++)
output[i] = 0;
for(var i = 0; i < input.length * 8; i += 8)
output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
return output;
}
/*
* Convert an array of little-endian words to a string
*/
function binl2rstr(input)
{
var output = "";
for(var i = 0; i < input.length * 32; i += 8)
output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
return output;
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function binl_md5(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
-1096
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+147
Ver Arquivo
@@ -0,0 +1,147 @@
var utils = require('express/utils');
var User = Base.extend({
constructor: function(id, data) {
this.id = id;
this.connection = null;
this.listeners = [];
this.message_queue = [];
this._data = data;
},
connected: function(conn) {
this.connection = conn;
},
listener: function(conn) {
this.listeners.push(conn);
},
respond: function(code, message, callback) {
this._send('connection', code, message, callback);
},
notify: function(code, message, callback) {
this._send('listener', code, message, callback);
},
_send: function(type, code, message, callback) {
if(!message && typeof code != 'number') {
callback = message;
message = code;
code = 200;
}
if(typeof message != 'string') {
try {
message = JSON.encode(message);
} except(e) {
throw new Error('Could not JSON encode message content!');
}
}
if(type == 'connection' && this.connection) {
this.connection.respond(code, message, 'UTF-8');
} else {
if(!this.listeners.length)
this.message_queue.push(arguments);
var notify_run, self = this;
(notify_run = function(conn) {
return function() {
if(!conn) (callback ? callback() : return);
conn.respond(code, message,
notify_run(self.listeners.pop()));
};
})(this.listeners.pop())();
}
},
get: function(key, def) {
if(key == 'id') return this.id;
if(key in this._data)
return this._data[key];
else
return def || false;
}
});
Store.Memory.IM = Store.Memory.extend({
name: 'Memory.IM',
constructor: function(options) {
Store.Memory.call(this);
this.auth = options.authenticate;
},
fetch: function(req, callback) {
var sid = req.cookie(this.auth.cookie);
if(sid && this.store[sid]) {
callback(null, this.store[sid], false);
} else {
this.generate(req, callback);
}
},
generate: function(req, callback) {
if(data = this.auth.authenticate(req)) {
var sid = req.cookie(this.auth.cookie);
callback(null, new User(sid, data), true);
}
}
});
Session.IM = Plugin.extend({
extend: {
init: function(options) {
this.cookie = {};
Object.merge(this, options);
this.store = new (this.dataStore || Store.Memory.IM)(options);
this.startReaper();
},
startReaper: function() {
setInterval(function(self) {
self.store.reap(self.lifetime || (1).day);
}, this.reapInterval || this.reapEvery || (1).hour, this);
}
},
on: {
request: function(event, callback) {
if(event.request.url.pathname === '/favicon.ico')
return;
Session.IM.store.fetch(event.request, function(err, session, is_new) {
if(err) return callback(err);
event.request.session = session;
event.request.session.touch();
if(event.request.url.pathname == '/listen') {
session.listener(event.request);
callback();
if(is_new) session.notify({type: 'noop'});
else if(session.message_queue.length)
session._send(session.message_queue.shift());
} else {
session.connection = event.request;
callback();
}
});
return true;
},
response: function(event, callback) {
if(event.request.session)
return Session.IM.store.commit(
event.request.session,
callback),
true;
}
}
});
+25
Ver Arquivo
@@ -0,0 +1,25 @@
// == Node.js Server Configuration ==
//
// This is the configuration file for the Node.js Ajax IM server. Here, you
// can set which ports will be used for the public and internal servers,
// as well as other settings such as the session cookie name and expiration.
// === {{{ host and port }}} ===
//
// Define the host and port that Ajax IM will run on.
APP_HOST = 'localhost';
APP_PORT = 8000;
// === API Key ===
//
// This is the **private** API key that is used for any REST calls to the
// server. Please change this key to something long and random. You should
// never use this key on the client side!
API_KEY = 'FG34tbNW$n5aw4E6Y&U&6inBFDs';
// === Authentication Library ===
//
// This is the library (from libs/authenticate/) that we will use to
// authenticate a user signing in. The value should be the name of the file
// without the '.js' part. 'index' is the default library.
AUTH_LIBRARY = 'index';