7 changed files with 64 additions and 397 deletions
@ -1,154 +0,0 @@ |
|||||
#!/usr/bin/python3 -OO |
|
||||
# Copyright 2007-2020 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] < (2, 6) or sys.version_info[:2] >= (3, 0): |
|
||||
print("Sorry, requires Python 2.6 or 2.7.") |
|
||||
sys.exit(1) |
|
||||
|
|
||||
import time |
|
||||
import subprocess |
|
||||
|
|
||||
|
|
||||
try: |
|
||||
import win32api |
|
||||
import win32file |
|
||||
import win32serviceutil |
|
||||
import win32evtlogutil |
|
||||
import win32event |
|
||||
import win32service |
|
||||
import pywintypes |
|
||||
except ImportError: |
|
||||
print("Sorry, requires Python module PyWin32.") |
|
||||
sys.exit(1) |
|
||||
|
|
||||
from util.mailslot import MailSlot |
|
||||
from util.apireg import del_connection_info, set_connection_info |
|
||||
|
|
||||
|
|
||||
WIN_SERVICE = None |
|
||||
|
|
||||
|
|
||||
def HandleCommandLine(allow_service=True): |
|
||||
""" Handle command line for a Windows Service |
|
||||
Prescribed name that will be called by Py2Exe. |
|
||||
You MUST set 'cmdline_style':'custom' in the package.py! |
|
||||
""" |
|
||||
win32serviceutil.HandleCommandLine(SABHelper) |
|
||||
|
|
||||
|
|
||||
def start_sab(): |
|
||||
return subprocess.Popen('net start SABnzbd', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) |
|
||||
|
|
||||
|
|
||||
def main(): |
|
||||
|
|
||||
mail = MailSlot() |
|
||||
if not mail.create(10): |
|
||||
return '- Cannot create Mailslot' |
|
||||
|
|
||||
active = False # SABnzbd should be running |
|
||||
counter = 0 # Time allowed for SABnzbd to be silent |
|
||||
while True: |
|
||||
msg = mail.receive() |
|
||||
if msg: |
|
||||
if msg == 'restart': |
|
||||
time.sleep(1.0) |
|
||||
counter = 0 |
|
||||
del_connection_info(user=False) |
|
||||
start_sab() |
|
||||
elif msg == 'stop': |
|
||||
active = False |
|
||||
del_connection_info(user=False) |
|
||||
elif msg == 'active': |
|
||||
active = True |
|
||||
counter = 0 |
|
||||
elif msg.startswith('api '): |
|
||||
active = True |
|
||||
counter = 0 |
|
||||
_cmd, url = msg.split() |
|
||||
if url: |
|
||||
set_connection_info(url.strip(), user=False) |
|
||||
|
|
||||
if active: |
|
||||
counter += 1 |
|
||||
if counter > 120: # 120 seconds |
|
||||
counter = 0 |
|
||||
start_sab() |
|
||||
|
|
||||
rc = win32event.WaitForMultipleObjects((WIN_SERVICE.hWaitStop, |
|
||||
WIN_SERVICE.overlapped.hEvent), 0, 1000) |
|
||||
if rc == win32event.WAIT_OBJECT_0: |
|
||||
del_connection_info(user=False) |
|
||||
mail.disconnect() |
|
||||
return '' |
|
||||
|
|
||||
|
|
||||
############################################################################## |
|
||||
# Windows Service Support |
|
||||
############################################################################## |
|
||||
import servicemanager |
|
||||
|
|
||||
|
|
||||
class SABHelper(win32serviceutil.ServiceFramework): |
|
||||
""" Win32 Service Handler """ |
|
||||
|
|
||||
_svc_name_ = 'SABHelper' |
|
||||
_svc_display_name_ = 'SABnzbd 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() # @UndefinedVariable |
|
||||
self.overlapped.hEvent = win32event.CreateEvent(None, 0, 0, None) |
|
||||
WIN_SERVICE = self |
|
||||
|
|
||||
def SvcDoRun(self): |
|
||||
msg = 'SABHelper-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_, str(msg))) |
|
||||
|
|
||||
def ErrLogger(self, msg, text): |
|
||||
win32evtlogutil.ReportEvent(self._svc_display_name_, |
|
||||
servicemanager.PYS_SERVICE_STOPPED, 0, |
|
||||
servicemanager.EVENTLOG_ERROR_TYPE, |
|
||||
(self._svc_name_, str(msg)), |
|
||||
str(text)) |
|
||||
|
|
||||
|
|
||||
############################################################################## |
|
||||
# Platform specific startup code |
|
||||
############################################################################## |
|
||||
if __name__ == '__main__': |
|
||||
|
|
||||
win32serviceutil.HandleCommandLine(SABHelper, argv=sys.argv) |
|
@ -1,125 +0,0 @@ |
|||||
#!/usr/bin/python3 -OO |
|
||||
# Copyright 2007-2020 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 sys |
|
||||
from time import sleep |
|
||||
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.CreateFileW |
|
||||
ReadFile = windll.kernel32.ReadFile |
|
||||
WriteFile = windll.kernel32.WriteFile |
|
||||
CloseHandle = windll.kernel32.CloseHandle |
|
||||
CreateMailslot = windll.kernel32.CreateMailslotW |
|
||||
|
|
||||
|
|
||||
class MailSlot: |
|
||||
""" 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, 0, timeout, None) |
|
||||
|
|
||||
return self.handle != -1 |
|
||||
|
|
||||
def connect(self): |
|
||||
""" Connect to existing Mailslot so that writing is possible """ |
|
||||
slot = r"\\.\%s" % 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 in bytes to Mailslot """ |
|
||||
if self.handle == -1: |
|
||||
return False |
|
||||
w = c_uint() |
|
||||
command_bytes = command.encode("utf-8") |
|
||||
return bool(WriteFile(self.handle, command_bytes, len(command_bytes), byref(w), 0)) |
|
||||
|
|
||||
def receive(self): |
|
||||
""" Receive one message from Mailslot, convert back to unicode """ |
|
||||
r = c_uint() |
|
||||
buf = c_buffer(1024) |
|
||||
if ReadFile(self.handle, buf, sizeof(buf), byref(r), 0): |
|
||||
return buf.value.decode("utf-8") |
|
||||
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__": |
|
||||
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(1.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 range(5): |
|
||||
ret = send.send("restart") |
|
||||
assert ret, "Failed to send" |
|
||||
sleep(1.0) |
|
||||
send.send("stop") |
|
||||
assert ret, "Failed to send" |
|
||||
send.disconnect() |
|
||||
|
|
||||
else: |
|
||||
print("Usage: mailslot.py server|client") |
|
Loading…
Reference in new issue