diff --git a/.pylintrc b/.pylintrc index e49732469..2e2a1ad54 100644 --- a/.pylintrc +++ b/.pylintrc @@ -293,7 +293,8 @@ ignored-modules=twisted.internet.reactor,leveldb # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). This supports can work # with qualified names. -ignored-classes=twisted.internet,RequestMessage +ignored-classes=twisted.internet.reactor,RequestMessage + # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular diff --git a/lbrynet/conf.py b/lbrynet/conf.py index 411acbe0a..30a783616 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -1,7 +1,9 @@ import copy +import json import logging import os import sys +import yaml from appdirs import user_data_dir @@ -246,20 +248,66 @@ class Config(DefaultSettings): def UI_ADDRESS(self): return "http://%s:%i" % (DEFAULT_SETTINGS.API_INTERFACE, self.api_port) + def ensure_data_dir(self): + # although there is a risk of a race condition here we don't + # expect there to be multiple processes accessing this + # directory so the risk can be ignored + if not os.path.isdir(self.data_dir): + os.makedirs(self.data_dir) + return self.data_dir -def get_data_dir(): - data_dir = default_data_dir - if not os.path.isdir(data_dir): - os.mkdir(data_dir) - return data_dir + def get_log_filename(self): + """Return the log file for this platform. + + Also ensure the containing directory exists + """ + return os.path.join(self.ensure_data_dir(), self.LOG_FILE_NAME) + + def get_conf_filename(self): + return os.path.join(self.ensure_data_dir(), "daemon_settings.yml") -def get_log_filename(): - """Return the log file for this platform. +def update_settings_from_file(filename=None): + filename = filename or settings.get_conf_filename() + try: + updates = load_settings(filename) + log.info("Loaded settings file: %s", updates) + settings.update(updates) + except OSError as ex: + log.info('%s: Failed to update settings from %s', ex, filename) - Also ensure the containing directory exists - """ - return os.path.join(get_data_dir(), settings.LOG_FILE_NAME) + +settings_decoders = { + '.json': json.loads, + '.yml': yaml.load +} + +settings_encoders = { + '.json': json.dumps, + '.yml': yaml.safe_dump +} + + +def load_settings(path=None): + path = path or settings.get_conf_filename() + ext = os.path.splitext(path)[1] + with open(path, 'r') as settings_file: + data = settings_file.read() + decoder = settings_decoders.get(ext, False) + assert decoder is not False, "Unknown settings format .%s" % ext + return decoder(data) + + +# TODO: be careful with this. If a setting is overriden by an environment variable +# or command line flag we don't want to persist it for future settings. +def save_settings(path=None): + path = path or settings.get_conf_filename() + to_save = {k: v for k, v in settings.__dict__.iteritems() if k in ADJUSTABLE_SETTINGS} + ext = os.path.splitext(path)[1] + encoder = settings_encoders.get(ext, False) + assert encoder is not False, "Unknown settings format .%s" % ext + with open(path, 'w') as settings_file: + settings_file.write(encoder(to_save)) # TODO: don't load the configuration automatically. The configuration diff --git a/lbrynet/core/utils.py b/lbrynet/core/utils.py index 7858e90f7..9bd5935d4 100644 --- a/lbrynet/core/utils.py +++ b/lbrynet/core/utils.py @@ -2,15 +2,11 @@ import base64 import datetime import distutils.version import logging -import json import random import os import socket import sys -import yaml -from lbrynet.conf import settings -from lbrynet.conf import AdjustableSettings from lbrynet.core.cryptoutils import get_lbry_hash_obj @@ -34,6 +30,7 @@ def isonow(): """Return utc now in isoformat with timezone""" return utcnow().isoformat() + 'Z' + def today(): return datetime.datetime.today() @@ -78,37 +75,6 @@ def obfuscate(plain): return base64.b64encode(plain).encode('rot13') -settings_decoders = { - '.json': json.loads, - '.yml': yaml.load -} - -settings_encoders = { - '.json': json.dumps, - '.yml': yaml.safe_dump -} - -ADJUSTABLE_SETTINGS = AdjustableSettings().get_dict() - - -def load_settings(path): - ext = os.path.splitext(path)[1] - with open(path, 'r') as settings_file: - data = settings_file.read() - decoder = settings_decoders.get(ext, False) - assert decoder is not False, "Unknown settings format .%s" % ext - return decoder(data) - - -def save_settings(path): - to_save = {k: v for k, v in settings.__dict__.iteritems() if k in ADJUSTABLE_SETTINGS} - ext = os.path.splitext(path)[1] - encoder = settings_encoders.get(ext, False) - assert encoder is not False, "Unknown settings format .%s" % ext - with open(path, 'w') as settings_file: - settings_file.write(encoder(to_save)) - - def check_connection(server="www.lbry.io", port=80): """Attempts to open a socket to server:port and returns True if successful.""" try: diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index d67df1fe4..58aef6e17 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -26,9 +26,9 @@ from lbrynet import __version__ as lbrynet_version from lbryum.version import LBRYUM_VERSION as lbryum_version from lbrynet import __version__ as lbrynet_version +from lbrynet import conf from lbrynet.conf import settings as lbrynet_settings from lbrynet import analytics -from lbrynet import conf from lbrynet import reflector from lbrynet.metadata.Metadata import Metadata, verify_name_characters from lbrynet.metadata.Fee import FeeValidator @@ -273,7 +273,7 @@ class Daemon(AuthJSONRPCServer): self.ui_version = None self.ip = None self.first_run = None - self.log_file = conf.get_log_filename() + self.log_file = lbrynet_settings.get_log_filename() self.current_db_revision = 1 self.session = None self.uploaded_temp_files = [] @@ -281,11 +281,11 @@ class Daemon(AuthJSONRPCServer): # TODO: this should probably be passed into the daemon, or # possibly have the entire log upload functionality taken out # of the daemon, but I don't want to deal with that now - self.log_uploader = log_support.LogUploader.load('lbrynet', conf.get_log_filename()) + self.log_uploader = log_support.LogUploader.load('lbrynet', self.log_file) self.analytics_manager = None self.lbryid = PENDING_LBRY_ID - self.daemon_conf = os.path.join(self.db_dir, 'daemon_settings.yml') + self.daemon_conf = lbrynet_settings.get_conf_filename() self.wallet_user = None self.wallet_password = None @@ -1071,8 +1071,7 @@ class Daemon(AuthJSONRPCServer): remaining_scripts = [s for s in self.startup_scripts if 'run_once' not in s.keys()] startup_scripts = self.startup_scripts self.startup_scripts = lbrynet_settings.startup_scripts = remaining_scripts - conf = os.path.join(lbrynet_settings.data_dir, "daemon_settings.yml") - utils.save_settings(conf) + conf.save_settings() for script in startup_scripts: if script['script_name'] == 'migrateto025': diff --git a/lbrynet/lbrynet_daemon/DaemonControl.py b/lbrynet/lbrynet_daemon/DaemonControl.py index d432e45d3..58b003e77 100644 --- a/lbrynet/lbrynet_daemon/DaemonControl.py +++ b/lbrynet/lbrynet_daemon/DaemonControl.py @@ -69,22 +69,12 @@ def start(): args = parser.parse_args() utils.setup_certs_for_windows() - lbrynet_log = conf.get_log_filename() - log_support.configure_logging(lbrynet_log, args.logtoconsole, args.verbose) - to_pass = {} - settings_path = os.path.join(settings.data_dir, "daemon_settings.yml") - if os.path.isfile(settings_path): - to_pass.update(utils.load_settings(settings_path)) - log.info("Loaded settings file") - if args.ui: - to_pass.update({'local_ui_path': args.ui}) - if args.branch: - to_pass.update({'ui_branch': args.branch}) - to_pass.update({'use_auth_http': args.useauth}) - to_pass.update({'wallet_type': args.wallet}) - log.debug('Settings overrides: %s', to_pass) - settings.update(to_pass) + conf.update_settings_from_file() + update_settings_from_args(args) + + lbrynet_log = settings.get_log_filename() + log_support.configure_logging(lbrynet_log, args.logtoconsole, args.verbose) log.debug('Final Settings: %s', settings.__dict__) try: @@ -92,8 +82,6 @@ def start(): log.info("lbrynet-daemon is already running") if not args.logtoconsole: print "lbrynet-daemon is already running" - if args.launchui: - webbrowser.open(settings.UI_ADDRESS) return except: pass @@ -120,12 +108,23 @@ def start(): return +def update_settings_from_args(args): + to_pass = {} + if args.ui: + to_pass['local_ui_path'] = args.ui + if args.branch: + to_pass['ui_branch'] = args.branch + to_pass['use_auth_http'] = args.useauth + to_pass['wallet_type'] = args.wallet + settings.update(to_pass) + + def log_and_kill(failure): log_support.failure(failure, log, 'Failed to startup: %s') reactor.stop() -def start_server_and_listen(launchui, use_auth, **kwargs): +def start_server_and_listen(launchui, use_auth): """The primary entry point for launching the daemon. Args: @@ -135,7 +134,7 @@ def start_server_and_listen(launchui, use_auth, **kwargs): """ lbry = DaemonServer() - d = lbry.start(**kwargs) + d = lbry.start() d.addCallback(lambda _: listen(lbry, use_auth)) if launchui: d.addCallback(lambda _: webbrowser.open(settings.UI_ADDRESS)) diff --git a/lbrynet/lbrynet_daemon/DaemonServer.py b/lbrynet/lbrynet_daemon/DaemonServer.py index 94a88f47b..d3951c2e3 100644 --- a/lbrynet/lbrynet_daemon/DaemonServer.py +++ b/lbrynet/lbrynet_daemon/DaemonServer.py @@ -3,7 +3,7 @@ import os from twisted.internet import defer -from lbrynet import conf +from lbrynet.conf import settings from lbrynet.lbrynet_daemon.Daemon import Daemon from lbrynet.lbrynet_daemon.Resources import LBRYindex, HostedEncryptedFile, EncryptedFileUpload from lbrynet.conf import settings @@ -14,7 +14,7 @@ log = logging.getLogger(__name__) class DaemonServer(object): def _setup_server(self): - ui_path = os.path.join(conf.get_data_dir(), "lbry-ui", "active") + ui_path = os.path.join(settings.ensure_data_dir(), "lbry-ui", "active") self.root = LBRYindex(ui_path) self._api = Daemon(self.root) self.root.putChild("view", HostedEncryptedFile(self._api)) diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py index 1a8f07577..48155576b 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -57,11 +57,9 @@ class LBRYDaemonApp(AppKit.NSApplication): self.statusitem.setToolTip_(settings.APP_NAME) if test_internet_connection(): - if platform.mac_ver()[0] >= "10.10": - LBRYNotify("Starting LBRY") + notify("Starting LBRY") else: - if platform.mac_ver()[0] >= "10.10": - LBRYNotify("LBRY needs an internet connection to start, try again when one is available") + notify("LBRY needs an internet connection to start, try again when one is available") sys.exit(0) DaemonControl.start_server_and_listen(launchui=True, use_auth=False) @@ -70,6 +68,10 @@ class LBRYDaemonApp(AppKit.NSApplication): webbrowser.open(settings.UI_ADDRESS) def replyToApplicationShouldTerminate_(self, shouldTerminate): - if platform.mac_ver()[0] >= "10.10": - LBRYNotify("Goodbye!") + notify("Goodbye!") reactor.stop() + + +def notify(msg): + if platform.mac_ver()[0] >= "10.10": + LBRYNotify(msg) diff --git a/packaging/osx/lbry-osx-app/lbrygui/main.py b/packaging/osx/lbry-osx-app/lbrygui/main.py index ce3e22631..ba9240a7f 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/main.py +++ b/packaging/osx/lbry-osx-app/lbrygui/main.py @@ -14,8 +14,9 @@ log = logging.getLogger() def main(): - log_file = conf.get_log_filename() - log_support.configure_logging(log_file, console=False) + conf.update_settings_from_file() + log_file = settings.get_log_filename() + log_support.configure_logging(log_file, console=True) app = LBRYDaemonApp.sharedApplication() reactor.addSystemEventTrigger("after", "shutdown", AppHelper.stopEventLoop) reactor.run() diff --git a/packaging/windows/lbry-win32-app/LBRYWin32App.py b/packaging/windows/lbry-win32-app/LBRYWin32App.py index 0f637d0d8..abfbdf89c 100644 --- a/packaging/windows/lbry-win32-app/LBRYWin32App.py +++ b/packaging/windows/lbry-win32-app/LBRYWin32App.py @@ -276,8 +276,11 @@ def main(lbry_name=None): if __name__ == '__main__': utils.setup_certs_for_windows() - log_file = conf.get_log_filename() - log_support.configure_logging(log_file, console=False) + conf.update_settings_from_file() + + log_file = settings.get_log_filename() + log_support.configure_logging(log_file, console=True) + lbry_daemon = JSONRPCProxy.from_url(settings.API_CONNECTION_STRING) try: