def do_events_register(user_profile, user_client, apply_markdown=True, event_types=None, queue_lifespan_secs=0, all_public_streams=False, include_subscribers=True, narrow=[], fetch_event_types=None): # type: (UserProfile, Client, bool, Optional[Iterable[str]], int, bool, bool, Iterable[Sequence[Text]], Optional[Iterable[str]]) -> Dict[str, Any] # Technically we don't need to check this here because # build_narrow_filter will check it, but it's nicer from an error # handling perspective to do it before contacting Tornado check_supported_events_narrow_filter(narrow) # Note that we pass event_types, not fetch_event_types here, since # that's what controls which future events are sent. queue_id = request_event_queue(user_profile, user_client, apply_markdown, queue_lifespan_secs, event_types, all_public_streams, narrow=narrow) if queue_id is None: raise JsonableError(_("Could not allocate event queue")) if fetch_event_types is not None: event_types_set = set(fetch_event_types) # type: Optional[Set[str]] elif event_types is not None: event_types_set = set(event_types) else: event_types_set = None # Fill up the UserMessage rows if a soft-deactivated user has returned maybe_catch_up_soft_deactivated_user(user_profile) ret = fetch_initial_state_data(user_profile, event_types_set, queue_id, include_subscribers=include_subscribers) # Apply events that came in while we were fetching initial data events = get_user_events(user_profile, queue_id, -1) apply_events(ret, events, user_profile, include_subscribers=include_subscribers, fetch_event_types=fetch_event_types) if len(events) > 0: ret['last_event_id'] = events[-1]['id'] else: ret['last_event_id'] = -1 return ret
def do_events_register(user_profile, user_client, apply_markdown=True, event_types=None, queue_lifespan_secs=0, all_public_streams=False, include_subscribers=True, narrow=[], fetch_event_types=None): # type: (UserProfile, Client, bool, Optional[Iterable[str]], int, bool, bool, Iterable[Sequence[Text]], Optional[Iterable[str]]) -> Dict[str, Any] # Technically we don't need to check this here because # build_narrow_filter will check it, but it's nicer from an error # handling perspective to do it before contacting Tornado check_supported_events_narrow_filter(narrow) # Note that we pass event_types, not fetch_event_types here, since # that's what controls which future events are sent. queue_id = request_event_queue(user_profile, user_client, apply_markdown, queue_lifespan_secs, event_types, all_public_streams, narrow=narrow) if queue_id is None: raise JsonableError(_("Could not allocate event queue")) if fetch_event_types is not None: event_types_set = set(fetch_event_types) # type: Optional[Set[str]] elif event_types is not None: event_types_set = set(event_types) else: event_types_set = None # Fill up the UserMessage rows if a soft-deactivated user has returned maybe_catch_up_soft_deactivated_user(user_profile) ret = fetch_initial_state_data(user_profile, event_types_set, queue_id, include_subscribers=include_subscribers) # Apply events that came in while we were fetching initial data events = get_user_events(user_profile, queue_id, -1) apply_events(ret, events, user_profile, include_subscribers=include_subscribers, fetch_event_types=fetch_event_types) ''' NOTE: Below is an example of post-processing initial state data AFTER we apply events. For large payloads like `unread_msgs`, it's helpful to have an intermediate data structure that is easy to manipulate with O(1)-type operations as we apply events. Then, only at the end, we put it in the form that's more appropriate for client. ''' if 'raw_unread_msgs' in ret: ret['unread_msgs'] = aggregate_unread_data(ret['raw_unread_msgs']) del ret['raw_unread_msgs'] if len(events) > 0: ret['last_event_id'] = events[-1]['id'] else: ret['last_event_id'] = -1 return ret
def do_events_register(user_profile: UserProfile, user_client: Client, apply_markdown: bool = True, client_gravatar: bool = False, event_types: Optional[Iterable[str]] = None, queue_lifespan_secs: int = 0, all_public_streams: bool = False, include_subscribers: bool = True, narrow: Iterable[Sequence[str]] = [], fetch_event_types: Optional[Iterable[str]] = None) -> Dict[str, Any]: # Technically we don't need to check this here because # build_narrow_filter will check it, but it's nicer from an error # handling perspective to do it before contacting Tornado check_supported_events_narrow_filter(narrow) # Note that we pass event_types, not fetch_event_types here, since # that's what controls which future events are sent. queue_id = request_event_queue(user_profile, user_client, apply_markdown, client_gravatar, queue_lifespan_secs, event_types, all_public_streams, narrow=narrow) if queue_id is None: raise JsonableError(_("Could not allocate event queue")) if fetch_event_types is not None: event_types_set = set(fetch_event_types) # type: Optional[Set[str]] elif event_types is not None: event_types_set = set(event_types) else: event_types_set = None # Fill up the UserMessage rows if a soft-deactivated user has returned maybe_catch_up_soft_deactivated_user(user_profile) ret = fetch_initial_state_data(user_profile, event_types_set, queue_id, client_gravatar=client_gravatar, include_subscribers=include_subscribers) # Apply events that came in while we were fetching initial data events = get_user_events(user_profile, queue_id, -1) apply_events(ret, events, user_profile, include_subscribers=include_subscribers, client_gravatar=client_gravatar, fetch_event_types=fetch_event_types) post_process_state(ret) if len(events) > 0: ret['last_event_id'] = events[-1]['id'] else: ret['last_event_id'] = -1 return ret
def do_events_register(user_profile, user_client, apply_markdown=True, client_gravatar=False, event_types=None, queue_lifespan_secs=0, all_public_streams=False, include_subscribers=True, narrow=[], fetch_event_types=None): # type: (UserProfile, Client, bool, bool, Optional[Iterable[str]], int, bool, bool, Iterable[Sequence[Text]], Optional[Iterable[str]]) -> Dict[str, Any] # Technically we don't need to check this here because # build_narrow_filter will check it, but it's nicer from an error # handling perspective to do it before contacting Tornado check_supported_events_narrow_filter(narrow) # Note that we pass event_types, not fetch_event_types here, since # that's what controls which future events are sent. queue_id = request_event_queue(user_profile, user_client, apply_markdown, client_gravatar, queue_lifespan_secs, event_types, all_public_streams, narrow=narrow) if queue_id is None: raise JsonableError(_("Could not allocate event queue")) if fetch_event_types is not None: event_types_set = set(fetch_event_types) # type: Optional[Set[str]] elif event_types is not None: event_types_set = set(event_types) else: event_types_set = None # Fill up the UserMessage rows if a soft-deactivated user has returned maybe_catch_up_soft_deactivated_user(user_profile) ret = fetch_initial_state_data(user_profile, event_types_set, queue_id, client_gravatar=client_gravatar, include_subscribers=include_subscribers) # Apply events that came in while we were fetching initial data events = get_user_events(user_profile, queue_id, -1) apply_events(ret, events, user_profile, include_subscribers=include_subscribers, client_gravatar=client_gravatar, fetch_event_types=fetch_event_types) ''' NOTE: Below is an example of post-processing initial state data AFTER we apply events. For large payloads like `unread_msgs`, it's helpful to have an intermediate data structure that is easy to manipulate with O(1)-type operations as we apply events. Then, only at the end, we put it in the form that's more appropriate for client. ''' if 'raw_unread_msgs' in ret: ret['unread_msgs'] = aggregate_unread_data(ret['raw_unread_msgs']) del ret['raw_unread_msgs'] ''' See the note above; the same technique applies below. ''' if 'raw_users'in ret: user_dicts = list(ret['raw_users'].values()) ret['realm_users'] = [d for d in user_dicts if d['is_active']] ret['realm_non_active_users'] = [d for d in user_dicts if not d['is_active']] ''' Be aware that we do intentional aliasing in the below code. We can now safely remove the `is_active` field from all the dicts that got partitioned into the two lists above. We remove the field because it's already implied, and sending it to clients makes clients prone to bugs where they "trust" the field but don't actually update in live updates. It also wastes bandwidth. ''' for d in user_dicts: d.pop('is_active') del ret['raw_users'] if len(events) > 0: ret['last_event_id'] = events[-1]['id'] else: ret['last_event_id'] = -1 return ret
def do_events_register(user_profile: UserProfile, user_client: Client, apply_markdown: bool = True, client_gravatar: bool = False, event_types: Optional[Iterable[str]] = None, queue_lifespan_secs: int = 0, all_public_streams: bool = False, include_subscribers: bool = True, narrow: Iterable[Sequence[Text]] = [], fetch_event_types: Optional[Iterable[str]] = None) -> Dict[str, Any]: # Technically we don't need to check this here because # build_narrow_filter will check it, but it's nicer from an error # handling perspective to do it before contacting Tornado check_supported_events_narrow_filter(narrow) # Note that we pass event_types, not fetch_event_types here, since # that's what controls which future events are sent. queue_id = request_event_queue(user_profile, user_client, apply_markdown, client_gravatar, queue_lifespan_secs, event_types, all_public_streams, narrow=narrow) if queue_id is None: raise JsonableError(_("Could not allocate event queue")) if fetch_event_types is not None: event_types_set = set(fetch_event_types) # type: Optional[Set[str]] elif event_types is not None: event_types_set = set(event_types) else: event_types_set = None # Fill up the UserMessage rows if a soft-deactivated user has returned maybe_catch_up_soft_deactivated_user(user_profile) ret = fetch_initial_state_data(user_profile, event_types_set, queue_id, client_gravatar=client_gravatar, include_subscribers=include_subscribers) # Apply events that came in while we were fetching initial data events = get_user_events(user_profile, queue_id, -1) apply_events(ret, events, user_profile, include_subscribers=include_subscribers, client_gravatar=client_gravatar, fetch_event_types=fetch_event_types) ''' NOTE: Below is an example of post-processing initial state data AFTER we apply events. For large payloads like `unread_msgs`, it's helpful to have an intermediate data structure that is easy to manipulate with O(1)-type operations as we apply events. Then, only at the end, we put it in the form that's more appropriate for client. ''' if 'raw_unread_msgs' in ret: ret['unread_msgs'] = aggregate_unread_data(ret['raw_unread_msgs']) del ret['raw_unread_msgs'] ''' See the note above; the same technique applies below. ''' if 'raw_users'in ret: user_dicts = list(ret['raw_users'].values()) ret['realm_users'] = [d for d in user_dicts if d['is_active']] ret['realm_non_active_users'] = [d for d in user_dicts if not d['is_active']] ''' Be aware that we do intentional aliasing in the below code. We can now safely remove the `is_active` field from all the dicts that got partitioned into the two lists above. We remove the field because it's already implied, and sending it to clients makes clients prone to bugs where they "trust" the field but don't actually update in live updates. It also wastes bandwidth. ''' for d in user_dicts: d.pop('is_active') del ret['raw_users'] if len(events) > 0: ret['last_event_id'] = events[-1]['id'] else: ret['last_event_id'] = -1 return ret