def start(self): """Start main application""" # pylint: disable=too-many-statements,too-many-branches,too-many-locals _fixSocket() adjustHalfOpenConnectionsLimit() config = BMConfigParser() daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') try: opts, _ = getopt.getopt( sys.argv[1:], "hcdt", ["help", "curses", "daemon", "test"]) except getopt.GetoptError: self.usage() sys.exit(2) for opt, _ in opts: if opt in ("-h", "--help"): self.usage() sys.exit() elif opt in ("-d", "--daemon"): daemon = True elif opt in ("-c", "--curses"): state.curses = True elif opt in ("-t", "--test"): state.testmode = True if os.path.isfile(os.path.join( state.appdata, 'unittest.lock')): daemon = True state.enableGUI = False # run without a UI # Fallback: in case when no api command was issued state.last_api_response = time.time() # Apply special settings config.set( 'bitmessagesettings', 'apienabled', 'true') config.set( 'bitmessagesettings', 'apiusername', 'username') config.set( 'bitmessagesettings', 'apipassword', 'password') config.set( 'bitmessagesettings', 'apinotifypath', os.path.join(app_dir, 'tests', 'apinotify_handler.py') ) if daemon: state.enableGUI = False # run without a UI if state.enableGUI and not state.curses and not depends.check_pyqt(): sys.exit( 'PyBitmessage requires PyQt unless you want' ' to run it as a daemon and interact with it' ' using the API. You can download PyQt from ' 'http://www.riverbankcomputing.com/software/pyqt/download' ' or by searching Google for \'PyQt Download\'.' ' If you want to run in daemon mode, see ' 'https://bitmessage.org/wiki/Daemon\n' 'You can also run PyBitmessage with' ' the new curses interface by providing' ' \'-c\' as a commandline argument.' ) # is the application already running? If yes then exit. state.thisapp = singleinstance("", daemon) if daemon: with printLock: print('Running as a daemon. Send TERM signal to end.') self.daemonize() self.setSignalHandler() set_thread_name("PyBitmessage") state.dandelion = config.safeGetInt('network', 'dandelion') # dandelion requires outbound connections, without them, # stem objects will get stuck forever if state.dandelion and not config.safeGetBoolean( 'bitmessagesettings', 'sendoutgoingconnections'): state.dandelion = 0 if state.testmode or config.safeGetBoolean( 'bitmessagesettings', 'extralowdifficulty'): defaults.networkDefaultProofOfWorkNonceTrialsPerByte = int( defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) defaults.networkDefaultPayloadLengthExtraBytes = int( defaults.networkDefaultPayloadLengthExtraBytes / 100) readKnownNodes() # Not needed if objproc is disabled if state.enableObjProc: # Start the address generation thread addressGeneratorThread = addressGenerator() # close the main program even if there are threads left addressGeneratorThread.daemon = True addressGeneratorThread.start() # Start the thread that calculates POWs singleWorkerThread = singleWorker() # close the main program even if there are threads left singleWorkerThread.daemon = True singleWorkerThread.start() # Start the SQL thread sqlLookup = sqlThread() # DON'T close the main program even if there are threads left. # The closeEvent should command this thread to exit gracefully. sqlLookup.daemon = False sqlLookup.start() Inventory() # init # init, needs to be early because other thread may access it early Dandelion() # Enable object processor and SMTP only if objproc enabled if state.enableObjProc: # SMTP delivery thread if daemon and config.safeGet( 'bitmessagesettings', 'smtpdeliver', '') != '': from class_smtpDeliver import smtpDeliver smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread if daemon and config.safeGetBoolean( 'bitmessagesettings', 'smtpd'): from class_smtpServer import smtpServer smtpServerThread = smtpServer() smtpServerThread.start() # Start the thread that calculates POWs objectProcessorThread = objectProcessor() # DON'T close the main program even the thread remains. # This thread checks the shutdown variable after processing # each object. objectProcessorThread.daemon = False objectProcessorThread.start() # Start the cleanerThread singleCleanerThread = singleCleaner() # close the main program even if there are threads left singleCleanerThread.daemon = True singleCleanerThread.start() # Not needed if objproc disabled if state.enableObjProc: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() # API is also objproc dependent if config.safeGetBoolean('bitmessagesettings', 'apienabled'): import api # pylint: disable=relative-import singleAPIThread = api.singleAPI() # close the main program even if there are threads left singleAPIThread.daemon = True singleAPIThread.start() # start network components if networking is enabled if state.enableNetwork: start_proxyconfig() BMConnectionPool().connectToStream(1) asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() for i in range(config.getint('threads', 'receive')): receiveQueueThread = ReceiveQueueThread(i) receiveQueueThread.daemon = True receiveQueueThread.start() announceThread = AnnounceThread() announceThread.daemon = True announceThread.start() state.invThread = InvThread() state.invThread.daemon = True state.invThread.start() state.addrThread = AddrThread() state.addrThread.daemon = True state.addrThread.start() state.downloadThread = DownloadThread() state.downloadThread.daemon = True state.downloadThread.start() state.uploadThread = UploadThread() state.uploadThread.daemon = True state.uploadThread.start() if config.safeGetBoolean('bitmessagesettings', 'upnp'): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() else: # Populate with hardcoded value (same as connectToStream above) state.streamsInWhichIAmParticipating.append(1) if not daemon and state.enableGUI: if state.curses: if not depends.check_curses(): sys.exit() print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() elif state.kivy: config.remove_option('bitmessagesettings', 'dontconnect') from bitmessagekivy.mpybit import NavigateApp NavigateApp().run() else: import bitmessageqt bitmessageqt.run() else: config.remove_option('bitmessagesettings', 'dontconnect') if daemon: while state.shutdown == 0: time.sleep(1) if ( state.testmode and time.time() - state.last_api_response >= 30 ): self.stop() elif not state.enableGUI: state.enableGUI = True # pylint: disable=relative-import from tests import core as test_core test_core_result = test_core.run() state.enableGUI = True self.stop() test_core.cleanup() sys.exit( 'Core tests failed!' if test_core_result.errors or test_core_result.failures else 0 )
def updateConfig(): """Save the config""" config = BMConfigParser() settingsversion = config.getint('bitmessagesettings', 'settingsversion') if settingsversion == 1: config.set('bitmessagesettings', 'socksproxytype', 'none') config.set('bitmessagesettings', 'sockshostname', 'localhost') config.set('bitmessagesettings', 'socksport', '9050') config.set('bitmessagesettings', 'socksauthentication', 'false') config.set('bitmessagesettings', 'socksusername', '') config.set('bitmessagesettings', 'sockspassword', '') config.set('bitmessagesettings', 'sockslisten', 'false') config.set('bitmessagesettings', 'keysencrypted', 'false') config.set('bitmessagesettings', 'messagesencrypted', 'false') settingsversion = 2 # let class_sqlThread update SQL and continue elif settingsversion == 4: config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(defaults.networkDefaultPayloadLengthExtraBytes)) settingsversion = 5 if settingsversion == 5: config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') settingsversion = 7 if not config.has_option('bitmessagesettings', 'sockslisten'): config.set('bitmessagesettings', 'sockslisten', 'false') if not config.has_option('bitmessagesettings', 'userlocale'): config.set('bitmessagesettings', 'userlocale', 'system') if not config.has_option('bitmessagesettings', 'sendoutgoingconnections'): config.set('bitmessagesettings', 'sendoutgoingconnections', 'True') if not config.has_option('bitmessagesettings', 'useidenticons'): config.set('bitmessagesettings', 'useidenticons', 'True') if not config.has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt config.set('bitmessagesettings', 'identiconsuffix', ''.join( helper_random.randomchoice( "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12) )) # a twelve character pseudo-password to salt the identicons # Add settings to support no longer resending messages after # a certain period of time even if we never get an ack if settingsversion == 7: config.set('bitmessagesettings', 'stopresendingafterxdays', '') config.set('bitmessagesettings', 'stopresendingafterxmonths', '') settingsversion = 8 # With the change to protocol version 3, reset the user-settable # difficulties to 1 if settingsversion == 8: config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(defaults.networkDefaultPayloadLengthExtraBytes)) previousTotalDifficulty = int( config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 previousSmallMessageDifficulty = int( config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) settingsversion = 9 # Adjust the required POW values for each of this user's addresses # to conform to protocol v3 norms. if settingsversion == 9: for addressInKeysFile in config.addresses(): try: previousTotalDifficulty = float( config.getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 previousSmallMessageDifficulty = float( config.getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 if previousTotalDifficulty <= 2: previousTotalDifficulty = 1 if previousSmallMessageDifficulty < 1: previousSmallMessageDifficulty = 1 config.set(addressInKeysFile, 'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) config.set(addressInKeysFile, 'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) except Exception: continue config.set('bitmessagesettings', 'maxdownloadrate', '0') config.set('bitmessagesettings', 'maxuploadrate', '0') settingsversion = 10 # sanity check if config.safeGetInt('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: config.set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(defaults.ridiculousDifficulty * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) if config.safeGetInt('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(defaults.ridiculousDifficulty * defaults.networkDefaultPayloadLengthExtraBytes)) if not config.has_option('bitmessagesettings', 'onionhostname'): config.set('bitmessagesettings', 'onionhostname', '') if not config.has_option('bitmessagesettings', 'onionport'): config.set('bitmessagesettings', 'onionport', '8444') if not config.has_option('bitmessagesettings', 'onionbindip'): config.set('bitmessagesettings', 'onionbindip', '127.0.0.1') if not config.has_option('bitmessagesettings', 'smtpdeliver'): config.set('bitmessagesettings', 'smtpdeliver', '') if not config.has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): config.set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') if config.safeGetInt('bitmessagesettings', 'maxoutboundconnections') < 1: config.set('bitmessagesettings', 'maxoutboundconnections', '8') print('WARNING: your maximum outbound connections must be a number.') # TTL is now user-specifiable. Let's add an option to save # whatever the user selects. if not config.has_option('bitmessagesettings', 'ttl'): config.set('bitmessagesettings', 'ttl', '367200') config.set('bitmessagesettings', 'settingsversion', str(settingsversion)) config.save()