Commit 2e1b6589 authored by mitshel's avatar mitshel
Browse files

Программа sopdsd.py теперь является "двойным" демоном и запускает два процесса-демона

сканирование и http-сервер
parent e8e7c8f2
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -124,13 +124,13 @@ book_shelf = yes
# По умолчанию logfile = sopds.log
# loglevel может быть одним из следующих значений: debug, info, warning, error, critical, none. 
# По умолчанию loglevel=info
logfile=sopds.log
logfile=sopds-scan.log
loglevel=info

[daemon]
# pid_file должен содержать путь к pid-файлу процесса. Для демона sopdsd.py по указанному пути должен быть доступ на запись
[scand]
# pid_file должен содержать путь к pid-файлу процесса OPDS-сканера. Для демона sopdsd.py по указанному пути должен быть доступ на запись
# по умолчанию pid_file=/tmp/sopds.pid
pid_file = /tmp/sopds.pid
pid_file = /tmp/sopds-scan.pid

# scan_day_of_week содержит день недели (1=пн, 7=вс, 0=каждый день) когда должен запускаться процесс сканирования
# по умолчанию scan_day_of_week=0
@@ -153,7 +153,11 @@ scan_interval = 360
scan_on_start = yes

[httpd]
# Если server = yes, то будет демон sopdsd.py запустит встроенный OPDS-сервер
# pid_file должен содержать путь к pid-файлу процесса OPDS-сервера. Для демона sopdsd.py по указанному пути должен быть доступ на запись
# по умолчанию pid_file=/tmp/sopds-http.pid
pid_file = /tmp/sopds-http.pid

# Если server = yes, то демон sopdsd.py запустит встроенный HTTP-OPDS-сервер
# по умолчнию server = yes
server = yes

@@ -174,6 +178,10 @@ auth = yes
# OPDS-сервере
accounts = user:pass user1:pass1

# Параметр logfile задает имя файла, куда будут складываться логи от HTTP-демона (путь задавать не нужно - логи будут находится в папке logs)
# По умолчанию logfile = access.log
logfile = sopds-http.log

[site]
id=http://sopds.ru/
title=SOPDS.RU | OPDS Catalog
+385 −0

File changed.

Preview size limit exceeded, changes collapsed.

+5 −1
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ class cfgreader:
       self.SITE_EMAIL=config.get(CFG_S_SITE,'email')
       self.SITE_MAINTITLE=config.get(CFG_S_SITE,'main_title')

       CFG_S_DAEMON='daemon'
       CFG_S_DAEMON='scand'
       self.SCAN_ON_START=config.getdefault_bool(CFG_S_DAEMON,'scan_on_start',True)
       self.PID_FILE=config.getdefault(CFG_S_DAEMON,'pid_file',r'/tmp/sopds.pid')
       self.DAY_OF_WEEK=config.getdefault_int(CFG_S_DAEMON,'scan_day_of_week',0)
@@ -157,8 +157,12 @@ class cfgreader:
          self.SCAN_TIMES=[self.SCAN_HOUR*60+self.SCAN_MIN]

       CFG_S_HTTPD='httpd'
       self.HTTPD_PID_FILE=config.getdefault(CFG_S_HTTPD,'pid_file',r'/tmp/sopds-http.pid')
       self.SERVER=config.getdefault_bool(CFG_S_HTTPD,'server',True)
       self.PORT=config.getdefault_int(CFG_S_HTTPD,'port',8081)
       self.BIND_ADDRESS=config.getdefault(CFG_S_HTTPD,'bind_address','0.0.0.0')
       self.AUTH=config.getdefault_bool(CFG_S_HTTPD,'auth',False)
       self.ACCOUNTS=config.getdefault(CFG_S_HTTPD,'accounts','')
       httpd_logfile=config.getdefault(CFG_S_HTTPD,'logfile','access.log')
       self.HTTPD_LOGFILE=os.path.join(LOG_PATH,httpd_logfile)
+133 −37
Original line number Diff line number Diff line
@@ -3,19 +3,28 @@
import logging
import sys, os, time, atexit
from signal import SIGTERM
from multiprocessing import Process

import sopdscfg
import sopdserve
from sopdscan import opdsScanner

typeSCAND = 0
typeHTTPD = 1
 
class Daemon(object):
    """
    Subclass Daemon class and override the run() method.
    """
    def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
    def __init__(self, scan_pidfile, http_pidfile, stdin='/dev/null', scan_stdout='/dev/null', http_stdout='/dev/null', scan_stderr='/dev/null', http_stderr='/dev/null'):
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.pidfile = pidfile
        self.scan_stdout = scan_stdout
        self.scan_stderr = scan_stderr
        self.http_stdout = http_stdout
        self.http_stderr = http_stderr
        self.scan_pidfile  = scan_pidfile
        self.http_pidfile  = http_pidfile
        self.daemon_type = 0
 
    def daemonize(self):
        """
@@ -36,18 +45,38 @@ class Daemon(object):
        os.setsid()
        os.umask(0)
 
        # Do second fork.
        # Do second fork (SCAN DAEMON)
        try:
            pid = os.fork()
            if pid > 0:
                # Exit from second parent.
                sys.exit(0)
        except OSError as e:
            message = "Fork #2 failed: {}\n".format(e)
            message = "Fork #2 (scand) failed: {}\n".format(e)
            sys.stderr.write(message)
            sys.exit(1)

        # Do third fork (HTTPD DAEMON)
        try: 
            pid = os.fork()
        except OSError as e:
            message = "Fork #3 (httpd) failed: {}. Exitting\n".format(e)
            sys.stderr.write(message)
            sys.exit(1)

        print('daemon going to background, PID: {}'.format(os.getpid(),end="\r"))
 
        if pid>0:
           print('SOPDS HTTP Daemon going to background, PID: {}'.format(os.getpid(),end="\r"))
           self.daemon_type=typeHTTPD
           self.pidfile=self.http_pidfile
           self.stdout=self.http_stdout
           self.stderr=self.http_stderr
        else:
           print('SOPDS SCAN Daemon going to background, PID: {}'.format(os.getpid(),end="\r"))
           self.daemon_type=typeSCAND
           self.pidfile=self.scan_pidfile
           self.stdout=self.scan_stdout
           self.stderr=self.scan_stderr
 
        # Redirect standard file descriptors.
        sys.stdout.flush()
@@ -75,17 +104,32 @@ class Daemon(object):
        """
        # Check pidfile to see if the daemon already runs.
        try:
            pf = open(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf = open(self.scan_pidfile,'r')
            scan_pid = int(pf.read().strip())
            pf.close()
        except IOError:
            scan_pid = None

        try:
            pf = open(self.http_pidfile,'r')
            http_pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None
            http_pid = None

        if pid:
            message = "Pidfile {} already exist. Daemon already running?\n".format(self.pidfile)
 
        if scan_pid:
            message = "Pidfile {} for SOPDS SCAN daemon already exist. Daemon already running?\n".format(self.scan_pidfile)
            sys.stderr.write(message)

        if http_pid:
            message = "Pidfile {} for SOPDS HTTP daemon already exist. Daemon already running?\n".format(self.http_pidfile)
            sys.stderr.write(message)

        if scan_pid or http_pid:
             sys.exit(1)

 
        # Start daemon.
        self.daemonize()
        self.run()
@@ -95,52 +139,96 @@ class Daemon(object):
        Get status of daemon.
        """
        try:
            pf = open(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf = open(self.scan_pidfile,'r')
            scan_pid = int(pf.read().strip())
            pf.close()
        except IOError:
            message = "There is not PID file. Daemon already running?\n"
            message = "There is not PID file {}. SOPDS SCAN Daemon already running?\n".format(self.scan_pidfile)
            sys.stderr.write(message)
            scan_pid = None

        try:
            pf = open(self.http_pidfile,'r')
            http_pid = int(pf.read().strip())
            pf.close()
        except IOError:
            message = "There is not PID file {}. SOPDS HTTP Daemon already running?\n".format(self.http_pidfile)
            sys.stderr.write(message)
            http_pid=None

        if not (scan_pid and http_pid):
            sys.exit(1)
 
        try:
            procfile = open("/proc/{}/status".format(pid), 'r')
            procfile = open("/proc/{}/status".format(scan_pid), 'r')
            procfile.close()
            message = "There is a SOPDS SCAN process with the PID {}\n".format(scan_pid)
            sys.stdout.write(message)
        except IOError:
            message = "There is not a SOPDS SCAN process with the PID {}\n".format(self.scan_pid)
            sys.stdout.write(message)

        try:
            procfile = open("/proc/{}/status".format(http_pid), 'r')
            procfile.close()
            message = "There is a process with the PID {}\n".format(pid)
            message = "There is a SOPDS HTTP process with the PID {}\n".format(http_pid)
            sys.stdout.write(message)
        except IOError:
            message = "There is not a process with the PID {}\n".format(self.pidfile)
            message = "There is not a SOPDS HTTP process with the PID {}\n".format(self.http_pid)
            sys.stdout.write(message)

 
    def stop(self):
        """
        Stop the daemon.
        """
        # Get the pid from pidfile.
        try:
            pf = open(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf = open(self.scan_pidfile,'r')
            scan_pid = int(pf.read().strip())
            pf.close()
        except IOError as e:
            message = str(e) + "\nDaemon not running?\n"
            message = str(e) + "\n SOPDS SCAN Daemon not running?\n"
            sys.stderr.write(message)
            sys.exit(1)
            scan_pid = None

        try:
            pf = open(self.http_pidfile,'r')
            http_pid = int(pf.read().strip())
            pf.close()
        except IOError as e:
            message = str(e) + "\n SOPDS HTTP Daemon not running?\n"
            sys.stderr.write(message)
            http_pid = None

        # Try killing daemon process.
        if scan_pid:
           try:
            os.kill(pid, SIGTERM)
               os.kill(scan_pid, SIGTERM)
               time.sleep(1)
           except OSError as e:
               print(str(e))
            sys.exit(1)

        if http_pid:
           try:
            if os.path.exists(self.pidfile):
                os.remove(self.pidfile)
               os.kill(http_pid, SIGTERM)
               time.sleep(1)
           except OSError as e:
               print(str(e))

        try:
            if os.path.exists(self.scan_pidfile):
                os.remove(self.scan_pidfile)
        except IOError as e:
            message = str(e) + "\nCan not remove pid file {}".format(self.pidfile)
            message = str(e) + "\nCan not remove pid file {}".format(self.scan_pidfile)
            sys.stderr.write(message)

        try:
            if os.path.exists(self.http_pidfile):
                os.remove(self.http_pidfile)
        except IOError as e:
            message = str(e) + "\nCan not remove pid file {}".format(self.scan_pidfile)
            sys.stderr.write(message)
            sys.exit(1)
 
    def restart(self):
        """
@@ -172,7 +260,7 @@ class opdsDaemon(Daemon):

        self.scanner=opdsScanner(self.cfg, self.logger)

        Daemon.__init__(self, self.cfg.PID_FILE, self.cfg.LOGFILE,self.cfg.LOGFILE,self.cfg.LOGFILE)
        Daemon.__init__(self, self.cfg.PID_FILE, self.cfg.HTTPD_PID_FILE, '/dev/null', self.cfg.LOGFILE,self.cfg.HTTPD_LOGFILE,self.cfg.LOGFILE,self.cfg.HTTPD_LOGFILE)

    def start(self):
        self.logger.info('sopdsDaemon start()...')
@@ -194,7 +282,7 @@ class opdsDaemon(Daemon):
        self.logger.info('sopdsDaemon restart()...')
        Daemon.restart(self)

    def run(self):
    def run_scanner(self):
        self.cfg.parse()
        self.fh.setLevel(self.cfg.LOGLEVEL)
        self.logger.info('sopdsDaemon entering in main loop...')
@@ -209,6 +297,14 @@ class opdsDaemon(Daemon):
            self.start_scan=True
            time.sleep(30)

    def run_server(self):
        sopdserve.start_server(self.cfg)

    def run(self):
        if self.daemon_type == typeSCAND:
           self.run_scanner()
        else:
           self.run_server()
 
if __name__ == "__main__":

Loading