<commit_before>"""Start Websocket server as main application."""
from configparser import ConfigParser
from logging.config import fileConfig
from os import path
from signal import signal
from signal import SIGTERM
import logging
import os
import sys

from autobahn.asyncio.websocket import WebSocketServerFactory
from ZODB import DB
from adhocracy.websockets.server import ClientCommunicator
from zodburi import resolve_uri
import asyncio


# FIXME make the port configurable
PORT = 8080
# FIXME make pid file path configurable
PID_FILE = 'var/WS_SERVER.pid'

logger = logging.getLogger(__name__)


def main(args=[]) -> int:
    """Start WebSockets server.

    :param args: the command-line arguments -- we expect just one: the
                 config file to use
    :return: 0 on success
    """
    if not args:
        args = sys.argv[1:]
    if len(args) != 1:
        raise ValueError('Expected 1 command-line argument (the config file), '
                         'but got {}'.format(len(args)))
    config_file = args[0]
    fileConfig(config_file)
    config = _read_config(config_file)
    _check_and_write_pid_file()
    _register_sigterm_handler()
    _start_loop(config)


def _check_and_write_pid_file():
    if os.path.isfile(PID_FILE):
        raise RuntimeError('Pidfile already exists: ' + PID_FILE)
    pid = os.getpid()
    pidfile = open(PID_FILE, 'w')
    pidfile.write('%s\n' % pid)
    pidfile.close


def _register_sigterm_handler():
    """Register handler for the SIGTERM signal ('kill' command).

    The new handler will remove the PID file and exit.
    """
    def sigterm_handler(sig, frame):
        logger.info('Kill signal (SIGTERM) received, exiting')
        _remove_pid_file()
        sys.exit()

    signal(SIGTERM, sigterm_handler)


def _start_loop(config: ConfigParser):
    try:
        connection = _get_zodb_connection(config)
        ClientCommunicator.zodb_connection = connection
        factory = WebSocketServerFactory('ws://localhost:{}'.format(PORT))
        factory.protocol = ClientCommunicator
        loop = asyncio.get_event_loop()
        coro = loop.create_server(factory, port=PORT)
        logger.debug('Started WebSocket server listening on port %i', PORT)
        server = loop.run_until_complete(coro)
        _run_loop_until_interrupted(loop, server)
    finally:
        logger.info('Stopped WebSocket server')
        _remove_pid_file()


def _remove_pid_file():
    if os.path.isfile(PID_FILE):
        os.unlink(PID_FILE)


def _run_loop_until_interrupted(loop, server):
    try:
        loop.run_forever()
    except KeyboardInterrupt:<commit_msg>Make port and pid file path configurable<commit_after>"""Start Websocket server as main application."""
from configparser import ConfigParser
from logging.config import fileConfig
from os import path
from signal import signal
from signal import SIGTERM
import logging
import os
import sys

from autobahn.asyncio.websocket import WebSocketServerFactory
from ZODB import DB
from adhocracy.websockets.server import ClientCommunicator
from zodburi import resolve_uri
import asyncio


logger = logging.getLogger(__name__)


def main(args=[]) -> int:
    """Start WebSockets server.

    :param args: the command-line arguments -- we expect just one: the
                 config file to use
    :return: 0 on success
    """
    if not args:
        args = sys.argv[1:]
    if len(args) != 1:
        raise ValueError('Expected 1 command-line argument (the config file), '
                         'but got {}'.format(len(args)))
    config_file = args[0]
    fileConfig(config_file)
    config = _read_config(config_file)
    port = _read_config_variable_or_die(config, 'port', is_int=True)
    pid_file = _read_config_variable_or_die(config, 'pid_file')
    _check_and_write_pid_file(pid_file)
    _register_sigterm_handler(pid_file)
    _start_loop(config, port, pid_file)


def _read_config_variable_or_die(config: ConfigParser, name: str,
                                 is_int: bool=False):
    """Read a variable from the [websockets] section of `config`.

    :raise RuntimeError: if the variable does not exist or doesn't have the
                         expected type
    """
    result = config.get('websockets', name, fallback=None)
    if not result:
        raise RuntimeError('Config entry "{}" in [websockets] section '
                           'missing or empty'.format(name))
    if is_int:
        try:
            result = int(result)
        except ValueError:
            raise RuntimeError('Config entry "{}" in [websockets] section is '
                               'not an integer: {}'.format(name, result))
    return result


def _check_and_write_pid_file(pid_file: str):
    if os.path.isfile(pid_file):
        raise RuntimeError('Pidfile already exists: ' + pid_file)
    pid = os.getpid()
    pidfile = open(pid_file, 'w')
    pidfile.write('%s\n' % pid)
    pidfile.close


def _register_sigterm_handler(pid_file: str):
    """Register handler for the SIGTERM signal ('kill' command).

    The new handler will remove the PID file and exit.
    """
    def sigterm_handler(sig, frame):
        logger.info('Kill signal (SIGTERM) received, exiting')
        _remove_pid_file(pid_file)
        sys.exit()

    signal(SIGTERM, sigterm_handler)


def _start_loop(config: ConfigParser, port: int, pid_file: str):
    try:
        connection = _get_zodb_connection(config)
        ClientCommunicator.zodb_connection = connection
        factory = WebSocketServerFactory('ws://localhost:{}'.format(port))
        factory.protocol = ClientCommunicator
        loop = asyncio.get_event_loop()
        coro = loop.create_server(factory, port=port)
        logger.debug('Started WebSocket server listening on port %i', port)
        server = loop.run_until_complete(coro)
        _run_loop_until_interrupted(loop, server)
    finally:
        logger.info('Stopped WebSocket server')
        _remove_pid_file(pid_file)


def _remove_pid_file(pid_file: str):
    if os.path.isfile(pid_file):
        os.unlink(pid_file)


def _run_loop_until_interrupted(loop, server):
    try:
        loop.run_forever()
    except KeyboardInterrupt:
{'fraction_non_alphanumeric': 0.09139523578026251, 'fraction_numerical': 0.0022686760654675093, 'mean_word_length': 3.1590296495956873, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4550735', 'n_tokens_mistral': 1879, 'n_tokens_neox': 1816, 'n_words': 499}