Source code for darc.proxy.zeronet

# -*- coding: utf-8 -*-
# pylint: disable=ungrouped-imports
"""ZeroNet Proxy
====================

The :mod:`darc.proxy.zeronet` module contains the auxiliary functions
around managing and processing the ZeroNet proxy.

"""

import os
import shlex
import signal
import subprocess  # nosec: B404
from typing import TYPE_CHECKING, cast

from darc.const import DEBUG
from darc.error import ZeroNetBootstrapFailed
from darc.logging import DEBUG as LOG_DEBUG
from darc.logging import INFO as LOG_INFO
from darc.logging import VERBOSE as LOG_VERBOSE
from darc.logging import WARNING as LOG_WARNING
from darc.logging import logger
from darc.proxy.tor import tor_bootstrap

if TYPE_CHECKING:
    from io import IO  # type: ignore[attr-defined] # pylint: disable=no-name-in-module
    from signal import Signals  # pylint: disable=no-name-in-module
    from subprocess import Popen  # nosec: B404
    from types import FrameType
    from typing import NoReturn, Optional, Union

# ZeroNet args
ZERONET_ARGS = shlex.split(os.getenv('ZERONET_ARGS', ''))

# bootstrap wait
BS_WAIT = float(os.getenv('ZERONET_WAIT', '90'))

# ZeroNet port
ZERONET_PORT = os.getenv('ZERONET_PORT', '43110')

# ZeroNet bootstrap retry
ZERONET_RETRY = int(os.getenv('ZERONET_RETRY', '3'))

# ZeroNet project path
ZERONET_PATH = os.getenv('ZERONET_PATH', '/usr/local/src/zeronet')

# manage ZeroNet through darc?
_MNG_ZERONET = bool(int(os.getenv('DARC_ZERONET', '1')))

# ZeroNet bootstrapped flag
_ZERONET_BS_FLAG = not _MNG_ZERONET
# ZeroNet daemon process
_ZERONET_PROC = None
# ZeroNet bootstrap args
_ZERONET_ARGS = [os.path.join(ZERONET_PATH, 'ZeroNet.sh'), 'main']
_ZERONET_ARGS.extend(ZERONET_ARGS)
logger.plog(LOG_DEBUG, '-*- ZERONET PROXY -*-', object=_ZERONET_ARGS)


[docs]def launch_zeronet() -> 'Popen[bytes]': """Launch ZeroNet process. See Also: This function mocks the behaviour of :func:`stem.process.launch_tor`. """ zeronet_process = None try: zeronet_process = subprocess.Popen( # pylint: disable=consider-using-with # nosec _ZERONET_ARGS, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) def timeout_handlet(signum: 'Optional[Union[int, Signals]]' = None, frame: 'Optional[FrameType]' = None) -> 'NoReturn': raise OSError('reached a %i second timeout without success' % BS_WAIT) signal.signal(signal.SIGALRM, timeout_handlet) signal.setitimer(signal.ITIMER_REAL, BS_WAIT) while True: init_line = cast( 'IO[bytes]', zeronet_process.stdout ).readline().decode('utf-8', 'replace').strip() logger.pline(LOG_VERBOSE, init_line) if not init_line: raise OSError('Process terminated: Timed out') if 'ConnServer Server port opened' in init_line: return zeronet_process except BaseException: if zeronet_process is not None: zeronet_process.kill() # don't leave a lingering process zeronet_process.wait() raise finally: signal.alarm(0) # stop alarm
[docs]def _zeronet_bootstrap() -> None: """ZeroNet bootstrap. The bootstrap arguments are defined as :data:`~darc.proxy.zeronet._ZERONET_ARGS`. Raises: subprocess.CalledProcessError: If the return code of :data:`~darc.proxy.zeronet._ZERONET_PROC` is non-zero. See Also: * :func:`darc.proxy.zeronet.zeronet_bootstrap` * :func:`darc.proxy.zeronet.launch_zeronet` * :data:`darc.proxy.zeronet.BS_WAIT` * :data:`darc.proxy.zeronet._ZERONET_BS_FLAG` * :data:`darc.proxy.zeronet._ZERONET_PROC` """ global _ZERONET_BS_FLAG, _ZERONET_PROC # pylint: disable=global-statement # launch Tor first tor_bootstrap() # launch ZeroNet process _ZERONET_PROC = launch_zeronet() # update flag _ZERONET_BS_FLAG = True
[docs]def zeronet_bootstrap() -> None: """Bootstrap wrapper for ZeroNet. The function will bootstrap the ZeroNet proxy. It will retry for :data:`~darc.proxy.zeronet.ZERONET_RETRY` times in case of failure. Also, it will **NOT** re-bootstrap the proxy as is guaranteed by :data:`~darc.proxy.zeronet._ZERONET_BS_FLAG`. Warns: ZeroNetBootstrapFailed: If failed to bootstrap ZeroNet proxy. Raises: :exc:`UnsupportedPlatform`: If the system is not supported, i.e. not macOS or Linux. See Also: * :func:`darc.proxy.zeronet._zeronet_bootstrap` * :data:`darc.proxy.zeronet.ZERONET_RETRY` * :data:`darc.proxy.zeronet._ZERONET_BS_FLAG` """ # don't re-bootstrap if _ZERONET_BS_FLAG: return logger.info('-*- ZeroNet Bootstrap -*-') for _ in range(ZERONET_RETRY+1): try: _zeronet_bootstrap() break except Exception: if DEBUG: logger.ptb('[Error bootstraping ZeroNet proxy]') logger.pexc(LOG_WARNING, category=ZeroNetBootstrapFailed, line='zeronet_bootstrap()') logger.pline(LOG_INFO, logger.horizon)