Skip to content

Commit

Permalink
Added parsing request as cython extension
Browse files Browse the repository at this point in the history
  • Loading branch information
igorcoding committed Jan 9, 2017
1 parent 67ecb58 commit b4f3a96
Show file tree
Hide file tree
Showing 15 changed files with 555 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "third_party/msgpuck"]
path = third_party/msgpuck
url = https://github.com/tarantool/msgpuck.git
Empty file added asynctnt/ciproto/__init__.py
Empty file.
44 changes: 44 additions & 0 deletions asynctnt/ciproto/cmsgpuck.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from libc.stdint cimport uint32_t, uint64_t, int64_t

cdef extern from "../../third_party/msgpuck/msgpuck.h":
cdef enum mp_type:
MP_NIL = 0
MP_UINT
MP_INT
MP_STR
MP_BIN
MP_ARRAY
MP_MAP
MP_BOOL
MP_FLOAT
MP_DOUBLE
MP_EXT

cdef mp_type mp_typeof(const char c);

cdef uint32_t mp_decode_array(const char **data);

cdef uint32_t mp_decode_map(const char **data);

cdef uint64_t mp_decode_uint(const char **data);

cdef int64_t mp_decode_int(const char **data);

cdef float mp_decode_float(const char **data);

cdef double mp_decode_double(const char **data);

cdef uint32_t mp_decode_strl(const char **data);
cdef const char *mp_decode_str(const char **data, uint32_t *len);

cdef uint32_t mp_decode_binl(const char **data);
cdef const char *mp_decode_bin(const char **data, uint32_t *len);

cdef uint32_t mp_decode_strbinl(const char **data);
cdef const char *mp_decode_strbin(const char **data, uint32_t *len);

cdef void mp_decode_nil(const char **data);
cdef bint mp_decode_bool(const char **data);

cdef void mp_next(const char **data);

26 changes: 26 additions & 0 deletions asynctnt/ciproto/const.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cdef enum tnt_header_key:
TP_CODE = 0x00
TP_SYNC = 0x01
TP_SERVER_ID = 0x02
TP_LSN = 0x03
TP_TIMESTAMP = 0x04
TP_SCHEMA_ID = 0x05


cdef enum tnt_body_key_t:
TP_SPACE = 0x10
TP_INDEX = 0x11
TP_LIMIT = 0x12
TP_OFFSET = 0x13
TP_ITERATOR = 0x14
TP_KEY = 0x20
TP_TUPLE = 0x21
TP_FUNCTION = 0x22
TP_USERNAME = 0x23
TP_EXPRESSION = 0x27
TP_OPERATIONS = 0x28


cdef enum tnt_response_key_t:
TP_DATA = 0x30
TP_ERROR = 0x31
183 changes: 183 additions & 0 deletions asynctnt/ciproto/encdec.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
from libc.stdint cimport uint32_t, uint64_t, int64_t

cimport cmsgpuck as mp
cimport const as tnt_const

from response cimport TntResponse


cdef _decode_obj(const char** p):
cdef:
uint32_t i
mp.mp_type obj_type

const char* s
uint32_t s_len

uint32_t arr_size
list arr

uint32_t map_size
dict map
mp.mp_type map_key_type
const char* map_key_str
uint32_t map_key_len
object map_key


obj_type = mp.mp_typeof(p[0][0])
if obj_type == mp.MP_UINT:
return mp.mp_decode_uint(p)
elif obj_type == mp.MP_INT:
return mp.mp_decode_int(p)
elif obj_type == mp.MP_STR:
s = NULL
s_len = 0
s = mp.mp_decode_str(p, &s_len)
return s[:s_len].decode()
elif obj_type == mp.MP_BIN:
s = NULL
s_len = 0
s = mp.mp_decode_bin(p, &s_len)
return <bytes>s
elif obj_type == mp.MP_BOOL:
return mp.mp_decode_bool(p)
elif obj_type == mp.MP_FLOAT:
return mp.mp_decode_float(p)
elif obj_type == mp.MP_DOUBLE:
return mp.mp_decode_double(p)
elif obj_type == mp.MP_ARRAY:
arr_size = mp.mp_decode_array(p)
value = []
for i in range(arr_size):
value.append(_decode_obj(p))
return value
elif obj_type == mp.MP_MAP:
map = {}
map_size = mp.mp_decode_map(p)
for i in range(map_size):
map_key_type = mp.mp_typeof(p[0][0])
if map_key_type == mp.MP_STR:
map_key_len = 0
map_key_str = mp.mp_decode_str(p, &map_key_len)
map_key = <object>(map_key_str[:map_key_len].decode())
elif map_key_type == mp.MP_UINT:
map_key = <object>mp.mp_decode_uint(p)
elif map_key_type == mp.MP_INT:
map_key = <object>mp.mp_decode_int(p)
else:
mp.mp_next(p) # skip current key
mp.mp_next(p) # skip value
print('Unexpected key type in map: {}'.format(map_key_type))

map[map_key] = _decode_obj(p)

return map
elif obj_type == mp.MP_NIL:
mp.mp_next(p)
return None
else:
print('Unexpected obj type: {}'.format(obj_type))
mp.mp_next(p)
return None


cdef _cresponse_parse_body_data(const char* b):
cdef:
uint32_t size
uint32_t tuple_size
list tuples
uint32_t i, k

size = mp.mp_decode_array(&b)
tuples = []
for i in range(size):
tuple_size = mp.mp_decode_array(&b)
t = []
for k in range(tuple_size):
t.append(_decode_obj(&b))
tuples.append(t)

return tuples


cdef cresponse_parse(bytes buf):
cdef:
const char* b
uint32_t size
uint32_t key
uint32_t s_len
const char* s
TntResponse resp

buf_len = len(buf)
begin = <const char*>buf
b = <const char*>buf
# if mp.mp_typeof(b[0]) != mp.MP_MAP:
# raise TypeError('Response header must be a MP_MAP')

resp = TntResponse()

# parsing header
size = mp.mp_decode_map(&b)
for _ in range(size):
# if mp.mp_typeof(b[0]) != mp.MP_UINT:
# raise TypeError('Header key must be a MP_UINT')

key = mp.mp_decode_uint(&b)
if key == tnt_const.TP_CODE:
# if mp.mp_typeof(b[0]) != mp.MP_UINT:
# raise TypeError('code type must be a MP_UINT')

resp.code = mp.mp_decode_uint(&b)
resp.code &= 0x7FFF
elif key == tnt_const.TP_SYNC:
# if mp.mp_typeof(b[0]) != mp.MP_UINT:
# raise TypeError('sync type must be a MP_UINT')

resp.sync = mp.mp_decode_uint(&b)
elif key == tnt_const.TP_SCHEMA_ID:
# if mp.mp_typeof(b[0]) != mp.MP_UINT:
# raise TypeError('schema_id type must be a MP_UINT')

resp.schema_id = mp.mp_decode_uint(&b)
else:
print('Unknown argument in header. Skipping.')
mp.mp_next(&b)


# parsing body
if b == &begin[buf_len]:
# buffer exceeded
return resp

# if mp.mp_typeof(b[0]) != mp.MP_MAP:
# raise TypeError('Response body must be a MP_MAP')

size = mp.mp_decode_map(&b)
for _ in range(size):
# if mp.mp_typeof(b[0]) != mp.MP_UINT:
# raise TypeError('Header key must be a MP_UINT')

key = mp.mp_decode_uint(&b)
if key == tnt_const.TP_ERROR:
# if mp.mp_typeof(b[0]) != mp.MP_STR:
# raise TypeError('errstr type must be a MP_STR')

s = NULL
s_len = 0
s = mp.mp_decode_str(&b, &s_len)
resp.errmsg = s[:s_len].decode()
elif key == tnt_const.TP_DATA:
if mp.mp_typeof(b[0]) != mp.MP_ARRAY:
raise TypeError('body data type must be a MP_ARRAY')
resp.body = _cresponse_parse_body_data(b)

return resp




cpdef response_parse(bytes buf):
res = cresponse_parse(buf)
return res
12 changes: 12 additions & 0 deletions asynctnt/ciproto/response.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from libc.stdint cimport uint64_t

cdef class TntResponse:
cdef:
int code
uint64_t sync
int schema_id
str errmsg
list body

cdef inline has_schema_id(self):
return self.schema_id != -1
10 changes: 10 additions & 0 deletions asynctnt/ciproto/response.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cdef class TntResponse:
def __cinit__(self):
self.code = 0
self.sync = 0
self.schema_id = -1
self.errmsg = None
self.body = None

def __repr__(self):
return '<TntResponse: code={}, sync={}>'.format(self.code, self.sync)
Loading

0 comments on commit b4f3a96

Please sign in to comment.