Add server and client HTML echo test and mootools library

This commit is contained in:
Joel Martin 2010-02-17 14:54:38 -06:00
commit 77c58e19ad
6 changed files with 4710 additions and 0 deletions

60
echo_local.html Normal file
View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Web Sockets echo test</title>
<meta charset="UTF-8">
<script src="mootools.js"></script>
<script src="mootools-more.js"></script>
<script>
var cnt = 0;
var s = null;
var timer = null;
function debug(str) {
cell = $('debug');
cell.innerHTML += str + "<br/>";
}
function send_data() {
debug(">> send_data: testing " + cnt);
s.send("testing " + cnt);
cnt ++;
}
window.onload = function() {
debug(">> window.onload");
var uri = new URI(window.location);
var host = uri.getData("host");
var port = uri.getData("port");
if ((!host) || (!port)) {
debug("must set host and port");
return;
}
var location = "ws://" + host + ":" + port
debug("connecting to " + location);
s = new WebSocket(location);
s.onmessage = function(e) {
debug(">> onmessage: " + e.data);
};
s.onopen = function(e) {
debug(">> onopen" + e);
timer = send_data.periodical(1000);
};
s.onclose = function(e) {
if (timer) {
timer = $clear(timer);
}
debug("<< onclose: " + e);
}
debug("<< window.onload");
};
</script>
</head>
<body>
Debug:
<div id="debug" style="width:600px;height:300px"></div>
</body>
</html>

4329
mootools-1.2.4-core-nc.js vendored Normal file

File diff suppressed because it is too large Load Diff

241
mootools-1.2.4.4-more.js Normal file
View File

@ -0,0 +1,241 @@
//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.
/*
---
script: More.js
description: MooTools More
license: MIT-style license
authors:
- Guillermo Rauch
- Thomas Aylott
- Scott Kyle
requires:
- core:1.2.4/MooTools
provides: [MooTools.More]
...
*/
MooTools.More = {
'version': '1.2.4.4',
'build': '6f6057dc645fdb7547689183b2311063bd653ddf'
};
/*
---
script: String.QueryString.js
description: Methods for dealing with URI query strings.
license: MIT-style license
authors:
- Sebastian Markbåge, Aaron Newton, Lennart Pilon, Valerio Proietti
requires:
- core:1.2.4/Array
- core:1.2.4/String
- /MooTools.More
provides: [String.QueryString]
...
*/
String.implement({
parseQueryString: function(){
var vars = this.split(/[&;]/), res = {};
if (vars.length) vars.each(function(val){
var index = val.indexOf('='),
keys = index < 0 ? [''] : val.substr(0, index).match(/[^\]\[]+/g),
value = decodeURIComponent(val.substr(index + 1)),
obj = res;
keys.each(function(key, i){
var current = obj[key];
if(i < keys.length - 1)
obj = obj[key] = current || {};
else if($type(current) == 'array')
current.push(value);
else
obj[key] = $defined(current) ? [current, value] : value;
});
});
return res;
},
cleanQueryString: function(method){
return this.split('&').filter(function(val){
var index = val.indexOf('='),
key = index < 0 ? '' : val.substr(0, index),
value = val.substr(index + 1);
return method ? method.run([key, value]) : $chk(value);
}).join('&');
}
});
/*
---
script: URI.js
description: Provides methods useful in managing the window location and uris.
license: MIT-style license
authors:
- Sebastian Markbåge
- Aaron Newton
requires:
- core:1.2.4/Selectors
- /String.QueryString
provides: URI
...
*/
var URI = new Class({
Implements: Options,
options: {
/*base: false*/
},
regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'],
schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0},
initialize: function(uri, options){
this.setOptions(options);
var base = this.options.base || URI.base;
if(!uri) uri = base;
if (uri && uri.parsed) this.parsed = $unlink(uri.parsed);
else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false);
},
parse: function(value, base){
var bits = value.match(this.regex);
if (!bits) return false;
bits.shift();
return this.merge(bits.associate(this.parts), base);
},
merge: function(bits, base){
if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false;
if (base){
this.parts.every(function(part){
if (bits[part]) return false;
bits[part] = base[part] || '';
return true;
});
}
bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()];
bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/';
return bits;
},
parseDirectory: function(directory, baseDirectory) {
directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory;
if (!directory.test(URI.regs.directoryDot)) return directory;
var result = [];
directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){
if (dir == '..' && result.length > 0) result.pop();
else if (dir != '.') result.push(dir);
});
return result.join('/') + '/';
},
combine: function(bits){
return bits.value || bits.scheme + '://' +
(bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') +
(bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') +
(bits.directory || '/') + (bits.file || '') +
(bits.query ? '?' + bits.query : '') +
(bits.fragment ? '#' + bits.fragment : '');
},
set: function(part, value, base){
if (part == 'value'){
var scheme = value.match(URI.regs.scheme);
if (scheme) scheme = scheme[1];
if (scheme && !$defined(this.schemes[scheme.toLowerCase()])) this.parsed = { scheme: scheme, value: value };
else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value });
} else if (part == 'data') {
this.setData(value);
} else {
this.parsed[part] = value;
}
return this;
},
get: function(part, base){
switch(part){
case 'value': return this.combine(this.parsed, base ? base.parsed : false);
case 'data' : return this.getData();
}
return this.parsed[part] || '';
},
go: function(){
document.location.href = this.toString();
},
toURI: function(){
return this;
},
getData: function(key, part){
var qs = this.get(part || 'query');
if (!$chk(qs)) return key ? null : {};
var obj = qs.parseQueryString();
return key ? obj[key] : obj;
},
setData: function(values, merge, part){
if (typeof values == 'string'){
data = this.getData();
data[arguments[0]] = arguments[1];
values = data;
} else if (merge) {
values = $merge(this.getData(), values);
}
return this.set(part || 'query', Hash.toQueryString(values));
},
clearData: function(part){
return this.set(part || 'query', '');
}
});
URI.prototype.toString = URI.prototype.valueOf = function(){
return this.get('value');
};
URI.regs = {
endSlash: /\/$/,
scheme: /^(\w+):/,
directoryDot: /\.\/|\.$/
};
URI.base = new URI(document.getElements('base[href]', true).getLast(), {base: document.location});
String.implement({
toURI: function(options){
return new URI(this, options);
}
});

1
mootools-more.js Symbolic link
View File

@ -0,0 +1 @@
mootools-1.2.4.4-more.js

1
mootools.js Symbolic link
View File

@ -0,0 +1 @@
mootools-1.2.4-core-nc.js

78
ws_echo.py Executable file
View File

@ -0,0 +1,78 @@
#!/usr/bin/python
# File: asynchat-example-1.py
import asyncore, asynchat
import sys, os, socket, string
server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r
Upgrade: WebSocket\r
Connection: Upgrade\r
WebSocket-Origin: %s\r
WebSocket-Location: ws://%s%s\r
WebSocket-Protocol: sample\r
\r
"""
class WSChannel(asynchat.async_chat):
def __init__(self, server, sock, addr):
print ">> WSChannel.__init__"
asynchat.async_chat.__init__(self, sock)
self.set_terminator("\r\n\r\n")
self.handshake = None
self.data = ""
self.shutdown = 0
def collect_incoming_data(self, data):
#print ">> WSChannel.collect_incoming_data"
self.data = self.data + data
def found_terminator(self):
#print ">> WSChannel.found_terminator"
if not self.handshake:
# got the client handshake lines
self.handshake = self.data
req_lines = self.handshake.split("\r\n")
_, path, _ = req_lines[0].split(" ")
_, origin = req_lines[4].split(" ")
_, host = req_lines[3].split(" ")
print "*** got handshake:\n%s" % self.handshake
print "*** origin: %s, location: ws://%s%s" % (origin, host, path)
self.push(server_handshake % (origin, host, path))
# self.push("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
# self.push("Upgrade: WebSocket\r\n")
# self.push("Connection: Upgrade\r\n")
# self.push("WebSocket-Origin: %s\r\n" % origin)
# self.push("WebSocket-Location: ws://%s%s\r\n" % (host, path))
# self.push("WebSocket-Protocol: sample\r\n")
# self.push("\r\n")
self.set_terminator("\xff") # look for frame terminators
else:
# return payload.
print "received: %s" % self.data
self.push("\x00 client sent: %s \xff" % self.data)
self.data = ""
class WSServer(asyncore.dispatcher):
def __init__(self, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(("", port))
self.listen(5)
print "<< WSServer.__init__"
def handle_accept(self):
print ">> WSServer.handle_accept"
conn, addr = self.accept()
WSChannel(self, conn, addr)
if __name__ == '__main__':
if len(sys.argv) < 2:
print "Usage: %s <port>" % sys.argv[0]
sys.exit(2)
PORT = int(sys.argv[1])
s = WSServer(PORT)
print "serving Web Socket at port", PORT, "..."
asyncore.loop()