* Added daemonizer for linux, adapted from old uds actor to work with

python 3 & 2.7, and a few fixes
This commit is contained in:
Adolfo Gómez García 2014-11-12 08:12:18 +01:00
parent 7a3692cc43
commit 74781c14c0
2 changed files with 186 additions and 14 deletions

View File

@ -36,6 +36,7 @@ from PyQt4 import QtGui
from PyQt4 import QtCore
import cPickle
from udsactor import ipc
from udsactor import utils
from udsactor.log import logger
@ -49,19 +50,27 @@ class MessagesProcessor(QtCore.QThread):
def __init__(self):
super(self.__class__, self).__init__()
self.ipc = ipc.ClientIPC(39188)
self.ipc.start()
try:
self.ipc = ipc.ClientIPC(39188)
self.ipc.start()
except Exception:
self.ipc = None
self.running = False
def stop(self):
self.running = False
self.ipc.stop()
if self.ipc:
self.ipc.stop()
def requestInformation(self):
info = self.ipc.requestInformation()
logger.debug('Request information: {}'.format(info))
if self.ipc:
info = self.ipc.requestInformation()
logger.debug('Request information: {}'.format(info))
def run(self):
if self.ipc is None:
return
self.running = True
while self.running and self.ipc.running:
try:
@ -80,11 +89,11 @@ class MessagesProcessor(QtCore.QThread):
self.information.emit(cPickle.loads(data))
except Exception as e:
try:
logger.error('Got error on IPC thread {}'.format(e))
logger.error('Got error on IPC thread {}'.format(utils.exceptionToMessage(e)))
except:
logger.error('Got error on IPC thread (and unicode error??)')
if self.ipc.running is False and self.running == True:
if self.ipc.running is False and self.running is True:
logger.warn('Lost connection with Service, closing program')
self.exit.emit()
@ -114,20 +123,19 @@ class SystemTrayIconApp(QtGui.QSystemTrayIcon):
def displayMessage(self, message):
self.counter += 1
print message.toUtf8(), '--', self.counter
print(message.toUtf8(), '--', self.counter)
def executeScript(self, message):
self.counter += 1
print message.toUtf8(), '--', self.counter
print(message.toUtf8(), '--', self.counter)
def loggof(self):
self.counter += 1
print "Loggof --", self.counter
print("Loggof --", self.counter)
def information(self, info):
self.counter += 1
print "Information:", info, '--', self.counter
print("Information:", info, '--', self.counter)
def quit(self):
self.ipc.stop()
@ -138,8 +146,7 @@ if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
QtGui.QMessageBox.critical(None, "Systray",
"I couldn't detect any system tray on this system.")
QtGui.QMessageBox.critical(None, "Systray", "I couldn't detect any system tray on this system.")
sys.exit(1)
style = app.style()

View File

@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@author: : http://www.jejik.com/authors/sander_marechal/
@see: : http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
'''
from __future__ import unicode_literals
import sys
import os
import time
import atexit
from signal import SIGTERM
class Daemon:
"""
A generic daemon class.
Usage: subclass the Daemon class and override the run() method
"""
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile
def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError as e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError as e:
sys.stderr.write("fork #2 failed: {} ({})\n".format(e.errno, e.strerror))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(self.stdin, 'r')
so = open(self.stdout, 'a+')
se = open(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
with open(self.pidfile, 'w+') as f:
f.write("%s\n" % pid)
def delpid(self):
os.remove(self.pidfile)
def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = open(self.pidfile, 'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if pid is None:
sys.stderr.write("pidfile {} does not exist. Daemon not running?\n".format(self.pidfile))
return # not an error in a restart
# Try killing the daemon process
try:
while True:
os.kill(pid, SIGTERM)
time.sleep(1)
except OSError as err:
if err.errno == 3: # No such process
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
sys.stderr.write(err)
sys.exit(1)
def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()
def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""