Beispiel #1
0
        def make_poll(response):
            session_id = _current_session_id()
            if session_id is None:
                return response

            _current_backend().poll(session_id)
            return response
Beispiel #2
0
def logout():
    """
    Notify WebLab-Deusto that the user left the laboratory, so next user can enter.

    This process is not real time. What it happens is that WebLab-Deusto periodically is requesting
    whether the user is still alive or not. If you call logout, weblablib will reply the next time
    that the user left. So it may take some seconds for WebLab-Deusto to realize of that. You can
    regulate this time with ``WEBLAB_POLL_INTERVAL`` setting (defaults to 5).
    """
    session_id = _current_session_id()
    if session_id:
        _current_backend().force_exit(session_id)
Beispiel #3
0
def store_initial_weblab_user_data():
    session_id = _current_session_id()
    if session_id:
        backend = _current_backend()
        current_user = backend.get_user(session_id)
        if current_user.active:
            g._initial_data = json.dumps(current_user.data)
Beispiel #4
0
def get_weblab_user(cached=True):
    """
    Get the current user. If ``cached=True`` it will store it and return the same each time.
    If you need to get always a different one get it with ``cached=False``. In long tasks, for
    example, it's normal to call it with ``cached=False`` so it gets updated with whatever
    information comes from other threads.

    Two shortcuts exist to this function:
     * :data:`weblab_user`: it is equivalent to ``get_weblab_user(cached=True)``
     * :data:`socket_weblab_user`: it is equivalent to ``get_weblab_user(cached=False)``

    Given that the function always returns a :class:`CurrentUser` or :class:`ExpiredUser` or :class:`AnonymousUser`, it's safe to do things like::

       if not weblab_user.anonymous:
           print(weblab_user.username)
           print(weblab_user.username_unique)

    :param cached: if this method is called twice in the same thread, it will return the same object.
    """
    if cached and hasattr(g, 'weblab_user'):
        return g.weblab_user

    # Cached: then use Redis
    session_id = _current_session_id()
    if session_id is None:
        return _set_weblab_user_cache(AnonymousUser())

    user = _current_backend().get_user(session_id)
    # Store it for next requests in the same call
    return _set_weblab_user_cache(user)
Beispiel #5
0
 def retrieve(self):
     backend = _current_backend()
     user = backend.get_user(self._user._session_id)
     if isinstance(user.data, DataHolder):
         self.update(user.data)
         for key in list(self):
             if key not in user.data:
                 self.pop(key, None)
Beispiel #6
0
def dispose_user(session_id, waiting):
    backend = _current_backend()
    user = backend.get_user(session_id)
    if user.is_anonymous:
        raise NotFoundError()

    if isinstance(user, CurrentUser):
        current_expired_user = user.to_expired_user()
        deleted = backend.delete_user(session_id, current_expired_user)

        if deleted:
            try:
                weblab = _current_weblab()
                weblab._set_session_id(session_id)
                if weblab._on_dispose:

                    _set_weblab_user_cache(user)
                    try:
                        weblab._on_dispose()
                    except Exception:
                        traceback.print_exc()
                    update_weblab_user_data(response=None)
            finally:
                backend.finished_dispose(session_id)

            unfinished_tasks = backend.get_unfinished_tasks(session_id)
            for task_id in unfinished_tasks:
                unfinished_task = weblab.get_task(task_id)
                if unfinished_task:
                    unfinished_task.stop()

            while unfinished_tasks:
                unfinished_tasks = backend.get_unfinished_tasks(session_id)
                time.sleep(0.1)

            backend.clean_session_tasks(session_id)

            backend.report_session_deleted(session_id)

    if waiting:
        # if another thread has started the _dispose process, it might take long
        # to process it. But this (sessions) is the one that tells WebLab-Deusto
        # that someone else can enter in this laboratory. So we should wait
        # here until the process is over.

        while not backend.is_session_deleted(session_id):
            # In the future, instead of waiting, this could be returning that it is still finishing
            time.sleep(0.1)
Beispiel #7
0
def update_weblab_user_data(response):
    # If a developer does:
    #
    # weblab_user.data["foo"] = "bar"
    #
    # Nothing is triggered in Redis. For this reason, after each request
    # we check that the data has changed or not.
    #
    session_id = _current_session_id()
    backend = _current_backend()
    if session_id:
        if weblab_user.active:
            # If there was no data in the beginning
            # OR there was data in the beginning and now it is different,
            # only then modify the current session
            if not hasattr(g,
                           '_initial_data') or g._initial_data != json.dumps(
                               weblab_user.data):
                backend.update_data(session_id, weblab_user.data)

    return response
Beispiel #8
0
 def store(self):
     backend = _current_backend()
     data = self.copy()
     backend.update_data(self._user._session_id, data)
     self._initial_hash = self._get_hash(data)
Beispiel #9
0
 def clean_actions(self, session_id): # pylint: disable=no-self-use
     """
     Remove all actions of a session_id
     """
     backend = _current_backend()
     backend.clean_actions(session_id)
Beispiel #10
0
 def store_action(self, session_id, action_id, action): # pylint: disable=no-self-use
     """
     Adds a new raw action to a new or existing session_id
     """
     backend = _current_backend()
     backend.store_action(session_id, action_id, action)
Beispiel #11
0
def _process_start_request(request_data):
    """ Auxiliar method, called also from the Flask CLI to fake_user """
    client_initial_data = request_data['client_initial_data']
    server_initial_data = request_data['server_initial_data']

    # Parse the initial date + assigned time to know the maximum time
    start_date_timestamp = server_initial_data.get(
        'priority.queue.slot.start.timestamp')
    if start_date_timestamp:  # if the time is available in timestamp, use it
        start_date = datetime.datetime.fromtimestamp(
            float(start_date_timestamp))
    else:
        # Otherwise, to keep backwards compatibility, assume that it's in the same timezone
        # as we are
        start_date_str = server_initial_data['priority.queue.slot.start']
        start_date_str, microseconds = start_date_str.split('.')
        difference = datetime.timedelta(microseconds=int(microseconds))
        start_date = datetime.datetime.strptime(
            start_date_str, "%Y-%m-%d %H:%M:%S") + difference

    slot_length = float(server_initial_data['priority.queue.slot.length'])
    max_date = start_date + datetime.timedelta(seconds=slot_length)
    locale = server_initial_data.get('request.locale')
    full_name = server_initial_data['request.full_name']

    experiment_name = server_initial_data[
        'request.experiment_id.experiment_name']
    category_name = server_initial_data['request.experiment_id.category_name']
    experiment_id = '{}@{}'.format(experiment_name, category_name)

    # Create a global session
    session_id = create_token()

    # Prepare adding this to backend
    user = CurrentUser(
        session_id=session_id,
        back=request_data['back'],
        last_poll=_current_timestamp(),
        max_date=float(_to_timestamp(max_date)),
        username=server_initial_data['request.username'],
        username_unique=server_initial_data['request.username.unique'],
        exited=False,
        data={},
        locale=locale,
        full_name=full_name,
        experiment_name=experiment_name,
        experiment_id=experiment_id,
        category_name=category_name,
        request_client_data=client_initial_data,
        request_server_data=server_initial_data,
        start_date=float(_to_timestamp(start_date)))

    backend = _current_backend()

    backend.add_user(
        session_id,
        user,
        expiration=30 +
        int(float(server_initial_data['priority.queue.slot.length'])))

    kwargs = {}
    scheme = current_app.config.get(ConfigurationKeys.WEBLAB_SCHEME)
    if scheme:
        kwargs['_scheme'] = scheme

    weblab = _current_weblab()
    if weblab._on_start:
        _set_weblab_user_cache(user)
        weblab._set_session_id(session_id)
        try:
            data = weblab._on_start(client_initial_data, server_initial_data)
        except Exception as error:
            traceback.print_exc()
            current_app.logger.warning(
                "Error calling _on_start: {}".format(error), exc_info=True)
            try:
                dispose_user(session_id, waiting=True)
            except Exception as nested_error:
                traceback.print_exc()
                current_app.logger.warning(
                    "Error calling _on_dispose after _on_start failed: {}".
                    format(nested_error),
                    exc_info=True)

            return dict(error=True, message="Error initializing laboratory")
        else:
            if data:
                user.data = data
            user.data.store_if_modified()
            update_weblab_user_data(response=None)

    link = url_for('weblab_callback_url',
                   session_id=session_id,
                   _external=True,
                   **kwargs)
    return dict(url=link, session_id=session_id)