Skip to content

Instantly share code, notes, and snippets.

@huangdongxu
Created November 18, 2011 16:04
Show Gist options
  • Save huangdongxu/1376867 to your computer and use it in GitHub Desktop.
Save huangdongxu/1376867 to your computer and use it in GitHub Desktop.
Jakiro-comet-server
/*
* Jakiro
* @desc Yet Another Comet Server
* @author Dongxu Huang <[email protected]>
* @date 2011-11-18
*/
var port = 8899 // default listen port
var createServer = require("http").createServer // createserver function
var puts = require("util").puts // output log
var url = require("url")
var timeout = 50000
var buf_size = 10
// out put debug string
function log(msg)
{
var time = new Date().toString().split(' ')[4]
puts('\033[32;49;1m['+time+']\033[39;49;0m '+msg)
}
// get current time stamp
function get_timestamp()
{
return new Date().getTime()
}
// send response to client
function response(res, code, body, callback)
{
var type;
body = JSON.stringify(body);
if (callback)
{
body = callback + '(' + body + ');';
type = 'application/javascript';
}
else
{
type = 'text/json';
}
res.writeHeader(code, {
"Content-Type": type,
"Content-Length": body.length
});
res.write(body);
res.end();
}
// message body
function Message(time, data)
{
this.time = time
this.data = data
}
// comet channel
function Channel()
{
// store messages
var messages = []
// current time stamp
var time = get_timestamp()
// waiting client's callbacks
var callbacks = []
// push data into a channel
this.put = function(data)
{
time = get_timestamp()
var message = new Message(time, data)
messages.push(message)
// call waiting clients' callback function
while(callbacks.length > 0)
callbacks.shift().callback([message])
// clean message buffer
while(messages.length > buf_size)
messages.shift()
return time
};
this.get = function(time, callback)
{
var i, message, new_msgs = []
for (i = 0;i < messages.length ; i++)
{
message = messages[i]
if (message.time > time)
new_msgs.push(message)
}
if (new_msgs.length > 0)
{
callback(new_msgs)
return 'unread'
}
else
{
callbacks.push({time: get_timestamp(), callback: callback})
return 'waiting'
}
};
// update client time; client fetch server time
this.update = function()
{
return time
}
// remove expire waiter or entire channel
this.remove = function(expire)
{
// if this channel has no waiter in queue meanwhile live a long time
var isdeletechannel = callbacks.length === 0 && time < expire
while (callbacks.length > 0 && callbacks[0].time < expire)
{
callbacks.shift().callback([]);
}
return isdeletechannel
};
}
var channels = []
// get channel by name, or create new channel
function get_channel(name)
{
var channel = channels[name]
if (channel)
return channel
channels[name] = new Channel()
return channels[name];
}
// check expire channels or clients
function check_channels()
{
var expire = get_timestamp() - timeout;
for (channel in channels)
{
if (channels[channel].remove(expire))
{
delete channels[channel]
}
}
}
// check timeout
setInterval(check_channels, 1000)
function on_client_arrive(req, res)
{
log("New Client From: " + req.connection.remoteAddress + " Query: " + req.url)
var q = url.parse(req.url, true).query || {method:'update', channel:'test'}
var channel_name = q.channel || 'test'
var method = q.method || 'update'
var channel = get_channel(channel_name)
var callback = q.callback || false
// handle get
if (method == 'get')
{
time = q.time || 0
channel.get(time, function(messages)
{
time = channel.update()
response(res, 200, {time:time, messages:messages}, callback)
})
}
// handle put
else if (method == 'put')
{
message = q.message || null
time = channel.put(message)
response(res, 200, {time:time}, callback);
}
// sync client time
else{
time = channel.update();
response(res, 200, {time:time}, callback);
}
}
var server = createServer(on_client_arrive);
server.listen(port);
log("Jakiro Server v0.01 Start ...")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment