"""
Python ProcPool plugin

Evennia contribution - Griatch 2012

This is a plugin for the Evennia services. It will make the service
and run_async in python_procpool.py available to the system.

To activate, add the following line to your settings file:

SERVER_SERVICES_PLUGIN_MODULES.append("contrib.procpools.python_procpool_plugin")

Next reboot the server and the new service will be available.

It is not recommended to use this with an SQLite3 database, at least
if you plan to do many out-of-process database writes. SQLite3 does
not work very well with a high frequency of off-process writes due to
file locking clashes. Test what works with your mileage.

"""
import os
import sys
from django.conf import settings


# Process Pool setup

# convenient flag to turn off process pool without changing settings
PROCPOOL_ENABLED = True
# relay process stdout to log (debug mode, very spammy)
PROCPOOL_DEBUG = False
# max/min size of the process pool. Will expand up to max limit on demand.
PROCPOOL_MIN_NPROC = 5
PROCPOOL_MAX_NPROC = 20
# maximum time (seconds) a process may idle before being pruned from
# pool (if pool bigger than minsize)
PROCPOOL_IDLETIME = 20
# after sending a command, this is the maximum time in seconds the process
# may run without returning. After this time the process will be killed. This
# can be seen as a fallback; the run_async method takes a keyword proc_timeout
# that will override this value on a per-case basis.
PROCPOOL_TIMEOUT = 10
# only change if the port clashes with something else on the system
PROCPOOL_PORT = 5001
# 0.0.0.0 means listening to all interfaces
PROCPOOL_INTERFACE = '127.0.0.1'
# user-id and group-id to run the processes as (for OS:es supporting this).
# If you plan to run unsafe code one could experiment with setting this
# to an unprivileged user.
PROCPOOL_UID = None
PROCPOOL_GID = None
# real path to a directory where all processes will be run. If
# not given, processes will be executed in game/.
PROCPOOL_DIRECTORY = None


# don't need to change normally
SERVICE_NAME = "PythonProcPool"


# plugin hook

def start_plugin_services(server):
    """
    This will be called by the Evennia Server when starting up.

    server - the main Evennia server application
    """
    if not PROCPOOL_ENABLED:
        return

    # terminal output
    print '  amp (Process Pool): %s' % PROCPOOL_PORT

    from contrib.procpools.ampoule import main as ampoule_main
    from contrib.procpools.ampoule import service as ampoule_service
    from contrib.procpools.ampoule import pool as ampoule_pool
    from contrib.procpools.ampoule.main import BOOTSTRAP as _BOOTSTRAP
    from contrib.procpools.python_procpool import PythonProcPoolChild

    # for some reason absolute paths don't work here, only relative ones.
    apackages = ("twisted",
                 os.path.join(os.pardir, "contrib", "procpools", "ampoule"),
                 os.path.join(os.pardir, "ev"),
                 "settings")
    aenv = {"DJANGO_SETTINGS_MODULE": "settings",
            "DATABASE_NAME": settings.DATABASES.get("default", {}).get("NAME") or settings.DATABASE_NAME}
    if PROCPOOL_DEBUG:
        _BOOTSTRAP = _BOOTSTRAP % "log.startLogging(sys.stderr)"
    else:
        _BOOTSTRAP = _BOOTSTRAP % ""
    procpool_starter = ampoule_main.ProcessStarter(packages=apackages,
                                                   env=aenv,
                                                   path=PROCPOOL_DIRECTORY,
                                                   uid=PROCPOOL_UID,
                                                   gid=PROCPOOL_GID,
                                                   bootstrap=_BOOTSTRAP,
                                                   childReactor=sys.platform == 'linux2' and "epoll" or "default")
    procpool = ampoule_pool.ProcessPool(name=SERVICE_NAME,
                                        min=PROCPOOL_MIN_NPROC,
                                        max=PROCPOOL_MAX_NPROC,
                                        recycleAfter=500,
                                        timeout=PROCPOOL_TIMEOUT,
                                        maxIdle=PROCPOOL_IDLETIME,
                                        ampChild=PythonProcPoolChild,
                                        starter=procpool_starter)
    procpool_service = ampoule_service.AMPouleService(procpool,
                                                      PythonProcPoolChild,
                                                      PROCPOOL_PORT,
                                                      PROCPOOL_INTERFACE)
    procpool_service.setName(SERVICE_NAME)
    # add the new services to the server
    server.services.addService(procpool_service)



