2019-01-07 11:16:16 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2019-01-28 18:15:54 +01:00
|
|
|
"""Console script to control the bot_z daemon"""
|
|
|
|
|
|
|
|
import errno
|
2019-01-28 21:08:04 +01:00
|
|
|
import logging
|
2019-01-28 18:15:54 +01:00
|
|
|
import os
|
2019-01-28 21:08:04 +01:00
|
|
|
import sys
|
2019-01-28 18:15:54 +01:00
|
|
|
import time
|
|
|
|
import typing as T
|
2019-01-07 11:16:16 +01:00
|
|
|
|
|
|
|
import click
|
2019-01-28 18:15:54 +01:00
|
|
|
import lockfile
|
|
|
|
|
|
|
|
from bot_z.zdaemon import daemon_process, Fifo
|
|
|
|
|
2019-01-28 21:08:04 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
logger.setLevel(logging.INFO)
|
|
|
|
sh = logging.StreamHandler(stream=sys.stdout)
|
|
|
|
sh.setFormatter(logging.Formatter("%(message)s"))
|
|
|
|
logger.addHandler(sh)
|
|
|
|
|
2019-01-28 18:15:54 +01:00
|
|
|
|
|
|
|
@click.group()
|
|
|
|
@click.option("-d", "--debug", is_flag=True, default=False, help="Enable debug mode.")
|
2019-01-28 21:08:04 +01:00
|
|
|
@click.option(
|
|
|
|
"-v",
|
|
|
|
"--verbose",
|
|
|
|
is_flag=True,
|
|
|
|
default=False,
|
|
|
|
help="More verbose output from this cli.",
|
|
|
|
)
|
2019-01-28 18:15:54 +01:00
|
|
|
@click.option(
|
|
|
|
"-f",
|
|
|
|
"--fifo",
|
|
|
|
type=click.Path(),
|
|
|
|
default="/tmp/bot_z.cmd",
|
|
|
|
help="Path to the control fifo.",
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
"-w",
|
|
|
|
"--workdir",
|
|
|
|
type=click.Path(exists=True, readable=True, writable=True, resolve_path=True),
|
|
|
|
default="/tmp/",
|
|
|
|
help="The working dir where to launch the daemon and where the lockfile is put.",
|
|
|
|
)
|
|
|
|
@click.pass_context
|
2019-01-28 21:08:04 +01:00
|
|
|
def cli(
|
|
|
|
ctx: click.Context, debug: bool, verbose: bool, fifo: str, workdir: str
|
|
|
|
) -> None:
|
2019-01-28 18:15:54 +01:00
|
|
|
"""
|
|
|
|
Group cli.
|
|
|
|
"""
|
2019-01-28 21:08:04 +01:00
|
|
|
if verbose:
|
|
|
|
logger.setLevel(logging.DEBUG)
|
2019-01-28 18:15:54 +01:00
|
|
|
ctx.ensure_object(dict)
|
|
|
|
ctx.obj["debug"] = debug
|
2019-01-28 21:08:04 +01:00
|
|
|
ctx.obj["verbose"] = verbose
|
2019-01-28 18:15:54 +01:00
|
|
|
ctx.obj["fifo"] = fifo
|
|
|
|
ctx.obj["workdir"] = workdir
|
|
|
|
|
|
|
|
|
|
|
|
@cli.command("start")
|
|
|
|
@click.option(
|
|
|
|
"-t", "--timeout", type=click.INT, default=20, help="Browser requests timeout."
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
"-m",
|
|
|
|
"--umask",
|
|
|
|
type=click.INT,
|
|
|
|
default=0o002,
|
|
|
|
help="The umask of the control fifo.",
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
"-n",
|
|
|
|
"--name",
|
|
|
|
type=click.STRING,
|
|
|
|
default="default_instance",
|
|
|
|
help="The daemon instance name.",
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
"-p",
|
|
|
|
"--proxy",
|
|
|
|
type=click.STRING,
|
|
|
|
default=None,
|
|
|
|
help="An optional string for the proxy with the form 'address:port'.",
|
|
|
|
)
|
|
|
|
@click.option(
|
|
|
|
"--foreground",
|
|
|
|
is_flag=True,
|
|
|
|
default=False,
|
|
|
|
help="Keep the process in foreground (do not daemonize).",
|
|
|
|
)
|
|
|
|
@click.argument("baseuri", type=click.STRING)
|
|
|
|
@click.pass_context
|
|
|
|
def start_command(
|
|
|
|
ctx: click.Context,
|
|
|
|
baseuri: str,
|
|
|
|
name: str,
|
|
|
|
umask: int,
|
|
|
|
timeout: int,
|
|
|
|
proxy: T.Optional[str] = None,
|
|
|
|
foreground: bool = False,
|
|
|
|
) -> None:
|
|
|
|
"""
|
|
|
|
Invokes daemon_process for the first time.
|
|
|
|
"""
|
2019-01-28 21:08:04 +01:00
|
|
|
lf = lockfile.FileLock(os.path.join(ctx.obj["workdir"], "bot_z"))
|
|
|
|
logger.debug("Daemon starting. Lockfile: %s", lf)
|
2019-01-28 18:15:54 +01:00
|
|
|
proxy_tuple = None
|
|
|
|
if proxy:
|
|
|
|
proxy_tuple = tuple(proxy.split(":"))
|
|
|
|
|
|
|
|
daemon_process(
|
|
|
|
fifo_path=ctx.obj["fifo"],
|
|
|
|
working_dir=ctx.obj["workdir"],
|
|
|
|
umask=umask,
|
|
|
|
pidfile=lf,
|
|
|
|
base_uri=baseuri,
|
|
|
|
name=name,
|
|
|
|
timeout=timeout,
|
|
|
|
proxy=proxy_tuple,
|
|
|
|
headless=not ctx.obj["debug"],
|
|
|
|
debug=ctx.obj["debug"],
|
|
|
|
foreground=foreground,
|
|
|
|
)
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.info("Daemon started.")
|
2019-01-28 18:15:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
@cli.command("stop")
|
|
|
|
@click.pass_context
|
|
|
|
def stop_command(ctx: click.Context):
|
|
|
|
"""
|
|
|
|
Writes on the fifo. Invokes the stop.
|
|
|
|
"""
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.debug("Sending the stop command down the pipe: %s", ctx.obj["fifo"])
|
2019-01-28 18:15:54 +01:00
|
|
|
with open(ctx.obj["fifo"], "w") as fifo:
|
|
|
|
fifo.write("stop")
|
|
|
|
fifo.flush()
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.info("Stop sent.")
|
2019-01-28 18:15:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
@cli.command("reload")
|
|
|
|
@click.pass_context
|
|
|
|
def reload_command(ctx: click.Context):
|
|
|
|
"""
|
|
|
|
Writes on the fifo. Invokes the reload.
|
|
|
|
"""
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.debug("Sending the reload command down the pipe: %s", ctx.obj["fifo"])
|
2019-01-28 18:15:54 +01:00
|
|
|
with open(ctx.obj["fifo"], "w") as fifo:
|
|
|
|
fifo.write("reload")
|
|
|
|
fifo.flush()
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.info("Reload sent.")
|
2019-01-28 18:15:54 +01:00
|
|
|
|
2019-01-07 11:16:16 +01:00
|
|
|
|
2019-01-28 18:15:54 +01:00
|
|
|
@cli.command("status")
|
|
|
|
@click.pass_context
|
|
|
|
def status_command(ctx: click.Context):
|
|
|
|
"""
|
|
|
|
Writes on the fifo. Queries the status.
|
|
|
|
"""
|
|
|
|
rfifo_path = os.path.join(ctx.obj["workdir"], "rfifo-{}".format(id(ctx)))
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.debug("Awaiting response on fifo: %s", rfifo_path)
|
2019-01-28 18:15:54 +01:00
|
|
|
try:
|
|
|
|
os.mkfifo(rfifo_path)
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.debug("Response fifo newly created.")
|
2019-01-28 18:15:54 +01:00
|
|
|
except OSError as err:
|
|
|
|
if err.errno != errno.EEXIST:
|
|
|
|
raise
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.debug("Response fifo exists.")
|
2019-01-07 11:16:16 +01:00
|
|
|
|
2019-01-28 18:15:54 +01:00
|
|
|
with Fifo(ctx.obj["fifo"], "w") as fifo:
|
|
|
|
fifo.write("status|{}".format(rfifo_path))
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.debug("Awaiting response...")
|
2019-01-28 18:15:54 +01:00
|
|
|
done = False
|
|
|
|
while not done:
|
|
|
|
try:
|
|
|
|
with open(rfifo_path, "r") as rfifo:
|
|
|
|
resp = rfifo.read()
|
|
|
|
done = True
|
|
|
|
except FileNotFoundError as e:
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.warning("File not found: %s", e)
|
2019-01-28 18:15:54 +01:00
|
|
|
pass
|
2019-01-28 21:08:04 +01:00
|
|
|
logger.info(resp)
|
2019-01-07 11:16:16 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2019-01-28 18:15:54 +01:00
|
|
|
cli()
|