def append_other_data(self, datagram): field_packer = DCPacker() for index in self._other_fields: field = self._dc_class.get_field_by_index(index) if not field: self.notify.error( 'Failed to append other data for field: %s dclass: %s, unknown field!' % (field_name, self._dc_class.get_name())) field_packer.begin_pack(field) field.pack_args(field_packer, self._other_fields[field.get_number()]) field_packer.end_pack() datagram.append_data(field_packer.get_string())
def handle_send_update(self, field, sender, channel, di): datagram = io.NetworkDatagram() datagram.add_header(channel, sender, types.STATESERVER_OBJECT_UPDATE_FIELD) datagram.add_uint32(self._do_id) datagram.add_uint16(field.get_number()) field_packer = DCPacker() field_packer.begin_pack(field) if di.get_remaining_size(): field_packer.pack_literal_value(di.get_remaining_bytes()) field_packer.end_pack() datagram.append_data(field_packer.get_string()) self._network.handle_send_connection_datagram(datagram)
def create_object(self, channel_id, database_id, dclass, fields={}, callback=None): """ Create an object in the specified database. database_id specifies the control channel of the target database. dclass specifies the class of the object to be created. fields is a dict with any fields that should be stored in the object on creation. callback will be called with callback(do_id) if specified. On failure, do_id is 0. """ # Save the callback: ctx = self.get_context() self._callbacks[ctx] = callback # Pack up/count valid fields. field_packer = DCPacker() field_count = 0 for k, v in fields.items(): field = dclass.get_field_by_name(k) if not field: self.notify.error( 'Creation request for %s object contains an invalid field named %s' % (dclass.get_name(), k)) field_packer.raw_pack_uint16(field.get_number()) field_packer.begin_pack(field) field.pack_args(field_packer, v) field_packer.end_pack() field_count += 1 # Now generate and send the datagram: dg = NetworkDatagram() dg.add_header(database_id, channel_id, types.DBSERVER_CREATE_OBJECT) dg.add_uint32(ctx) dg.add_uint16(dclass.get_number()) dg.add_uint16(field_count) dg.append_data(field_packer.get_string()) self._network.handle_send_connection_datagram(dg)
def update_object(self, channel_id, database_id, do_id, dclass, new_fields, old_fields=None, callback=None): """ Update field(s) on an object, optionally with the requirement that the fields must match some old value. database_id and do_id represent the database control channel and object ID for the update request. new_fields is to be a dict of fieldname->value, representing the fields to add/change on the database object. old_fields, if specified, is a similarly-formatted dict that contains the expected older values. If the values do not match, the database will refuse to process the update. This is useful for guarding against race conditions. On success, the callback is called as callback(None). On failure, the callback is called as callback(dict), where dict contains the current object values. This is so that the updater can try again, basing its updates off of the new values. """ # Ensure that the keys in new_fields and old_fields are the same if # old_fields is given... if old_fields is not None: if set(new_fields.keys()) != set(old_fields.keys()): self.notify.error( 'new_fields and old_fields must contain the same keys!') return field_packer = DCPacker() field_count = 0 for k, v in new_fields.items(): field = dclass.get_field_by_name(k) if not field: self.notify.error( 'Update for %s(%d) object contains invalid field named %s' % (dclass.get_name(), do_id, k)) field_packer.raw_pack_uint16(field.get_number()) if old_fields is not None: # Pack the old values: field_packer.begin_pack(field) field.pack_args(field_packer, old_fields[k]) field_packer.end() field_packer.begin_pack(field) field.pack_args(field_packer, v) field_packer.end_pack() field_count += 1 # Generate and send the datagram: dg = NetworkDatagram() if old_fields is not None: ctx = self.get_context() self._callbacks[ctx] = callback if field_count == 1: dg.add_header(database_id, channel_id, types.DBSERVER_OBJECT_SET_FIELD_IF_EQUALS) else: dg.add_header(database_id, channel_id, types.DBSERVER_OBJECT_SET_FIELDS_IF_EQUALS) dg.add_uint32(ctx) else: if field_count == 1: dg.add_header(database_id, channel_id, types.DBSERVER_OBJECT_SET_FIELD) else: dg.add_header(database_id, channel_id, types.DBSERVER_OBJECT_SET_FIELDS) dg.add_uint32(do_id) if field_count != 1: dg.add_uint16(field_count) dg.append_data(field_packer.getString()) self._network.handle_send_connection_datagram(dg) if old_fields is None and callback is not None: # Why oh why did they ask for a callback if there's no old_fields? # Oh well, better honor their request: callback(None)
def handle_object_get_all(self, sender, di): context = di.get_uint32() do_id = di.get_uint32() file_object = self._backend.open_file( self._backend.get_filename(do_id)) if not file_object: self.notify.warning( 'Failed to get fields for object: %d context: %d, unknown object!' % (do_id, context)) return dc_name = file_object.get_value('dclass') dc_class = self.dc_loader.dclasses_by_name.get(dc_name) if not dc_class: self.notify.warning( 'Failed to query object: %d context: %d, unknown dclass: %s!' % (do_id, context, dc_name)) return fields = file_object.get_value('fields') if not fields: self.notify.warning( 'Failed to query object: %d context %d, invalid fields!' % (do_id, context)) return datagram = io.NetworkDatagram() datagram.add_header(sender, self.channel, types.DBSERVER_OBJECT_GET_ALL_RESP) datagram.add_uint32(context) datagram.add_uint8(1) field_packer = DCPacker() field_count = 0 for field_name, field_args in fields.items(): field = dc_class.get_field_by_name(field_name) if not field: self.notify.warning( 'Failed to query object %d context: %d, unknown field: %s' % (do_id, context, field_name)) return field_packer.raw_pack_uint16(field.get_number()) field_packer.begin_pack(field) field.pack_args(field_packer, field_args) field_packer.end_pack() field_count += 1 self._backend.close_file(file_object) datagram.add_uint16(dc_class.get_number()) datagram.add_uint16(field_count) datagram.append_data(field_packer.get_string()) self.handle_send_connection_datagram(datagram)