def apply_program_changes(self): program = self.wizard().program if program == None: return start_mode = Constants.api_start_modes[self.get_field('start_mode')] continue_after_error = self.get_field('continue_after_error') start_interval = self.get_field('start_interval') start_fields = self.get_field('start_fields') try: program.set_schedule(start_mode, continue_after_error, start_interval, start_fields) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', u'Could not update stdio redirection of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', unicode, '<unknown>'), e)) return try: program.set_custom_option_value('started_once_after_upload', False) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', u'Could not update custom options of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', unicode, '<unknown>'), e)) return self.set_last_edit_timestamp()
def purge_selected_program(self): selected_items = self.tree_programs.selectedItems() if len(selected_items) == 0: return program_info = selected_items[0].data(0, Qt.UserRole) program = program_info.program name = program.cast_custom_option_value('name', unicode, '<unknown>') button = QMessageBox.question(get_main_window(), 'Delete Program', u'Deleting program [{0}] is irreversible. All files of this program will be deleted.'.format(name), QMessageBox.Ok, QMessageBox.Cancel) if not self.tab_is_alive or button != QMessageBox.Ok: return program_info.name_changed.disconnect(self.refresh_program_name) program_info.status_changed.disconnect(self.refresh_program_status) try: program.purge() # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Delete Program Error', u'Could not delete program [{0}]:\n\n{1}'.format(name, e)) return self.stacked_container.removeWidget(program_info) self.tree_programs.takeTopLevelItem(self.tree_programs.indexOfTopLevelItem(selected_items[0])) self.update_ui_state()
def button_p2p_discover_clicked(self): if self.combo_p2p_operation.currentIndex() == 1: if self.combo_p2p_write_record_type.currentIndex() == 0: text_raw = self.lineedit_p2p_write_data_text.text() if text_raw == '': QMessageBox.critical(get_main_window(), self.base_name + ' | Error', 'Input is empty. Please provide text input.') return self.nfc.p2p_write_ndef(self.pack_ndef_record_text(text_raw)) elif self.combo_p2p_write_record_type.currentIndex() == 1: uri_raw = self.lineedit_p2p_write_data_uri.text() if uri_raw == '': QMessageBox.critical(get_main_window(), self.base_name + ' | Error', 'Input is empty. Please provide URI.') return self.nfc.p2p_write_ndef(self.pack_ndef_record_uri(uri_raw, self.combo_p2p_write_uri_prefix.currentIndex())) self.nfc.p2p_start_discovery()
def button_cardemu_start_discovery_clicked(self): self.cardemu_start_discovery_clicked = True if self.combo_cardemu_record_type.currentIndex() == 0: text_raw = self.lineedit_cardemu_record_text_data.text() if text_raw == '': self.cardemu_record_text_start_discovery_clicked = False QMessageBox.critical(get_main_window(), self.base_name + ' | Error', 'Input is empty. Please provide text input.') return self.nfc.cardemu_write_ndef(self.pack_ndef_record_text(text_raw)) self.nfc.cardemu_start_discovery() elif self.combo_cardemu_record_type.currentIndex() == 1: uri_raw = self.lineedit_cardemu_record_uri_data.text() if uri_raw == '': self.cardemu_record_uri_start_discovery_clicked = False QMessageBox.critical(get_main_window(), self.base_name + ' | Error', 'Input is empty. Please provide URI.') return self.nfc.cardemu_write_ndef(self.pack_ndef_record_uri(uri_raw, self.combo_cardemu_record_uri_prefix.currentIndex())) self.nfc.cardemu_start_discovery()
def save_history(self): filename = get_save_file_name(get_main_window(), 'Save History', self.last_filename) if len(filename) == 0: return self.last_filename = filename try: f = open(filename, 'wb') except Exception as e: QMessageBox.critical(get_main_window(), 'Save History Error', u'Could not open {0} for writing:\n\n{1}'.format(filename, e)) return root = self.tree_frames.invisibleRootItem() content = ['Frame Type;Identifier [Hex];Data [Hex];Length\n'] for i in range(root.childCount()): child = root.child(i) row = [] for c in range(child.columnCount()): row.append(child.text(c)) content.append(';'.join(row) + '\n') try: # FIXME: add progress dialog if content is bigger than some megabytes f.write(''.join(content).encode('utf-8')) except Exception as e: QMessageBox.critical(get_main_window(), 'Save History Error', u'Could not write to {0}:\n\n{1}'.format(filename, e)) f.close()
def cb_open_error(error): if isinstance(error, REDError) and error.error_code == REDError.E_ALREADY_EXISTS: QMessageBox.critical(get_main_window(), 'New Config File Error', 'Config file {0} already exists.'.format(name)) else: QMessageBox.critical(get_main_window(), 'New Config File Error', 'Could not create config file {0}:\n\n{1}'.format(name, error))
def save_log(self): log = self.logs[self.combo_log.currentIndex()] content = log.content filename = get_save_file_name(get_main_window(), 'Save System Log', log.last_filename) if len(filename) == 0: return log.last_filename = filename try: f = open(filename, 'wb') except Exception as e: QMessageBox.critical(get_main_window(), 'Save System Log Error', u'Could not open {0} for writing:\n\n{1}'.format(filename, e)) return try: # FIXME: add progress dialog if content is bigger than some megabytes f.write(content) except Exception as e: QMessageBox.critical(get_main_window(), 'Save System Log Error', u'Could not write to {0}:\n\n{1}'.format(filename, e)) f.close()
def apply_program_changes(self): program = self.wizard().program if program == None: return name = self.get_field('name') try: program.set_custom_option_value('name', name) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', 'Could not update name of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', str, '<unknown>'), e)) return description = self.get_field('description') try: program.set_custom_option_value('description', description) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', 'Could not update description of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', str, '<unknown>'), e)) return self.set_last_edit_timestamp()
def cb_settings_services_apply(self, result): def done(): get_main_window().setEnabled(True) self.chkbox_gpu.setEnabled(True) self.chkbox_desktopenv.setEnabled(True) self.chkbox_webserver.setEnabled(True) self.chkbox_splashscreen.setEnabled(True) self.chkbox_ap.setEnabled(True) self.chkbox_server_monitoring.setEnabled(True) self.chkbox_openhab.setEnabled(True) self.chkbox_mobile_internet.setEnabled(True) self.pbutton_services_save.setText('Save and Reboot') self.pbutton_services_save.setEnabled(True) def cb_restart_reboot_shutdown(result): if not report_script_result(result, 'Settings | Services', 'Error rebooting RED Brick'): done() return if not report_script_result(result, 'Settings | Services', 'Error saving services status'): done() return get_main_window().setEnabled(True) QtGui.QMessageBox.information(get_main_window(), 'Settings | Services', 'Saved configuration successfully, will now reboot RED Brick.') self.script_manager.execute_script('restart_reboot_shutdown', cb_restart_reboot_shutdown, ['1'])
def slot_pbutton_services_save_clicked(self): state = {} state['gpu'] = self.chkbox_gpu.isChecked() state['desktopenv'] = self.chkbox_desktopenv.isChecked() state['webserver'] = self.chkbox_webserver.isChecked() state['splashscreen'] = self.chkbox_splashscreen.isChecked() state['ap'] = self.chkbox_ap.isChecked() state['servermonitoring'] = self.chkbox_server_monitoring.isChecked() state['openhab'] = self.chkbox_openhab.isChecked() state['mobileinternet'] = self.chkbox_mobile_internet.isChecked() self.chkbox_gpu.setEnabled(False) self.chkbox_desktopenv.setEnabled(False) self.chkbox_webserver.setEnabled(False) self.chkbox_splashscreen.setEnabled(False) self.chkbox_ap.setEnabled(False) self.chkbox_server_monitoring.setEnabled(False) self.chkbox_openhab.setEnabled(False) self.chkbox_mobile_internet.setEnabled(False) self.pbutton_services_save.setText('Saving...') self.pbutton_services_save.setEnabled(False) get_main_window().setEnabled(False) self.script_manager.execute_script('settings_services', self.cb_settings_services_apply, ['APPLY', json.dumps(state)])
def slot_pbutton_sm_add_host_add_clicked(self): if not self.ledit_sm_add_host_host.text(): QtGui.QMessageBox.critical(get_main_window(), "Settings | Server Monitoring", "Host name is empty.") return try: self.ledit_sm_add_host_host.text().encode("ascii") except: QtGui.QMessageBox.critical( get_main_window(), "Settings | Server Monitoring", "Host name contains non ASCII characters." ) return if ( self.chkbox_sm_add_host_authentication.checkState() == QtCore.Qt.Checked and not self.ledit_sm_add_host_secret.text() ): QtGui.QMessageBox.critical(get_main_window(), "Settings | Server Monitoring", "No secrets specified.") return self.host = self.ledit_sm_add_host_host.text() self.port = unicode(self.sbox_sm_add_host_port.value()) self.secret = self.ledit_sm_add_host_secret.text() self.accept()
def slot_pbutton_sm_add_host_add_clicked(self): if not self.ledit_sm_add_host_host.text(): QMessageBox.critical(get_main_window(), 'Settings | Server Monitoring', 'Host name is empty.') return try: self.ledit_sm_add_host_host.text().encode('ascii') except: QMessageBox.critical(get_main_window(), 'Settings | Server Monitoring', 'Host name contains non ASCII characters.') return if self.chkbox_sm_add_host_authentication.isChecked() and \ not self.ledit_sm_add_host_secret.text(): QMessageBox.critical(get_main_window(), 'Settings | Server Monitoring', 'No secrets specified.') return self.host = self.ledit_sm_add_host_host.text() self.port = self.sbox_sm_add_host_port.value() self.secret = self.ledit_sm_add_host_secret.text() self.accept()
def apply_program_custom_options_and_command_changes(self): program = self.wizard().program if program == None: return False # command command = self.get_command() if command != None: executable, arguments, environment, working_directory = command editable_arguments_offset = max(program.cast_custom_option_value('editable_arguments_offset', int, 0), 0) editable_arguments = program.arguments.items[editable_arguments_offset:] editable_environment_offset = max(program.cast_custom_option_value('editable_environment_offset', int, 0), 0) editable_environment = program.environment.items[editable_environment_offset:] editable_arguments_offset = len(arguments) editable_environment_offset = len(environment) arguments += editable_arguments environment += editable_environment else: executable = '/bin/false' arguments = [] environment = [] working_directory = '.' editable_arguments_offset = 0 editable_environment_offset = 0 try: program.set_command(executable, arguments, environment, working_directory) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', 'Could not update command of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', str, '<unknown>'), e)) return False # custom options custom_options = self.get_custom_options() custom_options['editable_arguments_offset'] = editable_arguments_offset custom_options['editable_environment_offset'] = editable_environment_offset for name, value in custom_options.items(): try: program.set_custom_option_value(name, value) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', 'Could not update custom options of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', str, '<unknown>'), e)) return False self.set_last_edit_timestamp() return True
def done(): get_main_window().setEnabled(True) self.chkbox_gpu.setEnabled(True) self.chkbox_desktopenv.setEnabled(True) self.chkbox_webserver.setEnabled(True) self.chkbox_splashscreen.setEnabled(True) self.chkbox_ap.setEnabled(True) self.chkbox_server_monitoring.setEnabled(True) self.chkbox_openhab.setEnabled(True) self.chkbox_mobile_internet.setEnabled(True) self.pbutton_services_save.setText('Save and Reboot') self.pbutton_services_save.setEnabled(True)
def cb_write(red_file, result): red_file.release() if result is not None: self.brickd_button_save_enabled(True) QtGui.QMessageBox.critical(get_main_window(), 'Settings | Brickd', 'Error writing brickd config file.') else: self.script_manager.execute_script('restart_brickd', None) QtGui.QMessageBox.information(get_main_window(), 'Settings | Brick Daemon', 'Saved configuration successfully, restarting brickd.')
def btn_save_config_clicked(self): filename = get_save_file_name(get_main_window(), 'Save Config', get_home_path(), 'JSON Files (*.json)') if len(filename) == 0: return if not filename.lower().endswith('.json'): filename += '.json' config = GuiConfigHandler.create_config(self) if not save_config(config, filename): QMessageBox.warning(get_main_window(), 'Save Config', 'Could not save config to file! See Debug tab for details.', QMessageBox.Ok)
def render_color_gradient(self): num_leds = self.box_num_led.value() if num_leds < 2: QMessageBox.warning(get_main_window(), 'Color gradient', 'Can not render color gradient: There is only one LED configured.', QMessageBox.Ok) return brightness = self.brightness_slider.value() * 8 chip_type, num_channels = self.chip_type_combobox.itemData(self.chip_type_combobox.currentIndex()) self.gradient_counter += num_leds * self.box_speed.value() / 100.0 / 4.0 range_leds = list(range(num_leds)) range_leds = range_leds[int(self.gradient_counter) % num_leds:] + range_leds[:int(self.gradient_counter) % num_leds] intensity = self.gradient_intensity.value() / 100.0 self.label_gradient_intensity.setText(str(self.gradient_intensity.value()) + '%') values = [] for i in reversed(range_leds): r, g, b = colorsys.hsv_to_rgb(1.0*i/(num_leds-1), 1, intensity) values.append(int(r*255)) values.append(int(g*255)) values.append(int(b*255)) if num_channels == 4: values.append(0) self.led_strip.set_led_values(0, values)
def delete_config(self): config = self.configs[self.combo_config.currentIndex()] button = QMessageBox.question( get_main_window(), "Delete Config File", "Irreversibly deleting config file {0}.".format(config.display_name), QMessageBox.Ok, QMessageBox.Cancel, ) if button != QMessageBox.Ok: # FIXME: check if tab is still alive return self.action_in_progress = True self.update_ui_state() self.label_progress.setText("Deleting " + config.absolute_name) def cb_delete(result): self.action_in_progress = False self.update_ui_state() self.refresh_all_configs(None) report_script_result( result, "Delete Config File Error", "Could not delete config file {0}:".format(config.display_name) ) self.script_manager.execute_script("delete", cb_delete, [json.dumps([config.absolute_name]), json.dumps([])])
def delete_selected_logs(self): button = QMessageBox.question(get_main_window(), 'Delete Logs', 'Irreversibly deleting selected logs.', QMessageBox.Ok, QMessageBox.Cancel) if not self.is_alive() or button != QMessageBox.Ok: return def cb_delete(result): self.refresh_logs() report_script_result(result, 'Delete Logs Error', 'Could not delete selected logs') index_list = self.tree_logs.selectedIndexes() if not index_list: return log_files_to_delete = self.load_log_files_for_ops(index_list) if not log_files_to_delete: return file_list = [] for f_path in log_files_to_delete['files']: file_list.append(f_path) if len(file_list) > 0: self.script_manager.execute_script('delete', cb_delete, [json.dumps(file_list), json.dumps([])], execute_as_user=True)
def cb_statistics(self, statistics): self.label_messages_from_brick.setText(str(statistics.messages_from_brick)) self.label_messages_from_bricklet.setText(str(statistics.messages_from_bricklet)) try: name = infos.get_info(statistics.connected_bricklet_uid).plugin.device_class.DEVICE_DISPLAY_NAME except: name = None if statistics.connected_bricklet_uid != '' and name != None: self.label_isolated_bricklet.setText('<b>{0}</b> with UID "{1}"'.format(name, statistics.connected_bricklet_uid)) self.button_bricklet.setText('Open {0}'.format(name)) if self.last_connected != statistics.connected_bricklet_uid: self.last_connected = statistics.connected_bricklet_uid try: self.button_bricklet.clicked.disconnect() except: pass self.button_bricklet.clicked.connect(lambda: get_main_window().show_plugin(statistics.connected_bricklet_uid)) self.button_bricklet.setEnabled(True) else: self.label_isolated_bricklet.setText('Unknown Bricklet (Did you connect a Bricklet?)') self.button_bricklet.setText('Open Bricklet') self.button_bricklet.setEnabled(False)
def download_selected_logs(self): index_list = self.tree_logs.selectedIndexes() if len(index_list) == 0: return log_files_to_download = self.load_log_files_for_ops(index_list) if len(log_files_to_download['foobar']) == 0: return download_directory = get_existing_directory(get_main_window(), 'Download Logs', self.last_download_directory) if len(download_directory) == 0: return self.last_download_directory = download_directory downloads = [] for file_name in log_files_to_download['foobar']: downloads.append(Download(file_name, file_name)) self.show_download_wizard('logs', download_directory, downloads)
def start_program(self): try: self.program.start() except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Start Error', u'Could not start program [{0}]:\n\n{1}' .format(self.program.cast_custom_option_value('name', unicode, '<unknown>'), e))
def cb_settings_ap_status(result): self.update_button_text_state(BUTTON_STATE_DEFAULT) self.label_working_wait.hide() self.pbar_working_wait.hide() self.sarea_ap.setEnabled(True) if not self.is_tab_on_focus: return if not report_script_result(result, 'Settings | Access Point', 'Error checking access point mode:', before_message_box=lambda: self.label_ap_status.setText('-')): return ap_mode_status = json.loads(result.stdout) if ap_mode_status is None or \ ap_mode_status['ap_first_time'] is None or \ ap_mode_status['ap_incomplete_config'] is None or \ ap_mode_status['ap_hardware_or_config_problem'] is None: self.label_ap_status.setText('-') QMessageBox.critical(get_main_window(), 'Settings | Access Point', 'Error checking access point mode.') elif not ap_mode_status['ap_incomplete_config'] and \ not ap_mode_status['ap_hardware_or_config_problem']: self.label_ap_status.setText('Active') elif ap_mode_status['ap_first_time']: self.label_ap_status.setText('Inactive - Select an interface and click save') elif ap_mode_status['ap_incomplete_config']: self.label_ap_status.setText('Inactive - Incomplete configuration, check your configuration and click save') elif ap_mode_status['ap_hardware_or_config_problem']: self.label_ap_status.setText('Inactive - Hardware not supported or wrong configuration') self.update_ui_state() self.read_config_files()
def download_selected_files(self): selected_name_items = self.get_directly_selected_name_items() if len(selected_name_items) == 0: return downloads = [] def expand(name_item): item_type = name_item.data(USER_ROLE_ITEM_TYPE) if item_type == ITEM_TYPE_DIRECTORY: for i in range(name_item.rowCount()): expand(name_item.child(i, 0)) elif item_type == ITEM_TYPE_FILE: filename = get_full_item_path(name_item) downloads.append(Download(filename, QDir.toNativeSeparators(filename))) for selected_name_item in selected_name_items: expand(selected_name_item) if len(downloads) == 0: return download_directory = get_existing_directory(get_main_window(), 'Download Files', self.last_download_directory) if len(download_directory) == 0: return self.last_download_directory = download_directory self.show_download_wizard('files', download_directory, downloads)
def cb_success(result): programs, message = result if message != None: QMessageBox.critical(get_main_window(), 'Import Error', message) else: sorted_programs = {} for program in programs: first_upload = program[4] if first_upload in sorted_programs: sorted_programs[first_upload][program[1]] = program else: sorted_programs[first_upload] = {program[1]: program} for first_upload in sorted(sorted_programs.keys()): for identifier in sorted(sorted_programs[first_upload].keys()): program = sorted_programs[first_upload][identifier] item = QTreeWidgetItem(program[0:4]) self.tree_programs.addTopLevelItem(item) item.setSelected(True) self.refresh_in_progress = False self.update_ui_state() self.tree_programs.setFocus()
def cb_import_directory(result): script_instance = script_instance_ref[0] if script_instance != None: aborted = script_instance.abort else: aborted = False script_instance_ref[0] = None if aborted: return if not report_script_result(result, 'Import Error', 'Could not create import directory', before_message_box=self.progress.close): return # step 2/4: upload archive to temporary import directory import_directory_ref[0] = result.stdout.strip() target_path = posixpath.join(import_directory_ref[0], 'archive.tfrba') self.chunked_uploader = ChunkedUploader(self, extract_archive) if not self.chunked_uploader.prepare(source_path): return try: target_file = REDFile(self.session).open(target_path, REDFile.FLAG_WRITE_ONLY | REDFile.FLAG_CREATE | REDFile.FLAG_NON_BLOCKING | REDFile.FLAG_EXCLUSIVE, 0o644, 1000, 1000) # FIXME: async_call except (Error, REDError) as e: QMessageBox.information(get_main_window(), 'Import Error', 'Could not open target file {0}: {1}'.format(target_path, e)) return self.progress.setLabelText('Step 2 of 4: Uploading archive') self.progress.set_progress_text_visible(True) self.chunked_uploader.start(target_path, target_file)
def auto_generate_identifier(self, name): if not self.check_auto_generate.isChecked() or self.edit_mode: return # ensure the identifier matches ^[a-zA-Z0-9_][a-zA-Z0-9._-]{2,}$ identifier = re.sub('[^a-zA-Z0-9._-]', '_', name).lstrip('-.') unique_identifier = identifier counter = 1 while len(unique_identifier) < 3: unique_identifier += '_' while unique_identifier in self.wizard().identifiers and counter < 10000: unique_identifier = identifier + str(counter) counter += 1 while len(unique_identifier) < 3: unique_identifier += '_' self.edit_identifier.setText(unique_identifier) if unique_identifier in self.wizard().identifiers: QMessageBox.critical(get_main_window(), 'New Program Error', 'Could not auto-generate unique identifier from program name [{0}] because all tested ones are already in use.' .format(name))
def apply_program_changes(self): program = self.wizard().program if program == None: return executable = program.executable editable_arguments_offset = max(program.cast_custom_option_value('editable_arguments_offset', int, 0), 0) arguments = program.arguments.items[:editable_arguments_offset] editable_environment_offset = max(program.cast_custom_option_value('editable_environment_offset', int, 0), 0) environment = program.environment.items[:editable_environment_offset] working_directory = program.working_directory arguments += self.get_arguments() environment += self.get_environment() try: program.set_command(executable, arguments, environment, working_directory) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', 'Could not update arguments and environment of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', str, '<unknown>'), e)) return self.set_last_edit_timestamp()
def continue_schedule(self): try: self.program.continue_schedule() except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Schedule Error', u'Could not continue schedule of program [{0}]:\n\n{1}' .format(self.program.cast_custom_option_value('name', unicode, '<unknown>'), e))
def cb_red_brick_time(result): if not report_script_result(result, 'Settings | Date/Time', 'Error getting time from RED Brick'): return try: self.time_red_old, tz = map(int, result.stdout.split('\n')[:2]) if tz < 0: tz_str_red = 'UTC' + str(tz) else: tz_str_red = 'UTC+' + str(tz) self.time_timezone_red.setText(tz_str_red) self.time_local_old = int(time.time()) tz = self.time_utc_offset() if tz < 0: tz_str_local = 'UTC' + str(tz) else: tz_str_local = 'UTC+' + str(tz) self.time_timezone_local.setText(tz_str_local) self.time_update_gui() self.time_refresh_timer.start() if (self.time_red_old == self.time_local_old) and (tz_str_local == tz_str_red): self.time_sync_button.setEnabled(False) else: self.time_sync_button.setEnabled(True) except Exception as e: QtGui.QMessageBox.critical(get_main_window(), 'Settings | Date/Time', 'Error parsing time from RED Brick:\n\n{0}'.format(e)) self.time_sync_button.setEnabled(True)
def get_certificate(self, url_edit): cert_path = url_edit.text() try: if os.path.isfile(cert_path): certificate_file = map(ord, file(cert_path, 'rb').read()) # Convert certificate to list of bytes certificate_length = len(certificate_file) if certificate_length > 6*1024: QMessageBox.critical(get_main_window(), "Save", "Certificate too big (max size: 6kB).", QMessageBox.Ok) return [] return certificate_file except: return [] return []
def send_stdin_pipe_input(self): if self.program.last_spawned_process != None and self.program.last_spawned_process.stdin != None: try: self.program.last_spawned_process.stdin.write_async( (self.edit_stdin_pipe_input.text() + u'\n').encode('utf-8')) except (Error, REDError) as e: QMessageBox.critical( get_main_window(), 'Pipe Input Error', u'Could not write to stdin of current process of program [{0}]:\n\n{1}' .format( self.program.cast_custom_option_value( 'name', unicode, '<unknown>'), e)) else: self.edit_stdin_pipe_input.setText('')
def btn_browse_log_file_name_clicked(self): if len(self.edit_log_file_name.text()) > 0: last_dir = os.path.dirname( os.path.realpath(self.edit_log_file_name.text())) else: last_dir = get_home_path() filename = get_save_file_name(get_main_window(), 'Choose Log File', last_dir, "Log Files (*.log)") if len(filename) > 0: if not filename.lower().endswith('.log'): filename += '.log' self.edit_log_file_name.setText(filename)
def slot_fs_expand_clicked(self): def cb_settings_fs_expand(result): def cb_restart_reboot_shutdown(result): report_script_result(result, 'Settings | File System', 'Error rebooting RED Brick') get_main_window().setEnabled(True) if not report_script_result(result, 'Settings | File System', 'Error expanding file system'): return QtGui.QMessageBox.information( get_main_window(), 'Settings | Services', 'File system expansion will be complete after reboot, rebooting RED Brick now.' ) self.script_manager.execute_script('restart_reboot_shutdown', cb_restart_reboot_shutdown, ['1']) get_main_window().setEnabled(False) self.script_manager.execute_script('settings_fs_expand', cb_settings_fs_expand)
def check_ascii(text, message): try: text.encode('ascii') return True except: self.label_working_wait.hide() self.pbar_working_wait.hide() self.saving = False self.sarea_ap.show() self.update_button_text_state(BUTTON_STATE_DEFAULT) QtGui.QMessageBox.critical(get_main_window(), 'Settings | Access Point', message) return False
def set_last_edit_timestamp(self): program = self.wizard().program if program == None: return try: program.set_custom_option_value('last_edit', int( time.time())) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical( get_main_window(), 'Edit Program Error', 'Could not update last edit timestamp of program [{0}]:\n\n{1}' .format( program.cast_custom_option_value('name', str, '<unknown>'), e))
def gui_after_apply(result): self.label_working_wait.hide() self.pbar_working_wait.hide() self.saving = False self.sarea_ap.setEnabled(True) self.update_button_text_state(BUTTON_STATE_DEFAULT) if not report_script_result(result, 'Settings | Access Point', 'Error saving access point settings:'): return self.slot_pbutton_ap_refresh_clicked() QMessageBox.information(get_main_window(), 'Settings | Access Point', 'Access point settings saved.')
def open_console(): self.combo_serial_port.setEnabled(False) self.refresh_button.setEnabled(False) self.console.setEnabled(True) self.connect_button.setText("Disconnect") port = self.combo_serial_port.itemData(self.combo_serial_port.currentIndex()) if self.console._session == None: try: self.console.execute(command=port) self.console.setFocus() except Exception as e: self.destroy_session() QtGui.QMessageBox.critical(get_main_window(), 'Serial Connect Error', u'Could not connect to serial console:\n\n{0}'.format(e))
def report_script_result(result, title, message_header, decode_stderr=False, before_message_box=None): okay, message = check_script_result(result, decode_stderr) if okay: return True if before_message_box != None: before_message_box() QMessageBox.critical(get_main_window(), title, message_header + u':\n\n' + message) return False
def change_permissions_of_selected_file(self): selection_count = len(self.tree_files.selectionModel().selectedRows()) if selection_count != 1: return selected_name_items = self.get_directly_selected_name_items() if len(selected_name_items) != 1: return name_item = selected_name_items[0] item_type = name_item.data(USER_ROLE_ITEM_TYPE) old_permissions = name_item.data(USER_ROLE_PERMISSIONS) if item_type == ITEM_TYPE_FILE: title = 'Change File Permissions' type_name = 'file' else: title = 'Change Directory Permissions' type_name = 'directory' dialog = ProgramInfoFilesPermissions(get_main_window(), title, old_permissions) if dialog.exec_() != QDialog.Accepted: return new_permissions = dialog.get_permissions() if new_permissions == (old_permissions & 0o777): return absolute_name = posixpath.join(self.bin_directory, get_full_item_path(name_item)) def cb_change_permissions(result): if not report_script_result( result, title + ' Error', 'Could change {0} permissions'.format(type_name)): return name_item.setData(new_permissions, USER_ROLE_PERMISSIONS) self.script_manager.execute_script( 'change_permissions', cb_change_permissions, [absolute_name, str(new_permissions)])
def get_certificate(self, url_edit): cert_path = url_edit.text() try: if os.path.isfile(cert_path): with open(cert_path, 'rb') as f: certificate_file = f.read() certificate_length = len(certificate_file) if certificate_length > 6 * 1024: QMessageBox.critical( get_main_window(), "Save", "Certificate too big (max size: 6kB).", QMessageBox.Ok) return [] return certificate_file except: return [] return []
def cb_red_brick_time(result): if not report_script_result(result, 'Settings | Date/Time', 'Error getting time from RED Brick'): return try: self.time_local_old = int(time.time()) self.time_red_old, self.time_iso8601_red, timezone = result.stdout.split( '\n')[:3] self.time_red_old = int(self.time_red_old) try: self.timezone_red = pytz.timezone(timezone) except: self.timezone_red = None timezone = self.convert_from_posix(timezone) timezone = "Unknown ({})".format( timezone) if len(timezone) > 0 else "Unknown" self.red_reconfigure_label.show() self.save_timezone_button.setEnabled(False) self.time_timezone_red.setCurrentText(timezone) try: tz_str_local = self.convert_from_posix( get_localzone().zone) except: tz_str_local = 'Unknown ({})'.format( self.format_time_utc_offset(self.time_utc_offset())) self.time_timezone_local.setText(tz_str_local) self.time_update_gui() self.time_refresh_timer.start() self.time_sync_button.setEnabled(True) except Exception as e: QMessageBox.critical( get_main_window(), 'Settings | Date/Time', 'Error parsing time from RED Brick:\n\n{0}'.format(e)) self.time_sync_button.setEnabled(True)
def cb_import_directory(result): script_instance = script_instance_ref[0] if script_instance != None: aborted = script_instance.abort else: aborted = False script_instance_ref[0] = None if aborted: return if not report_script_result( result, 'Import Error', 'Could not create import directory', before_message_box=self.progress.close): return # step 2/4: upload archive to temporary import directory import_directory_ref[0] = result.stdout.strip() target_path = posixpath.join(import_directory_ref[0], 'archive.tfrba') self.chunked_uploader = ChunkedUploader(self, extract_archive) if not self.chunked_uploader.prepare(source_path): return try: target_file = REDFile(self.session).open( target_path, REDFile.FLAG_WRITE_ONLY | REDFile.FLAG_CREATE | REDFile.FLAG_NON_BLOCKING | REDFile.FLAG_EXCLUSIVE, 0o644, 1000, 1000) # FIXME: async_call except (Error, REDError) as e: QMessageBox.information( get_main_window(), 'Import Error', 'Could not open target file {0}: {1}'.format( target_path, e)) return self.progress.setLabelText('Step 2 of 4: Uploading archive') self.progress.set_progress_text_visible(True) self.chunked_uploader.start(target_path, target_file)
def cb_settings_mobile_internet_connect(self, result): self.update_gui(EVENT_GUI_CONNECT_RETURNED) if result.exit_code == 2: QtGui.QMessageBox.critical(get_main_window(), MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT_TEST) return if result.exit_code == 3: QtGui.QMessageBox.critical(get_main_window(), MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT_SERVICE_CREATION) return if result.exit_code == 4: QtGui.QMessageBox.critical( get_main_window(), MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT_SERVICE_EXECUTION) return if result.exit_code == 7 or \ result.exit_code == 8: QtGui.QMessageBox.critical( get_main_window(), MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT_TEST_DEVICE_UNAVAILABLE) return if result.exit_code == 12: QtGui.QMessageBox.critical(get_main_window(), MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT_TEST_PIN) return if result.exit_code == 13 or \ result.exit_code == 98: QtGui.QMessageBox.critical( get_main_window(), MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT_TEST_REGISTER_NETWORK) return if not report_script_result(result, MESSAGEBOX_TITLE, MESSAGE_ERROR_CONNECT): return QtGui.QMessageBox.information(get_main_window(), MESSAGEBOX_TITLE, MESSAGE_INFORMATION_CONNECT_OK) self.pbutton_mi_refresh_clicked()
def state_changed(process, t, p): if p.state == REDProcess.STATE_ERROR: process.release() QtGui.QMessageBox.critical(get_main_window(), 'Settings | Date/Time', 'Error syncing time.') elif p.state == REDProcess.STATE_EXITED: if t == 0: #timezone self.time_timezone_red.setText(self.time_timezone_local.text()) elif t == 1: #time self.time_red_old = self.time_local_old process.release() if self.time_red_old == self.time_local_old and \ self.time_timezone_red.text() == self.time_timezone_local.text(): self.time_sync_button.setEnabled(False) else: self.time_sync_button.setEnabled(True)
def cb_settings_ap_status(result): self.update_button_text_state(BUTTON_STATE_DEFAULT) self.label_working_wait.hide() self.pbar_working_wait.hide() self.sarea_ap.setEnabled(True) if not self.is_tab_on_focus: return if not report_script_result(result, 'Settings | Access Point', 'Error checking access point mode:', before_message_box=lambda: self. label_ap_status.setText('-')): return ap_mode_status = json.loads(result.stdout) if ap_mode_status is None or \ ap_mode_status['ap_first_time'] is None or \ ap_mode_status['ap_incomplete_config'] is None or \ ap_mode_status['ap_hardware_or_config_problem'] is None: self.label_ap_status.setText('-') QMessageBox.critical(get_main_window(), 'Settings | Access Point', 'Error checking access point mode.') elif not ap_mode_status['ap_incomplete_config'] and \ not ap_mode_status['ap_hardware_or_config_problem']: self.label_ap_status.setText('Active') elif ap_mode_status['ap_first_time']: self.label_ap_status.setText( 'Inactive - Select an interface and click save') elif ap_mode_status['ap_incomplete_config']: self.label_ap_status.setText( 'Inactive - Incomplete configuration, check your configuration and click save' ) elif ap_mode_status['ap_hardware_or_config_problem']: self.label_ap_status.setText( 'Inactive - Hardware not supported or wrong configuration') self.update_ui_state() self.read_config_files()
def show_add_files_dialog(self): filenames = get_open_file_names(get_main_window(), 'Add Files', self.last_directory) if len(filenames) > 0: self.last_directory = os.path.split(filenames[0])[0] for filename in filenames: if len(self.list_files.findItems(filename, Qt.MatchFixedString)) > 0: continue uploads = [Upload(filename, os.path.split(filename)[1])] item = QListWidgetItem(filename) item.setData(Qt.UserRole, uploads) item.setData(Qt.DecorationRole, self.file_icon) self.list_files.addItem(item) self.completeChanged.emit()
def sync_rect_toggled(self, checked): if not self.setting_sync_rect_checkbox and checked: rc = QMessageBox.warning( get_main_window(), 'Synchronous Rectification', 'If you want to use high speeds (> 10000 steps/s) for a large stepper motor with a ' + 'large inductivity we strongly suggest that you do not enable synchronous rectification. ' + 'Otherwise the Brick may not be able to cope with the load and overheat.', QMessageBox.Ok | QMessageBox.Cancel) if rc != QMessageBox.Ok: self.sync_rect_checkbox.setChecked(False) return try: self.stepper.set_sync_rect(checked) except ip_connection.Error: return self.decay_widget.setVisible(checked)
def cb_write(error): def cb_openhab_set_configs_ownership(result): okay, message = check_script_result(result, decode_stderr=True) if not okay: QMessageBox.critical(get_main_window(), 'Apply Changes Error', 'Error while setting ownership of {0}: {1}'.format(config.display_name, message)) else: config.set_content(content) red_file.release() self.action_in_progress = False self.update_ui_state() if error != None: QMessageBox.critical(get_main_window(), 'Apply Changes Error', 'Error while writing {0}: {1}'.format(config.display_name, error)) return self.script_manager.execute_script('openhab_set_configs_ownership', cb_openhab_set_configs_ownership)
def add_class_path_entry(self): dialog = ExpandingInputDialog(self) dialog.setModal(True) dialog.setWindowTitle('Add Class Path Entry') dialog.setLabelText('Enter/Choose new class path entry:') dialog.setOkButtonText('Add') dialog.setComboBoxItems(self.class_path_candidates) dialog.setComboBoxEditable(True) dialog.setTextValue('') if dialog.exec_() != QDialog.Accepted: return entry = dialog.textValue() if len(entry) == 0: QMessageBox.critical(get_main_window(), 'Add Class Path Entry Error', 'A valid class path entry cannot be empty.') return self.class_path_list_editor.add_item(entry, select_item=True)
def cb_delete(result): script_instance = script_instance_ref[0] if script_instance != None: aborted = script_instance.abort else: aborted = False script_instance_ref[0] = None progress.cancel() self.refresh_files() if aborted: QMessageBox.information(get_main_window(), 'Delete Files', 'Delete operation was aborted.') return report_script_result( result, 'Delete Files Error', 'Could not delete selected files/directories:')
def pbutton_mi_connect_clicked(self): if self.working: return result, message = self.validate_configuration_fields() if not result: QtGui.QMessageBox.critical(get_main_window(), MESSAGEBOX_TITLE, message) return self.update_gui(EVENT_GUI_CONNECT_CLICKED) usb_modem = self.cbox_mi_modem.itemData( self.cbox_mi_modem.currentIndex()) if self.ledit_mi_dial.text(): dial = self.ledit_mi_dial.text() else: dial = '*99#' apn = self.ledit_mi_apn.text() if self.ledit_mi_username.text(): apn_user = self.ledit_mi_username.text() else: apn_user = '******' if self.ledit_mi_password.text(): apn_pass = self.ledit_mi_password.text() else: apn_pass = '******' sim_pin = self.ledit_mi_sim_card_pin.text() self.script_manager.execute_script( 'settings_mobile_internet', self.cb_settings_mobile_internet_connect, ['CONNECT', usb_modem, dial, apn, apn_user, apn_pass, sim_pin])
def device_info_changed(self, uid): if uid != self.device_info.uid: return if self.device_info.tab_window is None: return if self.device_info.firmware_version_installed < self.device_info.firmware_version_latest: self.show_update() else: self.hide_update() self.hardware_version = self.device_info.hardware_version self.firmware_version = self.device_info.firmware_version_installed self.label_version.setText(get_version_string(self.firmware_version)) if self.button_parent is not None: self.button_parent.setText(self.device_info.connected_uid) self.button_parent.clicked.connect(lambda: get_main_window().show_plugin(self.device_info.connected_uid)) if self.label_position is not None: self.label_position.setText(self.device_info.position.title())
def apply_program_changes(self): if not self.apply_program_custom_options_and_command_changes(): return # stop scheduler if switching to browser flavor program = self.wizard().program if program == None: return if self.get_field( 'javascript.flavor') == Constants.JAVASCRIPT_FLAVOR_BROWSER: try: program.set_schedule(REDProgram.START_MODE_NEVER, False, 0, '') # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical( get_main_window(), 'Edit Program Error', u'Could not update schedule of program [{0}]:\n\n{1}'. format( program.cast_custom_option_value( 'name', unicode, '<unknown>'), e))
def save_queue_configuration(self): write_buffer_size = self.spin_write_buffer_size.value() write_buffer_timeout = self.spin_write_buffer_timeout.value() write_backlog_size = self.spin_write_backlog_size.value() read_buffer_sizes_str = self.edit_read_buffer_sizes.text().replace(' ', '') read_backlog_size = self.spin_read_backlog_size.value() if len(read_buffer_sizes_str) == 0: read_buffer_sizes = [] else: try: read_buffer_sizes = list(map(int, read_buffer_sizes_str.split(','))) except: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'Read Buffer Sizes could not be parsed as comma-separated list of integers.') return if len(read_buffer_sizes) > 32: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'More than 32 Read Buffer Sizes specified.') return for read_buffer_size in read_buffer_sizes: if read_buffer_size == 0: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'Read Buffer Sizes cannot be 0.') return if read_buffer_size < -32 or read_buffer_size > 32: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'Read Buffer Sizes must be in [-32..+32] range.') return if write_buffer_size + sum(map(abs, read_buffer_sizes)) > 32: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'More than 32 buffers used in total.') return if write_backlog_size + read_backlog_size > 768: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'Backlog cannot be longer than 768 frames in total.') return # FIXME: add validation self.can.set_queue_configuration(write_buffer_size, write_buffer_timeout, write_backlog_size, read_buffer_sizes, read_backlog_size) self.button_save_queue_configuration.setEnabled(False)
def delete_config(self): config = self.configs[self.combo_config.currentIndex()] button = QMessageBox.question(get_main_window(), 'Delete Config File', 'Irreversibly deleting config file {0}.'.format(config.display_name), QMessageBox.Ok, QMessageBox.Cancel) if button != QMessageBox.Ok: # FIXME: check if tab is still alive return self.action_in_progress = True self.update_ui_state() self.label_progress.setText('Deleting ' + config.absolute_name) def cb_delete(result): self.action_in_progress = False self.update_ui_state() self.refresh_all_configs(None) report_script_result(result, 'Delete Config File Error', 'Could not delete config file {0}:'.format(config.display_name)) self.script_manager.execute_script('delete', cb_delete, [json.dumps([config.absolute_name]), json.dumps([])])
def button_pressed(self): main_window = get_main_window() main_window.flashing_clicked() QApplication.processEvents() main_window.flashing_window.tab_widget.setCurrentPage(2) QApplication.processEvents() combo_parent = main_window.flashing_window.combo_parent combo_port = main_window.flashing_window.combo_port connected_uid = self.info.connected_uid # If the Bricklet is connected to an isolator, # we have to find the Brick that the isolator is connected to. if self.info.position.startswith('i-'): for bricklet_info in infos.get_bricklet_infos(): if bricklet_info.uid == connected_uid: connected_uid = bricklet_info.connected_uid break for i in range(combo_parent.count()): if '[' + connected_uid + ']' in combo_parent.itemText(i): combo_parent.setCurrentIndex(i) QApplication.processEvents() break port_index = 0 try: for i in range(combo_port.count()): if combo_port.itemText(i).startswith( self.info.position.upper()): port_index = i break except: port_index = 0 combo_port.setCurrentIndex(port_index) QApplication.processEvents()
def apply_program_changes(self): program = self.wizard().program if program == None: return stdin_redirection = Constants.api_stdin_redirections[self.get_field('stdin_redirection')] stdout_redirection = Constants.api_stdout_redirections[self.get_field('stdout_redirection')] stderr_redirection = Constants.api_stderr_redirections[self.get_field('stderr_redirection')] stdin_file = self.get_field('stdin_file') stdout_file = self.get_field('stdout_file') stderr_file = self.get_field('stderr_file') try: program.set_stdio_redirection(stdin_redirection, stdin_file, stdout_redirection, stdout_file, stderr_redirection, stderr_file) # FIXME: async_call except (Error, REDError) as e: QMessageBox.critical(get_main_window(), 'Edit Program Error', u'Could not update stdio redirection of program [{0}]:\n\n{1}' .format(program.cast_custom_option_value('name', unicode, '<unknown>'), e)) return self.set_last_edit_timestamp()
def cb_open_error(): get_main_window().setEnabled(True) QtGui.QMessageBox.critical(get_main_window(), 'Settings | Brickd', 'Error opening brickd config file.')
def slot_brickd_save_clicked(self): adr = '.'.join((str(self.sbox_brickd_la_ip1.value()), str(self.sbox_brickd_la_ip2.value()), str(self.sbox_brickd_la_ip3.value()), str(self.sbox_brickd_la_ip4.value()))) self.brickd_conf['listen.address'] = adr self.brickd_conf['listen.plain_port'] = str( self.sbox_brickd_lp.value()) self.brickd_conf['listen.websocket_port'] = str( self.sbox_brickd_lwsp.value()) self.brickd_conf[ 'authentication.secret'] = self.ledit_brickd_secret.text() index = self.cbox_brickd_ll.currentIndex() if index == CBOX_BRICKD_LOG_LEVEL_ERROR: self.brickd_conf['log.level'] = 'error' elif index == CBOX_BRICKD_LOG_LEVEL_WARN: self.brickd_conf['log.level'] = 'warn' elif index == CBOX_BRICKD_LOG_LEVEL_INFO: self.brickd_conf['log.level'] = 'info' elif index == CBOX_BRICKD_LOG_LEVEL_DEBUG: self.brickd_conf['log.level'] = 'debug' index = self.cbox_brickd_gt.currentIndex() if index == CBOX_BRICKD_LED_TRIGGER_CPU: self.brickd_conf['led_trigger.green'] = 'cpu' elif index == CBOX_BRICKD_LED_TRIGGER_GPIO: self.brickd_conf['led_trigger.green'] = 'gpio' elif index == CBOX_BRICKD_LED_TRIGGER_HEARTBEAT: self.brickd_conf['led_trigger.green'] = 'heartbeat' elif index == CBOX_BRICKD_LED_TRIGGER_MMC: self.brickd_conf['led_trigger.green'] = 'mmc' elif index == CBOX_BRICKD_LED_TRIGGER_OFF: self.brickd_conf['led_trigger.green'] = 'off' elif index == CBOX_BRICKD_LED_TRIGGER_ON: self.brickd_conf['led_trigger.green'] = 'on' index = self.cbox_brickd_rt.currentIndex() if index == CBOX_BRICKD_LED_TRIGGER_CPU: self.brickd_conf['led_trigger.red'] = 'cpu' elif index == CBOX_BRICKD_LED_TRIGGER_GPIO: self.brickd_conf['led_trigger.red'] = 'gpio' elif index == CBOX_BRICKD_LED_TRIGGER_HEARTBEAT: self.brickd_conf['led_trigger.red'] = 'heartbeat' elif index == CBOX_BRICKD_LED_TRIGGER_MMC: self.brickd_conf['led_trigger.red'] = 'mmc' elif index == CBOX_BRICKD_LED_TRIGGER_OFF: self.brickd_conf['led_trigger.red'] = 'off' elif index == CBOX_BRICKD_LED_TRIGGER_ON: self.brickd_conf['led_trigger.red'] = 'on' self.brickd_conf['poll_delay.spi'] = str( self.sbox_brickd_spi_dly.value()) self.brickd_conf['poll_delay.rs485'] = str( self.sbox_brickd_rs485_dly.value()) config = config_parser.to_string(self.brickd_conf) def cb_open(config, red_file): def cb_write(red_file, result): red_file.release() get_main_window().setEnabled(True) if result is not None: QtGui.QMessageBox.critical( get_main_window(), 'Settings | Brickd', 'Error writing brickd config file.') return QtGui.QMessageBox.information( get_main_window(), 'Settings | Brick Daemon', 'Saved configuration successfully, will now restart Brick Daemon.' ) self.script_manager.execute_script('restart_brickd', None) red_file.write_async(config, lambda x: cb_write(red_file, x), None) def cb_open_error(): get_main_window().setEnabled(True) QtGui.QMessageBox.critical(get_main_window(), 'Settings | Brickd', 'Error opening brickd config file.') get_main_window().setEnabled(False) async_call( self.brickd_conf_rfile.open, (BRICKD_CONF_PATH, REDFile.FLAG_WRITE_ONLY | REDFile.FLAG_CREATE | REDFile.FLAG_NON_BLOCKING | REDFile.FLAG_TRUNCATE, 0o500, 0, 0), lambda x: cb_open(config, x), cb_open_error)