Main process fixes
- handles old dialog versions better if using curses - can spawn SMTP delivery thread if configured (only when in daemon mode) - daemonized mode now works more like it's properly supposed to on unix (double fork etc). You may have to adjust your init scripts, when when using upstart for example you should now use "expect daemon" - daemon mode now cleanly shuts down when TERM/INT signal is received
This commit is contained in:
parent
e5c9e6d383
commit
4865659d72
|
@ -38,6 +38,7 @@ from class_outgoingSynSender import outgoingSynSender
|
||||||
from class_singleListener import singleListener
|
from class_singleListener import singleListener
|
||||||
from class_singleWorker import singleWorker
|
from class_singleWorker import singleWorker
|
||||||
from class_addressGenerator import addressGenerator
|
from class_addressGenerator import addressGenerator
|
||||||
|
from class_smtpDeliver import smtpDeliver
|
||||||
from debug import logger
|
from debug import logger
|
||||||
|
|
||||||
# Helper Functions
|
# Helper Functions
|
||||||
|
@ -153,16 +154,21 @@ class Main:
|
||||||
_fixWinsock()
|
_fixWinsock()
|
||||||
|
|
||||||
shared.daemon = daemon
|
shared.daemon = daemon
|
||||||
|
|
||||||
|
# get curses flag
|
||||||
|
shared.curses = False
|
||||||
|
if '-c' in sys.argv:
|
||||||
|
shared.curses = True
|
||||||
|
|
||||||
# is the application already running? If yes then exit.
|
# is the application already running? If yes then exit.
|
||||||
shared.thisapp = singleton.singleinstance("", daemon)
|
shared.thisapp = singleton.singleinstance("", daemon)
|
||||||
|
|
||||||
# get curses flag
|
if daemon:
|
||||||
curses = False
|
with shared.printLock:
|
||||||
if '-c' in sys.argv:
|
print('Running as a daemon. Send TERM signal to end.')
|
||||||
curses = True
|
self.daemonize()
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, helper_generic.signal_handler)
|
self.setSignalHandler()
|
||||||
# signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
||||||
|
|
||||||
helper_bootstrap.knownNodes()
|
helper_bootstrap.knownNodes()
|
||||||
# Start the address generation thread
|
# Start the address generation thread
|
||||||
|
@ -180,6 +186,11 @@ class Main:
|
||||||
sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully.
|
sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully.
|
||||||
sqlLookup.start()
|
sqlLookup.start()
|
||||||
|
|
||||||
|
# SMTP delivery thread
|
||||||
|
if daemon and shared.config.get("bitmessagesettings", "smtpdeliver", None):
|
||||||
|
smtpDeliveryThread = smtpDeliver()
|
||||||
|
smtpDeliveryThread.start()
|
||||||
|
|
||||||
# Start the thread that calculates POWs
|
# Start the thread that calculates POWs
|
||||||
objectProcessorThread = objectProcessor()
|
objectProcessorThread = objectProcessor()
|
||||||
objectProcessorThread.daemon = False # DON'T close the main program even the thread remains. This thread checks the shutdown variable after processing each object.
|
objectProcessorThread.daemon = False # DON'T close the main program even the thread remains. This thread checks the shutdown variable after processing each object.
|
||||||
|
@ -221,7 +232,7 @@ class Main:
|
||||||
upnpThread.start()
|
upnpThread.start()
|
||||||
|
|
||||||
if daemon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False:
|
if daemon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False:
|
||||||
if curses == False:
|
if shared.curses == False:
|
||||||
if not depends.check_pyqt():
|
if not depends.check_pyqt():
|
||||||
print('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')
|
print('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')
|
||||||
print('You can also run PyBitmessage with the new curses interface by providing \'-c\' as a commandline argument.')
|
print('You can also run PyBitmessage with the new curses interface by providing \'-c\' as a commandline argument.')
|
||||||
|
@ -230,22 +241,38 @@ class Main:
|
||||||
import bitmessageqt
|
import bitmessageqt
|
||||||
bitmessageqt.run()
|
bitmessageqt.run()
|
||||||
else:
|
else:
|
||||||
if depends.check_curses():
|
if True:
|
||||||
|
# if depends.check_curses():
|
||||||
print('Running with curses')
|
print('Running with curses')
|
||||||
import bitmessagecurses
|
import bitmessagecurses
|
||||||
bitmessagecurses.runwrapper()
|
bitmessagecurses.runwrapper()
|
||||||
else:
|
else:
|
||||||
shared.config.remove_option('bitmessagesettings', 'dontconnect')
|
shared.config.remove_option('bitmessagesettings', 'dontconnect')
|
||||||
|
|
||||||
if daemon:
|
|
||||||
with shared.printLock:
|
|
||||||
print('Running as a daemon. The main program should exit this thread.')
|
|
||||||
else:
|
|
||||||
with shared.printLock:
|
|
||||||
print('Running as a daemon. You can use Ctrl+C to exit.')
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
|
|
||||||
|
def daemonize(self):
|
||||||
|
if os.fork():
|
||||||
|
exit(0)
|
||||||
|
os.umask(0)
|
||||||
|
os.setsid()
|
||||||
|
if os.fork():
|
||||||
|
exit(0)
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
si = file('/dev/null', 'r')
|
||||||
|
so = file('/dev/null', 'a+')
|
||||||
|
se = file('/dev/null', 'a+', 0)
|
||||||
|
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||||
|
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||||
|
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||||
|
|
||||||
|
def setSignalHandler(self):
|
||||||
|
signal.signal(signal.SIGINT, helper_generic.signal_handler)
|
||||||
|
signal.signal(signal.SIGTERM, helper_generic.signal_handler)
|
||||||
|
# signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print('Stopping Bitmessage Deamon.')
|
print('Stopping Bitmessage Deamon.')
|
||||||
|
|
|
@ -2,6 +2,7 @@ import socket
|
||||||
import sys
|
import sys
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
|
|
||||||
|
from debug import logger
|
||||||
import shared
|
import shared
|
||||||
|
|
||||||
def convertIntToString(n):
|
def convertIntToString(n):
|
||||||
|
@ -17,11 +18,10 @@ def convertIntToString(n):
|
||||||
def convertStringToInt(s):
|
def convertStringToInt(s):
|
||||||
return int(hexlify(s), 16)
|
return int(hexlify(s), 16)
|
||||||
|
|
||||||
|
|
||||||
def signal_handler(signal, frame):
|
def signal_handler(signal, frame):
|
||||||
|
logger.error("Got signal %i", signal)
|
||||||
if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'):
|
if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'):
|
||||||
shared.doCleanShutdown()
|
shared.doCleanShutdown()
|
||||||
sys.exit(0)
|
|
||||||
else:
|
else:
|
||||||
print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.'
|
print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.'
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,11 @@ class singleinstance:
|
||||||
"""
|
"""
|
||||||
def __init__(self, flavor_id="", daemon=False):
|
def __init__(self, flavor_id="", daemon=False):
|
||||||
self.initialized = False
|
self.initialized = False
|
||||||
|
self.counter = 0
|
||||||
self.daemon = daemon
|
self.daemon = daemon
|
||||||
self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id))
|
self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id))
|
||||||
|
|
||||||
if not self.daemon:
|
if not self.daemon and not shared.curses:
|
||||||
# Tells the already running (if any) application to get focus.
|
# Tells the already running (if any) application to get focus.
|
||||||
import bitmessageqt
|
import bitmessageqt
|
||||||
bitmessageqt.init()
|
bitmessageqt.init()
|
||||||
|
@ -55,6 +56,10 @@ class singleinstance:
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
if not self.initialized:
|
if not self.initialized:
|
||||||
return
|
return
|
||||||
|
self.counter += 1
|
||||||
|
if self.daemon and self.counter < 3:
|
||||||
|
# these are the two initial forks while daemonizing
|
||||||
|
return
|
||||||
print "Cleaning up lockfile"
|
print "Cleaning up lockfile"
|
||||||
try:
|
try:
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
|
|
Reference in New Issue
Block a user