Exemple #1
0
    def handle_query_object_resp(self, message_type, di):
        ctx = di.get_uint32()
        success = di.get_uint8()

        if ctx not in self._callbacks:
            self.notify.warning('Received unexpected %s (ctx %d)' %
                                (MsgId2Names[message_type], ctx))

            return

        try:
            if not success:
                if self._callbacks[ctx]:
                    self._callbacks[ctx](None, None)

                return

            if message_type == types.DBSERVER_OBJECT_GET_ALL_RESP:
                dclass_id = di.get_uint16()
                dclass = self._network.dc_loader.dclasses_by_number.get(
                    dclass_id)
            else:
                dclass = self._dclasses[ctx]

            if not dclass:
                self.notify.error(
                    'Received bad dclass %d in DBSERVER_OBJECT_GET_ALL_RESP' %
                    (dclass_id))

            if message_type == types.DBSERVER_OBJECT_GET_FIELD_RESP:
                field_count = 1
            else:
                field_count = di.get_uint16()

            field_packer = DCPacker()
            field_packer.set_unpack_data(di.get_remaining_bytes())
            fields = {}
            for x in xrange(field_count):
                field_id = field_packer.raw_unpack_uint16()
                field = dclass.get_field_by_index(field_id)

                if not field:
                    self.notify.error(
                        'Received bad field %d in query for %s object' %
                        (field_id, dclass.get_name()))

                field_packer.begin_unpack(field)
                fields[field.get_name()] = field.unpack_args(field_packer)
                field_packer.end_unpack()

            if self._callbacks[ctx]:
                self._callbacks[ctx](dclass, fields)

        finally:
            del self._callbacks[ctx]
            del self._dclasses[ctx]
Exemple #2
0
    def sendActivate(self, doId, parentId, zoneId, dclass=None, fields=None):
        """
        Activate a DBSS object, given its doId, into the specified parentId/zoneId.

        If both dclass and fields are specified, an ACTIVATE_WITH_DEFAULTS_OTHER
        will be sent instead. In other words, the specified fields will be
        auto-applied during the activation.
        """

        fieldPacker = DCPacker()
        fieldCount = 0
        if dclass and fields:
            for k, v in fields.items():
                field = dclass.getFieldByName(k)
                if not field:
                    self.notify.error(
                        'Activation request for %s object contains '
                        'invalid field named %s' % (dclass.getName(), k))

                fieldPacker.rawPackUint16(field.getNumber())
                fieldPacker.beginPack(field)
                field.packArgs(fieldPacker, v)
                fieldPacker.endPack()
                fieldCount += 1

            dg = PyDatagram()
            dg.addServerHeader(doId, self.ourChannel,
                               DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS)
            dg.addUint32(doId)
            dg.addUint32(0)
            dg.addUint32(0)
            self.send(dg)
            # DEFAULTS_OTHER isn't implemented yet, so we chase it with a SET_FIELDS
            dg = PyDatagram()
            dg.addServerHeader(doId, self.ourChannel,
                               STATESERVER_OBJECT_SET_FIELDS)
            dg.addUint32(doId)
            dg.addUint16(fieldCount)
            dg.appendData(fieldPacker.getString())
            self.send(dg)
            # Now slide it into the zone we expect to see it in (so it
            # generates onto us with all of the fields in place)
            dg = PyDatagram()
            dg.addServerHeader(doId, self.ourChannel,
                               STATESERVER_OBJECT_SET_LOCATION)
            dg.addUint32(parentId)
            dg.addUint32(zoneId)
            self.send(dg)
        else:
            dg = PyDatagram()
            dg.addServerHeader(doId, self.ourChannel,
                               DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS)
            dg.addUint32(doId)
            dg.addUint32(parentId)
            dg.addUint32(zoneId)
            self.send(dg)
Exemple #3
0
    def handle_object_set_field(self, sender, di):
        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 set fields for object: %d, unknown object!' %
                (do_id))

            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 set fields for object: %d, unknown dclass: %s!' %
                (do_id, dc_name))

            return

        fields = file_object.get_value('fields')

        if not fields:
            self.notify.warning(
                'Failed to set fields for object: %d, invalid fields!' %
                (do_id))

            return

        field_packer = DCPacker()
        field_packer.set_unpack_data(di.get_remaining_bytes())
        field_id = field_packer.raw_unpack_uint16()
        field = dc_class.get_field_by_index(field_id)

        if not field:
            self.notify.error(
                'Failed to unpack field: %d dclass: %s, invalid field!' %
                (field_id, dc_class.get_name()))

        field_packer.begin_unpack(field)
        field_args = field.unpack_args(field_packer)
        field_packer.end_unpack()

        if not field_args:
            self.notify.error(
                'Failed to unpack field args for field: %d dclass: %s, invalid result!'
                % (field.get_name(), dc_class.get_name()))

        fields[field.get_name()] = field_args
        file_object.set_value('fields', fields)

        self._backend.close_file(file_object)
    def handleQueryObjectResp(self, msgType, di):
        ctx = di.getUint32()
        success = di.getUint8()

        if ctx not in self._callbacks:
            self.notify.warning('Received unexpected %s'
                                ' (ctx %d)' % (MsgId2Names[msgType], ctx))
            return

        try:
            if not success:
                if self._callbacks[ctx]:
                    self._callbacks[ctx](None, None)
                return

            if msgType == DBSERVER_OBJECT_GET_ALL_RESP:
                dclassId = di.getUint16()
                dclass = self.air.dclassesByNumber.get(dclassId)
            else:
                dclass = self._dclasses[ctx]

            if not dclass:
                self.notify.error('Received bad dclass %d in'
                                  ' DBSERVER_OBJECT_GET_ALL_RESP' % (dclassId))

            if msgType == DBSERVER_OBJECT_GET_FIELD_RESP:
                fieldCount = 1
            else:
                fieldCount = di.getUint16()
            unpacker = DCPacker()
            unpacker.setUnpackData(di.getRemainingBytes())
            fields = {}
            for x in range(fieldCount):
                fieldId = unpacker.rawUnpackInt16()
                field = dclass.getFieldByIndex(fieldId)

                if not field:
                    self.notify.error('Received bad field %d in query for'
                                      ' %s object' %
                                      (fieldId, dclass.getName()))

                unpacker.beginUnpack(field)
                fields[field.getName()] = field.unpackArgs(unpacker)
                unpacker.endUnpack()

            if self._callbacks[ctx]:
                self._callbacks[ctx](dclass, fields)

        finally:
            del self._callbacks[ctx]
            del self._dclasses[ctx]
Exemple #5
0
    def handle_update_object_resp(self, di, multi):
        ctx = di.get_uint32()
        success = di.get_uint8()

        if ctx not in self._callbacks:
            self.notify.warning(
                'Received unexpected DBSERVER_OBJECT_SET_FIELD(S)_IF_EQUALS_RESP (ctx %d)'
                % (ctx))

            return

        try:
            if success:
                if self._callbacks[ctx]:
                    self._callbacks[ctx](None)

                return

            if not di.get_remaining_size():
                # We failed due to other reasons.
                if self._callbacks[ctx]:
                    return self._callbacks[ctx]({})

            if multi:
                field_count = di.get_uint16()
            else:
                field_count = 1

            field_packer = DCPacker()
            field_packer.set_unpack_data(di.get_remaining_bytes())
            fields = {}
            for x in xrange(field_count):
                fieldId = field_packer.raw_pack_uint16()
                field = self._network.dc_loader.dc_file.get_field_by_index(
                    fieldId)

                if not field:
                    self.notify.error(
                        'Received bad field %d in update failure response message'
                        % (fieldId))

                field_packer.begin_unpack(field)
                fields[field.get_name()] = field.unpack_args(field_packer)
                field_packer.end_unpack()

            if self._callbacks[ctx]:
                self._callbacks[ctx](fields)

        finally:
            del self._callbacks[ctx]
    def __handleObjectMessage(self, dgi):
        doId = dgi.getUint32()
        do = self.doId2do.get(doId)
        if not do:
            self.notify.warning("Received message for unknown object %i" %
                                doId)
            return

        fieldNumber = dgi.getUint16()
        field = do.dclass.getFieldByIndex(fieldNumber)
        if not field:
            self.notify.warning(
                "Received message on unknown field %i on object %i" %
                (fieldNumber, doId))
            return

        if field.asParameter():
            self.notify.warning("Received message for parameter field?")
            return

        # We can safely pass this message onto the object
        packer = DCPacker()
        packer.setUnpackData(dgi.getRemainingBytes())
        packer.beginUnpack(field)
        field.receiveUpdate(packer, do)
        if not packer.endUnpack():
            self.notify.warning("Failed to unpack message")
    def handleUpdateObjectResp(self, di, multi):
        ctx = di.getUint32()
        success = di.getUint8()

        if ctx not in self._callbacks:
            self.notify.warning('Received unexpected'
                                ' DBSERVER_OBJECT_SET_FIELD(S)_IF_EQUALS_RESP'
                                ' (ctx %d)' % (ctx))
            return

        try:
            if success:
                if self._callbacks[ctx]:
                    self._callbacks[ctx](None)
                return

            if not di.getRemainingSize():
                # We failed due to other reasons.
                if self._callbacks[ctx]:
                    return self._callbacks[ctx]({})

            if multi:
                fieldCount = di.getUint16()
            else:
                fieldCount = 1

            unpacker = DCPacker()
            unpacker.setUnpackData(di.getRemainingBytes())
            fields = {}
            for x in range(fieldCount):
                fieldId = unpacker.rawUnpackInt16()
                field = self.air.getDcFile().getFieldByIndex(fieldId)

                if not field:
                    self.notify.error('Received bad field %d in update'
                                      ' failure response message' % (fieldId))

                unpacker.beginUnpack(field)
                fields[field.getName()] = field.unpackArgs(unpacker)
                unpacker.endUnpack()

            if self._callbacks[ctx]:
                self._callbacks[ctx](fields)

        finally:
            del self._callbacks[ctx]
    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)
Exemple #9
0
    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 createObject(self, databaseId, dclass, fields={}, callback=None):
        """
        Create an object in the specified database.

        databaseId 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(doId) if specified. On failure, doId is 0.
        """

        # Save the callback:
        ctx = self.air.getContext()
        self._callbacks[ctx] = callback

        # Pack up/count valid fields.
        fieldPacker = DCPacker()
        fieldCount = 0
        for k, v in fields.items():
            field = dclass.getFieldByName(k)
            if not field:
                self.notify.error('Creation request for %s object contains '
                                  'invalid field named %s' %
                                  (dclass.getName(), k))

            fieldPacker.rawPackUint16(field.getNumber())
            fieldPacker.beginPack(field)
            field.packArgs(fieldPacker, v)
            fieldPacker.endPack()
            fieldCount += 1

        # Now generate and send the datagram:
        dg = PyDatagram()
        dg.addServerHeader(databaseId, self.air.ourChannel,
                           DBSERVER_CREATE_OBJECT)
        dg.addUint32(ctx)
        dg.addUint16(dclass.getNumber())
        dg.addUint16(fieldCount)
        dg.appendData(fieldPacker.getBytes())
        self.air.send(dg)
    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 __init__(self, network, do_id, parent_id, zone_id, dc_class, has_other,
                 di):
        self._network = network
        self._do_id = do_id

        self._old_owner_id = 0
        self._owner_id = 0

        self._old_parent_id = 0
        self._parent_id = parent_id

        self._old_zone_id = 0
        self._zone_id = zone_id

        self._dc_class = dc_class
        self._has_other = has_other

        self._required_fields = {}
        self._other_fields = {}

        field_packer = DCPacker()
        field_packer.set_unpack_data(di.get_remaining_bytes())

        for field_index in xrange(self._dc_class.get_num_inherited_fields()):
            field = self._dc_class.get_inherited_field(field_index)

            if not field:
                self.notify.error(
                    'Failed to unpack required field: %d dclass: %s, unknown field!'
                    % (field_index, self._dc_class.get_name()))

            if field.as_molecular_field() or not field.is_required():
                continue

            field_packer.begin_unpack(field)
            field_args = field.unpack_args(field_packer)
            field_packer.end_unpack()

            self._required_fields[field.get_number()] = field_args

        self._network.register_for_channel(self._do_id)
    def handleObjectMessage(self, client, dgi):
        doId = dgi.getUint32()
        do = self.doId2do.get(doId)
        if not do:
            self.notify.warning(
                "SUSPICIOUS: client %i tried to send message to unknown doId %i"
                % (client.id, doId))
            return

        fieldNumber = dgi.getUint16()
        field = do.dclass.getFieldByIndex(fieldNumber)
        if field.asParameter():
            self.notify.warning(
                "SUSPICIOUS: client %i tried to send message on a parameter field!"
            )
            return

        if not field:
            self.notify.warning(
                "SUSPICIOUS: client %i tried to send message on unknown field %i on doId %i"
                % (client.id, doId, fieldNumber))
            return

        if do.owner != client:
            if not field.isClsend():
                # Not client-send
                self.notify.warning(
                    "SUSPICIOUS: client %i tried to send non-clsend message on doId %i"
                    % (client.id, doId))
                return
        else:
            if not field.isOwnsend() and not field.isClsend():
                # Not client-send or owner-send
                self.notify.warning(
                    "SUSPICIOUS: owner client %i tried to send non-ownsend and non-clsend message on doId %i"
                    % (client.id, doId))
                return

        # We can safely pass this message onto the object
        packer = DCPacker()
        packer.setUnpackData(dgi.getRemainingBytes())
        packer.beginUnpack(field)
        field.receiveUpdate(packer, do)
        if not packer.endUnpack():
            self.notify.warning("Failed to unpack object message")
Exemple #14
0
    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 sendUpdate(self, do, name, args):
        if not do:
            return
        if not do.dclass:
            return
        field = do.dclass.getFieldByName(name)
        if not field:
            self.notify.warning(
                "Tried to send update for non-existent field %s" % name)
            return
        if field.asParameter():
            self.notify.warning("Tried to send parameter field as a message")
            return

        packer = DCPacker()
        packer.rawPackUint16(NetMessages.B_ObjectMessage)
        packer.rawPackUint32(do.doId)
        packer.rawPackUint16(field.getNumber())

        packer.beginPack(field)
        field.packArgs(packer, args)
        if not packer.endPack():
            self.notify.warning("Failed to pack object message")
            return

        dg = PyDatagram(packer.getBytes())
        self.sendDatagram(dg)
Exemple #16
0
    def sendUpdate(self, do, name, args, client = None):
        if not do:
            return
        if not do.dclass:
            return

        field = do.dclass.getFieldByName(name)
        if not field:
            self.notify.warning("Tried to send unknown field %s" % name)
            return
        if field.asParameter():
            self.notify.warning("Can't sent parameter field as a message")
            return

        packer = DCPacker()
        packer.rawPackUint16(NetMessages.B_ObjectMessage)
        packer.rawPackUint32(do.doId)
        packer.rawPackUint16(field.getNumber())

        packer.beginPack(field)
        field.packArgs(packer, args)
        if not packer.endPack():
            self.notify.warning("Failed to pack message")
            return

        dg = PyDatagram(packer.getBytes())
        if not client:
            if field.isBroadcast():
                # Send to all interested clients
                for cl in self.zonesToClients.get(do.zoneId, set()):
                    self.sendDatagram(dg, cl.connection)
            else:
                self.notify.warning("Can't send non-broadcast object message without a target client")
                return
        else:
            self.sendDatagram(dg, client.connection)
Exemple #17
0
    def handleGetObjectResp(self, di):
        ctx = di.getUint32()
        doId = di.getUint32()
        parentId = di.getUint32()
        zoneId = di.getUint32()
        classId = di.getUint16()

        if ctx not in self.__callbacks:
            self.notify.warning(
                'Received unexpected STATESERVER_OBJECT_GET_ALL_RESP (ctx: %d)'
                % ctx)
            return

        if classId not in self.dclassesByNumber:
            self.notify.warning(
                'Received STATESERVER_OBJECT_GET_ALL_RESP for unknown dclass=%d! (Object %d)'
                % (classId, doId))
            return

        dclass = self.dclassesByNumber[classId]

        fields = {}
        unpacker = DCPacker()
        unpacker.setUnpackData(di.getRemainingBytes())

        # Required:
        for i in xrange(dclass.getNumInheritedFields()):
            field = dclass.getInheritedField(i)
            if not field.isRequired() or field.asMolecularField(): continue
            unpacker.beginUnpack(field)
            fields[field.getName()] = field.unpackArgs(unpacker)
            unpacker.endUnpack()

        # Other:
        other = unpacker.rawUnpackUint16()
        for i in xrange(other):
            field = dclass.getFieldByIndex(unpacker.rawUnpackUint16())
            unpacker.beginUnpack(field)
            fields[field.getName()] = field.unpackArgs(unpacker)
            unpacker.endUnpack()

        try:
            self.__callbacks[ctx](doId, parentId, zoneId, dclass, fields)
        finally:
            del self.__callbacks[ctx]
Exemple #18
0
    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)
    def handle_update_field(self, sender, channel, di):
        field_id = di.get_uint16()
        field = self._dc_class.get_field_by_index(field_id)

        if not field:
            self.notify.warning(
                'Failed to update field: %d dclass: %s, unknown field!' %
                (field_id, self._dc_class.get_name()))

            return

        # copy the field update so we can unpack it and
        # update any required fields here on the state server.
        # we must do this after we allow the field to be updated
        # because the checks to ensure the field is valid must be ran first...
        datagram = io.NetworkDatagram()
        datagram.append_data(di.get_remaining_bytes())

        # create a new datagram iterator object that the field
        # response update can unpack from...
        di = io.NetworkDatagramIterator(datagram)

        # ensure this field is not a bogus field...
        if field.is_bogus_field():
            self.notify.debug(
                'Cannot handle field update for field: %s dclass: %s, field is bogus!'
                % (field.get_name(), self._dc_class.get_name()))

            return

        if not self._network.shard_manager.has_shard(sender):
            avatar_id = self._network.get_avatar_id_from_connection_channel(
                sender)

            if not avatar_id:
                self.notify.warning(
                    'Cannot handle field update for field: %s dclass: %s, unknown avatar: %d!'
                    % (field.get_name(), self._dc_class.get_name(), avatar_id))

                return

            if field.is_ownsend():
                if sender != self._owner_id:
                    self.notify.warning(
                        'Cannot handle field update for field: %s dclass: %s, field not sendable!'
                        % (field.get_name(), self._dc_class.get_name()))

                    return
            else:
                if not field.is_clsend():
                    self.notify.warning(
                        'Cannot handle field update for field: %s dclass: %s, field not sendable!'
                        % (field.get_name(), self._dc_class.get_name()))

                    return

            if not field.is_broadcast():
                self.handle_send_update(field, sender, self._parent_id, di)
            else:
                self.handle_send_update_broadcast(field,
                                                  sender,
                                                  di,
                                                  excludes=[avatar_id])
        else:
            if not field.is_broadcast():
                self.handle_send_update(field, self._parent_id, channel, di)
            else:
                self.handle_send_update_broadcast(field,
                                                  self._parent_id,
                                                  di,
                                                  excludes=[self._do_id])

        # unpack the field arguments so that we can update our
        # view of the object's required or other fields dictionaries...
        di = io.NetworkDatagramIterator(datagram)

        # if the iterator is empty, this means that the field
        # has no arguents and that we should not attempt to update it...
        if not di.get_remaining_size():
            return

        field_packer = DCPacker()
        field_packer.set_unpack_data(di.get_remaining_bytes())

        field_packer.begin_unpack(field)
        field_args = field.unpack_args(field_packer)
        field_packer.end_unpack()

        # check to see if the field is a required or other field,
        # and store the new arguments appropriately.
        if field.is_required():
            self._required_fields[field.get_number()] = field_args
        elif field.is_ram():
            self._other_fields[field.get_number()] = field_args
Exemple #20
0
    def handle_create_object(self, sender, di):
        context = di.get_uint32()
        dc_id = di.get_uint16()
        field_count = di.get_uint16()
        dc_class = self.dc_loader.dclasses_by_number.get(dc_id)

        if not dc_class:
            self.notify.error(
                'Failed to create object: %d context: %d, unknown dclass!' %
                (dc_id, context))

        do_id = self._backend.allocator.allocate()
        file_object = self._backend.open_file(
            self._backend.get_filename(do_id))

        file_object.set_value('dclass', dc_class.get_name())
        file_object.set_value('do_id', do_id)

        fields = {}
        field_packer = DCPacker()
        field_packer.set_unpack_data(di.get_remaining_bytes())

        for _ in xrange(field_count):
            field_id = field_packer.raw_unpack_uint16()
            field = dc_class.get_field_by_index(field_id)

            if not field:
                self.notify.error(
                    'Failed to unpack field: %d dclass: %s, invalid field!' %
                    (field_id, dc_class.get_name()))

            field_packer.begin_unpack(field)
            field_args = field.unpack_args(field_packer)
            field_packer.end_unpack()

            if not field_args:
                self.notify.error(
                    'Failed to unpack field args for field: %d dclass: %s, invalid result!'
                    % (field.get_name(), dc_class.get_name()))

            fields[field.get_name()] = field_args

        for index in xrange(dc_class.get_num_inherited_fields()):
            field_packer = DCPacker()
            field = dc_class.get_inherited_field(index)

            if not field:
                continue

            if field.get_name() in fields:
                continue

            if not field.is_db() or not field.has_default_value():
                continue

            field_packer.set_unpack_data(field.get_default_value())
            field_packer.begin_unpack(field)
            field_args = field.unpack_args(field_packer)
            field_packer.end_unpack()

            if not field_args:
                self.notify.error(
                    'Failed to unpack field args for field: %d dclass: %s, invalid result!'
                    % (field.get_name(), dc_class.get_name()))

            fields[field.get_name()] = field_args

        file_object.set_value('fields', fields)

        self._backend.close_file(file_object)
        self._backend.tracker.set_value('next', do_id + 1)

        datagram = io.NetworkDatagram()
        datagram.add_header(sender, self.channel,
                            types.DBSERVER_CREATE_OBJECT_RESP)

        datagram.add_uint32(context)
        datagram.add_uint32(do_id)
        self.handle_send_connection_datagram(datagram)