<commit_before>import atexit
import logging
import os

import cherrypy
import ifcfg
import requests
from django.conf import settings
from kolibri.content.utils import paths

from .system import kill_pid, pid_exists

logger = logging.getLogger(__name__)

# Status codes for kolibri
STATUS_RUNNING = 0
STATUS_STOPPED = 1
STATUS_STARTING_UP = 4
STATUS_NOT_RESPONDING = 5
STATUS_FAILED_TO_START = 6
STATUS_UNCLEAN_SHUTDOWN = 7
STATUS_UNKNOWN_INSTANCE = 8
STATUS_SERVER_CONFIGURATION_ERROR = 9
STATUS_PID_FILE_READ_ERROR = 99
STATUS_PID_FILE_INVALID = 100
STATUS_UNKNOWN = 101

# Used to store PID and port number (both in foreground and daemon mode)
PID_FILE = os.path.join(os.environ['KOLIBRI_HOME'], "server.pid")

# Used to PID, port during certain exclusive startup process, before we fork
# to daemon mode
STARTUP_LOCK = os.path.join(os.environ['KOLIBRI_HOME'], "server.lock")

# This is a special file with daemon activity. It logs ALL stderr output, some
# might not have made it to the log file!
DAEMON_LOG = os.path.join(os.environ['KOLIBRI_HOME'], "server.log")

# Currently non-configurable until we know how to properly handle this
LISTEN_ADDRESS = "0.0.0.0"


class NotRunning(Exception):
    """
    Raised when server was expected to run, but didn't. Contains a status
    code explaining why.
    """

    def __init__(self, status_code):
        self.status_code = status_code
        super(NotRunning, self).__init__()


def start(port=8080):
    """
    Starts the server.

    :param: port: Port number (default: 8080)
    """

    # Write the new PID
    with open(PID_FILE, 'w') as f:
        f.write("%d\n%d" % (os.getpid(), port))

    # This should be run every time the server is started for now.
    # Events to trigger it are hard, because of copying a content folder into
    # ~/.kolibri, or deleting a channel DB on disk
    from kolibri.content.utils.annotation import update_channel_metadata
    update_channel_metadata()

    # This is also run every time the server is started to clear all the tasks
    # in the queue
    from kolibri.tasks.client import get_client
    get_client().clear(force=True)

    def rm_pid_file():
        os.unlink(PID_FILE)

    atexit.register(rm_pid_file)

    run_server(port=port)


def stop(pid=None, force=False):
    """
    Stops the kalite server, either from PID or through a management command

    :param args: List of options to parse to the django management command
    :raises: NotRunning
    """

    if not force:
        # Kill the KA lite server
        kill_pid(pid)
    else:
        try:
            pid, __ = _read_pid_file(PID_FILE)
            kill_pid(pid)
        except ValueError:
            logger.error("Could not find PID in .pid file\n")<commit_msg>Run ping command as daemonized thread during server start.<commit_after>import atexit
import logging
import os
import threading

import cherrypy
import ifcfg
import requests
from django.conf import settings
from django.core.management import ManagementUtility
from kolibri.content.utils import paths

from .system import kill_pid, pid_exists

logger = logging.getLogger(__name__)

# Status codes for kolibri
STATUS_RUNNING = 0
STATUS_STOPPED = 1
STATUS_STARTING_UP = 4
STATUS_NOT_RESPONDING = 5
STATUS_FAILED_TO_START = 6
STATUS_UNCLEAN_SHUTDOWN = 7
STATUS_UNKNOWN_INSTANCE = 8
STATUS_SERVER_CONFIGURATION_ERROR = 9
STATUS_PID_FILE_READ_ERROR = 99
STATUS_PID_FILE_INVALID = 100
STATUS_UNKNOWN = 101

# Used to store PID and port number (both in foreground and daemon mode)
PID_FILE = os.path.join(os.environ['KOLIBRI_HOME'], "server.pid")

# Used to PID, port during certain exclusive startup process, before we fork
# to daemon mode
STARTUP_LOCK = os.path.join(os.environ['KOLIBRI_HOME'], "server.lock")

# This is a special file with daemon activity. It logs ALL stderr output, some
# might not have made it to the log file!
DAEMON_LOG = os.path.join(os.environ['KOLIBRI_HOME'], "server.log")

# Currently non-configurable until we know how to properly handle this
LISTEN_ADDRESS = "0.0.0.0"


class NotRunning(Exception):
    """
    Raised when server was expected to run, but didn't. Contains a status
    code explaining why.
    """

    def __init__(self, status_code):
        self.status_code = status_code
        super(NotRunning, self).__init__()


def start(port=8080):
    """
    Starts the server.

    :param: port: Port number (default: 8080)
    """

    # start the pingback thread
    PingbackThread.start_command()

    # Write the new PID
    with open(PID_FILE, 'w') as f:
        f.write("%d\n%d" % (os.getpid(), port))

    # This should be run every time the server is started for now.
    # Events to trigger it are hard, because of copying a content folder into
    # ~/.kolibri, or deleting a channel DB on disk
    from kolibri.content.utils.annotation import update_channel_metadata
    update_channel_metadata()

    # This is also run every time the server is started to clear all the tasks
    # in the queue
    from kolibri.tasks.client import get_client
    get_client().clear(force=True)

    def rm_pid_file():
        os.unlink(PID_FILE)

    atexit.register(rm_pid_file)

    run_server(port=port)


class PingbackThread(threading.Thread):

    @classmethod
    def start_command(cls):
        thread = cls()
        thread.daemon = True
        thread.start()

    def run(self):
        command = ManagementUtility().fetch_command("ping")
        command.execute(server="http://telemetry.learningequality.org/api/v1/pingback", interval=0.2, checkrate=0.1)


def stop(pid=None, force=False):
    """
    Stops the kalite server, either from PID or through a management command

    :param args: List of options to parse to the django management command
    :raises: NotRunning
    """

    if not force:
        # Kill the KA lite server
        kill_pid(pid)
    else:
        try:
            pid, __ = _read_pid_file(PID_FILE)
            kill_pid(pid)
        except ValueError:
            logger.error("Could not find PID in .pid file\n")
{'fraction_non_alphanumeric': 0.0828775070445881, 'fraction_numerical': 0.010111055859439748, 'mean_word_length': 3.443298969072165, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6402140', 'n_tokens_mistral': 1943, 'n_tokens_neox': 1857, 'n_words': 615}