Esempio n. 1
0
    def persist(
        self, sender=USER_ID, room_id=ROOM_ID, type={}, key=None, internal={},
        state=None, reset_state=False, backfill=False,
        depth=None, prev_events=[], auth_events=[], prev_state=[], redacts=None,
        push_actions=[],
        **content
    ):
        """
        Returns:
            synapse.events.FrozenEvent: The event that was persisted.
        """
        if depth is None:
            depth = self.event_id

        event_dict = {
            "sender": sender,
            "type": type,
            "content": content,
            "event_id": "$%d:blue" % (self.event_id,),
            "room_id": room_id,
            "depth": depth,
            "origin_server_ts": self.event_id,
            "prev_events": prev_events,
            "auth_events": auth_events,
        }
        if key is not None:
            event_dict["state_key"] = key
            event_dict["prev_state"] = prev_state

        if redacts is not None:
            event_dict["redacts"] = redacts

        event = FrozenEvent(event_dict, internal_metadata_dict=internal)

        self.event_id += 1

        context = EventContext(current_state=state)
        context.push_actions = push_actions

        ordering = None
        if backfill:
            yield self.master_store.persist_events(
                [(event, context)], backfilled=True
            )
        else:
            ordering, _ = yield self.master_store.persist_event(
                event, context, current_state=reset_state
            )

        if ordering:
            event.internal_metadata.stream_ordering = ordering

        defer.returnValue(event)
Esempio n. 2
0
    def _handle_request(self, request, event_id):
        with Measure(self.clock, "repl_send_event_parse"):
            content = parse_json_object_from_request(request)

            event_dict = content["event"]
            internal_metadata = content["internal_metadata"]
            rejected_reason = content["rejected_reason"]
            event = FrozenEvent(event_dict, internal_metadata, rejected_reason)

            requester = Requester.deserialize(self.store, content["requester"])
            context = yield EventContext.deserialize(self.store, content["context"])

            ratelimit = content["ratelimit"]
            extra_users = [UserID.from_string(u) for u in content["extra_users"]]

        if requester.user:
            request.authenticated_entity = requester.user.to_string()

        logger.info(
            "Got event to send with ID: %s into room: %s",
            event.event_id, event.room_id,
        )

        yield self.event_creation_handler.persist_and_notify_client_event(
            requester, event, context,
            ratelimit=ratelimit,
            extra_users=extra_users,
        )

        defer.returnValue((200, {}))
Esempio n. 3
0
    def compute_event_context(self, event, old_state=None):
        """ Fills out the context with the `current state` of the graph. The
        `current state` here is defined to be the state of the event graph
        just before the event - i.e. it never includes `event`

        If `event` has `auth_events` then this will also fill out the
        `auth_events` field on `context` from the `current_state`.

        Args:
            event (EventBase)
        Returns:
            an EventContext
        """
        context = EventContext()

        if event.internal_metadata.is_outlier():
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.
            if old_state:
                context.prev_state_ids = {
                    (s.type, s.state_key): s.event_id for s in old_state
                }
                if event.is_state():
                    context.current_state_events = dict(context.prev_state_ids)
                    key = (event.type, event.state_key)
                    context.current_state_events[key] = event.event_id
                else:
                    context.current_state_events = context.prev_state_ids
            else:
                context.current_state_ids = {}
                context.prev_state_ids = {}
            context.prev_state_events = []
            context.state_group = self.store.get_next_state_group()
            defer.returnValue(context)

        if old_state:
            context.prev_state_ids = {
                (s.type, s.state_key): s.event_id for s in old_state
            }
            context.state_group = self.store.get_next_state_group()

            if event.is_state():
                key = (event.type, event.state_key)
                if key in context.prev_state_ids:
                    replaces = context.prev_state_ids[key]
                    if replaces != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces
                context.current_state_ids = dict(context.prev_state_ids)
                context.current_state_ids[key] = event.event_id
            else:
                context.current_state_ids = context.prev_state_ids

            context.prev_state_events = []
            defer.returnValue(context)

        if event.is_state():
            entry = yield self.resolve_state_groups(
                event.room_id, [e for e, _ in event.prev_events],
                event_type=event.type,
                state_key=event.state_key,
            )
        else:
            entry = yield self.resolve_state_groups(
                event.room_id, [e for e, _ in event.prev_events],
            )

        curr_state = entry.state

        context.prev_state_ids = curr_state
        if event.is_state():
            context.state_group = self.store.get_next_state_group()

            key = (event.type, event.state_key)
            if key in context.prev_state_ids:
                replaces = context.prev_state_ids[key]
                event.unsigned["replaces_state"] = replaces

            context.current_state_ids = dict(context.prev_state_ids)
            context.current_state_ids[key] = event.event_id

            context.prev_group = entry.prev_group
            context.delta_ids = entry.delta_ids
            if context.delta_ids is not None:
                context.delta_ids = dict(context.delta_ids)
                context.delta_ids[key] = event.event_id
        else:
            if entry.state_group is None:
                entry.state_group = self.store.get_next_state_group()
                entry.state_id = entry.state_group

            context.state_group = entry.state_group
            context.current_state_ids = context.prev_state_ids
            context.prev_group = entry.prev_group
            context.delta_ids = entry.delta_ids

        context.prev_state_events = []
        defer.returnValue(context)
Esempio n. 4
0
    def compute_event_context(self, event, old_state=None):
        """ Fills out the context with the `current state` of the graph. The
        `current state` here is defined to be the state of the event graph
        just before the event - i.e. it never includes `event`

        If `event` has `auth_events` then this will also fill out the
        `auth_events` field on `context` from the `current_state`.

        Args:
            event (EventBase)
        Returns:
            an EventContext
        """
        context = EventContext()

        yield run_on_reactor()

        if old_state:
            context.current_state = {
                (s.type, s.state_key): s for s in old_state
            }
            context.state_group = None

            if hasattr(event, "auth_events") and event.auth_events:
                auth_ids = zip(*event.auth_events)[0]
                context.auth_events = {
                    k: v
                    for k, v in context.current_state.items()
                    if v.event_id in auth_ids
                }
            else:
                context.auth_events = {}

            if event.is_state():
                key = (event.type, event.state_key)
                if key in context.current_state:
                    replaces = context.current_state[key]
                    if replaces.event_id != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces.event_id

            context.prev_state_events = []
            defer.returnValue(context)

        if event.is_state():
            ret = yield self.resolve_state_groups(
                [e for e, _ in event.prev_events],
                event_type=event.type,
                state_key=event.state_key,
            )
        else:
            ret = yield self.resolve_state_groups(
                [e for e, _ in event.prev_events],
            )

        group, curr_state, prev_state = ret

        context.current_state = curr_state
        context.state_group = group if not event.is_state() else None

        prev_state = yield self.store.add_event_hashes(
            prev_state
        )

        if event.is_state():
            key = (event.type, event.state_key)
            if key in context.current_state:
                replaces = context.current_state[key]
                event.unsigned["replaces_state"] = replaces.event_id

        if hasattr(event, "auth_events") and event.auth_events:
            auth_ids = zip(*event.auth_events)[0]
            context.auth_events = {
                k: v
                for k, v in context.current_state.items()
                if v.event_id in auth_ids
            }
        else:
            context.auth_events = {}

        context.prev_state_events = prev_state
        defer.returnValue(context)
Esempio n. 5
0
    def compute_event_context(self, event, old_state=None):
        """Build an EventContext structure for the event.

        This works out what the current state should be for the event, and
        generates a new state group if necessary.

        Args:
            event (synapse.events.EventBase):
            old_state (dict|None): The state at the event if it can't be
                calculated from existing events. This is normally only specified
                when receiving an event from federation where we don't have the
                prev events for, e.g. when backfilling.
        Returns:
            synapse.events.snapshot.EventContext:
        """

        if event.internal_metadata.is_outlier():
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.
            if old_state:
                prev_state_ids = {
                    (s.type, s.state_key): s.event_id for s in old_state
                }
                if event.is_state():
                    current_state_ids = dict(prev_state_ids)
                    key = (event.type, event.state_key)
                    current_state_ids[key] = event.event_id
                else:
                    current_state_ids = prev_state_ids
            else:
                current_state_ids = {}
                prev_state_ids = {}

            # We don't store state for outliers, so we don't generate a state
            # group for it.
            context = EventContext.with_state(
                state_group=None,
                current_state_ids=current_state_ids,
                prev_state_ids=prev_state_ids,
            )

            defer.returnValue(context)

        if old_state:
            # We already have the state, so we don't need to calculate it.
            # Let's just correctly fill out the context and create a
            # new state group for it.

            prev_state_ids = {
                (s.type, s.state_key): s.event_id for s in old_state
            }

            if event.is_state():
                key = (event.type, event.state_key)
                if key in prev_state_ids:
                    replaces = prev_state_ids[key]
                    if replaces != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces
                current_state_ids = dict(prev_state_ids)
                current_state_ids[key] = event.event_id
            else:
                current_state_ids = prev_state_ids

            state_group = yield self.store.store_state_group(
                event.event_id,
                event.room_id,
                prev_group=None,
                delta_ids=None,
                current_state_ids=current_state_ids,
            )

            context = EventContext.with_state(
                state_group=state_group,
                current_state_ids=current_state_ids,
                prev_state_ids=prev_state_ids,
            )

            defer.returnValue(context)

        logger.debug("calling resolve_state_groups from compute_event_context")

        entry = yield self.resolve_state_groups_for_events(
            event.room_id, event.prev_event_ids(),
        )

        prev_state_ids = entry.state
        prev_group = None
        delta_ids = None

        if event.is_state():
            # If this is a state event then we need to create a new state
            # group for the state after this event.

            key = (event.type, event.state_key)
            if key in prev_state_ids:
                replaces = prev_state_ids[key]
                event.unsigned["replaces_state"] = replaces

            current_state_ids = dict(prev_state_ids)
            current_state_ids[key] = event.event_id

            if entry.state_group:
                # If the state at the event has a state group assigned then
                # we can use that as the prev group
                prev_group = entry.state_group
                delta_ids = {
                    key: event.event_id
                }
            elif entry.prev_group:
                # If the state at the event only has a prev group, then we can
                # use that as a prev group too.
                prev_group = entry.prev_group
                delta_ids = dict(entry.delta_ids)
                delta_ids[key] = event.event_id

            state_group = yield self.store.store_state_group(
                event.event_id,
                event.room_id,
                prev_group=prev_group,
                delta_ids=delta_ids,
                current_state_ids=current_state_ids,
            )
        else:
            current_state_ids = prev_state_ids
            prev_group = entry.prev_group
            delta_ids = entry.delta_ids

            if entry.state_group is None:
                entry.state_group = yield self.store.store_state_group(
                    event.event_id,
                    event.room_id,
                    prev_group=entry.prev_group,
                    delta_ids=entry.delta_ids,
                    current_state_ids=current_state_ids,
                )
                entry.state_id = entry.state_group

            state_group = entry.state_group

        context = EventContext.with_state(
            state_group=state_group,
            current_state_ids=current_state_ids,
            prev_state_ids=prev_state_ids,
            prev_group=prev_group,
            delta_ids=delta_ids,
        )

        defer.returnValue(context)
Esempio n. 6
0
    def compute_event_context(self, event, old_state=None, outlier=False):
        """ Fills out the context with the `current state` of the graph. The
        `current state` here is defined to be the state of the event graph
        just before the event - i.e. it never includes `event`

        If `event` has `auth_events` then this will also fill out the
        `auth_events` field on `context` from the `current_state`.

        Args:
            event (EventBase)
        Returns:
            an EventContext
        """
        yield run_on_reactor()

        context = EventContext()

        if outlier:
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.
            if old_state:
                context.current_state = {
                    (s.type, s.state_key): s for s in old_state
                }
            else:
                context.current_state = {}
            context.prev_state_events = []
            context.state_group = None
            defer.returnValue(context)

        if old_state:
            context.current_state = {
                (s.type, s.state_key): s for s in old_state
            }
            context.state_group = None

            if event.is_state():
                key = (event.type, event.state_key)
                if key in context.current_state:
                    replaces = context.current_state[key]
                    if replaces.event_id != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces.event_id

            context.prev_state_events = []
            defer.returnValue(context)

        if event.is_state():
            ret = yield self.resolve_state_groups(
                event.room_id, [e for e, _ in event.prev_events],
                event_type=event.type,
                state_key=event.state_key,
            )
        else:
            ret = yield self.resolve_state_groups(
                event.room_id, [e for e, _ in event.prev_events],
            )

        group, curr_state, prev_state = ret

        context.current_state = curr_state
        context.state_group = group if not event.is_state() else None

        if event.is_state():
            key = (event.type, event.state_key)
            if key in context.current_state:
                replaces = context.current_state[key]
                event.unsigned["replaces_state"] = replaces.event_id

        context.prev_state_events = prev_state
        defer.returnValue(context)
Esempio n. 7
0
    def compute_event_context(self, event, old_state=None):
        """Build an EventContext structure for the event.

        Args:
            event (synapse.events.EventBase):
        Returns:
            synapse.events.snapshot.EventContext:
        """
        context = EventContext()

        if event.internal_metadata.is_outlier():
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.
            if old_state:
                context.prev_state_ids = {
                    (s.type, s.state_key): s.event_id for s in old_state
                }
                if event.is_state():
                    context.current_state_ids = dict(context.prev_state_ids)
                    key = (event.type, event.state_key)
                    context.current_state_ids[key] = event.event_id
                else:
                    context.current_state_ids = context.prev_state_ids
            else:
                context.current_state_ids = {}
                context.prev_state_ids = {}
            context.prev_state_events = []
            context.state_group = self.store.get_next_state_group()
            defer.returnValue(context)

        if old_state:
            context.prev_state_ids = {
                (s.type, s.state_key): s.event_id for s in old_state
            }
            context.state_group = self.store.get_next_state_group()

            if event.is_state():
                key = (event.type, event.state_key)
                if key in context.prev_state_ids:
                    replaces = context.prev_state_ids[key]
                    if replaces != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces
                context.current_state_ids = dict(context.prev_state_ids)
                context.current_state_ids[key] = event.event_id
            else:
                context.current_state_ids = context.prev_state_ids

            context.prev_state_events = []
            defer.returnValue(context)

        logger.debug("calling resolve_state_groups from compute_event_context")
        if event.is_state():
            entry = yield self.resolve_state_groups(
                event.room_id, [e for e, _ in event.prev_events],
                event_type=event.type,
                state_key=event.state_key,
            )
        else:
            entry = yield self.resolve_state_groups(
                event.room_id, [e for e, _ in event.prev_events],
            )

        curr_state = entry.state

        context.prev_state_ids = curr_state
        if event.is_state():
            context.state_group = self.store.get_next_state_group()

            key = (event.type, event.state_key)
            if key in context.prev_state_ids:
                replaces = context.prev_state_ids[key]
                event.unsigned["replaces_state"] = replaces

            context.current_state_ids = dict(context.prev_state_ids)
            context.current_state_ids[key] = event.event_id

            context.prev_group = entry.prev_group
            context.delta_ids = entry.delta_ids
            if context.delta_ids is not None:
                context.delta_ids = dict(context.delta_ids)
                context.delta_ids[key] = event.event_id
        else:
            if entry.state_group is None:
                entry.state_group = self.store.get_next_state_group()
                entry.state_id = entry.state_group

            context.state_group = entry.state_group
            context.current_state_ids = context.prev_state_ids
            context.prev_group = entry.prev_group
            context.delta_ids = entry.delta_ids

        context.prev_state_events = []
        defer.returnValue(context)
Esempio n. 8
0
    def compute_event_context(self, event, old_state=None):
        """Build an EventContext structure for the event.

        This works out what the current state should be for the event, and
        generates a new state group if necessary.

        Args:
            event (synapse.events.EventBase):
            old_state (dict|None): The state at the event if it can't be
                calculated from existing events. This is normally only specified
                when receiving an event from federation where we don't have the
                prev events for, e.g. when backfilling.
        Returns:
            synapse.events.snapshot.EventContext:
        """

        if event.internal_metadata.is_outlier():
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.
            if old_state:
                prev_state_ids = {
                    (s.type, s.state_key): s.event_id for s in old_state
                }
                if event.is_state():
                    current_state_ids = dict(prev_state_ids)
                    key = (event.type, event.state_key)
                    current_state_ids[key] = event.event_id
                else:
                    current_state_ids = prev_state_ids
            else:
                current_state_ids = {}
                prev_state_ids = {}

            # We don't store state for outliers, so we don't generate a state
            # group for it.
            context = EventContext.with_state(
                state_group=None,
                current_state_ids=current_state_ids,
                prev_state_ids=prev_state_ids,
            )

            defer.returnValue(context)

        if old_state:
            # We already have the state, so we don't need to calculate it.
            # Let's just correctly fill out the context and create a
            # new state group for it.

            prev_state_ids = {
                (s.type, s.state_key): s.event_id for s in old_state
            }

            if event.is_state():
                key = (event.type, event.state_key)
                if key in prev_state_ids:
                    replaces = prev_state_ids[key]
                    if replaces != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces
                current_state_ids = dict(prev_state_ids)
                current_state_ids[key] = event.event_id
            else:
                current_state_ids = prev_state_ids

            state_group = yield self.store.store_state_group(
                event.event_id,
                event.room_id,
                prev_group=None,
                delta_ids=None,
                current_state_ids=current_state_ids,
            )

            context = EventContext.with_state(
                state_group=state_group,
                current_state_ids=current_state_ids,
                prev_state_ids=prev_state_ids,
            )

            defer.returnValue(context)

        logger.debug("calling resolve_state_groups from compute_event_context")
        entry = yield self.resolve_state_groups_for_events(
            event.room_id, [e for e, _ in event.prev_events],
        )

        prev_state_ids = entry.state
        prev_group = None
        delta_ids = None

        if event.is_state():
            # If this is a state event then we need to create a new state
            # group for the state after this event.

            key = (event.type, event.state_key)
            if key in prev_state_ids:
                replaces = prev_state_ids[key]
                event.unsigned["replaces_state"] = replaces

            current_state_ids = dict(prev_state_ids)
            current_state_ids[key] = event.event_id

            if entry.state_group:
                # If the state at the event has a state group assigned then
                # we can use that as the prev group
                prev_group = entry.state_group
                delta_ids = {
                    key: event.event_id
                }
            elif entry.prev_group:
                # If the state at the event only has a prev group, then we can
                # use that as a prev group too.
                prev_group = entry.prev_group
                delta_ids = dict(entry.delta_ids)
                delta_ids[key] = event.event_id

            state_group = yield self.store.store_state_group(
                event.event_id,
                event.room_id,
                prev_group=prev_group,
                delta_ids=delta_ids,
                current_state_ids=current_state_ids,
            )
        else:
            current_state_ids = prev_state_ids
            prev_group = entry.prev_group
            delta_ids = entry.delta_ids

            if entry.state_group is None:
                entry.state_group = yield self.store.store_state_group(
                    event.event_id,
                    event.room_id,
                    prev_group=entry.prev_group,
                    delta_ids=entry.delta_ids,
                    current_state_ids=current_state_ids,
                )
                entry.state_id = entry.state_group

            state_group = entry.state_group

        context = EventContext.with_state(
            state_group=state_group,
            current_state_ids=current_state_ids,
            prev_state_ids=prev_state_ids,
            prev_group=prev_group,
            delta_ids=delta_ids,
        )

        defer.returnValue(context)
Esempio n. 9
0
    def persist(
        self, sender=USER_ID, room_id=ROOM_ID, type={}, key=None, internal={},
        state=None, reset_state=False, backfill=False,
        depth=None, prev_events=[], auth_events=[], prev_state=[], redacts=None,
        push_actions=[],
        **content
    ):
        """
        Returns:
            synapse.events.FrozenEvent: The event that was persisted.
        """
        if depth is None:
            depth = self.event_id

        if not prev_events:
            latest_event_ids = yield self.master_store.get_latest_event_ids_in_room(
                room_id
            )
            prev_events = [(ev_id, {}) for ev_id in latest_event_ids]

        event_dict = {
            "sender": sender,
            "type": type,
            "content": content,
            "event_id": "$%d:blue" % (self.event_id,),
            "room_id": room_id,
            "depth": depth,
            "origin_server_ts": self.event_id,
            "prev_events": prev_events,
            "auth_events": auth_events,
        }
        if key is not None:
            event_dict["state_key"] = key
            event_dict["prev_state"] = prev_state

        if redacts is not None:
            event_dict["redacts"] = redacts

        event = FrozenEvent(event_dict, internal_metadata_dict=internal)

        self.event_id += 1

        if state is not None:
            state_ids = {
                key: e.event_id for key, e in state.items()
            }
            context = EventContext()
            context.current_state_ids = state_ids
            context.prev_state_ids = state_ids
        else:
            state_handler = self.hs.get_state_handler()
            context = yield state_handler.compute_event_context(event)

        yield self.master_store.add_push_actions_to_staging(
            event.event_id, {
                user_id: actions
                for user_id, actions in push_actions
            },
        )

        ordering = None
        if backfill:
            yield self.master_store.persist_events(
                [(event, context)], backfilled=True
            )
        else:
            ordering, _ = yield self.master_store.persist_event(
                event, context,
            )

        if ordering:
            event.internal_metadata.stream_ordering = ordering

        defer.returnValue(event)
Esempio n. 10
0
    def compute_event_context(self, event, old_state=None):
        """ Fills out the context with the `current state` of the graph. The
        `current state` here is defined to be the state of the event graph
        just before the event - i.e. it never includes `event`

        If `event` has `auth_events` then this will also fill out the
        `auth_events` field on `context` from the `current_state`.

        Args:
            event (EventBase)
        Returns:
            an EventContext
        """
        context = EventContext()

        yield run_on_reactor()

        if old_state:
            context.current_state = {(s.type, s.state_key): s
                                     for s in old_state}
            context.state_group = None

            if hasattr(event, "auth_events") and event.auth_events:
                auth_ids = zip(*event.auth_events)[0]
                context.auth_events = {
                    k: v
                    for k, v in context.current_state.items()
                    if v.event_id in auth_ids
                }
            else:
                context.auth_events = {}

            if event.is_state():
                key = (event.type, event.state_key)
                if key in context.current_state:
                    replaces = context.current_state[key]
                    if replaces.event_id != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces.event_id

            context.prev_state_events = []
            defer.returnValue(context)

        if event.is_state():
            ret = yield self.resolve_state_groups(
                [e for e, _ in event.prev_events],
                event_type=event.type,
                state_key=event.state_key,
            )
        else:
            ret = yield self.resolve_state_groups(
                [e for e, _ in event.prev_events], )

        group, curr_state, prev_state = ret

        context.current_state = curr_state
        context.state_group = group if not event.is_state() else None

        prev_state = yield self.store.add_event_hashes(prev_state)

        if event.is_state():
            key = (event.type, event.state_key)
            if key in context.current_state:
                replaces = context.current_state[key]
                event.unsigned["replaces_state"] = replaces.event_id

        if hasattr(event, "auth_events") and event.auth_events:
            auth_ids = zip(*event.auth_events)[0]
            context.auth_events = {
                k: v
                for k, v in context.current_state.items()
                if v.event_id in auth_ids
            }
        else:
            context.auth_events = {}

        context.prev_state_events = prev_state
        defer.returnValue(context)
Esempio n. 11
0
    def build_event(self,
                    sender=USER_ID,
                    room_id=ROOM_ID,
                    type="m.room.message",
                    key=None,
                    internal={},
                    state=None,
                    depth=None,
                    prev_events=[],
                    auth_events=[],
                    prev_state=[],
                    redacts=None,
                    push_actions=[],
                    **content):

        if depth is None:
            depth = self.event_id

        if not prev_events:
            latest_event_ids = self.get_success(
                self.master_store.get_latest_event_ids_in_room(room_id))
            prev_events = [(ev_id, {}) for ev_id in latest_event_ids]

        event_dict = {
            "sender": sender,
            "type": type,
            "content": content,
            "event_id": "$%d:blue" % (self.event_id, ),
            "room_id": room_id,
            "depth": depth,
            "origin_server_ts": self.event_id,
            "prev_events": prev_events,
            "auth_events": auth_events,
        }
        if key is not None:
            event_dict["state_key"] = key
            event_dict["prev_state"] = prev_state

        if redacts is not None:
            event_dict["redacts"] = redacts

        event = make_event_from_dict(event_dict,
                                     internal_metadata_dict=internal)

        self.event_id += 1

        if state is not None:
            state_ids = {key: e.event_id for key, e in state.items()}
            context = EventContext.with_state(state_group=None,
                                              current_state_ids=state_ids,
                                              prev_state_ids=state_ids)
        else:
            state_handler = self.hs.get_state_handler()
            context = self.get_success(
                state_handler.compute_event_context(event))

        self.master_store.add_push_actions_to_staging(
            event.event_id,
            {user_id: actions
             for user_id, actions in push_actions})
        return event, context
Esempio n. 12
0
    async def compute_event_context(
            self,
            event: EventBase,
            old_state: Optional[Iterable[EventBase]] = None):
        """Build an EventContext structure for the event.

        This works out what the current state should be for the event, and
        generates a new state group if necessary.

        Args:
            event:
            old_state: The state at the event if it can't be
                calculated from existing events. This is normally only specified
                when receiving an event from federation where we don't have the
                prev events for, e.g. when backfilling.
        Returns:
            synapse.events.snapshot.EventContext:
        """

        if event.internal_metadata.is_outlier():
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.

            # FIXME: why do we populate current_state_ids? I thought the point was
            # that we weren't supposed to have any state for outliers?
            if old_state:
                prev_state_ids = {(s.type, s.state_key): s.event_id
                                  for s in old_state}
                if event.is_state():
                    current_state_ids = dict(prev_state_ids)
                    key = (event.type, event.state_key)
                    current_state_ids[key] = event.event_id
                else:
                    current_state_ids = prev_state_ids
            else:
                current_state_ids = {}
                prev_state_ids = {}

            # We don't store state for outliers, so we don't generate a state
            # group for it.
            context = EventContext.with_state(
                state_group=None,
                state_group_before_event=None,
                current_state_ids=current_state_ids,
                prev_state_ids=prev_state_ids,
            )

            return context

        #
        # first of all, figure out the state before the event
        #

        if old_state:
            # if we're given the state before the event, then we use that
            state_ids_before_event = {(s.type, s.state_key): s.event_id
                                      for s in old_state}
            state_group_before_event = None
            state_group_before_event_prev_group = None
            deltas_to_state_group_before_event = None

        else:
            # otherwise, we'll need to resolve the state across the prev_events.
            logger.debug(
                "calling resolve_state_groups from compute_event_context")

            entry = await self.resolve_state_groups_for_events(
                event.room_id, event.prev_event_ids())

            state_ids_before_event = entry.state
            state_group_before_event = entry.state_group
            state_group_before_event_prev_group = entry.prev_group
            deltas_to_state_group_before_event = entry.delta_ids

        #
        # make sure that we have a state group at that point. If it's not a state event,
        # that will be the state group for the new event. If it *is* a state event,
        # it might get rejected (in which case we'll need to persist it with the
        # previous state group)
        #

        if not state_group_before_event:
            state_group_before_event = await self.state_store.store_state_group(
                event.event_id,
                event.room_id,
                prev_group=state_group_before_event_prev_group,
                delta_ids=deltas_to_state_group_before_event,
                current_state_ids=state_ids_before_event,
            )

            # XXX: can we update the state cache entry for the new state group? or
            # could we set a flag on resolve_state_groups_for_events to tell it to
            # always make a state group?

        #
        # now if it's not a state event, we're done
        #

        if not event.is_state():
            return EventContext.with_state(
                state_group_before_event=state_group_before_event,
                state_group=state_group_before_event,
                current_state_ids=state_ids_before_event,
                prev_state_ids=state_ids_before_event,
                prev_group=state_group_before_event_prev_group,
                delta_ids=deltas_to_state_group_before_event,
            )

        #
        # otherwise, we'll need to create a new state group for after the event
        #

        key = (event.type, event.state_key)
        if key in state_ids_before_event:
            replaces = state_ids_before_event[key]
            if replaces != event.event_id:
                event.unsigned["replaces_state"] = replaces

        state_ids_after_event = dict(state_ids_before_event)
        state_ids_after_event[key] = event.event_id
        delta_ids = {key: event.event_id}

        state_group_after_event = await self.state_store.store_state_group(
            event.event_id,
            event.room_id,
            prev_group=state_group_before_event,
            delta_ids=delta_ids,
            current_state_ids=state_ids_after_event,
        )

        return EventContext.with_state(
            state_group=state_group_after_event,
            state_group_before_event=state_group_before_event,
            current_state_ids=state_ids_after_event,
            prev_state_ids=state_ids_before_event,
            prev_group=state_group_before_event,
            delta_ids=delta_ids,
        )
Esempio n. 13
0
    def persist(self,
                sender=USER_ID,
                room_id=ROOM_ID,
                type={},
                key=None,
                internal={},
                state=None,
                reset_state=False,
                backfill=False,
                depth=None,
                prev_events=[],
                auth_events=[],
                prev_state=[],
                redacts=None,
                push_actions=[],
                **content):
        """
        Returns:
            synapse.events.FrozenEvent: The event that was persisted.
        """
        if depth is None:
            depth = self.event_id

        if not prev_events:
            latest_event_ids = self.get_success(
                self.master_store.get_latest_event_ids_in_room(room_id))
            prev_events = [(ev_id, {}) for ev_id in latest_event_ids]

        event_dict = {
            "sender": sender,
            "type": type,
            "content": content,
            "event_id": "$%d:blue" % (self.event_id, ),
            "room_id": room_id,
            "depth": depth,
            "origin_server_ts": self.event_id,
            "prev_events": prev_events,
            "auth_events": auth_events,
        }
        if key is not None:
            event_dict["state_key"] = key
            event_dict["prev_state"] = prev_state

        if redacts is not None:
            event_dict["redacts"] = redacts

        event = FrozenEvent(event_dict, internal_metadata_dict=internal)

        self.event_id += 1

        if state is not None:
            state_ids = {key: e.event_id for key, e in state.items()}
            context = EventContext.with_state(state_group=None,
                                              current_state_ids=state_ids,
                                              prev_state_ids=state_ids)
        else:
            state_handler = self.hs.get_state_handler()
            context = self.get_success(
                state_handler.compute_event_context(event))

        self.master_store.add_push_actions_to_staging(
            event.event_id,
            {user_id: actions
             for user_id, actions in push_actions})

        ordering = None
        if backfill:
            self.get_success(
                self.master_store.persist_events([(event, context)],
                                                 backfilled=True))
        else:
            ordering, _ = self.get_success(
                self.master_store.persist_event(event, context))

        if ordering:
            event.internal_metadata.stream_ordering = ordering

        return event
Esempio n. 14
0
    def compute_event_context(self, event, old_state=None, outlier=False):
        """ Fills out the context with the `current state` of the graph. The
        `current state` here is defined to be the state of the event graph
        just before the event - i.e. it never includes `event`

        If `event` has `auth_events` then this will also fill out the
        `auth_events` field on `context` from the `current_state`.

        Args:
            event (EventBase)
        Returns:
            an EventContext
        """
        context = EventContext()

        if outlier:
            # If this is an outlier, then we know it shouldn't have any current
            # state. Certainly store.get_current_state won't return any, and
            # persisting the event won't store the state group.
            if old_state:
                context.current_state = {(s.type, s.state_key): s
                                         for s in old_state}
            else:
                context.current_state = {}
            context.prev_state_events = []
            context.state_group = None
            defer.returnValue(context)

        if old_state:
            context.current_state = {(s.type, s.state_key): s
                                     for s in old_state}
            context.state_group = None

            if event.is_state():
                key = (event.type, event.state_key)
                if key in context.current_state:
                    replaces = context.current_state[key]
                    if replaces.event_id != event.event_id:  # Paranoia check
                        event.unsigned["replaces_state"] = replaces.event_id

            context.prev_state_events = []
            defer.returnValue(context)

        if event.is_state():
            ret = yield self.resolve_state_groups(
                event.room_id,
                [e for e, _ in event.prev_events],
                event_type=event.type,
                state_key=event.state_key,
            )
        else:
            ret = yield self.resolve_state_groups(
                event.room_id,
                [e for e, _ in event.prev_events],
            )

        group, curr_state, prev_state = ret

        context.current_state = curr_state
        context.state_group = group if not event.is_state() else None

        if event.is_state():
            key = (event.type, event.state_key)
            if key in context.current_state:
                replaces = context.current_state[key]
                event.unsigned["replaces_state"] = replaces.event_id

        context.prev_state_events = prev_state
        defer.returnValue(context)
Esempio n. 15
0
    async def compute_event_context(
        self, event: EventBase, old_state: Optional[Iterable[EventBase]] = None
    ) -> EventContext:
        """Build an EventContext structure for a non-outlier event.

        (for an outlier, call EventContext.for_outlier directly)

        This works out what the current state should be for the event, and
        generates a new state group if necessary.

        Args:
            event:
            old_state: The state at the event if it can't be
                calculated from existing events. This is normally only specified
                when receiving an event from federation where we don't have the
                prev events for, e.g. when backfilling.
        Returns:
            The event context.
        """

        assert not event.internal_metadata.is_outlier()

        #
        # first of all, figure out the state before the event
        #

        if old_state:
            # if we're given the state before the event, then we use that
            state_ids_before_event: StateMap[str] = {
                (s.type, s.state_key): s.event_id for s in old_state
            }
            state_group_before_event = None
            state_group_before_event_prev_group = None
            deltas_to_state_group_before_event = None
            entry = None

        else:
            # otherwise, we'll need to resolve the state across the prev_events.
            logger.debug("calling resolve_state_groups from compute_event_context")

            entry = await self.resolve_state_groups_for_events(
                event.room_id, event.prev_event_ids()
            )

            state_ids_before_event = entry.state
            state_group_before_event = entry.state_group
            state_group_before_event_prev_group = entry.prev_group
            deltas_to_state_group_before_event = entry.delta_ids

        #
        # make sure that we have a state group at that point. If it's not a state event,
        # that will be the state group for the new event. If it *is* a state event,
        # it might get rejected (in which case we'll need to persist it with the
        # previous state group)
        #

        if not state_group_before_event:
            state_group_before_event = await self.state_store.store_state_group(
                event.event_id,
                event.room_id,
                prev_group=state_group_before_event_prev_group,
                delta_ids=deltas_to_state_group_before_event,
                current_state_ids=state_ids_before_event,
            )

            # Assign the new state group to the cached state entry.
            #
            # Note that this can race in that we could generate multiple state
            # groups for the same state entry, but that is just inefficient
            # rather than dangerous.
            if entry and entry.state_group is None:
                entry.state_group = state_group_before_event

        #
        # now if it's not a state event, we're done
        #

        if not event.is_state():
            return EventContext.with_state(
                state_group_before_event=state_group_before_event,
                state_group=state_group_before_event,
                current_state_ids=state_ids_before_event,
                prev_state_ids=state_ids_before_event,
                prev_group=state_group_before_event_prev_group,
                delta_ids=deltas_to_state_group_before_event,
            )

        #
        # otherwise, we'll need to create a new state group for after the event
        #

        key = (event.type, event.state_key)
        if key in state_ids_before_event:
            replaces = state_ids_before_event[key]
            if replaces != event.event_id:
                event.unsigned["replaces_state"] = replaces

        state_ids_after_event = dict(state_ids_before_event)
        state_ids_after_event[key] = event.event_id
        delta_ids = {key: event.event_id}

        state_group_after_event = await self.state_store.store_state_group(
            event.event_id,
            event.room_id,
            prev_group=state_group_before_event,
            delta_ids=delta_ids,
            current_state_ids=state_ids_after_event,
        )

        return EventContext.with_state(
            state_group=state_group_after_event,
            state_group_before_event=state_group_before_event,
            current_state_ids=state_ids_after_event,
            prev_state_ids=state_ids_before_event,
            prev_group=state_group_before_event,
            delta_ids=delta_ids,
        )