def get_next_message(request, timeout=30):
    msg = None
    try:
        rc = get_redis_connection()
        mailbox_id = get_mailbox_id(request)
        if 0 == timeout:
            response = rc.lpop(mailbox_id)
            if response is not None:
                msg = parse_tutalk_msg(response.decode())
        else:
            response = rc.blpop(mailbox_id, timeout)
            if response is None:
                raise exc.MailboxTimeoutException()
            else:
                msg = parse_tutalk_msg(response[1].decode())
    except exc.NoUidInSessionException as nuide:
        msg = msgs.mk_no_uid_error_msg(request, None)
    except exc.InvalidMessageException as ime:
        msg = msgs.mk_invalid_message_error(request, 'tutalk', response)
    except exc.MsgMissingTypeException as mmte:
        msg = msgs.mk_missing_msg_type_error_msg(request, 'tutalk', response)
    except exc.MailboxTimeoutException as mte:
        msg = msgs.mk_mailbox_timeout_error_msg(request)

    return msg
def push_message(request, msg):
    rc = get_redis_connection()
    mailbox_id = get_mailbox_id(request)
    if isinstance(msg, str):
        rc.lpush(mailbox_id, msg)
    else:
        rc.lpush(mailbox_id, json.dumps(msg))
Beispiel #3
0
def force_logout_participant(request, exptr_name=None, scen_name=None, part_id=None):
    rc = get_redis_connection()
    logout_msg = {"uid": part_id, "gid": "group-%s" % part_id, "type": "logout", "payload": {"text": "logout"}}
    routing_key = "%s.%s.%s.logout" % (get_tutalk_host(), exptr_name, scen_name)
    ret_val = rc.publish(routing_key, json.dumps(logout_msg))
    time.sleep(2)  # allow tutalk to logout user before re-displaying page
    return redirect("scenario-runner:index")
def store_reload_msgs(request, messages):
    """stores messages for problem reload in a separate queue
    sets expire for 30 secs, so it doesn't stick around
    """
    rc = get_redis_connection()
    reload_id = get_reload_id(request)
    for msg in messages:
        rc.rpush(reload_id, json.dumps(msg))
    rc.expire(reload_id, 30)
def delete_mailbox(request):
    """deletes the user's mailbox, if it exists"""
    mailbox_id = get_mailbox_id(request)
    if mailbox_id is not None:
        if not mailbox_exists(mailbox_id):
            # no-op, mailbox doesn't exist. Unfortuantely, it's unknown if this
            # is because it is merely empty, has been already deleted, or if
            # it never existed in the first place. this means that we shouldn't
            # treat this as an error
            pass
        else:
            rc = get_redis_connection()
            rc.delete(mailbox_id)
def fetch_all_messages(request):
    rc = get_redis_connection()
    mailbox_id = get_mailbox_id(request)
    messages = []
    num_msgs = rc.llen(mailbox_id)
    for idx in range(0, num_msgs):
        msg = get_next_message(request, timeout=0)
        if msg is not None:
            msg_type = msg.get("type", None)
            if msg_type is not None:
                if msg_type not in ["tutor-logout", "error"]:
                    messages.append(msg)
    return messages
def publish_message(request, tutalk_message):
    """sends a message to tutalk via redis pub/sub

    not all 'Rimac' messages are valid 'TuTalk' messages. The message
    types in SHOULDNT_PUBLISH_MESSAGE_TYPES should merely be logged.

    also adds the uid and gid fields, so the client doesn't need to
    pass them

    FIXME? I suppose ideally, rimac system should only deal with
    'Rimac' messages, and there should be a rimac<->tutalk message
    translation layer.  rimac-event-listener partially does this for
    messages originating from tutalk, but it would probably be better
    if it instead translated them into rimac-specific message types
    rather than simply adding more information to the payload
    """
    msg_type = tutalk_message.get('type', None)
    if msg_type is None:
        raise exc.MsgMissingTypeException()

    try:
        add_uid_gid_fields(request, tutalk_message)
    except Exception:
        raise exc.NoUidInSessionException()

    db.log_message(request, tutalk_message)
    if should_publish_message(msg_type):
        if "logout" == msg_type:
            # we don't want to recieve any messages other than the
            # corresponding tutor-logout
            delete_mailbox(request)
        rc = get_redis_connection()
        tutalk_host = encode_tutalk_host(request.session['tutalk_host'])
        routing_key = '%s.%s.%s.%s' % (tutalk_host,
                                       request.session['experimenter'],
                                       request.session['scenario'],
                                       msg_type)
        msg = json.dumps(tutalk_message)
        LOGGER.debug("attempting to publish %s", routing_key)
        LOGGER.debug("message: %s", msg)
        success = rc.publish(routing_key, msg)
        if 0 == success:
            raise exc.ScenarioNotRunningException()
def logged_in_to_tutalk(request):
    """checks the redis database that the user is logged in.

    FIXME? should I be double-checking with tutalk itself?
    """
    found = False
    tutalk_host = encode_tutalk_host(request.session['tutalk_host'])
    experimenter = request.session['experimenter']
    scenario = request.session['scenario']
    top_level_key = '%s.scenarios' % tutalk_host
    groups_key = '%s.%s.groups' % (experimenter, scenario)
    rc = get_redis_connection()
    val = rc.hget(top_level_key, groups_key)
    if val is not None:
        groups = json.loads(val)
        for group in groups:
            for agent in group['agents']:
                if agent['uid'] == request.session['tutalk_uid']:
                    found = True
                    break
    return found
Beispiel #9
0
def stop_scenario(request, exptr_name=None, scen_name=None):
    get_object_or_404(models.Experimenter, name=exptr_name)
    exptr_scens = get_scenarios()
    if exptr_name in exptr_scens:
        if scen_name in exptr_scens[exptr_name]:
            if "pid" in exptr_scens[exptr_name][scen_name]:
                pid = exptr_scens[exptr_name][scen_name]["pid"]
                if check_pid(pid):
                    try:
                        os.kill(pid, signal.SIGINT)
                        time.sleep(1)
                        if check_pid(pid):
                            os.kill(pid, signal.SIGKILL)
                            pfx = "%s.%s" % (exptr_name, scen_name)
                            rc = get_redis_connection()
                            rc.hdel(
                                "%s.scenarios" % get_tutalk_host(), "%s.status" % pfx, "%s.pid" % pfx, "%s.groups" % pfx
                            )
                        time.sleep(2)
                    except OSError as ose:
                        LOGGER.error(ose)
    return redirect("scenario-runner:index")
Beispiel #10
0
def get_running_scenarios():
    rc = get_redis_connection()
    scenarios_key = "%s.scenarios" % get_tutalk_host()
    dct = rc.hgetall(scenarios_key)
    return dct
def mailbox_exists(mailbox_id):
    rc = get_redis_connection()
    return rc.exists(mailbox_id)