From 4843dede4add1764ced095ecf3e41ecc3a53240e Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 16 Jan 2012 16:42:17 +0000 Subject: Added networking compatible send/recv functions as helpers, plus a bunch of docs. --- python/gats.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 5 deletions(-) (limited to 'python/gats.py') diff --git a/python/gats.py b/python/gats.py index 7e66f52..760314a 100644 --- a/python/gats.py +++ b/python/gats.py @@ -1,18 +1,68 @@ + +"""Provides pickle-compatible functions for working with Gats packets. +Converts to and from normal python structures like dictionaries, lists, +tuples, booleans, strings, etc. + +This also provides a couple of helpers to make working with sockets a bit +easier, recv and send work with sockets in blocking mode.""" + import struct -from cStringIO import StringIO +from cStringIO import StringIO as _StringIO import math _scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') +def recv( s ): + '''A helper that reads a single packet from the provided socket (s). The + socket should be in blocking mode for this to work correctly. This function + doesn't handle any exceptions, so if the socket closes while reading + handling the exception is up to you.''' + while True: + version = s.recv(1) + if len(version) == 0: + return None + version = ord(version[0]) + if version != 0: + break + + if version == 1: + sBuf = _StringIO() + iSize = 5 + buf = '' + while len(buf) < 4: + buf += s.recv(4-len(buf)) + iGoalSize = struct.unpack('>I', buf )[0] + while iSize < iGoalSize: + buf = s.recv( min(iGoalSize-iSize, 4096) ) + sBuf.write( buf ) + iSize += len(buf) + + sBuf.seek( 0 ) + return _readObj( sBuf ) + +def send( obj, s ): + '''A helper that sends the entire object (obj), in a Gats encoded packet to + the provided socket (s). This buffers the data first, so it should use + as few network packets as possible to send the data.''' + s.send( dumps( obj ) ) + def loads( sIn ): - return load( StringIO( sIn ) ) + '''Loads a complete Gats packet as described by the string sIn and returns + the contained object. The string can only contain one packet. Any data + after the first packet will simply be ignored.''' + return load( _StringIO( sIn ) ) def dumps( obj ): - sTmp = StringIO() + '''Returns the provided object (obj) as a complete Gats packet in a string, + since Gats encoded objects are not in plain text, it'll probably be useless + to print these strings out.''' + sTmp = _StringIO() dump( obj, sTmp ) return sTmp.getvalue() def load( sIn ): + '''Reads a single Gats packet (one object) from the provided file-like + object and returns it. If it can't read anything it returns None.''' # Scan for a valid packet header while True: version = sIn.read(1) @@ -27,7 +77,9 @@ def load( sIn ): return _readObj( sIn ) def dump( obj, sOut ): - sTmp = StringIO() + '''Writes the given object (obj) to the file-like object sOut as a complete + Gats packet.''' + sTmp = _StringIO() _writeObj( obj, sTmp ) sCore = sTmp.getvalue() sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) ) @@ -152,7 +204,7 @@ def _writeObj( obj, sOut ): if iScale < 0: iScale -= 1 - sTmp = StringIO() + sTmp = _StringIO() d /= pow( 256.0, iScale ) sTmp.write( chr( int(d) ) ) @@ -175,6 +227,8 @@ def _writeObj( obj, sOut ): raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj))) def _readPackedInt( sIn ): + '''Internal helper function that reads an integer in packed format from the + provided file-like object and returns it.''' bNeg = False b = ord(sIn.read(1)[0]) @@ -191,6 +245,8 @@ def _readPackedInt( sIn ): return rOut def _writePackedInt( iIn, sOut ): + '''Internal helper function that writes an integer in packed format to the + provided file-like object.''' if iIn < 0: iIn = -iIn b = iIn&0x3F -- cgit v1.2.3