def on_show_menu(slot): # find target target = get_target(request.args) if not target: return json_bad_request_error('TARGET_MISSING', "target missing") # get parameters if 'visible' not in request.args: return json_bad_request_error('ARGUMENT_MISSING', 'no visibility argument specified') visibleParam = str(request.args.get('visible')).lower() if visibleParam in ['true', '1', 'yes']: visible = True elif visibleParam in ['false', '0', 'no']: visible = False else: return json_bad_request_error('INVALID_ARGUMENT', 'visibility argument invalid') # send command socketio.emit('showmenu', { 'time': datetime.utcnow().timestamp(), 'slot': slot, 'visible': visible }, room=target) return json_success("menu shown")
def on_update_alive(sid): if 'type' not in request.args: return json_bad_request_error("ARGUMENT_MISSING", "device type missing") device_type = request.args['type'] if device_type not in ['box', 'sensor', 'mobile']: return json_bad_request_error("INVALID_ARGUMENT", "invalid device type") if 'name' not in request.args: return json_bad_request_error("ARGUMENT_MISSING", "device name missing") device_name = request.args['name'] now = datetime.utcnow().timestamp() if sid not in socketio_sessions: socketio_sessions[sid] = {'sid': sid, 'connect_time': now, 'env': {}} socketio_sessions[sid]['type'] = device_type socketio_sessions[sid]['name'] = device_name socketio_sessions[sid]['connected'] = True socketio_sessions[sid]['alive_time'] = now socketio_sessions[sid]['env']['REMOTE_ADDR'] = request.args.get( 'ip', default='-') info = request.args.get('info') activity_description = info + " " + str( datetime.utcnow()) if info else request.args.get('activity') if activity_description: socketio_sessions[sid]['activity'] = activity_description return json_success("alive state updated")
def on_trigger_simple_trigger(sensor_name): # find sensor sensor = mongo.db.objects.find_one( { 'type': 'simpletrigger', 'fields.name': sensor_name, 'timestamp-deleted': { '$exists': False } }, {'_id': False}) if not sensor or 'id' not in sensor or 'fields' not in sensor: log.warning(f"sensor {sensor_name} not registered") return json_not_found_error('SENSOR_NOT_REGISTERED', "sensor not registered") sensor_fields = sensor['fields'] # execute effects effect_ids = sensor_fields.get('triggereffects') or [] log.info( f"{len(effect_ids)} effects(s) triggered by simple trigger {sensor_name}" ) errors = execute_effects(datetime.utcnow(), effect_ids, None, None, [], False) if errors: return json_action_execution_error(errors) else: return json_success("sensor triggered successfully")
def on_play_scene_json(): # find visitor type visitor_type = get_visitor_type(request.args) visitor_type_id = visitor_type['id'] if visitor_type else None # find target target = get_target(request.args) # find avatar avatars = visitor_type['fields'][ 'avatar'] if visitor_type and 'fields' in visitor_type and 'avatar' in visitor_type[ 'fields'] else [] avatar_id = avatars[0] if avatars else None # execute scene scene = request.get_json() targets = [target] if target else [] now = datetime.utcnow() storyline = str(uuid.uuid4()) errors = execute_scene(now, scene, storyline, { 'individual': 'anyone', 'avatar': avatar_id }, targets) if errors: return json_action_execution_error(errors) else: return json_success("scene played")
def on_send_play_object_id_command(object_id): now = datetime.utcnow() # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # find object item = mongo.db.objects.find_one({'id': object_id}, {'_id': False}) if not item: return json_not_found_error('OBJECT_NOT_FOUND', 'object not found') referenced_items = find_referenced_items(item) # send command log.debug( f"playing object {item} with {len(referenced_items)} referenced item(s)" ) socketio.emit('playobject', { 'time': now.timestamp(), 'object': item, 'loop': False, 'referenced': referenced_items }, room=target) return json_success("object playback command sent to " + target)
def on_set_log_level(level): log.info("Changing log level to " + level) if level.lower() == "info": log.setLevel(logging.INFO) elif level.lower() == "debug": log.setLevel(logging.DEBUG) log.info("New log level: " + str(log.level)) log.debug("debug New log level: " + str(log.level)) return json_success("log level set to " + level)
def on_send_stop_command(): now = datetime.utcnow() # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # send command socketio.emit('stop', {'time': now.timestamp()}, room=target) return json_success("stop command sent to " + target)
def on_send_ping_command(): # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # send command now = datetime.utcnow() socketio.emit('pingbox', { 'target': target, 'time': now.timestamp() }, room=target) log.info("pinging target " + target) return json_success("ping command sent to " + target)
def on_send_show_notification_command(): now = datetime.utcnow() # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # send command text = request.args.get('text') socketio.emit('shownotification', { 'time': now.timestamp(), 'text': text }, room=target) return json_success("notification command sent to " + target)
def on_get_recycle_object(id): if id is None: return json_error_wrong_parameters() # undelete item item = mongo.db.objects.find_one_and_update( {'id': id}, {'$unset': { 'timestamp-deleted': '', 'user-deleted': '' }}) if not item: return json_error_no_record_found() # signal success handle_object_change(item) return json_success('Object successfully restored.')
def on_send_play_story_command(): # find visitor type and target visitor_type = get_visitor_type(request.args) target = get_target(request.args) method = request.args.get('method') # execute story story = request.get_json() errors = execute_story(story, 'anyone', visitor_type, [target] if target else [], method == 'leave') if errors: return json_action_execution_error(errors) else: return json_success( f"story {'stopped' if method == 'leave' else 'started'} successfully" )
def on_post_change_menu(slot): # find target target = get_target(request.args) if not target: return json_bad_request_error('TARGET_MISSING', "target missing") # send command menu = request.get_json() socketio.emit('changemenu', { 'time': datetime.utcnow().timestamp(), 'slot': slot, 'menu': menu, 'visible': True, 'referencedObjects': find_referenced_items(menu) }, room=target) return json_success("menu changed")
def on_send_chat_text_command(): now = datetime.utcnow() # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # send command text = request.args.get('text') socketio.emit('chatmessage', { 'time': now.timestamp(), 'text': text, 'objects': [] }, room=target) return json_success("chat message command sent to " + target)
def on_send_play_media_url_command(): now = datetime.utcnow() # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # send command url = request.args.get('url') log.debug(f"playing media URL {url}") socketio.emit('playmedia', { 'time': now.timestamp(), 'url': url }, room=target) return json_success("media playback command sent to " + target)
def on_shortcut(cbox_name, index): try: index = int(index) except: return json_bad_request_error('INVALID_ARGUMENTS', 'index argument must be numeric') # find cbox by name cbox = find_box(cbox_name) if not cbox or 'fields' not in cbox: return json_not_found_error('CBOX_NOT_FOUND', 'cbox not found') log.debug(f"picked cbox {cbox}") # get body data body = request.get_json() log.info(f"executing shortcut action {index} of {cbox} with {body}") # find shortcut shortcut = cbox.get('fields').get( 'shortcuts')[index] if cbox.get('fields').get('shortcuts') and len( cbox.get('fields').get('shortcuts')) > index else None if not shortcut or 'fields' not in shortcut: return json_not_acceptable_error('INVALID_ITEM', 'invalid shortcut item') log.debug(f"picked shortcut {shortcut}") # execute actions context = body.get('context') if body else {} individual = context.get('individual') if context else None shortcut_fields = shortcut['fields'] actions = shortcut_fields.get('actions') or [] targets = [cbox['id']] errors = schedule_actions(datetime.utcnow(), actions, None, None, {'individual': individual or 'anyone'}, targets) if errors: return json_action_execution_error(errors) else: return json_success("shortcut actions executed")
def on_send_adjust_volume_command(): now = datetime.utcnow() # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # get parameters if 'percent' not in request.args: return json_bad_request_error('ARGUMENT_MISSING', 'no volume argument specified') percent = request.args.get('percent') # send command socketio.emit('setvolume', { 'time': now.timestamp(), 'volume': percent }, room=target) return json_success("volume command sent to " + target)
def on_get_logfile(bytes_hint): log.info("logfile:" + app.config['LOGFILE_PATH']) f = open(app.config['LOGFILE_PATH'], "r") result = "".join(f.readlines(bytes_hint)) f.close() return json_success(result)
def on_post_menu_action(menu_id, index): # parse index try: index_list = [int(i) for i in index.split(";")] except: return json_bad_request_error('INVALID_ARGUMENTS', 'arguments must be numeric') # get body data body = request.get_json() log.info(f"executing menu action {index} of {menu_id} with {body}") # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() targets = [target] # find object menu = mongo.db.objects.find_one({'id': menu_id}, {'_id': False}) if not menu or 'fields' not in menu: return json_not_found_error('MENU_NOT_FOUND', 'menu not found') log.debug(f"picked menu {menu}") menu_fields = menu['fields'] # find item item, parent = find_menu_item_and_parent_by_index_list(menu, index_list) if parent and parent.get('type') == 'menuobjectselection': item = parent if not item or 'fields' not in item: return json_not_acceptable_error('INVALID_ITEM', 'invalid menu item') item_fields = item.get('fields') or {} log.debug(f"picked item {item}") # alternative targets defined? # currently not possible and probably a bad idea # if 'target' in menu_fields and menu_fields['target']: # targets = menu_fields['target'] context = body.get('context') or {} if body else {} context['individual'] = context.get('individual') or 'anyone' # find visitor type visitor_type = get_visitor_type(request.args) visitor_type_id = visitor_type['id'] if visitor_type else None # find avatar avatars = visitor_type['fields'][ 'avatar'] if visitor_type and 'fields' in visitor_type and 'avatar' in visitor_type[ 'fields'] else [] avatar_id = avatars[0] if avatars else None context['avatar'] = avatar_id # find subjects if item['type'] == 'menuobjectselection': subject_ids = item_fields.get('items') or [] subject_id = subject_ids[index_list[-1]] context['subjects'] = [ mongo.db.objects.find_one({'id': subject_id}, {'_id': False}) ] # execute actions if item['type'] == 'submenu': header = item_fields.get('header') if header: header_fields = header[0].get('fields') or {} actions = header_fields.get('actions') or [] else: actions = [] else: actions = item_fields.get('actions') or [] additional_actions = menu_fields.get('additionalactions') or [] errors = schedule_actions(datetime.utcnow(), actions + additional_actions, None, None, context, targets) if errors: return json_action_execution_error(errors) else: return json_success("menu actions executed")
def on_answer_interaction(scene_id, index, answer): # validate arguments assert index >= 0 and answer >= 0 # get body data body = request.get_json() log.info(f"got interaction answer {answer} of {scene_id} with {body}") # find target target = get_target(request.args) if not target: return json_no_command_target_found_error() # find scene scene = mongo.db.objects.find_one({'id': scene_id}, {'_id': False}) if not scene or 'fields' not in scene: return json_not_found_error('SCENE_NOT_FOUND', 'scene not found') scene_fields = scene['fields'] if 'actions' not in scene_fields: return json_not_acceptable_error('INVALID_ANSWER', 'invalid answer') log.debug(f"picked scene {scene}") # find action actions = scene_fields['actions'] if not actions or index >= len(actions): return json_not_acceptable_error('INVALID_ANSWER', 'invalid answer') action = actions[index] if not action or 'fields' not in action or 'type' not in action or action[ 'type'] != 'interaction': return json_not_acceptable_error('INVALID_ANSWER', 'invalid answer') log.debug(f"picked action {action}") # find option action_fields = action['fields'] if 'options' not in action_fields: return json_not_acceptable_error('INVALID_ANSWER', 'invalid answer') options = action_fields['options'] if not options or answer >= len(options): return json_not_acceptable_error('INVALID_ANSWER', 'invalid answer') option = options[answer] if not option or 'fields' not in option or 'type' not in option or option[ 'type'] != 'interactioncase': return json_not_acceptable_error('INVALID_ANSWER', 'invalid answer') log.debug(f"picked option {option}") # find visitor type visitor_type = get_visitor_type(request.args) visitor_type_id = visitor_type['id'] if visitor_type else None # find avatar avatars = visitor_type['fields'][ 'avatar'] if visitor_type and 'fields' in visitor_type and 'avatar' in visitor_type[ 'fields'] else [] avatar_id = avatars[0] if avatars else None # execute option context = body.get('context') errors = execute_interaction_option(datetime.utcnow(), option, context, [target]) if errors: return json_action_execution_error(errors) else: return json_success("interaction executed")
def on_trigger_badgesensor(sensor_name, range_index): # find method method = request.args.get('method') signature = request.args.get('signature') # find sensor sensor_info = find_badgesensor_info(sensor_name) if not sensor_info: log.warning(f"sensor {sensor_name} not registered") return json_not_found_error('SENSOR_NOT_REGISTERED', "sensor not registered") if signature and signature != sensor_info.get('signature'): return json_gone_error( 'SENSOR_CONFIGURATION_CHANGED', "sensor configuration has been changed and must be updated") # find beacon range beacon_ranges = sensor_info['ranges'] if range_index >= len(beacon_ranges): log.warning( f"beacon range {range_index} not defined for {sensor_name}") return json_not_found_error('INVALID_BEACON_RANGE', "invalid beacon range") beacon_range = beacon_ranges[range_index] # find individual / visitor type from badge badge = find_badge(request.args) if not badge or 'id' not in badge or 'fields' not in badge: return json_not_found_error('BADGE_NOT_REGISTERED', "badge not registered") badge_fields = badge['fields'] individual = badge['id'] visitor_type_field = badge_fields.get('visitortype') if visitor_type_field: visitor_type_id = visitor_type_field[0] visitor_type = mongo.db.objects.find_one( {'id': visitor_type_id}, {'_id': False}) if visitor_type_id else None else: visitor_type = None # update sensor state now = datetime.utcnow() if method == 'hold': hold_badgesensor_range(sensor_info, range_index, individual, now) return json_success("sensor hold successfully") elif method == 'leave': leave_badgesensor_range(sensor_info, range_index, individual, now) else: enter_badgesensor_range(sensor_info, range_index, individual, now) # find effects sensor_effect_ids = beacon_range.get('effects') or [] badge_effect_ids = badge_fields.get('effects') or [] effect_ids = sensor_effect_ids + badge_effect_ids if not effect_ids: return json_success("sensor triggered without effects") # execute effects log.info( f"{len(effect_ids)} effects(s) on {method} for {individual} of visitor type {visitor_type and visitor_type.get('title')} triggered by badge sensor {sensor_name}" ) errors = execute_effects(now, effect_ids, individual, visitor_type, [], method == 'leave') if errors: return json_action_execution_error(errors) else: return json_success("sensor triggered successfully")