aboutsummaryrefslogtreecommitdiff
path: root/python/gats.py
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2012-01-16 16:42:17 +0000
committerMike Buland <eichlan@xagasoft.com>2012-01-16 16:42:17 +0000
commit4843dede4add1764ced095ecf3e41ecc3a53240e (patch)
treecea32f881e5760dd417e3e8a0eaf2b3b15ecd32e /python/gats.py
parentdfeb2636eb83098ebd621ce2add83ef9e256318f (diff)
downloadlibgats-4843dede4add1764ced095ecf3e41ecc3a53240e.tar.gz
libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.tar.bz2
libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.tar.xz
libgats-4843dede4add1764ced095ecf3e41ecc3a53240e.zip
Added networking compatible send/recv functions as helpers, plus a bunch of
docs.
Diffstat (limited to 'python/gats.py')
-rw-r--r--python/gats.py66
1 files changed, 61 insertions, 5 deletions
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 @@
1
2"""Provides pickle-compatible functions for working with Gats packets.
3Converts to and from normal python structures like dictionaries, lists,
4tuples, booleans, strings, etc.
5
6This also provides a couple of helpers to make working with sockets a bit
7easier, recv and send work with sockets in blocking mode."""
8
1import struct 9import struct
2from cStringIO import StringIO 10from cStringIO import StringIO as _StringIO
3import math 11import math
4 12
5_scalarMagic = float.fromhex('0x1.62e42fefa39efp+2') 13_scalarMagic = float.fromhex('0x1.62e42fefa39efp+2')
6 14
15def recv( s ):
16 '''A helper that reads a single packet from the provided socket (s). The
17 socket should be in blocking mode for this to work correctly. This function
18 doesn't handle any exceptions, so if the socket closes while reading
19 handling the exception is up to you.'''
20 while True:
21 version = s.recv(1)
22 if len(version) == 0:
23 return None
24 version = ord(version[0])
25 if version != 0:
26 break
27
28 if version == 1:
29 sBuf = _StringIO()
30 iSize = 5
31 buf = ''
32 while len(buf) < 4:
33 buf += s.recv(4-len(buf))
34 iGoalSize = struct.unpack('>I', buf )[0]
35 while iSize < iGoalSize:
36 buf = s.recv( min(iGoalSize-iSize, 4096) )
37 sBuf.write( buf )
38 iSize += len(buf)
39
40 sBuf.seek( 0 )
41 return _readObj( sBuf )
42
43def send( obj, s ):
44 '''A helper that sends the entire object (obj), in a Gats encoded packet to
45 the provided socket (s). This buffers the data first, so it should use
46 as few network packets as possible to send the data.'''
47 s.send( dumps( obj ) )
48
7def loads( sIn ): 49def loads( sIn ):
8 return load( StringIO( sIn ) ) 50 '''Loads a complete Gats packet as described by the string sIn and returns
51 the contained object. The string can only contain one packet. Any data
52 after the first packet will simply be ignored.'''
53 return load( _StringIO( sIn ) )
9 54
10def dumps( obj ): 55def dumps( obj ):
11 sTmp = StringIO() 56 '''Returns the provided object (obj) as a complete Gats packet in a string,
57 since Gats encoded objects are not in plain text, it'll probably be useless
58 to print these strings out.'''
59 sTmp = _StringIO()
12 dump( obj, sTmp ) 60 dump( obj, sTmp )
13 return sTmp.getvalue() 61 return sTmp.getvalue()
14 62
15def load( sIn ): 63def load( sIn ):
64 '''Reads a single Gats packet (one object) from the provided file-like
65 object and returns it. If it can't read anything it returns None.'''
16 # Scan for a valid packet header 66 # Scan for a valid packet header
17 while True: 67 while True:
18 version = sIn.read(1) 68 version = sIn.read(1)
@@ -27,7 +77,9 @@ def load( sIn ):
27 return _readObj( sIn ) 77 return _readObj( sIn )
28 78
29def dump( obj, sOut ): 79def dump( obj, sOut ):
30 sTmp = StringIO() 80 '''Writes the given object (obj) to the file-like object sOut as a complete
81 Gats packet.'''
82 sTmp = _StringIO()
31 _writeObj( obj, sTmp ) 83 _writeObj( obj, sTmp )
32 sCore = sTmp.getvalue() 84 sCore = sTmp.getvalue()
33 sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) ) 85 sOut.write( struct.pack('>BI', 1, len(sCore)+5 ) )
@@ -152,7 +204,7 @@ def _writeObj( obj, sOut ):
152 if iScale < 0: 204 if iScale < 0:
153 iScale -= 1 205 iScale -= 1
154 206
155 sTmp = StringIO() 207 sTmp = _StringIO()
156 208
157 d /= pow( 256.0, iScale ) 209 d /= pow( 256.0, iScale )
158 sTmp.write( chr( int(d) ) ) 210 sTmp.write( chr( int(d) ) )
@@ -175,6 +227,8 @@ def _writeObj( obj, sOut ):
175 raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj))) 227 raise Exception('A type that is not gats-encodable was encountered: ' + str(type(obj)))
176 228
177def _readPackedInt( sIn ): 229def _readPackedInt( sIn ):
230 '''Internal helper function that reads an integer in packed format from the
231 provided file-like object and returns it.'''
178 bNeg = False 232 bNeg = False
179 233
180 b = ord(sIn.read(1)[0]) 234 b = ord(sIn.read(1)[0])
@@ -191,6 +245,8 @@ def _readPackedInt( sIn ):
191 return rOut 245 return rOut
192 246
193def _writePackedInt( iIn, sOut ): 247def _writePackedInt( iIn, sOut ):
248 '''Internal helper function that writes an integer in packed format to the
249 provided file-like object.'''
194 if iIn < 0: 250 if iIn < 0:
195 iIn = -iIn 251 iIn = -iIn
196 b = iIn&0x3F 252 b = iIn&0x3F