def device_changed(self, id_, **kwargs): if id_ not in self.connected: # backend didn't send a connected message self.device_connected(id_, **kwargs) return info = self.connected[id_] if info.mount: # turn off the autosaving on the old database info.database.disconnect_all() eventloop.add_idle(write_database, 'writing database on change', (info.database, info.mount)) info = self._set_connected(id_, kwargs) if self._is_hidden(info): # don't bother with change message on devices we're not showing return if info.mount: self.info_cache.setdefault(info.mount, {}) on_mount(info) else: sync_manager = app.device_manager.get_sync_for_device(info, create=False) if sync_manager: sync_manager.cancel() messages.TabsChanged('connect', [], [info], []).send_to_frontend() messages.DeviceChanged(info).send_to_frontend()
def _copy_as_iter(self): while self.copying: final_path, info = self.copying.popitem() iterable = fileutil.copy_with_progress(info.video_path, final_path, block_size=128 * 1024) try: for count in iterable: self.progress_size[info.id] += count if self.stopping: iterable.close() eventloop.add_idle(fileutil.delete, "deleting canceled sync", args=(final_path,)) final_path = None break # let other stuff run self._schedule_sync_changed() yield except IOError: final_path = None if final_path: self._add_item(final_path, info) # don't throw off the progress bar; we're done so pretend we got # all the bytes self.progress_size[info.id] = self.total_size[info.id] self.finished += 1 self._check_finished() if self.stopping: break # no more copies yield self._copy_iter_running = False
def device_changed(self, id_, **kwargs): if id_ not in self.connected: # backend didn't send a connected message self.device_connected(id_, **kwargs) return info = self.connected[id_] if info.mount: # turn off the autosaving on the old database info.database.disconnect_all() eventloop.add_idle(write_database, 'writing database on change', (info.database, info.mount)) info = self._set_connected(id_, kwargs) if self._is_hidden(info): # don't bother with change message on devices we're not showing return if info.mount: self.info_cache.setdefault(info.mount, {}) scan_device_for_files(info) else: sync_manager = app.device_manager.get_sync_for_device(info, create=False) if sync_manager: sync_manager.cancel() messages.TabsChanged('connect', [], [info], []).send_to_frontend() messages.DeviceChanged(info).send_to_frontend()
def openURL_withReplyEvent_(self, event, replyEvent): keyDirectObject = struct.unpack(">i", "----")[0] url = event.paramDescriptorForKeyword_( keyDirectObject).stringValue().encode('utf8') eventloop.add_idle(lambda: commandline.parse_command_line_args([url]), "Open URL")
def update_finished(self, feed): for callback_handle in self.callback_handles.pop(feed.id): feed.disconnect(callback_handle) self.currently_updating.remove(feed) # call run_update_queue in an idle to avoid re-updating the feed that # just finished. That could cause weird effects since we are in the # update-finished callback right now. See #16277 eventloop.add_idle(self.run_update_queue, 'run feed update queue')
def check_description(self, data): if len(data) > MAX_TORRENT_SIZE or data[0] != 'd': # Bailout if we get too much data or it doesn't begin with # "d" (see #12301 for details) eventloop.add_idle(self.handle_corrupt_torrent, 'description check failed') return False else: return True
def run_next_update(self): if len(self.vital) > 0: item = self.vital.popleft() elif len(self.idle) > 0: item = self.idle.popleft() else: self.running_count -= 1 return eventloop.add_idle(item.request_icon, "Icon Request")
def call_handler(self, method, message): # this executes in the thread reading from the subprocess pipe. Move # things into the backend thread. self.handler_queue.put((method, message)) if not self.safe_to_skip_add_idle: # we can skip calling add_idle() again if we put objects on the # queue before process_handler_queue() starts getting from it in # the event loop thread. self.safe_to_skip_add_idle = True eventloop.add_idle(self.process_handler_queue, 'process handler queue')
def test_callbacks(self): eventloop.add_idle(self.callback, "foo") eventloop.add_timeout(0.1, self.callback, "foo", args=("chris",), kwargs={'hula': "hula"}) eventloop.add_timeout(0.2, self.callback, "foo", args=("ben",), kwargs={'hula': 'moreHula', 'stop': 1}) self.runEventLoop() self.assertEquals(self.got_args[0], ()) self.assertEquals(self.got_args[1], ("chris",)) self.assertEquals(self.got_args[2], ("ben",)) self.assertEquals(self.got_kwargs[0], {}) self.assertEquals(self.got_kwargs[1], {'hula':'hula'}) self.assertEquals(self.got_kwargs[2], {'hula': 'moreHula', 'stop': 1})
def request_update(self, item, is_vital=False): if is_vital: item.dbItem.confirm_db_thread() if (item.filename and fileutil.access(item.filename, os.R_OK) and item.url == item.dbItem.get_thumbnail_url()): is_vital = False if self.running_count < RUNNING_MAX: eventloop.add_idle(item.request_icon, "Icon Request") self.running_count += 1 else: if is_vital: self.vital.append(item) else: self.idle.append(item)
def update_finished(self): if self.in_shutdown: self.running_count -= 1 return if len(self.vital) > 0: item = self.vital.popleft() elif len(self.idle) > 0: item = self.idle.popleft() else: self.running_count -= 1 return eventloop.add_idle(item.request_icon, "Icon Request")
def request_update(self, item, is_vital=False): if is_vital: item.dbItem.confirm_db_thread() if (item.filename and fileutil.access(item.filename, os.R_OK) and item.url == item.dbItem.get_thumbnail_url()): is_vital = False if self.started and self.running_count < RUNNING_MAX: eventloop.add_idle(item.request_icon, "Icon Request") self.running_count += 1 else: if is_vital: self.vital.append(item) else: self.idle.append(item)
def handle_message(self, data): # import this stuff inside the function, so that import errors don't # mess with other code, which is part of the startup process from miro import app from miro import eventloop from miro.commandline import parse_command_line_args import gobject try: cmd_line = pickle.loads(data) except: logging.warn("Error unpickling message (%r)" % data) else: args = commandline.parse_command_line_string(cmd_line) eventloop.add_idle(parse_command_line_args, 'parse command line', args=(args[1:],)) if (hasattr(app, "widgetapp") and app.widgetapp is not None and app.widgetapp.window is not None): gobject.idle_add(app.widgetapp.window._window.present)
def exec_codegen(codegen_info, media_path, callback, errback): """Run an echonest codegen in a worker thread. This method should work for both ENMFP and echoprint. On success, callback(media_path, echonest_code) will be called. On error, errback(media_path, exception) will be called. """ if cant_run_codegen(): # use add_idle to send the errback to make the timing closer to normal # operations. Some code could potentially break if the errback runs # before this function returns. eventloop.add_idle(errback, 'exec_codegen errback', args=(CodegenNotSupported(), )) return codegen_path = codegen_info['path'] codegen_env = codegen_info.get('env') def thread_function(): stdout = util.call_command(codegen_path, media_path, env=codegen_env) results = json.loads(stdout) # not sure why the code generator always returns a 1-element list, but # it does results = results[0] if 'error' in results: raise CodegenError(results['error']) # NOTE: both codegens return some metadata that we can use, but # mutagen can get the same data so let's just pay attention to the # code. return results['code'] def thread_callback(code): callback(media_path, code) def thread_errback(error): errback(media_path, error) logging.debug("Invoking echonest codegen on %s", media_path) eventloop.call_in_thread(thread_callback, thread_errback, thread_function, 'exec echonest codegen')
def handle_message(self, data): # import this stuff inside the function, so that import errors # don't mess with other code, which is part of the startup # process from miro import app from miro import eventloop from miro.commandline import parse_command_line_args import gobject try: cmd_line = pickle.loads(data) except: logging.warn("Error unpickling message (%r)" % data) else: args = commandline.parse_command_line_string(cmd_line) eventloop.add_idle(parse_command_line_args, 'parse command line', args=(args[1:], )) if (hasattr(app, "widgetapp") and app.widgetapp is not None and app.widgetapp.window is not None): gobject.idle_add(app.widgetapp.window._window.present)
def exec_codegen(codegen_info, media_path, callback, errback): """Run an echonest codegen in a worker thread. This method should work for both ENMFP and echoprint. On success, callback(media_path, echonest_code) will be called. On error, errback(media_path, exception) will be called. """ if cant_run_codegen(): # use add_idle to send the errback to make the timing closer to normal # operations. Some code could potentially break if the errback runs # before this function returns. eventloop.add_idle(errback, 'exec_codegen errback', args=(CodegenNotSupported(),)) return codegen_path = codegen_info['path'] codegen_env = codegen_info.get('env') def thread_function(): stdout = util.call_command(codegen_path, media_path, env=codegen_env) results = json.loads(stdout) # not sure why the code generator always returns a 1-element list, but # it does results = results[0] if 'error' in results: raise CodegenError(results['error']) # NOTE: both codegens return some metadata that we can use, but # mutagen can get the same data so let's just pay attention to the # code. return results['code'] def thread_callback(code): callback(media_path, code) def thread_errback(error): errback(media_path, error) logging.debug("Invoking echonest codegen on %s", media_path) eventloop.call_in_thread(thread_callback, thread_errback, thread_function, 'exec echonest codegen')
def _grab_file_url(url, callback, errback, default_mime_type): path = download_utils.get_file_url_path(url) try: f = file(path) except EnvironmentError: eventloop.add_idle(errback, 'grab file url errback', args=(FileURLNotFoundError(path), )) else: try: data = f.read() except IOError: eventloop.add_idle(errback, 'grab file url errback', args=(FileURLReadError(path), )) else: info = { "body": data, "updated-url": url, "redirected-url": url, "content-type": default_mime_type, } eventloop.add_idle(callback, 'grab file url callback', args=(info, ))
def launch(): # Make all output flush immediately. # Don't add extra import statements here. If there's a problem importing # something we want to see the error in the log. import logging import sys import os from miro import util sys.stdout = util.AutoFlushingStream(sys.stdout) sys.stderr = sys.stdout override_modules() from miro.plat.utils import setup_logging, initialize_locale setup_logging(in_downloader=True) util.setup_logging() initialize_locale() if os.environ.get('DEMOCRACY_DOWNLOADER_FIRST_LAUNCH') != '1': logging.info("Starting new downloader log") else: logging.info("Launching Downloader Daemon") log_versions() # Start of normal imports import threading from miro.dl_daemon import daemon from miro import httpclient addr = os.environ['DEMOCRACY_DOWNLOADER_ADDR'] port = int(os.environ['DEMOCRACY_DOWNLOADER_PORT']) short_app_name = os.environ['DEMOCRACY_SHORT_APP_NAME'] httpclient.start_thread() server = daemon.DownloaderDaemon(addr, port, short_app_name) # setup config for the downloader from miro import eventloop config.load(config.DownloaderConfig()) app.downloader_config_watcher = config.ConfigWatcher( lambda foo, *args: eventloop.add_idle(foo, "config watcher", args=args)) # start things up eventloop.startup()
def launch(): # Make all output flush immediately. # Don't add extra import statements here. If there's a problem importing # something we want to see the error in the log. from miro import util sys.stdout = util.AutoFlushingStream(sys.stdout) sys.stderr = sys.stdout override_modules() from miro.plat.utils import setup_logging, initialize_locale setup_logging(in_downloader=True) util.setup_logging() initialize_locale() if os.environ.get('DEMOCRACY_DOWNLOADER_FIRST_LAUNCH') != '1': logging.info("Starting new downloader log") else: logging.info("Launching Downloader Daemon") log_versions() # Start of normal imports from miro.dl_daemon import daemon from miro import httpclient addr = os.environ['DEMOCRACY_DOWNLOADER_ADDR'] port = int(os.environ['DEMOCRACY_DOWNLOADER_PORT']) short_app_name = os.environ['DEMOCRACY_SHORT_APP_NAME'] httpclient.start_thread() daemon.DownloaderDaemon(addr, port, short_app_name) # setup config for the downloader from miro import eventloop config.load(config.ManualConfig()) app.downloader_config_watcher = config.ConfigWatcher( lambda foo, *args: eventloop.add_idle(foo, "config watcher", args=args )) # start things up eventloop.startup()
def _grab_file_url(url, callback, errback, default_mime_type): path = download_utils.get_file_url_path(url) try: f = file(path) except EnvironmentError: eventloop.add_idle(errback, 'grab file url errback', args=(FileURLNotFoundError(path),)) else: try: data = f.read() except IOError: eventloop.add_idle(errback, 'grab file url errback', args=(FileURLReadError(path),)) else: info = {"body": data, "updated-url":url, "redirected-url":url, "content-type": default_mime_type, } eventloop.add_idle(callback, 'grab file url callback', args=(info,))
def call_errback(self, error): self._cleanup_filehandle() msg = 'curl transfer errback: %s' % (self.errback, ) eventloop.add_idle(self.errback, msg, args=(error, ))
def trap_call(when, function, *args, **kwargs): """Version of trap_call for the libcurl thread. :retval the return value of the function, or the exception raised. """ try: return function(*args, **kwargs) except (SystemExit, KeyboardInterrupt), e: # If we just re-raise these, then we will just crash the libcurl # thread. Instead, we want to shutdown the eventloop. logging.warn("saw %s in libcurl thread, quitting") app.controller.shutdown() except Exception, e: logging.stacktrace("libcurl thread exception while %s" % when) eventloop.add_idle("sending exception", signals.system.failed, args=(when,)) return e class HTTPError(NetworkError): def __init__(self, longDescription): NetworkError.__init__(self, _("HTTP error"), longDescription) class ServerClosedConnection(HTTPError): def __init__(self, host): HTTPError.__init__(self, _('%(host)s closed connection', {"host": host})) class EmptyResponse(HTTPError): def __init__(self, host): HTTPError.__init__(self, _('%(host)s gave us an empty response', {"host": host}))
def send(self, callback=None): if self.daemon.shutdown: return eventloop.add_idle(lambda: self.daemon.send(self, callback), "sending command %r" % self)
def _send_added(self, path): # use add_idle() to pass things over to the backend thread # FIXME: there should be a cleaner way to do this eventloop.add_idle(self.emit, "emit added signal", args=("added", utf8_to_filename(path)))
def add_idle(self, function, name, args=None, kwargs=None): eventloop.add_idle(function, name, args=None, kwargs=None)
def call_callback(self, info): self._cleanup_filehandle() msg = 'curl transfer callback: %s' % (self.callback,) eventloop.add_idle(self.callback, msg, args=(info,))
def call_callback(self, info): self._cleanup_filehandle() eventloop.add_idle(self.callback, 'curl transfer callback', args=(info, ))
def send(self, callback=None): if self.daemon.shutdown: return eventloop.add_idle(lambda : self.daemon.send(self, callback), "sending command %r" % self)
for msg in _read_from_pipe(self.subprocess_stdout): self.responder.handle(msg) except LoadError, e: logging.warn("Quiting from bad data from our subprocess in " "SubprocessResponderThread: %s", e) self.quit_type = self.QUIT_BAD_DATA except IOError, e: logging.warn("Quiting on read error from pipe in " "SubprocessResponderThread: %s", e) self.quit_type = self.QUIT_READ_ERROR except Exception, e: logging.exception("Unknown error in SubprocessResponderThread") self.quit_type = self.QUIT_UNKNOWN else: self.quit_type = self.QUIT_NORMAL eventloop.add_idle(self.quit_callback, 'subprocess quit callback', args=(self,)) def subprocess_main(): """Run loop inside the subprocess.""" # make sure that we are using binary mode for stdout if _on_windows(): import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) # unset stdin and stdout so that we don't accidentally print to them stdin = sys.stdin stdout = sys.stdout sys.stdout = sys.stdin = None # initialize things try: handler = _subprocess_setup(stdin, stdout) except Exception, e:
def call_callback(self, info): self._cleanup_filehandle() msg = 'curl transfer callback: %s' % (self.callback, ) eventloop.add_idle(self.callback, msg, args=(info, ))
def call_handler(self, method, message): # this executes in the thread reading from the subprocess pipe. Move # things into the backend thread. name = 'handle subprocess message: %s' % message eventloop.add_idle(method, name, args=(message,))
def _on_menu_update(self, manager, reason): eventloop.add_idle(self.calculate_popup_menu, "Update app indicator menu")
def _on_menu_update(self, manager): eventloop.add_idle(self.calculate_popup_menu, "Update app indicator menu")
def _send_deleted(self, path): eventloop.add_idle(self.emit, "emit deleted signal", args=("deleted", utf8_to_filename(path)))
def on_headers_finished(self): if self.header_callback: eventloop.add_idle(self.header_callback, 'httpclient header callback', args=(self._make_callback_info(),))
def trap_call(when, function, *args, **kwargs): """Version of trap_call for the libcurl thread. :retval the return value of the function, or the exception raised. """ try: return function(*args, **kwargs) except (SystemExit, KeyboardInterrupt), e: # If we just re-raise these, then we will just crash the libcurl # thread. Instead, we want to shutdown the eventloop. logging.warn("saw %s in libcurl thread, quitting") app.controller.shutdown() except Exception, e: logging.stacktrace("libcurl thread exception while %s" % when) eventloop.add_idle("sending exception", signals.system.failed, args=(when, )) return e class HTTPError(NetworkError): def __init__(self, longDescription): NetworkError.__init__(self, _("HTTP error"), longDescription) class ServerClosedConnection(HTTPError): def __init__(self, host): HTTPError.__init__(self, _('%(host)s closed connection', {"host": host}))
def call_callback(self, info): self._cleanup_filehandle() eventloop.add_idle(self.callback, 'curl transfer callback', args=(info,))
def on_headers_finished(self): if self.header_callback: eventloop.add_idle(self.header_callback, 'httpclient header callback', args=(self._make_callback_info(), ))
def call_errback(self, error): self._cleanup_filehandle() eventloop.add_idle(self.errback, 'curl transfer errback', args=(error,))
def call_errback(self, error): self._cleanup_filehandle() eventloop.add_idle(self.errback, 'curl transfer errback', args=(error, ))
def start_downloads(self): if self.dc or self.paused: return self.dc = eventloop.add_idle(self.start_downloads_idle, "Start Downloads")
for msg in _read_from_pipe(self.subprocess_stdout): self.responder.handle(msg) except LoadError, e: logging.warn("Quiting from bad data from our subprocess in " "SubprocessResponderThread: %s", e) self.quit_type = self.QUIT_BAD_DATA except IOError, e: logging.warn("Quiting on read error from pipe in " "SubprocessResponderThread: %s", e) self.quit_type = self.QUIT_READ_ERROR except Exception, e: logging.exception("Unknown error in SubprocessResponderThread") self.quit_type = self.QUIT_UNKNOWN else: self.quit_type = self.QUIT_NORMAL eventloop.add_idle(self.quit_callback, 'subprocess quit callback', args=(self,)) def subprocess_main(): """Run loop inside the subprocess.""" global logging_setup logging_setup = False if _on_windows(): # On windows, both STDIN and STDOUT get opened as text mode. This # can causes all kinds of weirdress when reading from our pipes. # (See #17804). Change the mode to binary for both streams. import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) # unset stdin and stdout so that we don't accidentally print to them stdin = sys.stdin
def call_errback(self, error): self._cleanup_filehandle() msg = 'curl transfer errback: %s' % (self.errback,) eventloop.add_idle(self.errback, msg, args=(error,))
def openURL_withReplyEvent_(self, event, replyEvent): keyDirectObject = struct.unpack(">i", "----")[0] url = event.paramDescriptorForKeyword_(keyDirectObject).stringValue().encode('utf8') eventloop.add_idle(lambda: commandline.parse_command_line_args([url]), "Open URL")