# 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 3 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, see <http://www.gnu.org/licenses/>. import argparse import os import signal import sys import traceback from PyQt5.QtCore import QCoreApplication, QTimer from .shared.server import Server from .shared.utils import start_logging class DedicatedServer(Server): """ This is the dedicated server. It can be invoked from the command line. It requires only PyQt5 and should be invoked from Python 3. The dedicated server should be used when the integrated doesn't fulfil the user's needs. """ def __init__(self, level, parent=None): # Get the path to the log file log_dir = os.path.join(os.path.dirname(__file__), "logs") log_dir = os.path.abspath(log_dir) if not os.path.exists(log_dir): os.makedirs(log_dir) log_path = os.path.join(log_dir, "idarling.%s.log" % os.getpid()) logger = start_logging(log_path, "IDArling.Server", level) Server.__init__(self, logger, parent) def server_file(self, filename): """ This function returns the absolute path to a server's file. It should be located within a files/ subdirectory of the current directory. """ files_dir = os.path.join(os.path.dirname(__file__), "files") files_dir = os.path.abspath(files_dir) if not os.path.exists(files_dir): os.makedirs(files_dir) return os.path.join(files_dir, filename) def start(args): app = QCoreApplication(sys.argv) sys.excepthook = traceback.print_exception server = DedicatedServer(args.level) server.SNAPSHOT_INTERVAL = args.interval server.start(args.host, args.port, args.ssl) # Allow the use of Ctrl-C to stop the server def sigint_handler(_, __): server.stop() app.exit(0) signal.signal(signal.SIGINT, sigint_handler) # This timer gives the application a chance to be interrupted every 50 ms # even if it stuck in a loop or something def safe_timer(timeout, func, *args, **kwargs): def timer_event(): try: func(*args, **kwargs) finally: QTimer.singleShot(timeout, timer_event) QTimer.singleShot(timeout, timer_event) safe_timer(50, lambda: None) return app.exec_() def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument( "--help", action="help", help="show this help message and exit" ) # Users can specify the host and port to start the server on parser.add_argument( "-h", "--host", type=str, default="127.0.0.1", help="the hostname to start listening on", ) parser.add_argument( "-p", "--port", type=int, default=31013, help="the port to start listening on", ) # Users must specify the path to the certificate chain and the # corresponding private key of the server, or disable SSL altogether. security = parser.add_mutually_exclusive_group(required=True) security.add_argument( "--ssl", type=str, nargs=2, metavar=("fullchain.pem", "privkey.pem"), help="the certificate and private key files", ) security.add_argument( "--no-ssl", action="store_true", help="disable SSL (not recommended)" ) # Users can also change the logging level if the they want some debug levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE"] parser.add_argument( "-l", "--level", type=str, choices=levels, default="INFO", help="the log level", ) # Interval in ticks between database snapshot parser.add_argument( "-i", "--interval", type=int, default=0, help="database snapshot interval", ) start(parser.parse_args())