From 693fef1964e281eaf7b39f9bd9f5728406942a14 Mon Sep 17 00:00:00 2001 From: Job Evers-Meltzer Date: Thu, 3 Nov 2016 10:43:24 -0500 Subject: [PATCH 1/6] remove reactor.iterate from dht shutdown --- lbrynet/dht/protocol.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lbrynet/dht/protocol.py b/lbrynet/dht/protocol.py index a3b5936cf..8eae3bc0e 100644 --- a/lbrynet/dht/protocol.py +++ b/lbrynet/dht/protocol.py @@ -21,6 +21,7 @@ import msgtypes import msgformat from contact import Contact + reactor = twisted.internet.reactor log = logging.getLogger(__name__) @@ -124,10 +125,10 @@ class KademliaProtocol(protocol.DatagramProtocol): except IndexError: log.warning("Couldn't decode dht datagram from %s", address) return - + message = self._translator.fromPrimitive(msgPrimitive) remoteContact = Contact(message.nodeID, address[0], address[1], self) - + # Refresh the remote node's details in the local node's k-buckets self._node.addContact(remoteContact) @@ -143,7 +144,9 @@ class KademliaProtocol(protocol.DatagramProtocol): del self._sentMessages[message.id] if hasattr(df, '_rpcRawResponse'): - # The RPC requested that the raw response message and originating address be returned; do not interpret it + # The RPC requested that the raw response message + # and originating address be returned; do not + # interpret it df.callback((message, address)) elif isinstance(message, msgtypes.ErrorMessage): # The RPC request raised a remote exception; raise it locally @@ -175,7 +178,7 @@ class KademliaProtocol(protocol.DatagramProtocol): def _send(self, data, rpcID, address): """ Transmit the specified data over UDP, breaking it up into several packets if necessary - + If the data is spread over multiple UDP datagrams, the packets have the following structure:: | | | | | |||||||||||| 0x00 | @@ -183,7 +186,7 @@ class KademliaProtocol(protocol.DatagramProtocol): | type ID | of packets |of this packet | | indicator| | (1 byte) | (2 bytes) | (2 bytes) |(20 bytes)| (1 byte) | | | | | | |||||||||||| | - + @note: The header used for breaking up large data segments will possibly be moved out of the KademliaProtocol class in the future, into something similar to a message translator/encoder @@ -301,19 +304,19 @@ class KademliaProtocol(protocol.DatagramProtocol): df.errback(failure.Failure(TimeoutError(remoteContactID))) else: # This should never be reached - print "ERROR: deferred timed out, but is not present in sent messages list!" + log.error("deferred timed out, but is not present in sent messages list!") def stopProtocol(self): """ Called when the transport is disconnected. - + Will only be called once, after all ports are disconnected. """ + log.info('Stopping dht') for key in self._callLaterList.keys(): try: if key > time.time(): + log.info('Cancelling %s', self._callLaterList[key]) self._callLaterList[key].cancel() except Exception, e: - print e + log.exception('Failed to cancel %s', self._callLaterList[key]) del self._callLaterList[key] - #TODO: test: do we really need the reactor.iterate() call? - reactor.iterate() From 10cb20d08fe1a421d54c3e3b36ffdb44b2dcaf4b Mon Sep 17 00:00:00 2001 From: Job Evers-Meltzer Date: Thu, 3 Nov 2016 14:22:16 -0500 Subject: [PATCH 2/6] fix whitespace and long-lines --- lbrynet/core/Session.py | 141 +++++++++++------- lbrynet/lbrynet_daemon/Daemon.py | 9 +- packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py | 1 + 3 files changed, 93 insertions(+), 58 deletions(-) diff --git a/lbrynet/core/Session.py b/lbrynet/core/Session.py index ff5cf80d7..5b33bfd6d 100644 --- a/lbrynet/core/Session.py +++ b/lbrynet/core/Session.py @@ -18,60 +18,87 @@ log = logging.getLogger(__name__) class Session(object): - """This class manages all important services common to any application that uses the network: - the hash announcer, which informs other peers that this peer is associated with some hash. Usually, - this means this peer has a blob identified by the hash in question, but it can be used for other - purposes. - the peer finder, which finds peers that are associated with some hash. - the blob manager, which keeps track of which blobs have been downloaded and provides access to them, - the rate limiter, which attempts to ensure download and upload rates stay below a set maximum, - and upnp, which opens holes in compatible firewalls so that remote peers can connect to this peer.""" - def __init__(self, blob_data_payment_rate, db_dir=None, lbryid=None, peer_manager=None, dht_node_port=None, - known_dht_nodes=None, peer_finder=None, hash_announcer=None, blob_dir=None, blob_manager=None, - peer_port=None, use_upnp=True, rate_limiter=None, wallet=None, dht_node_class=node.Node, - blob_tracker_class=None, payment_rate_manager_class=None, is_generous=True): - """ - @param blob_data_payment_rate: The default payment rate for blob data + """This class manages all important services common to any application that uses the network. + + the hash announcer, which informs other peers that this peer is + associated with some hash. Usually, this means this peer has a + blob identified by the hash in question, but it can be used for + other purposes. + + the peer finder, which finds peers that are associated with some + hash. + + the blob manager, which keeps track of which blobs have been + downloaded and provides access to them, + + the rate limiter, which attempts to ensure download and upload + rates stay below a set maximum + + upnp, which opens holes in compatible firewalls so that remote + peers can connect to this peer. + """ + def __init__(self, blob_data_payment_rate, db_dir=None, + lbryid=None, peer_manager=None, dht_node_port=None, + known_dht_nodes=None, peer_finder=None, + hash_announcer=None, blob_dir=None, + blob_manager=None, peer_port=None, use_upnp=True, + rate_limiter=None, wallet=None, + dht_node_class=node.Node, blob_tracker_class=None, + payment_rate_manager_class=None, is_generous=True): + """@param blob_data_payment_rate: The default payment rate for blob data @param db_dir: The directory in which levelDB files should be stored @param lbryid: The unique ID of this node - @param peer_manager: An object which keeps track of all known peers. If None, a PeerManager will be created + @param peer_manager: An object which keeps track of all known + peers. If None, a PeerManager will be created - @param dht_node_port: The port on which the dht node should listen for incoming connections + @param dht_node_port: The port on which the dht node should + listen for incoming connections - @param known_dht_nodes: A list of nodes which the dht node should use to bootstrap into the dht + @param known_dht_nodes: A list of nodes which the dht node + should use to bootstrap into the dht - @param peer_finder: An object which is used to look up peers that are associated with some hash. If None, - a DHTPeerFinder will be used, which looks for peers in the distributed hash table. + @param peer_finder: An object which is used to look up peers + that are associated with some hash. If None, a + DHTPeerFinder will be used, which looks for peers in the + distributed hash table. - @param hash_announcer: An object which announces to other peers that this peer is associated with some hash. - If None, and peer_port is not None, a DHTHashAnnouncer will be used. If None and - peer_port is None, a DummyHashAnnouncer will be used, which will not actually announce - anything. + @param hash_announcer: An object which announces to other + peers that this peer is associated with some hash. If + None, and peer_port is not None, a DHTHashAnnouncer will + be used. If None and peer_port is None, a + DummyHashAnnouncer will be used, which will not actually + announce anything. - @param blob_dir: The directory in which blobs will be stored. If None and blob_manager is None, blobs will - be stored in memory only. + @param blob_dir: The directory in which blobs will be + stored. If None and blob_manager is None, blobs will be + stored in memory only. - @param blob_manager: An object which keeps track of downloaded blobs and provides access to them. If None, - and blob_dir is not None, a DiskBlobManager will be used, with the given blob_dir. - If None and blob_dir is None, a TempBlobManager will be used, which stores blobs in - memory only. + @param blob_manager: An object which keeps track of downloaded + blobs and provides access to them. If None, and blob_dir + is not None, a DiskBlobManager will be used, with the + given blob_dir. If None and blob_dir is None, a + TempBlobManager will be used, which stores blobs in memory + only. - @param peer_port: The port on which other peers should connect to this peer + @param peer_port: The port on which other peers should connect + to this peer - @param use_upnp: Whether or not to try to open a hole in the firewall so that outside peers can connect to - this peer's peer_port and dht_node_port + @param use_upnp: Whether or not to try to open a hole in the + firewall so that outside peers can connect to this peer's + peer_port and dht_node_port - @param rate_limiter: An object which keeps track of the amount of data transferred to and from this peer, - and can limit that rate if desired + @param rate_limiter: An object which keeps track of the amount + of data transferred to and from this peer, and can limit + that rate if desired - @param wallet: An object which will be used to keep track of expected payments and which will pay peers. - If None, a wallet which uses the Point Trader system will be used, which is meant for testing - only + @param wallet: An object which will be used to keep track of + expected payments and which will pay peers. If None, a + wallet which uses the Point Trader system will be used, + which is meant for testing only - @return: """ self.db_dir = db_dir @@ -178,7 +205,9 @@ class Session(object): self.external_ip = external_ip if self.peer_port is not None: if u.getspecificportmapping(self.peer_port, 'TCP') is None: - u.addportmapping(self.peer_port, 'TCP', u.lanaddr, self.peer_port, 'LBRY peer port', '') + u.addportmapping( + self.peer_port, 'TCP', u.lanaddr, self.peer_port, + 'LBRY peer port', '') self.upnp_redirects.append((self.peer_port, 'TCP')) log.info("Set UPnP redirect for TCP port %d", self.peer_port) else: @@ -187,16 +216,23 @@ class Session(object): self.upnp_redirects.append((self.peer_port, 'TCP')) if self.dht_node_port is not None: if u.getspecificportmapping(self.dht_node_port, 'UDP') is None: - u.addportmapping(self.dht_node_port, 'UDP', u.lanaddr, self.dht_node_port, 'LBRY DHT port', '') + u.addportmapping( + self.dht_node_port, 'UDP', u.lanaddr, self.dht_node_port, + 'LBRY DHT port', '') self.upnp_redirects.append((self.dht_node_port, 'UDP')) log.info("Set UPnP redirect for UPD port %d", self.dht_node_port) else: - # TODO: check that the existing redirect was put up by an old lbrynet session before grabbing it - # if such a disconnected redirect exists, then upnp won't work unless the redirect is appended - # or is torn down and set back up. a bad shutdown of lbrynet could leave such a redirect up - # and cause problems on the next start. - # this could be problematic if a previous lbrynet session didn't make the redirect, and it was - # made by another application + # TODO: check that the existing redirect was + # put up by an old lbrynet session before + # grabbing it if such a disconnected redirect + # exists, then upnp won't work unless the + # redirect is appended or is torn down and set + # back up. a bad shutdown of lbrynet could + # leave such a redirect up and cause problems + # on the next start. this could be + # problematic if a previous lbrynet session + # didn't make the redirect, and it was made by + # another application log.warning("UPnP redirect already set for UDP port %d", self.dht_node_port) self.upnp_redirects.append((self.dht_node_port, 'UDP')) return True @@ -271,9 +307,10 @@ class Session(object): self.peer_finder, self.dht_node) if self.payment_rate_manager is None: - self.payment_rate_manager = self.payment_rate_manager_class(self.base_payment_rate_manager, - self.blob_tracker, - self.is_generous) + self.payment_rate_manager = self.payment_rate_manager_class( + self.base_payment_rate_manager, + self.blob_tracker, + self.is_generous) self.rate_limiter.start() d1 = self.blob_manager.setup() @@ -294,7 +331,9 @@ class Session(object): u.selectigd() for port, protocol in self.upnp_redirects: if u.getspecificportmapping(port, protocol) is None: - log.warning("UPnP redirect for %s %d was removed by something else.", protocol, port) + log.warning( + "UPnP redirect for %s %d was removed by something else.", + protocol, port) else: u.deleteportmapping(port, protocol) log.info("Removed UPnP redirect for %s %d.", protocol, port) @@ -307,5 +346,3 @@ class Session(object): def _subfailure(self, err): log.error(err.getTraceback()) return err.value - - diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index 845ac3e92..6e9692ece 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -769,14 +769,11 @@ class Daemon(AuthJSONRPCServer): d = self.lbry_file_metadata_manager.setup() def set_lbry_file_manager(): - self.lbry_file_manager = EncryptedFileManager(self.session, - self.lbry_file_metadata_manager, - self.sd_identifier, - download_directory=self.download_directory) + self.lbry_file_manager = EncryptedFileManager( + self.session, self.lbry_file_metadata_manager, + self.sd_identifier, download_directory=self.download_directory) return self.lbry_file_manager.setup() - d.addCallback(lambda _: set_lbry_file_manager()) - return d def _get_analytics(self): diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py index 72f27755e..3fd149fa1 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -29,6 +29,7 @@ from lbrynet.core import utils if platform.mac_ver()[0] >= "10.10": from LBRYNotify import LBRYNotify + log = logging.getLogger(__name__) From 5bccfdb2445c7ef023e68bf2cdee85efa0e804b9 Mon Sep 17 00:00:00 2001 From: Job Evers-Meltzer Date: Thu, 3 Nov 2016 14:42:45 -0500 Subject: [PATCH 3/6] add logging to shutdown process --- lbrynet/core/BlobAvailability.py | 3 ++- lbrynet/core/RateLimiter.py | 7 +++++++ lbrynet/core/Session.py | 3 ++- lbrynet/core/Wallet.py | 3 +-- lbrynet/core/client/DHTPeerFinder.py | 6 ++++++ lbrynet/core/server/DHTHashAnnouncer.py | 8 +++++++- lbrynet/lbryfilemanager/EncryptedFileManager.py | 2 +- lbrynet/lbrynet_daemon/Daemon.py | 8 +++++--- packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py | 1 + 9 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lbrynet/core/BlobAvailability.py b/lbrynet/core/BlobAvailability.py index 6cfe52852..5131a7cd4 100644 --- a/lbrynet/core/BlobAvailability.py +++ b/lbrynet/core/BlobAvailability.py @@ -25,11 +25,12 @@ class BlobAvailabilityTracker(object): self._check_mine = LoopingCall(self._update_mine) def start(self): - log.info("Starting blob tracker") + log.info("Starting %s", self) self._check_popular.start(30) self._check_mine.start(120) def stop(self): + log.info("Stopping %s", self) if self._check_popular.running: self._check_popular.stop() if self._check_mine.running: diff --git a/lbrynet/core/RateLimiter.py b/lbrynet/core/RateLimiter.py index 2063dd939..04b153577 100644 --- a/lbrynet/core/RateLimiter.py +++ b/lbrynet/core/RateLimiter.py @@ -1,8 +1,13 @@ +import logging + from zope.interface import implements from lbrynet.interfaces import IRateLimiter from twisted.internet import task +log = logging.getLogger(__name__) + + class DummyRateLimiter(object): def __init__(self): self.dl_bytes_this_second = 0 @@ -64,6 +69,7 @@ class RateLimiter(object): self.protocols = [] def start(self): + log.info("Starting %s", self) self.tick_call = task.LoopingCall(self.tick) self.tick_call.start(self.tick_interval) @@ -74,6 +80,7 @@ class RateLimiter(object): self.unthrottle_ul() def stop(self): + log.info("Stopping %s", self) if self.tick_call is not None: self.tick_call.stop() self.tick_call = None diff --git a/lbrynet/core/Session.py b/lbrynet/core/Session.py index 5b33bfd6d..450e4e556 100644 --- a/lbrynet/core/Session.py +++ b/lbrynet/core/Session.py @@ -169,6 +169,7 @@ class Session(object): def shut_down(self): """Stop all services""" + log.info('Shutting down %s', self) ds = [] if self.blob_manager is not None: ds.append(defer.maybeDeferred(self.blob_tracker.stop)) @@ -323,7 +324,7 @@ class Session(object): return dl def _unset_upnp(self): - + log.info("Unsetting upnp for %s", self) def threaded_unset_upnp(): u = miniupnpc.UPnP() num_devices_found = u.discover() diff --git a/lbrynet/core/Wallet.py b/lbrynet/core/Wallet.py index 3bfb41287..1e3f72567 100644 --- a/lbrynet/core/Wallet.py +++ b/lbrynet/core/Wallet.py @@ -97,9 +97,8 @@ class Wallet(object): log.error("An error occurred stopping the wallet: %s", err.getTraceback()) def stop(self): - + log.info("Stopping %s", self) self.stopped = True - # If self.next_manage_call is None, then manage is currently running or else # start has not been called, so set stopped and do nothing else. if self.next_manage_call is not None: diff --git a/lbrynet/core/client/DHTPeerFinder.py b/lbrynet/core/client/DHTPeerFinder.py index ab5dd1b3a..46c34ee52 100644 --- a/lbrynet/core/client/DHTPeerFinder.py +++ b/lbrynet/core/client/DHTPeerFinder.py @@ -1,8 +1,13 @@ import binascii +import logging + from zope.interface import implements from lbrynet.interfaces import IPeerFinder +log = logging.getLogger(__name__) + + class DHTPeerFinder(object): """This class finds peers which have announced to the DHT that they have certain blobs""" implements(IPeerFinder) @@ -21,6 +26,7 @@ class DHTPeerFinder(object): self.next_manage_call = reactor.callLater(60, self.run_manage_loop) def stop(self): + log.info("Stopping %s", self) if self.next_manage_call is not None and self.next_manage_call.active(): self.next_manage_call.cancel() self.next_manage_call = None diff --git a/lbrynet/core/server/DHTHashAnnouncer.py b/lbrynet/core/server/DHTHashAnnouncer.py index 574f50ceb..eca877f73 100644 --- a/lbrynet/core/server/DHTHashAnnouncer.py +++ b/lbrynet/core/server/DHTHashAnnouncer.py @@ -1,6 +1,11 @@ import binascii -from twisted.internet import defer, reactor import collections +import logging + +from twisted.internet import defer, reactor + + +log = logging.getLogger(__name__) class DHTHashAnnouncer(object): @@ -22,6 +27,7 @@ class DHTHashAnnouncer(object): self.next_manage_call = reactor.callLater(60, self.run_manage_loop) def stop(self): + log.info("Stopping %s", self) if self.next_manage_call is not None: self.next_manage_call.cancel() self.next_manage_call = None diff --git a/lbrynet/lbryfilemanager/EncryptedFileManager.py b/lbrynet/lbryfilemanager/EncryptedFileManager.py index 9c774d3d9..996c9bd28 100644 --- a/lbrynet/lbryfilemanager/EncryptedFileManager.py +++ b/lbrynet/lbryfilemanager/EncryptedFileManager.py @@ -160,7 +160,7 @@ class EncryptedFileManager(object): return defer.fail(Failure(ValueError("Could not find that LBRY file"))) def stop(self): - + log.info('Stopping %s', self) ds = [] def wait_for_finished(lbry_file, count=2): diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index 6e9692ece..48e758df4 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -560,6 +560,7 @@ class Daemon(AuthJSONRPCServer): try: if self.lbry_server_port is not None: self.lbry_server_port, p = None, self.lbry_server_port + log.info('Stop listening to %s', p) return defer.maybeDeferred(p.stopListening) else: return defer.succeed(True) @@ -649,13 +650,14 @@ class Daemon(AuthJSONRPCServer): log.warn('Failed to upload log', exc_info=True) d = defer.succeed(None) d.addCallback(lambda _: self._stop_server()) + d.addErrback(log_support.failure, log, 'Failure while shutting down: %s') d.addCallback(lambda _: self._stop_reflector()) - d.addErrback(lambda err: True) + d.addErrback(log_support.failure, log, 'Failure while shutting down: %s') d.addCallback(lambda _: self.lbry_file_manager.stop()) - d.addErrback(lambda err: True) + d.addErrback(log_support.failure, log, 'Failure while shutting down: %s') if self.session is not None: d.addCallback(lambda _: self.session.shut_down()) - d.addErrback(lambda err: True) + d.addErrback(log_support.failure, log, 'Failure while shutting down: %s') return d def _update_settings(self, settings): diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py index 3fd149fa1..787bfc8bd 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -66,6 +66,7 @@ class LBRYDaemonApp(AppKit.NSApplication): webbrowser.open(settings.UI_ADDRESS) def replyToApplicationShouldTerminate_(self, shouldTerminate): + log.info('Shutting down') notify("Goodbye!") reactor.stop() From 59c4593bf448bc379d09736051cef5156f7be7ef Mon Sep 17 00:00:00 2001 From: Job Evers-Meltzer Date: Thu, 3 Nov 2016 14:42:57 -0500 Subject: [PATCH 4/6] whitespace --- lbrynet/core/RateLimiter.py | 2 +- lbrynet/core/client/DHTPeerFinder.py | 2 +- lbrynet/lbryfilemanager/EncryptedFileManager.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lbrynet/core/RateLimiter.py b/lbrynet/core/RateLimiter.py index 04b153577..b8facfc6b 100644 --- a/lbrynet/core/RateLimiter.py +++ b/lbrynet/core/RateLimiter.py @@ -151,4 +151,4 @@ class RateLimiter(object): def unregister_protocol(self, protocol): if protocol in self.protocols: - self.protocols.remove(protocol) \ No newline at end of file + self.protocols.remove(protocol) diff --git a/lbrynet/core/client/DHTPeerFinder.py b/lbrynet/core/client/DHTPeerFinder.py index 46c34ee52..d4f299d8e 100644 --- a/lbrynet/core/client/DHTPeerFinder.py +++ b/lbrynet/core/client/DHTPeerFinder.py @@ -51,4 +51,4 @@ class DHTPeerFinder(object): return d def get_most_popular_hashes(self, num_to_return): - return self.dht_node.get_most_popular_hashes(num_to_return) \ No newline at end of file + return self.dht_node.get_most_popular_hashes(num_to_return) diff --git a/lbrynet/lbryfilemanager/EncryptedFileManager.py b/lbrynet/lbryfilemanager/EncryptedFileManager.py index 996c9bd28..66241dec0 100644 --- a/lbrynet/lbryfilemanager/EncryptedFileManager.py +++ b/lbrynet/lbryfilemanager/EncryptedFileManager.py @@ -243,4 +243,4 @@ class EncryptedFileManager(object): @rerun_if_locked def _get_count_for_stream_hash(self, stream_hash): return self.sql_db.runQuery("select count(*) from lbry_file_options where stream_hash = ?", - (stream_hash,)) \ No newline at end of file + (stream_hash,)) From 3c977f961fb70c58762086f271be642cb1bc2e35 Mon Sep 17 00:00:00 2001 From: Job Evers-Meltzer Date: Thu, 3 Nov 2016 16:57:29 -0500 Subject: [PATCH 5/6] improve osx app shutdown --- packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py | 12 ++++++++---- packaging/osx/lbry-osx-app/lbrygui/main.py | 7 ++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py index 787bfc8bd..45274f5a5 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -65,10 +65,14 @@ class LBRYDaemonApp(AppKit.NSApplication): def openui_(self, sender): webbrowser.open(settings.UI_ADDRESS) - def replyToApplicationShouldTerminate_(self, shouldTerminate): - log.info('Shutting down') - notify("Goodbye!") - reactor.stop() + # this code is from the example https://pythonhosted.org/pyobjc/examples/Cocoa/Twisted/WebServicesTool/index.html + def applicationShouldTerminate_(self, sender): + if reactor.running: + log.info('Stopping twisted event loop') + notify("Goodbye!") + reactor.stop() + return False + return True def notify(msg): diff --git a/packaging/osx/lbry-osx-app/lbrygui/main.py b/packaging/osx/lbry-osx-app/lbrygui/main.py index 17a3ee838..5a0aa10d7 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/main.py +++ b/packaging/osx/lbry-osx-app/lbrygui/main.py @@ -18,9 +18,14 @@ def main(): log_file = conf.settings.get_log_filename() log_support.configure_logging(log_file, console=True) app = LBRYDaemonApp.sharedApplication() - reactor.addSystemEventTrigger("after", "shutdown", AppHelper.stopEventLoop) + reactor.addSystemEventTrigger("after", "shutdown", shutdown) reactor.run() +def shutdown(): + log.info('Stopping event loop') + AppHelper.stopEventLoop() + + if __name__ == "__main__": main() From 6d6cfbc7cc51ea732147f10b5fcae9e2d44b7b53 Mon Sep 17 00:00:00 2001 From: Job Evers-Meltzer Date: Thu, 3 Nov 2016 16:57:42 -0500 Subject: [PATCH 6/6] whitespace --- packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py index 45274f5a5..d2d6cf878 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -47,9 +47,11 @@ class LBRYDaemonApp(AppKit.NSApplication): self.icon.setSize_((20, 20)) self.statusitem.setImage_(self.icon) self.menubarMenu = AppKit.NSMenu.alloc().init() - self.open = AppKit.NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Open", "openui:", "") + self.open = AppKit.NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + "Open", "openui:", "") self.menubarMenu.addItem_(self.open) - self.quit = AppKit.NSMenuItem.alloc().initWithTitle_action_keyEquivalent_("Quit", "replyToApplicationShouldTerminate:", "") + self.quit = AppKit.NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + "Quit", "applicationShouldTerminate:", "") self.menubarMenu.addItem_(self.quit) self.statusitem.setMenu_(self.menubarMenu) self.statusitem.setToolTip_(settings.APP_NAME)