def field_spec_getter(msg_reg, chan): # we have already read the header containing the field number # read the byte count, the length of the spec byte_count = read_raw_varint(chan) end = chan.position + byte_count # read field 0 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER string = read_raw_len_plus(chan) name = string.decode('utf-8') # convert bytes to str # read field 1 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER field_type = VENUM_GET(chan) # read field 2 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER quant = VENUM_GET(chan) # read field 3 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER f_nbr = VENUM_GET(chan) # XXX IGNORING DEFAULT default = None val = FieldSpec(msg_reg, name, field_type, quant, f_nbr, default) return val
def enum_spec_getter(dummy_reg, chan): # we have already read the header containing the field number # read the byte count, the length of the spec byte_count = read_raw_varint(chan) end = chan.position + byte_count # XXX should use for validation # read field 0 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER string = read_raw_len_plus(chan) name = string.decode('utf-8') # convert bytes to str # read instances of field 1: should enforce the + quantifier here pairs = [] while chan.position < end: hdr = read_raw_varint(chan) if hdr_field_nbr(hdr) != 1: # XXX SHOULD COMPLAIN IF WRONG HEADER # XXX This is a a peek: pos only gets advanced if OK print("EXPECTED FIELD 1, FOUND %s" % hdr_field_nbr(hdr)) break exc = enum_pair_spec_getter(dummy_reg, chan) pairs.append(exc) # create EnumSpec instance, which gets returned val = EnumSpec(name, pairs) return val
def round_trip(self, nnn): """ Test writing and reading a varint as the first and only field in a buffer. """ # -- write varint ------------------------------------------- field_nbr = 1 + self.rng.next_int16(1024) chan = Channel(LEN_BUFFER) write_varint_field(chan, nnn, field_nbr) chan.flip() # -- read varint -------------------------------------------- # first the header (which is a varint) ------------ (prim_type, field_nbr2) = read_field_hdr(chan) offset2 = chan.position self.assertEqual(PrimTypes.VARINT, prim_type) self.assertEqual(field_nbr, field_nbr2) self.assertEqual(length_as_varint(field_nbr << 3), offset2) # then the varint proper -------------------------- varint_ = read_raw_varint(chan) chan.flip() offset3 = chan.limit self.assertEqual(nnn, varint_) self.assertEqual(offset2 + length_as_varint(nnn), offset3)
def enum_pair_spec_getter(dummy_reg, chan): # we have already read the header containing the field number # read the byte count, the length of the spec byte_count = read_raw_varint(chan) end = chan.position + byte_count # XXX should use for validation # read field 0 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER string = read_raw_len_plus(chan) sym = string.decode('utf-8') # convert bytes to str # read field 1 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER val = read_raw_varint(chan) # construct the EnumPairSpec object from field values obj = EnumPairSpec(sym, val) return obj
def msg_spec_getter(msg_reg, chan): # read the byte count, the length of the spec byte_count = read_raw_varint(chan) end = chan.position + byte_count # read field 0 hdr = read_raw_varint(chan) # SHOULD COMPLAIN IF WRONG HEADER string = read_raw_len_plus(chan) name = string.decode('utf8') # convert byte to str # read instances of field 1: should enforce the + quantifier here fields = [] while chan.position < end: hdr = read_raw_varint(chan) if hdr_field_nbr(hdr) != 1: # XXX SHOULD COMPLAIN IF WRONG HEADER # XXX This is a a peek: pos only gets advanced if OK print("EXPECTED FIELD 1, FOUND %s" % hdr_field_nbr(hdr)) break # XXX params should be (msgReg, chan) file = field_spec_getter(msg_reg, chan) # was chan0 fields.append(file) # we may have multiple enums enums = [] while chan.position < end: hdr = read_raw_varint(chan) if hdr_field_nbr(hdr) != 2: print("EXPECTED FIELD 2, FOUND %s" % hdr_field_nbr(hdr)) break enum = enum_spec_getter(chan) # was chan0 enums.append(enum) # XXX WRONG PARAMETER LIST # val = MsgSpec(name, fields, enums) dummy_parent = MsgSpec('dummy', msg_reg, None) val = MsgSpec(name, msg_reg, dummy_parent) return val
def recv_from_cnx(cnx, chan): """ Receive a serialized message from a connection into a channel. On return the channel has been flipped (offset = 0, limit = data length). Returns the msgNbr. """ # --------------------------------------------------------------- # SEE fieldz.msgImpl for an example of this kind of Channel # manipulation. Use a Python buffer to select the region of the # buffer we want to write into. # --------------------------------------------------------------- # receive something from the connection chan.clear() count = cnx.recv_into(chan.buffer, BUFSIZE) if count <= 0: raise IOError('initial read of message gets zero bytes') # read the header to determine the message type and its length (p_type, msg_nbr) = read_field_hdr(chan) # DEBUG print("CHAN_IO: count = %d; pType = %s, msgNbr = %s" % (count, p_type, msg_nbr)) # END if p_type != PrimTypes.LEN_PLUS: raise IOError('message header type is %d, not PrimTypes.LEN_PLUS' % p_type) # XXX raise exception of msgNbr <0 or msgNbr > 2 msg_len = read_raw_varint(chan) # XXX ignoring pathological possibility that offset > count # if we don't have all of the data, loop getting the rest while count < msg_len: # vBuf = buffer(chan.buffer, count) v_buf = memoryview(chan.buffer)[count:] count += cnx.recv_into(v_buf, BUFSIZE - count) chan.position = count chan.flip() return msg_nbr
def vsint64_get(chan): varint_ = read_raw_varint(chan) return decode_sint64(varint_)
def vuint64_get(chan): return read_raw_varint(chan)
def vbool_get(chan): varint_ = read_raw_varint(chan) return bool(varint_)
def venum_get(chan): return read_raw_varint(chan)
def read(cls, chan, parent_spec): """msg refers to the msg, n is field number; returns msg, n""" (p_type, nnn) = read_field_hdr(chan) if nnn < 0 or nnn >= len(parent_spec.msgs): raise RuntimeError("msg ID '%s' out of range" % nnn) msg_spec = parent_spec.msgs[nnn] msg_len = read_raw_varint(chan) # DEBUG print("IMPL_GETTER, P_TYPE %d, MSG/FIELD NBR %d, MSG_LEN %d" % ( p_type, nnn, msg_len)) # END end = chan.position + msg_len cls = _make_msg_class(parent_spec, msg_spec) # generated class fields = [] # ??? values = [] # ??? # XXX THIS IS NOT GOING TO WORK, BECAUSE WE NEED TO PEEK XXX for f_class in cls._fieldClasses: field_type = f_class._field_type # a number f_quant = f_class._quantifier field_nbr = f_class._field_nbr # read the field header (p_type, nbr) = read_field_hdr(chan) # DEBUG print( " GET_FROM_CHAN, FIELD %u, TYPE %u" % (field_nbr, field_type)) # END if field_nbr != nbr: raise RuntimeError(" EXPECTED FIELD_NBR %d, GOT %d" % ( field_nbr, nbr)) if f_quant == Q_REQUIRED or f_quant == Q_OPTIONAL: if field_type > 23: reg = cls.msg_spec.reg # BEGIN JUNK ------------------------------------ # DEBUG print( "READING: FIELD TYPE IS %s" % reg.reg_id2name(field_type)) # END entry = reg.reg_id2entry(field_type) print("READING: FIELD TYPE bis IS %s" % entry.name) # END JUNK -------------------------------------- child_spec = entry.msg_spec child_class = _make_msg_class(msg_spec, child_spec) # RECURSE: read(childCls, chan, msgSpec) # msgSpec is parentSpec here value = T_GET_FUNCS[field_type](chan) # XXX WRONG else: value = T_GET_FUNCS[field_type](chan) _check_position(chan, end) values.append(value) elif f_quant == Q_PLUS or f_quant == Q_STAR: v_list = [] # we are reading a list of values # WORKING HERE else: raise RuntimeError("unknown quantifier, index '%u'" % f_quant) # DEBUG print("AFTER COLLECTING %u FIELDS, OFFSET IS %u" % ( len(fields), chan.position)) # END # XXX BLOWS UP: can't handle Q_PLUS or Q_STAR (about line 407) return (cls(values), nnn) # GEEP