Created
July 9, 2013 14:45
-
-
Save jkal/5957918 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* Install dependencies: | |
pip install -r requirements.txt | |
* Build executable: | |
make osx | |
* Start server and client: | |
open dist/app.app | |
open client.html | |
tail -f dist/app.app/Contents/Resources/app.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import logging | |
import tornado | |
import tornadio | |
import tornadio.server | |
logging.basicConfig(filename='app.log', level=logging.INFO) | |
class SocketHandler(tornadio.SocketConnection): | |
clients = set() | |
def on_open(self, request, *args, **kwargs): | |
self.clients.add(self) | |
self.ip = request.remote_ip | |
logging.info("Connection opened.") | |
def on_message(self, message): | |
# Process message and send to the usb port. | |
# Use pyserial or something. | |
# Reply to the client. | |
# self.send(message) | |
logging.info("Received message: %s", message) | |
def on_close(self): | |
self.clients.remove(self) | |
logging.info("Connection closed.") | |
router = tornadio.get_router(SocketHandler, { | |
'enabled_protocols': [ | |
'websocket', 'xhr-multipart', 'xhr-polling' | |
] | |
}) | |
app = tornado.web.Application([ | |
router.route() | |
], socket_io_port=8000) | |
if __name__ == '__main__': | |
tornadio.server.SocketServer(app) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script src="http://cdn.socket.io/stable/socket.io.js"></script> | |
<script src="msgpack.js"></script> | |
<script>WEB_SOCKET_SWF_LOCATION = 'http://cdn.socket.io/stable/WebSocketMain.swf';</script> | |
<script> | |
var byteArray = new ArrayBuffer(16); | |
for (var i = 0; i < byteArray.byteLength; i++) { | |
byteArray[i] = i*2; | |
} | |
console.log(msgpack.encode(byteArray)); | |
var socket = new io.Socket('localhost',{ | |
port: 8000 | |
}); | |
socket.connect(); | |
socket.on('connect',function() { | |
console.log('connected'); | |
}); | |
socket.on('message',function(data) { | |
console.log('received:', data); | |
}); | |
socket.on('disconnect',function() { | |
console.log('disconnected'); | |
}); | |
socket.send("data"); | |
</script> | |
</head> | |
<body></body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
osx: app.py | |
py2applet --make-setup app.py --iconfile icon.icns | |
python setup.py py2app -A | |
clean: | |
rm -rf build/ dist/ setup.py app.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
( // Module boilerplate to support browser globals and browserify and AMD. | |
typeof define === "function" ? function (m) { define("msgpack-js", m); } : | |
typeof exports === "object" ? function (m) { module.exports = m(); } : | |
function(m){ this.msgpack = m(); } | |
)(function () { | |
"use strict"; | |
var exports = {}; | |
exports.inspect = inspect; | |
function inspect(buffer) { | |
if (buffer === undefined) return "undefined"; | |
var view; | |
var type; | |
if (buffer instanceof ArrayBuffer) { | |
type = "ArrayBuffer"; | |
view = new DataView(buffer); | |
} | |
else if (buffer instanceof DataView) { | |
type = "DataView"; | |
view = buffer; | |
} | |
if (!view) return JSON.stringify(buffer); | |
var bytes = []; | |
for (var i = 0; i < buffer.byteLength; i++) { | |
if (i > 20) { | |
bytes.push("..."); | |
break; | |
} | |
var byte = view.getUint8(i).toString(16); | |
if (byte.length === 1) byte = "0" + byte; | |
bytes.push(byte); | |
} | |
return "<" + type + " " + bytes.join(" ") + ">"; | |
} | |
// Encode string as utf8 into dataview at offset | |
exports.utf8Write = utf8Write; | |
function utf8Write(view, offset, string) { | |
var byteLength = view.byteLength; | |
for(var i = 0, l = string.length; i < l; i++) { | |
var codePoint = string.charCodeAt(i); | |
// One byte of UTF-8 | |
if (codePoint < 0x80) { | |
view.setUint8(offset++, codePoint >>> 0 & 0x7f | 0x00); | |
continue; | |
} | |
// Two bytes of UTF-8 | |
if (codePoint < 0x800) { | |
view.setUint8(offset++, codePoint >>> 6 & 0x1f | 0xc0); | |
view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80); | |
continue; | |
} | |
// Three bytes of UTF-8. | |
if (codePoint < 0x10000) { | |
view.setUint8(offset++, codePoint >>> 12 & 0x0f | 0xe0); | |
view.setUint8(offset++, codePoint >>> 6 & 0x3f | 0x80); | |
view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80); | |
continue; | |
} | |
// Four bytes of UTF-8 | |
if (codePoint < 0x110000) { | |
view.setUint8(offset++, codePoint >>> 18 & 0x07 | 0xf0); | |
view.setUint8(offset++, codePoint >>> 12 & 0x3f | 0x80); | |
view.setUint8(offset++, codePoint >>> 6 & 0x3f | 0x80); | |
view.setUint8(offset++, codePoint >>> 0 & 0x3f | 0x80); | |
continue; | |
} | |
throw new Error("bad codepoint " + codePoint); | |
} | |
} | |
exports.utf8Read = utf8Read; | |
function utf8Read(view, offset, length) { | |
var string = ""; | |
for (var i = offset, end = offset + length; i < end; i++) { | |
var byte = view.getUint8(i); | |
// One byte character | |
if ((byte & 0x80) === 0x00) { | |
string += String.fromCharCode(byte); | |
continue; | |
} | |
// Two byte character | |
if ((byte & 0xe0) === 0xc0) { | |
string += String.fromCharCode( | |
((byte & 0x0f) << 6) | | |
(view.getUint8(++i) & 0x3f) | |
); | |
continue; | |
} | |
// Three byte character | |
if ((byte & 0xf0) === 0xe0) { | |
string += String.fromCharCode( | |
((byte & 0x0f) << 12) | | |
((view.getUint8(++i) & 0x3f) << 6) | | |
((view.getUint8(++i) & 0x3f) << 0) | |
); | |
continue; | |
} | |
// Four byte character | |
if ((byte & 0xf8) === 0xf0) { | |
string += String.fromCharCode( | |
((byte & 0x07) << 18) | | |
((view.getUint8(++i) & 0x3f) << 12) | | |
((view.getUint8(++i) & 0x3f) << 6) | | |
((view.getUint8(++i) & 0x3f) << 0) | |
); | |
continue; | |
} | |
throw new Error("Invalid byte " + byte.toString(16)); | |
} | |
return string; | |
} | |
exports.utf8ByteCount = utf8ByteCount; | |
function utf8ByteCount(string) { | |
var count = 0; | |
for(var i = 0, l = string.length; i < l; i++) { | |
var codePoint = string.charCodeAt(i); | |
if (codePoint < 0x80) { | |
count += 1; | |
continue; | |
} | |
if (codePoint < 0x800) { | |
count += 2; | |
continue; | |
} | |
if (codePoint < 0x10000) { | |
count += 3; | |
continue; | |
} | |
if (codePoint < 0x110000) { | |
count += 4; | |
continue; | |
} | |
throw new Error("bad codepoint " + codePoint); | |
} | |
return count; | |
} | |
exports.encode = function (value) { | |
var buffer = new ArrayBuffer(sizeof(value)); | |
var view = new DataView(buffer); | |
encode(value, view, 0); | |
return buffer; | |
} | |
exports.decode = decode; | |
// http://wiki.msgpack.org/display/MSGPACK/Format+specification | |
// I've extended the protocol to have two new types that were previously reserved. | |
// buffer 16 11011000 0xd8 | |
// buffer 32 11011001 0xd9 | |
// These work just like raw16 and raw32 except they are node buffers instead of strings. | |
// | |
// Also I've added a type for `undefined` | |
// undefined 11000100 0xc4 | |
function Decoder(view, offset) { | |
this.offset = offset || 0; | |
this.view = view; | |
} | |
Decoder.prototype.map = function (length) { | |
var value = {}; | |
for (var i = 0; i < length; i++) { | |
var key = this.parse(); | |
value[key] = this.parse(); | |
} | |
return value; | |
}; | |
Decoder.prototype.buf = function (length) { | |
var value = new ArrayBuffer(length); | |
(new Uint8Array(value)).set(new Uint8Array(this.view.buffer, this.offset, length), 0); | |
this.offset += length; | |
return value; | |
}; | |
Decoder.prototype.raw = function (length) { | |
var value = utf8Read(this.view, this.offset, length); | |
this.offset += length; | |
return value; | |
}; | |
Decoder.prototype.array = function (length) { | |
var value = new Array(length); | |
for (var i = 0; i < length; i++) { | |
value[i] = this.parse(); | |
} | |
return value; | |
}; | |
Decoder.prototype.parse = function () { | |
var type = this.view.getUint8(this.offset); | |
var value, length; | |
// FixRaw | |
if ((type & 0xe0) === 0xa0) { | |
length = type & 0x1f; | |
this.offset++; | |
return this.raw(length); | |
} | |
// FixMap | |
if ((type & 0xf0) === 0x80) { | |
length = type & 0x0f; | |
this.offset++; | |
return this.map(length); | |
} | |
// FixArray | |
if ((type & 0xf0) === 0x90) { | |
length = type & 0x0f; | |
this.offset++; | |
return this.array(length); | |
} | |
// Positive FixNum | |
if ((type & 0x80) === 0x00) { | |
this.offset++; | |
return type; | |
} | |
// Negative Fixnum | |
if ((type & 0xe0) === 0xe0) { | |
value = this.view.getInt8(this.offset); | |
this.offset++; | |
return value; | |
} | |
switch (type) { | |
// raw 16 | |
case 0xda: | |
length = this.view.getUint16(this.offset + 1); | |
this.offset += 3; | |
return this.raw(length); | |
// raw 32 | |
case 0xdb: | |
length = this.view.getUint32(this.offset + 1); | |
this.offset += 5; | |
return this.raw(length); | |
// nil | |
case 0xc0: | |
this.offset++; | |
return null; | |
// false | |
case 0xc2: | |
this.offset++; | |
return false; | |
// true | |
case 0xc3: | |
this.offset++; | |
return true; | |
// undefined | |
case 0xc4: | |
this.offset++; | |
return undefined; | |
// uint8 | |
case 0xcc: | |
value = this.view.getUint8(this.offset + 1); | |
this.offset += 2; | |
return value; | |
// uint 16 | |
case 0xcd: | |
value = this.view.getUint16(this.offset + 1); | |
this.offset += 3; | |
return value; | |
// uint 32 | |
case 0xce: | |
value = this.view.getUint32(this.offset + 1); | |
this.offset += 5; | |
return value; | |
// int 8 | |
case 0xd0: | |
value = this.view.getInt8(this.offset + 1); | |
this.offset += 2; | |
return value; | |
// int 16 | |
case 0xd1: | |
value = this.view.getInt16(this.offset + 1); | |
this.offset += 3; | |
return value; | |
// int 32 | |
case 0xd2: | |
value = this.view.getInt32(this.offset + 1); | |
this.offset += 5; | |
return value; | |
// map 16 | |
case 0xde: | |
length = this.view.getUint16(this.offset + 1); | |
this.offset += 3; | |
return this.map(length); | |
// map 32 | |
case 0xdf: | |
length = this.view.getUint32(this.offset + 1); | |
this.offset += 5; | |
return this.map(length); | |
// array 16 | |
case 0xdc: | |
length = this.view.getUint16(this.offset + 1); | |
this.offset += 3; | |
return this.array(length); | |
// array 32 | |
case 0xdd: | |
length = this.view.getUint32(this.offset + 1); | |
this.offset += 5; | |
return this.array(length); | |
// buffer 16 | |
case 0xd8: | |
length = this.view.getUint16(this.offset + 1); | |
this.offset += 3; | |
return this.buf(length); | |
// buffer 32 | |
case 0xd9: | |
length = this.view.getUint32(this.offset + 1); | |
this.offset += 5; | |
return this.buf(length); | |
// float | |
case 0xca: | |
value = this.view.getFloat32(this.offset + 1); | |
this.offset += 5; | |
return value; | |
// double | |
case 0xcb: | |
value = this.view.getFloat64(this.offset + 1); | |
this.offset += 9; | |
return value; | |
} | |
throw new Error("Unknown type 0x" + type.toString(16)); | |
}; | |
function decode(buffer) { | |
var view = new DataView(buffer); | |
var decoder = new Decoder(view); | |
var value = decoder.parse(); | |
if (decoder.offset !== buffer.byteLength) throw new Error((buffer.byteLength - decoder.offset) + " trailing bytes"); | |
return value; | |
} | |
function encode(value, view, offset) { | |
var type = typeof value; | |
// Strings Bytes | |
if (type === "string") { | |
var length = utf8ByteCount(value); | |
// fix raw | |
if (length < 0x20) { | |
view.setUint8(offset, length | 0xa0); | |
utf8Write(view, offset + 1, value); | |
return 1 + length; | |
} | |
// raw 16 | |
if (length < 0x10000) { | |
view.setUint8(offset, 0xda); | |
view.setUint16(offset + 1, length); | |
utf8Write(view, offset + 3, value); | |
return 3 + length; | |
} | |
// raw 32 | |
if (length < 0x100000000) { | |
view.setUint8(offset, 0xdb); | |
view.setUint32(offset + 1, length); | |
utf8Write(view, offset + 5, value); | |
return 5 + length; | |
} | |
} | |
if (value instanceof ArrayBuffer) { | |
var length = value.byteLength; | |
// buffer 16 | |
if (length < 0x10000) { | |
view.setUint8(offset, 0xd8); | |
view.setUint16(offset + 1, length); | |
(new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 3); | |
return 3 + length; | |
} | |
// buffer 32 | |
if (length < 0x100000000) { | |
view.setUint8(offset, 0xd9); | |
view.setUint32(offset + 1, length); | |
(new Uint8Array(view.buffer)).set(new Uint8Array(value), offset + 5); | |
return 5 + length; | |
} | |
} | |
if (type === "number") { | |
// Floating Point | |
if ((value << 0) !== value) { | |
view.setUint8(offset, 0xcb); | |
view.setFloat64(offset + 1, value); | |
return 9; | |
} | |
// Integers | |
if (value >=0) { | |
// positive fixnum | |
if (value < 0x80) { | |
view.setUint8(offset, value); | |
return 1; | |
} | |
// uint 8 | |
if (value < 0x100) { | |
view.setUint8(offset, 0xcc); | |
view.setUint8(offset + 1, value); | |
return 2; | |
} | |
// uint 16 | |
if (value < 0x10000) { | |
view.setUint8(offset, 0xcd); | |
view.setUint16(offset + 1, value); | |
return 3; | |
} | |
// uint 32 | |
if (value < 0x100000000) { | |
view.setUint8(offset, 0xce); | |
view.setUint32(offset + 1, value); | |
return 5; | |
} | |
throw new Error("Number too big 0x" + value.toString(16)); | |
} | |
// negative fixnum | |
if (value >= -0x20) { | |
view.setInt8(offset, value); | |
return 1; | |
} | |
// int 8 | |
if (value >= -0x80) { | |
view.setUint8(offset, 0xd0); | |
view.setInt8(offset + 1, value); | |
return 2; | |
} | |
// int 16 | |
if (value >= -0x8000) { | |
view.setUint8(offset, 0xd1); | |
view.setInt16(offset + 1, value); | |
return 3; | |
} | |
// int 32 | |
if (value >= -0x80000000) { | |
view.setUint8(offset, 0xd2); | |
view.setInt32(offset + 1, value); | |
return 5; | |
} | |
throw new Error("Number too small -0x" + (-value).toString(16).substr(1)); | |
} | |
// undefined | |
if (type === "undefined") { | |
view.setUint8(offset, 0xc4); | |
return 1; | |
} | |
// null | |
if (value === null) { | |
view.setUint8(offset, 0xc0); | |
return 1; | |
} | |
// Boolean | |
if (type === "boolean") { | |
view.setUint8(offset, value ? 0xc3 : 0xc2); | |
return 1; | |
} | |
// Container Types | |
if (type === "object") { | |
var length, size = 0; | |
var isArray = Array.isArray(value); | |
if (isArray) { | |
length = value.length; | |
} | |
else { | |
var keys = Object.keys(value); | |
length = keys.length; | |
} | |
var size; | |
if (length < 0x10) { | |
view.setUint8(offset, length | (isArray ? 0x90 : 0x80)); | |
size = 1; | |
} | |
else if (length < 0x10000) { | |
view.setUint8(offset, isArray ? 0xdc : 0xde); | |
view.setUint16(offset + 1, length); | |
size = 3; | |
} | |
else if (length < 0x100000000) { | |
view.setUint8(offset, isArray ? 0xdd : 0xdf); | |
view.setUint32(offset + 1, length); | |
size = 5; | |
} | |
if (isArray) { | |
for (var i = 0; i < length; i++) { | |
size += encode(value[i], view, offset + size); | |
} | |
} | |
else { | |
for (var i = 0; i < length; i++) { | |
var key = keys[i]; | |
size += encode(key, view, offset + size); | |
size += encode(value[key], view, offset + size); | |
} | |
} | |
return size; | |
} | |
throw new Error("Unknown type " + type); | |
} | |
function sizeof(value) { | |
var type = typeof value; | |
// Raw Bytes | |
if (type === "string") { | |
var length = utf8ByteCount(value); | |
if (length < 0x20) { | |
return 1 + length; | |
} | |
if (length < 0x10000) { | |
return 3 + length; | |
} | |
if (length < 0x100000000) { | |
return 5 + length; | |
} | |
} | |
if (value instanceof ArrayBuffer) { | |
var length = value.byteLength; | |
if (length < 0x10000) { | |
return 3 + length; | |
} | |
if (length < 0x100000000) { | |
return 5 + length; | |
} | |
} | |
if (type === "number") { | |
// Floating Point | |
// double | |
if (value << 0 !== value) return 9; | |
// Integers | |
if (value >=0) { | |
// positive fixnum | |
if (value < 0x80) return 1; | |
// uint 8 | |
if (value < 0x100) return 2; | |
// uint 16 | |
if (value < 0x10000) return 3; | |
// uint 32 | |
if (value < 0x100000000) return 5; | |
// uint 64 | |
if (value < 0x10000000000000000) return 9; | |
throw new Error("Number too big 0x" + value.toString(16)); | |
} | |
// negative fixnum | |
if (value >= -0x20) return 1; | |
// int 8 | |
if (value >= -0x80) return 2; | |
// int 16 | |
if (value >= -0x8000) return 3; | |
// int 32 | |
if (value >= -0x80000000) return 5; | |
// int 64 | |
if (value >= -0x8000000000000000) return 9; | |
throw new Error("Number too small -0x" + value.toString(16).substr(1)); | |
} | |
// Boolean, null, undefined | |
if (type === "boolean" || type === "undefined" || value === null) return 1; | |
// Container Types | |
if (type === "object") { | |
var length, size = 0; | |
if (Array.isArray(value)) { | |
length = value.length; | |
for (var i = 0; i < length; i++) { | |
size += sizeof(value[i]); | |
} | |
} | |
else { | |
var keys = Object.keys(value); | |
length = keys.length; | |
for (var i = 0; i < length; i++) { | |
var key = keys[i]; | |
size += sizeof(key) + sizeof(value[key]); | |
} | |
} | |
if (length < 0x10) { | |
return 1 + size; | |
} | |
if (length < 0x10000) { | |
return 3 + size; | |
} | |
if (length < 0x100000000) { | |
return 5 + size; | |
} | |
throw new Error("Array or object too long 0x" + length.toString(16)); | |
} | |
throw new Error("Unknown type " + type); | |
} | |
return exports; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tornado==3.1 | |
TornadIO==0.0.5 | |
py2app==0.7.3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment