diff --git a/lbrynet/analytics/api.py b/lbrynet/analytics/api.py index 50c20212d..f064a466d 100644 --- a/lbrynet/analytics/api.py +++ b/lbrynet/analytics/api.py @@ -56,11 +56,10 @@ class Api(object): def track(self, event): """Send a single tracking event""" log.debug('Sending track event: %s', event) - import base64 return self.session.post(self.url + '/track', json=event, auth=self.auth) @classmethod - def load(cls, session=None): + def new_instance(cls, session=None): """Initialize an instance using values from the configuration""" if not session: session = sessions.FuturesSession() diff --git a/lbrynet/analytics/events.py b/lbrynet/analytics/events.py index 3b2e879be..87894b92f 100644 --- a/lbrynet/analytics/events.py +++ b/lbrynet/analytics/events.py @@ -1,7 +1,7 @@ import logging from lbrynet.core import utils - +from lbrynet.conf import LBRYUM_WALLET log = logging.getLogger(__name__) @@ -22,6 +22,20 @@ class Events(object): self.lbry_id = lbry_id self.session_id = session_id + def update_context(self, context): + self.context = context + + def server_startup(self): + return self._event('Server Startup') + + def server_startup_success(self): + return self._event('Server Startup Success') + + def server_startup_error(self, message): + return self._event('Server Startup Error', { + 'message': message, + }) + def heartbeat(self): return self._event('Heartbeat') @@ -32,6 +46,13 @@ class Events(object): } return self._event('Download Started', properties) + def error(self, message, sd_hash=None): + properties = { + 'message': message, + 'stream_info': sd_hash + } + return self._event('Error', properties) + def metric_observed(self, metric_name, value): properties = { 'value': value, @@ -57,19 +78,18 @@ class Events(object): return properties -def make_context(platform, wallet, is_dev=False): - # TODO: distinguish between developer and release instances +def make_context(platform, wallet): return { - 'is_dev': is_dev, 'app': { 'name': 'lbrynet', 'version': platform['lbrynet_version'], 'ui_version': platform['ui_version'], 'python_version': platform['python_version'], + 'build': platform['build'], 'wallet': { 'name': wallet, # TODO: add in version info for lbrycrdd - 'version': platform['lbryum_version'] if wallet == 'lbryum' else None + 'version': platform['lbryum_version'] if wallet == LBRYUM_WALLET else None }, }, # TODO: expand os info to give linux/osx specific info diff --git a/lbrynet/analytics/manager.py b/lbrynet/analytics/manager.py index fecc1a0d2..e6c9fbc15 100644 --- a/lbrynet/analytics/manager.py +++ b/lbrynet/analytics/manager.py @@ -3,7 +3,13 @@ from lbrynet.core import looping_call_manager from twisted.internet import defer from twisted.internet import task +from lbrynet.core.Platform import get_platform +from lbrynet.conf import settings + import constants +from api import Api +from events import Events, make_context +from track import Track class Manager(object): @@ -12,28 +18,63 @@ class Manager(object): self.events_generator = events_generator self.track = track self.looping_call_manager = self.setup_looping_calls() + self.is_started = False + + @classmethod + def new_instance(cls, api=None, events=None): + if api is None: + api = Api.new_instance() + if events is None: + events = Events( + make_context(get_platform(), settings.wallet), + 'not loaded', 'not loaded' + ) + return cls(api, events, Track()) + + def update_events_generator(self, events_generator): + self.events_generator = events_generator + + def _get_looping_calls(self): + return [ + ('send_heartbeat', self._send_heartbeat, 60), + ('update_tracked_metrics', self._update_tracked_metrics, 300), + ] def setup_looping_calls(self): call_manager = looping_call_manager.LoopingCallManager() - looping_calls = [ - ('send_heartbeat', self._send_heartbeat), - ('update_tracked_metrics', self._update_tracked_metrics), - ] - for name, fn in looping_calls: + for name, fn, _ in self._get_looping_calls(): call_manager.register_looping_call(name, task.LoopingCall(fn)) return call_manager def start(self): - self.looping_call_manager.start('send_heartbeat', 60) - self.looping_call_manager.start('update_tracked_metrics', 300) + if not self.is_started: + for name, _, interval in self._get_looping_calls(): + self.looping_call_manager.start(name, interval) + self.is_started = True def shutdown(self): self.looping_call_manager.shutdown() + def send_server_startup(self): + event = self.events_generator.server_startup() + self.analytics_api.track(event) + + def send_server_startup_success(self): + event = self.events_generator.server_startup_success() + self.analytics_api.track(event) + + def send_server_startup_error(self, message): + event = self.events_generator.server_startup_error(message) + self.analytics_api.track(event) + def send_download_started(self, name, stream_info=None): event = self.events_generator.download_started(name, stream_info) self.analytics_api.track(event) + def send_error(self, message, sd_hash=None): + event = self.events_generator.error(message, sd_hash) + self.analytics_api.track(event) + def register_repeating_metric(self, event_name, value_generator, frequency=300): lcall = task.LoopingCall(self._send_repeating_metric, event_name, value_generator) self.looping_call_manager.register_looping_call(event_name, lcall) diff --git a/lbrynet/build_type.py b/lbrynet/build_type.py new file mode 100644 index 000000000..ffbf0ae1e --- /dev/null +++ b/lbrynet/build_type.py @@ -0,0 +1,2 @@ +# dont touch this. Travis changes this during build/deployment +BUILD = "dev" diff --git a/lbrynet/conf.py b/lbrynet/conf.py index 2a12af014..abc60e5ed 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -7,6 +7,9 @@ import yaml from appdirs import user_data_dir +LBRYCRD_WALLET = 'lbrycrd' +LBRYUM_WALLET = 'lbryum' +PTC_WALLET = 'ptc' log = logging.getLogger(__name__) @@ -173,7 +176,7 @@ class AdjustableSettings(Setting): ] self.pointtrader_server = 'http://127.0.0.1:2424' self.reflector_servers = [("reflector.lbry.io", 5566)] - self.wallet = "lbryum" + self.wallet = LBRYUM_WALLET self.ui_branch = "master" self.default_ui_branch = 'master' self.data_dir = default_data_dir @@ -201,7 +204,7 @@ class ApplicationSettings(Setting): self.ICON_PATH = "icons" if platform is WINDOWS else "app.icns" self.APP_NAME = "LBRY" self.PROTOCOL_PREFIX = "lbry" - self.WALLET_TYPES = ["lbryum", "lbrycrd"] + self.WALLET_TYPES = [LBRYUM_WALLET, LBRYCRD_WALLET] self.SOURCE_TYPES = ['lbry_sd_hash', 'url', 'btih'] self.CURRENCIES = { 'BTC': {'type': 'crypto'}, diff --git a/lbrynet/core/Platform.py b/lbrynet/core/Platform.py new file mode 100644 index 000000000..5584e0020 --- /dev/null +++ b/lbrynet/core/Platform.py @@ -0,0 +1,29 @@ +import platform +import simplejson as json + +from urllib2 import urlopen + +from lbrynet import __version__ as lbrynet_version +from lbrynet import build_type +from lbryum.version import LBRYUM_VERSION as lbryum_version + + +def get_platform(): + p = { + "processor": platform.processor(), + "python_version": platform.python_version(), + "platform": platform.platform(), + "os_release": platform.release(), + "os_system": platform.system(), + "lbrynet_version": lbrynet_version, + "lbryum_version": lbryum_version, + "ui_version": "not loaded yet", + "build": build_type.BUILD, # travis sets this during build step + } + + try: + p['ip'] = json.load(urlopen('http://jsonip.com'))['ip'] + except: + p['ip'] = "Could not determine IP" + + return p diff --git a/lbrynet/lbrynet_daemon/Daemon.py b/lbrynet/lbrynet_daemon/Daemon.py index 068f17e18..2e03a94ac 100644 --- a/lbrynet/lbrynet_daemon/Daemon.py +++ b/lbrynet/lbrynet_daemon/Daemon.py @@ -2,7 +2,6 @@ import binascii import logging.handlers import mimetypes import os -import platform import random import re import subprocess @@ -21,35 +20,23 @@ from twisted.internet.task import LoopingCall from txjsonrpc import jsonrpclib from jsonschema import ValidationError -from lbrynet import __version__ as lbrynet_version # TODO: importing this when internet is disabled raises a socket.gaierror 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.conf import LBRYCRD_WALLET, LBRYUM_WALLET, PTC_WALLET from lbrynet import analytics -from lbrynet import reflector -from lbrynet.metadata.Metadata import Metadata, verify_name_characters from lbrynet.metadata.Fee import FeeValidator -from lbrynet.core import log_support -from lbrynet.core import utils -from lbrynet.core.utils import generate_id -from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob, BlobStreamDescriptorReader -from lbrynet.core.Session import Session +from lbrynet.core import Platform from lbrynet.core.looping_call_manager import LoopingCallManager from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory from lbrynet.core.server.ServerProtocol import ServerProtocolFactory from lbrynet.core.Error import InsufficientFundsError, InvalidNameError -from lbrynet.core.PTCWallet import PTCWallet -from lbrynet.core.Wallet import LBRYcrdWallet, LBRYumWallet -from lbrynet.lbrynet_console.Settings import Settings -from lbrynet.lbryfilemanager.EncryptedFileManager import EncryptedFileManager from lbrynet.lbryfile.StreamDescriptor import EncryptedFileStreamType from lbrynet.lbryfile.client.EncryptedFileDownloader import EncryptedFileSaverFactory, EncryptedFileOpenerFactory from lbrynet.lbryfile.client.EncryptedFileOptions import add_lbry_file_to_sd_identifier -from lbrynet.lbryfile.EncryptedFileMetadataManager import DBEncryptedFileMetadataManager -from lbrynet.lbryfile.EncryptedFileMetadataManager import TempEncryptedFileMetadataManager from lbrynet.lbrynet_daemon.UIManager import UIManager from lbrynet.lbrynet_daemon.Downloader import GetStream from lbrynet.lbrynet_daemon.Publisher import Publisher @@ -221,7 +208,7 @@ class Daemon(AuthJSONRPCServer): LBRYnet daemon, a jsonrpc interface to lbry functions """ - def __init__(self, root): + def __init__(self, root, analytics_manager): AuthJSONRPCServer.__init__(self, lbrynet_settings.use_auth_http) reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown) @@ -273,7 +260,7 @@ class Daemon(AuthJSONRPCServer): self.git_lbrynet_version = None self.git_lbryum_version = None self.ui_version = None - self.ip = None + self.platform = None self.first_run = None self.log_file = lbrynet_settings.get_log_filename() self.current_db_revision = 1 @@ -313,6 +300,7 @@ class Daemon(AuthJSONRPCServer): self.blob_request_payment_rate_manager = None self.lbry_file_metadata_manager = None self.lbry_file_manager = None + self.analytics_manager = analytics_manager @AuthJSONRPCServer.subhandler def _exclude_lbrycrd_only_commands_from_lbryum_session(self, request): @@ -320,14 +308,14 @@ class Daemon(AuthJSONRPCServer): content = request.content.read() parsed = jsonrpclib.loads(content) function_path = parsed.get("method") - if self.wallet_type == "lbryum" and function_path in ['set_miner', 'get_miner_status']: + if self.wallet_type == LBRYUM_WALLET and function_path in ['set_miner', 'get_miner_status']: log.warning("Mining commands are not available in lbryum") raise Exception("Command not available in lbryum") return True def set_wallet_attributes(self): self.wallet_dir = None - if self.wallet_type != "lbrycrd": + if self.wallet_type != LBRYCRD_WALLET: return if os.name == "nt": from lbrynet.winhelpers.knownpaths import get_path, FOLDERID, UserHandle @@ -411,24 +399,10 @@ class Daemon(AuthJSONRPCServer): return d def _get_platform(self): - r = { - "processor": platform.processor(), - "python_version": platform.python_version(), - "platform": platform.platform(), - "os_release": platform.release(), - "os_system": platform.system(), - "lbrynet_version": lbrynet_version, - "lbryum_version": lbryum_version, - "ui_version": self.lbry_ui_manager.loaded_git_version, - } - if not self.ip: - try: - r['ip'] = json.load(urlopen('http://jsonip.com'))['ip'] - self.ip = r['ip'] - except: - r['ip'] = "Could not determine" - - return r + if self.platform is None: + self.platform = Platform.get_platform() + self.platform["ui_version"] = self.lbry_ui_manager.loaded_git_version + return self.platform def _initial_setup(self): def _log_platform(): @@ -556,6 +530,11 @@ class Daemon(AuthJSONRPCServer): return defer.succeed(True) return defer.succeed(True) + def _stop_file_manager(self): + if self.lbry_file_manager: + self.lbry_file_manager.stop() + return defer.succeed(True) + def _stop_server(self): try: if self.lbry_server_port is not None: @@ -653,11 +632,12 @@ class Daemon(AuthJSONRPCServer): except Exception: 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(log_support.failure, log, 'Failure while shutting down: %s') - d.addCallback(lambda _: self.lbry_file_manager.stop()) + d.addCallback(lambda _: self._stop_file_manager()) d.addErrback(log_support.failure, log, 'Failure while shutting down: %s') if self.session is not None: d.addCallback(lambda _: self.session.shut_down()) @@ -783,18 +763,23 @@ class Daemon(AuthJSONRPCServer): return d def _get_analytics(self): - analytics_api = analytics.Api.load() context = analytics.make_context(self._get_platform(), self.wallet_type) events_generator = analytics.Events( context, base58.b58encode(self.lbryid), self._session_id) - self.analytics_manager = analytics.Manager( - analytics_api, events_generator, analytics.Track()) - self.analytics_manager.start() - self.analytics_manager.register_repeating_metric( - analytics.BLOB_BYTES_AVAILABLE, - AlwaysSend(calculate_available_blob_size, self.session.blob_manager), - frequency=300 - ) + if self.analytics_manager is None: + self.analytics_manager = analytics.Manager.new_instance( + events=events_generator + ) + else: + self.analytics_manager.update_events_generator(events_generator) + + if not self.analytics_manager.is_started: + self.analytics_manager.start() + self.analytics_manager.register_repeating_metric( + analytics.BLOB_BYTES_AVAILABLE, + AlwaysSend(calculate_available_blob_size, self.session.blob_manager), + frequency=300 + ) def _get_session(self): def get_default_data_rate(): @@ -804,25 +789,25 @@ class Daemon(AuthJSONRPCServer): return d def get_wallet(): - if self.wallet_type == "lbrycrd": + if self.wallet_type == LBRYCRD_WALLET: log.info("Using lbrycrd wallet") wallet = LBRYcrdWallet(self.db_dir, wallet_dir=self.wallet_dir, wallet_conf=self.lbrycrd_conf, lbrycrdd_path=self.lbrycrdd_path) d = defer.succeed(wallet) - elif self.wallet_type == "lbryum": + elif self.wallet_type == LBRYUM_WALLET: log.info("Using lbryum wallet") config = {'auto-connect': True} if lbrynet_settings.lbryum_wallet_dir: config['lbryum_path'] = lbrynet_settings.lbryum_wallet_dir d = defer.succeed(LBRYumWallet(self.db_dir, config)) - elif self.wallet_type == "ptc": + elif self.wallet_type == PTC_WALLET: log.info("Using PTC wallet") d = defer.succeed(PTCWallet(self.db_dir)) else: raise ValueError('Wallet Type {} is not valid'.format(self.wallet_type)) - d.addCallback(lambda wallet: {"wallet": wallet}) + d.addCallback(lambda w: {"wallet": w}) return d d1 = get_default_data_rate() @@ -867,11 +852,14 @@ class Daemon(AuthJSONRPCServer): def eb(): if not r.called: + self.analytics_manager.send_error("sd blob download timed out", sd_hash) r.errback(Exception("sd timeout")) r = defer.Deferred(None) reactor.callLater(timeout, eb) d = download_sd_blob(self.session, sd_hash, self.session.payment_rate_manager) + d.addErrback(lambda err: self.analytics_manager.send_error( + "error downloading sd blob: " + err, sd_hash)) d.addCallback(BlobStreamDescriptorReader) d.addCallback(lambda blob: blob.get_info()) d.addCallback(cb) @@ -1046,12 +1034,6 @@ class Daemon(AuthJSONRPCServer): ) return run_reflector_factory(factory) - def _log_to_slack(self, msg): - URL = "https://hooks.slack.com/services/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" - msg = platform.platform() + ": " + base58.b58encode(self.lbryid)[:20] + ", " + msg - requests.post(URL, json.dumps({"text": msg})) - return defer.succeed(None) - def _run_scripts(self): if len([k for k in self.startup_scripts if 'run_once' in k.keys()]): log.info("Removing one time startup scripts") @@ -1113,7 +1095,7 @@ class Daemon(AuthJSONRPCServer): r['message'] = self.connection_problem[1] r['is_lagging'] = True elif self.startup_status[0] == LOADING_wallet_CODE: - if self.wallet_type == 'lbryum': + if self.wallet_type == LBRYUM_WALLET: if self.session.wallet.blocks_behind_alert != 0: r['message'] = r['message'] % (str(self.session.wallet.blocks_behind_alert) + " blocks behind") r['progress'] = self.session.wallet.catchup_progress @@ -2127,8 +2109,6 @@ class Daemon(AuthJSONRPCServer): exclude_previous = True d = self._upload_log(log_type=log_type, exclude_previous=exclude_previous, force=force) - if 'message' in p.keys(): - d.addCallback(lambda _: self._log_to_slack(p['message'])) d.addCallback(lambda _: self._render_response(True, OK_CODE)) return d diff --git a/lbrynet/lbrynet_daemon/DaemonControl.py b/lbrynet/lbrynet_daemon/DaemonControl.py index abf18bb5f..b549d175a 100644 --- a/lbrynet/lbrynet_daemon/DaemonControl.py +++ b/lbrynet/lbrynet_daemon/DaemonControl.py @@ -9,6 +9,7 @@ from twisted.internet import defer, reactor, error from twisted.cred import portal from jsonrpc.proxy import JSONRPCProxy +from lbrynet import analytics from lbrynet.lbrynet_daemon.auth.auth import PasswordChecker, HttpPasswordRealm from lbrynet.lbrynet_daemon.auth.util import initialize_api_key_file from lbrynet import conf @@ -46,7 +47,7 @@ def start(): parser.add_argument("--wallet", help="lbrycrd or lbryum, default lbryum", type=str, - default='lbryum') + default=conf.LBRYUM_WALLET) parser.add_argument("--ui", help="path to custom UI folder", default=None) parser.add_argument( "--branch", @@ -98,7 +99,9 @@ def start(): print "To quit press ctrl-c or call 'stop' via the API" if test_internet_connection(): - start_server_and_listen(args.launchui, args.useauth) + analytics_manager = analytics.Manager.new_instance() + analytics_manager.send_server_startup() + start_server_and_listen(args.launchui, args.useauth, analytics_manager) reactor.run() if not args.logtoconsole and not args.quiet: @@ -121,29 +124,32 @@ def update_settings_from_args(args): settings.update(to_pass) -def log_and_kill(failure): +def log_and_kill(failure, analytics_manager): + analytics_manager.send_server_startup_error(failure.getErrorMessage() + " " + str(failure)) log_support.failure(failure, log, 'Failed to startup: %s') reactor.callFromThread(reactor.stop) -def start_server_and_listen(launchui, use_auth): +def start_server_and_listen(launchui, use_auth, analytics_manager): """The primary entry point for launching the daemon. Args: launchui: set to true to open a browser window use_auth: set to true to enable http authentication + analytics_manager: to send analytics kwargs: passed along to `DaemonServer().start()` """ - lbry = DaemonServer() - d = lbry.start() - d.addCallback(lambda _: listen(lbry, use_auth)) + daemon_server = DaemonServer(analytics_manager) + d = daemon_server.start() + d.addCallback(lambda _: listen(daemon_server, use_auth)) if launchui: d.addCallback(lambda _: webbrowser.open(settings.UI_ADDRESS)) - d.addErrback(log_and_kill) + d.addCallback(lambda _: analytics_manager.send_server_startup_success()) + d.addErrback(log_and_kill, analytics_manager) -def listen(lbry, use_auth): - site_base = get_site_base(use_auth, lbry.root) +def listen(daemon_server, use_auth): + site_base = get_site_base(use_auth, daemon_server.root) lbrynet_server = server.Site(site_base) lbrynet_server.requestFactory = DaemonRequest try: diff --git a/lbrynet/lbrynet_daemon/DaemonServer.py b/lbrynet/lbrynet_daemon/DaemonServer.py index d3951c2e3..93fb5b0fd 100644 --- a/lbrynet/lbrynet_daemon/DaemonServer.py +++ b/lbrynet/lbrynet_daemon/DaemonServer.py @@ -3,7 +3,6 @@ import os from twisted.internet import defer -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 @@ -13,10 +12,14 @@ log = logging.getLogger(__name__) class DaemonServer(object): + def __init__(self, analytics_manager=None): + self.root = None + self.analytics_manager = analytics_manager + def _setup_server(self): ui_path = os.path.join(settings.ensure_data_dir(), "lbry-ui", "active") self.root = LBRYindex(ui_path) - self._api = Daemon(self.root) + self._api = Daemon(self.root, self.analytics_manager) self.root.putChild("view", HostedEncryptedFile(self._api)) self.root.putChild("upload", EncryptedFileUpload(self._api)) self.root.putChild(settings.API_ADDRESS, self._api) diff --git a/lbrynet/lbrynet_daemon/auth/server.py b/lbrynet/lbrynet_daemon/auth/server.py index 4a3637fe6..979568d9a 100644 --- a/lbrynet/lbrynet_daemon/auth/server.py +++ b/lbrynet/lbrynet_daemon/auth/server.py @@ -8,6 +8,7 @@ from txjsonrpc import jsonrpclib from lbrynet.core.Error import InvalidAuthenticationToken, InvalidHeaderError, SubhandlerError from lbrynet.conf import settings +from lbrynet.core import log_support from lbrynet.lbrynet_daemon.auth.util import APIKey, get_auth_message from lbrynet.lbrynet_daemon.auth.client import LBRY_SECRET @@ -262,10 +263,7 @@ class AuthJSONRPCServer(AuthorizedBase): self._render_message(request, encoded_message) def _errback_render(self, failure, id): - log.error("Request failed:") - log.error(failure) - log.error(failure.value) - log.error(id) + log_support.failure(failure, log, "Request failed. Id: %s, Failure: %s", id) if isinstance(failure.value, jsonrpclib.Fault): return failure.value return server.failure diff --git a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py index d2d6cf878..a257e57e9 100644 --- a/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py +++ b/packaging/osx/lbry-osx-app/lbrygui/LBRYApp.py @@ -22,6 +22,7 @@ if not os.path.isfile(lbrycrdd_path_conf): f.close() from lbrynet.lbrynet_daemon import DaemonControl +from lbrynet import analytics from lbrynet.conf import settings from lbrynet.core import utils @@ -62,7 +63,10 @@ class LBRYDaemonApp(AppKit.NSApplication): 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) + DaemonControl.start_server_and_listen( + launchui=True, use_auth=False, + analytics_manager=analytics.Manager.new_instance() + ) def openui_(self, sender): webbrowser.open(settings.UI_ADDRESS) diff --git a/packaging/windows/lbry-win32-app/LBRYWin32App.py b/packaging/windows/lbry-win32-app/LBRYWin32App.py index 988227a54..f61048b67 100644 --- a/packaging/windows/lbry-win32-app/LBRYWin32App.py +++ b/packaging/windows/lbry-win32-app/LBRYWin32App.py @@ -15,7 +15,7 @@ try: except ImportError: import win32gui -from lbrynet import conf +from lbrynet import conf, analytics from lbrynet.core import log_support from lbrynet.core import utils from lbrynet.lbrynet_daemon import DaemonControl @@ -267,7 +267,10 @@ def main(lbry_name=None): systray_thread.daemon = True systray_thread.start() - DaemonControl.start_server_and_listen(launchui=True, use_auth=False) + DaemonControl.start_server_and_listen( + launchui=True, use_auth=False, + analytics_manager=analytics.Manager.new_instance() + ) reactor.run()