def __autoreload(self): wait = 3 if os.name == "nt": sub_kwargs = { 'creationflags': subprocess.CREATE_NEW_PROCESS_GROUP } break_signal = signal.CTRL_BREAK_EVENT else: sub_kwargs = {} break_signal = signal.SIGTERM sub_args = [x for x in sys.argv if x != '-r' and x != "--auto-reload"] try: sub_args = [sys.executable] + sub_args process = subprocess.Popen(sub_args, **sub_kwargs) except: Logs.error("Couldn't find a suitable python executable") sys.exit(1) last_mtime = max(self.__file_times(".")) while True: try: max_mtime = max(self.__file_times(".")) if max_mtime > last_mtime: last_mtime = max_mtime Logs.message("Restarting plugin") process.send_signal(break_signal) process = subprocess.Popen(sub_args, **sub_kwargs) time.sleep(wait) except KeyboardInterrupt: process.send_signal(break_signal) break
def __loop(self): to_remove = [] try: while True: if self.__connected == False: elapsed = timer() - self.__disconnection_time if elapsed >= try_reconnection_time: Logs.message("Trying to reconnect...") if self.__connect() == False: self.__disconnection_time = timer() continue else: time.sleep(try_reconnection_time - elapsed) continue if self._network.receive() == False: self.__connected = False self.__disconnect() continue if timer() - self.__last_keep_alive >= keep_alive_time_interval: self.__last_keep_alive = timer() packet = Network._Packet() packet.set(_Plugin._plugin_id, Network._Packet.packet_type_keep_alive, 0) self._network.send(packet) to_remove.clear() for id, session in self._sessions.items(): if session._read_from_plugin() == False: session.close_pipes() to_remove.append(id) for id in to_remove: self._sessions[id]._send_disconnection_message(_Plugin._plugin_id) del self._sessions[id] self._process_manager._update() except KeyboardInterrupt: self.__exit()
def run(self, host="config", port="config", key_file="config"): """ | Starts the plugin by connecting to the server specified. | If arguments (-a, -p) are given when starting plugin, host/port will be ignored. | Function will return only when plugin exits. :param host: NTS IP address if plugin started without -a option :param port: NTS port if plugin started without -p option :type host: str :type port: int """ if (host == "config"): self.__host = config.fetch("host") else: self.__host = host if (port == "config"): self.__port = config.fetch("port") else: self.__port = port if (key_file == "config"): self.__key_file = config.fetch("key_file") else: self.__key_file = key_file self.__parse_args() Logs.debug("Start plugin") if self.__has_autoreload: self.__autoreload() else: self.__run()
def _button_pressed(network, arg, request_id): content_id = arg[0] btn = __find_content(network, content_id) if btn != None: btn._on_button_pressed() else: Logs.error("Can't find UI content for callback")
def __exit(self): Logs.debug('Exiting') for session in _Plugin.instance._sessions.values(): session.signal_and_close_pipes() session.plugin_process.join() if self._post_run != None: self._post_run() sys.exit(0)
def _button_hover(network, arg, request_id): content_id = arg[0] state = arg[1] btn = __find_content(network, content_id) if btn != None: btn._on_button_hover(state) else: Logs.error("Can't find UI content for callback")
def __on_client_connection(self, session_id, version_table): main_conn_net, process_conn_net = Pipe() main_conn_proc, process_conn_proc = Pipe() session = Network._Session(session_id, self._network, self._process_manager, main_conn_net, main_conn_proc) process = Process(target=_Plugin._launch_plugin, args=(self._plugin_class, session_id, process_conn_net, process_conn_proc, _Plugin.__serializer, _Plugin._plugin_id, version_table, _TypeSerializer.get_version_table(), Logs._is_verbose(), _Plugin._custom_data)) process.start() session.plugin_process = process self._sessions[session_id] = session Logs.debug("Registered new session:", session_id)
def _image_pressed(network, arg, request_id): content_id = arg[0] x = arg[1] y = arg[2] img = __find_content(network, content_id) if img != None: img._on_image_pressed(x, y) else: Logs.error("Can't find UI content for callback")
def _launch_plugin(cls, plugin_class, session_id, pipe_net, pipe_proc, serializer, plugin_id, version_table, original_version_table, verbose, custom_data): plugin = plugin_class() _PluginInstance.__init__(plugin, session_id, pipe_net, pipe_proc, serializer, plugin_id, version_table, original_version_table, verbose, custom_data) Logs.debug("Starting plugin") plugin._run()
def _text_changed(network, arg, request_id): tuple_obj = arg content_id = tuple_obj[0] text_value = tuple_obj[1] active_txt = __find_content(network, content_id) if active_txt != None: active_txt.input_text = text_value active_txt._on_text_changed() else: Logs.error("Can't find UI content for callback")
def _slider_changed(network, arg, request_id): tuple_obj = arg content_id = tuple_obj[0] slider_value = tuple_obj[1] active_slider = __find_content(network, content_id) if active_slider != None: active_slider.current_value = slider_value active_slider._on_slider_changed() else: Logs.error("Can't find UI content for callback")
def _menu_toggled(network, arg, request_id): index = arg[0] enabled = arg[1] active_menu = network._plugin._menus[index] if active_menu != None: active_menu._enabled = enabled if enabled == True: active_menu._on_opened_callback() elif enabled == False: active_menu._on_closed_callback() else: Logs.error("Can't find Menu for callback")
def _dropdown_item_clicked(network, arg, request_id): content_id = arg[0] index = arg[1] dropdown = __find_content(network, content_id) if dropdown != None: for item in dropdown._items: item._selected = False clickedItem = dropdown._items[index] clickedItem._selected = True dropdown._on_item_clicked(clickedItem) else: Logs.error("Can't find UI content for callback")
def _on_packet_received(self, packet): if packet.packet_type == Network._Packet.packet_type_message_to_plugin: session_id = packet.session_id if session_id in self._sessions: # packet.decompress() self._sessions[session_id]._on_packet_received(packet.payload) return # If we don't know this session_id, try to register it first if _Plugin.__serializer.try_register_session(packet.payload) == True: received_version_table, _, _ = _Plugin.__serializer.deserialize_command(packet.payload, None) version_table = _TypeSerializer.get_best_version_table(received_version_table) self.__on_client_connection(session_id, version_table) # Doesn't register? It's an error else: Logs.warning("Received a command from an unregistered session", session_id) elif packet.packet_type == Network._Packet.packet_type_plugin_connection: _Plugin._plugin_id = packet.plugin_id Logs.message("Registered with plugin ID", _Plugin._plugin_id, "\n=======================================\n") elif packet.packet_type == Network._Packet.packet_type_plugin_disconnection: if _Plugin._plugin_id == -1: if self._description['auth'] == None: Logs.error("Connection refused by NTS. Are you missing a security key file?") else: Logs.error("Connection refused by NTS. Your security key file might be invalid") sys.exit(1) else: Logs.debug("Connection ended by NTS") sys.exit(0) elif packet.packet_type == Network._Packet.packet_type_client_disconnection: try: id = packet.session_id self._sessions[id].signal_and_close_pipes() del self._sessions[id] Logs.debug("Session", id, "disconnected") except: pass elif packet.packet_type == Network._Packet.packet_type_keep_alive: pass else: Logs.warning("Received a packet of unknown type", packet.packet_type, ". Ignoring")
def __parse_args(self): Logs._set_verbose(False) for i in range(1, len(sys.argv)): if sys.argv[i] == "-h": Logs.message("Usage:", sys.argv[1],"[-h] [-a ADDRESS] [-p PORT]") Logs.message(" -h display this help") Logs.message(" -a connects to a NTS at the specified IP address") Logs.message(" -p connects to a NTS at the specified port") Logs.message(" -k specifies a key file to use to connect to NTS") Logs.message(" -n name to display for this plugin in Nanome") Logs.message(" -v enable verbose mode, to display Logs.debug") Logs.message(" -r, --auto-reload restart plugin automatically if a .py or .json file in current directory changes") Logs.message(" --ignore to use with auto-reload. All paths matching this pattern will be ignored, " \ "use commas to specify several. Supports */?/[seq]/[!seq]") sys.exit(0) elif sys.argv[i] == "-a": if i >= len(sys.argv): Logs.error("Error: -a requires an argument") sys.exit(1) self.__host = sys.argv[i + 1] i += 1 elif sys.argv[i] == "-p": if i >= len(sys.argv): Logs.error("Error: -p requires an argument") sys.exit(1) try: self.__port = int(sys.argv[i + 1]) except ValueError: Logs.error("Error: -p argument has to be an integer") sys.exit(1) i += 1 elif sys.argv[i] == "-k": if i >= len(sys.argv): Logs.error("Error: -k requires an argument") sys.exit(1) self.__key_file = sys.argv[i + 1] i += 1 elif sys.argv[i] == "-n": if i >= len(sys.argv): Logs.error("Error: -n requires an argument") sys.exit(1) self._description['name'] = sys.argv[i + 1] i += 1 elif sys.argv[i] == "-v": self.__has_verbose = True Logs._set_verbose(True) elif sys.argv[i] == "-r" or sys.argv[i] == "--auto-reload": self.__has_autoreload = True elif sys.argv[i] == "--ignore": if i >= len(sys.argv): Logs.error("Error: --ignore requires an argument") sys.exit(1) split = sys.argv[i + 1].split(",") self.__to_ignore.extend(split)