Browse Source

Adding SABnzbdHelper service for restarting SABnzbd when it runs as a Windows Service.

MailSlot.py is used by both services.
tags/0.6.0
ShyPike 15 years ago
parent
commit
ae28a79b8a
  1. 122
      SABHelper.py
  2. 13
      SABnzbd.py
  3. 130
      sabnzbd/utils/mailslot.py

122
SABHelper.py

@ -0,0 +1,122 @@
#!/usr/bin/python -OO
# Copyright 2008-2010 The SABnzbd-Team <team@sabnzbd.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys
if sys.version_info < (2,4):
print "Sorry, requires Python 2.4 or higher."
sys.exit(1)
import logging
import logging.handlers
import os
import getopt
import signal
import glob
import socket
import platform
import time
import subprocess
#------------------------------------------------------------------------------
try:
import win32api, win32file
import win32serviceutil, win32evtlogutil, win32event, win32service, pywintypes
except ImportError:
if sabnzbd.WIN32:
print "Sorry, requires Python module PyWin32."
sys.exit(1)
from sabnzbd.utils.mailslot import MailSlot
#------------------------------------------------------------------------------
WIN_SERVICE = None
#------------------------------------------------------------------------------
def main():
mail = MailSlot()
if not mail.create(200):
return '- Cannot create Mailslot'
while True:
msg = mail.receive()
if msg == 'restart':
time.sleep(1.0)
res = subprocess.Popen('net start SABnzbd', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.read()
rc = win32event.WaitForMultipleObjects((WIN_SERVICE.hWaitStop,
WIN_SERVICE.overlapped.hEvent), 0, 500)
if rc == win32event.WAIT_OBJECT_0:
mail.disconnect()
return ''
#####################################################################
#
# Windows Service Support
#
import servicemanager
class SABnzbdHelper(win32serviceutil.ServiceFramework):
""" Win32 Service Handler """
_svc_name_ = 'SABnzbdHelper'
_svc_display_name_ = 'SABnzbd Binary Newsreader (Helper)'
_svc_deps_ = ["EventLog", "Tcpip"]
_svc_description_ = 'Automated downloading from Usenet. ' \
'This service helps SABnzbd to restart itself.'
def __init__(self, args):
global WIN_SERVICE
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.overlapped = pywintypes.OVERLAPPED()
self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None)
WIN_SERVICE = self
def SvcDoRun(self):
msg = 'SABnzbdHelper-service'
self.Logger(servicemanager.PYS_SERVICE_STARTED, msg + ' has started')
res = main()
self.Logger(servicemanager.PYS_SERVICE_STOPPED, msg + ' has stopped' + res)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def Logger(self, state, msg):
win32evtlogutil.ReportEvent(self._svc_display_name_,
state, 0,
servicemanager.EVENTLOG_INFORMATION_TYPE,
(self._svc_name_, unicode(msg)))
def ErrLogger(self, msg, text):
win32evtlogutil.ReportEvent(self._svc_display_name_,
servicemanager.PYS_SERVICE_STOPPED, 0,
servicemanager.EVENTLOG_ERROR_TYPE,
(self._svc_name_, unicode(msg)),
unicode(text))
#####################################################################
#
# Platform specific startup code
#
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(SABnzbdHelper, argv=sys.argv)

13
SABnzbd.py

@ -97,7 +97,10 @@ try:
import win32api
import win32serviceutil, win32evtlogutil, win32event, win32service, pywintypes
win32api.SetConsoleCtrlHandler(sabnzbd.sig_handler, True)
from sabnzbd.utils.mailslot import MailSlot
except ImportError:
class MailSlot:
pass
if sabnzbd.WIN32:
print "Sorry, requires Python module PyWin32."
sys.exit(1)
@ -1290,8 +1293,14 @@ def main():
if pid == 0:
os.execv(sys.executable, args)
elif sabnzbd.WIN_SERVICE:
# Hope for the service manager to restart us
sys.exit(1)
logging.info('Asking the SABnzbdHelper service for a restart')
mail = MailSlot()
if mail.connect():
mail.send('restart')
mail.disconnect()
else:
logging.error('Cannot reach the SABnzbdHelper service')
return
else:
cherrypy.engine._do_execv()

130
sabnzbd/utils/mailslot.py

@ -0,0 +1,130 @@
#!/usr/bin/python -OO
# Copyright 2008-2010 The SABnzbd-Team <team@sabnzbd.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
sabnzbd.mailslot - Mailslot communication
"""
import os
from win32file import GENERIC_WRITE, FILE_SHARE_READ, \
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL
from ctypes import c_uint, c_buffer, byref, sizeof, windll
# Win32API Shortcuts
CreateFile = windll.kernel32.CreateFileA
ReadFile = windll.kernel32.ReadFile
WriteFile = windll.kernel32.WriteFile
CloseHandle = windll.kernel32.CloseHandle
CreateMailslot = windll.kernel32.CreateMailslotA
class MailSlot(object):
""" Simple Windows Mailslot communication
"""
slotname = r'mailslot\SABnzbd\ServiceSlot'
def __init__(self):
self.handle = -1
def create(self, timeout):
""" Create the Mailslot, after this only receiving is possible
timeout is the read timeout used for receive calls.
"""
slot = r'\\.\%s' % MailSlot.slotname
self.handle = CreateMailslot(slot, 50, timeout, None)
return self.handle != -1
def connect(self):
""" Connect to existing Mailslot so that writing is possible
"""
slot = r'\\%s\%s' % (os.environ['COMPUTERNAME'], MailSlot.slotname)
self.handle = CreateFile(slot, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
return self.handle != -1
def disconnect(self):
""" Disconnect from Mailslot
"""
if self.handle != -1:
CloseHandle(self.handle)
self.handle = -1
return True
def send(self, command):
""" Send one message to Mailslot
"""
if self.handle == -1:
return False
w = c_uint()
return bool(WriteFile(self.handle, command, len(command), byref(w), 0))
def receive(self):
""" Receive one message from Mailslot
"""
r = c_uint()
buf = c_buffer(1024)
if ReadFile(self.handle, buf, sizeof(buf), byref(r), 0):
return buf.value
else:
return None
#------------------------------------------------------------------------------
# Simple test
#
# First start "mailslot.py server" in one process,
# Then start "mailslot.py client" in another.
# Five "restart" and one "stop" will be send from client to server.
# The server will stop after receiving "stop"
if __name__ == '__main__':
import sys
from time import sleep
if not __debug__:
print 'Run this test in non-optimized mode'
exit(1)
if len(sys.argv) > 1 and 'server' in sys.argv[1]:
recv = MailSlot()
ret = recv.create(2)
assert ret, 'Failed to create'
while True:
data = recv.receive()
if data is not None:
print data
if data.startswith('stop'):
break
sleep(2.0)
recv.disconnect()
elif len(sys.argv) > 1 and 'client' in sys.argv[1]:
send = MailSlot()
ret = send.connect()
assert ret, 'Failed to connect'
for n in xrange(5):
ret = send.send('restart')
assert ret, 'Failed to send'
sleep(2.0)
send.send('stop')
assert ret, 'Failed to send'
send.disconnect()
else:
print 'Usage: mailslot.py server|client'
Loading…
Cancel
Save