Ejemplo n.º 1
0
def tor_bootstrap() -> None:
    """Bootstrap wrapper for Tor.

    The function will bootstrap the Tor proxy. It will retry for
    :data:`~darc.proxy.tor.TOR_RETRY` times in case of failure.

    Also, it will **NOT** re-bootstrap the proxy as is guaranteed by
    :data:`~darc.proxy.tor._TOR_BS_FLAG`.

    Warns:
        TorBootstrapFailed: If failed to bootstrap Tor proxy.

    See Also:
        * :func:`darc.proxy.tor._tor_bootstrap`
        * :data:`darc.proxy.tor.TOR_RETRY`
        * :data:`darc.proxy.tor._TOR_BS_FLAG`

    """
    # don't re-bootstrap
    if _TOR_BS_FLAG:
        return

    logger.info('-*- Tor Bootstrap -*-')
    for _ in range(TOR_RETRY + 1):
        try:
            _tor_bootstrap()
            break
        except Exception:
            if DEBUG:
                logger.ptb('[Error bootstraping Tor proxy]')
            logger.pexc(LOG_WARNING,
                        category=TorBootstrapFailed,
                        line='tor_bootstrap()')
    logger.pline(LOG_INFO, logger.horizon)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
def launch_freenet() -> 'Popen[bytes]':
    """Launch Freenet process.

    See Also:
        This function mocks the behaviour of :func:`stem.process.launch_tor`.

    """
    pidfile = os.path.join(FREENET_PATH, 'Freenet.pid')
    with contextlib.suppress(OSError):
        os.remove(pidfile)

    zeronet_process = None
    try:
        zeronet_process = subprocess.Popen(  # pylint: disable=consider-using-with # nosec
            _FREENET_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:
                if (code :=
                        zeronet_process.returncode) is not None and code == 0:
                    return zeronet_process
                raise OSError(f'Process terminated: Timed out [{code}]')

            if os.path.exists(pidfile):
                pid = getpid(pidfile)

                time.sleep(1)  # wait a little bit
                if psutil.pid_exists(pid):
                    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
Ejemplo n.º 4
0
def freenet_bootstrap() -> None:
    """Bootstrap wrapper for Freenet.

    The function will bootstrap the Freenet proxy. It will retry for
    :data:`~darc.proxy.freenet.FREENET_RETRY` times in case of failure.

    Also, it will **NOT** re-bootstrap the proxy as is guaranteed by
    :data:`~darc.proxy.freenet._FREENET_BS_FLAG`.

    Warns:
        FreenetBootstrapFailed: If failed to bootstrap Freenet proxy.

    Raises:
        :exc:`UnsupportedPlatform`: If the system is not supported, i.e. not macOS or Linux.

    See Also:
        * :func:`darc.proxy.freenet._freenet_bootstrap`
        * :data:`darc.proxy.freenet.FREENET_RETRY`
        * :data:`darc.proxy.freenet._FREENET_BS_FLAG`

    """
    if _unsupported:
        raise UnsupportedPlatform(f'unsupported system: {platform.system()}')

    # don't re-bootstrap
    if _FREENET_BS_FLAG:
        return

    logger.info('-*- Freenet Bootstrap -*-')
    for _ in range(FREENET_RETRY + 1):
        try:
            _freenet_bootstrap()
            break
        except Exception:
            if DEBUG:
                logger.ptb('[Error bootstraping Freenet proxy]')
            logger.pexc(LOG_WARNING,
                        category=FreenetBootstrapFailed,
                        line='freenet_bootstrap()')
    logger.pline(LOG_INFO, logger.horizon)
Ejemplo n.º 5
0
def launch_i2p() -> 'Popen[bytes]':
    """Launch I2P process.

    See Also:
        This function mocks the behaviour of :func:`stem.process.launch_tor`.

    """
    i2p_process = None
    try:
        i2p_process = subprocess.Popen(  # pylint: disable=consider-using-with # nosec
            _I2P_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]', i2p_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 'running: PID:' in init_line:
                return i2p_process
            if 'I2P Service is already running.' in init_line:
                return i2p_process
    except BaseException:
        if i2p_process is not None:
            i2p_process.kill()  # don't leave a lingering process
            i2p_process.wait()
        raise
    finally:
        signal.alarm(0)  # stop alarm
Ejemplo n.º 6
0
def main(argv: 'Optional[List[str]]' = None) -> int:
    """Entrypoint.

    Args:
        argv: Optional command line arguments.

    Returns:
        Exit code.

    """
    parser = get_parser()
    args = parser.parse_args(argv)

    pid = os.getpid()
    with open(PATH_ID, 'w') as file:
        print(pid, file=file)

    # wait for Redis
    if _WAIT_REDIS:
        if not FLAG_DB:
            _redis_command('set', 'darc', pid)

    if FLAG_DB:
        while True:
            try:
                with DB:
                    _db_operation(DB.create_tables, [
                        HostnameQueueModel,
                        RequestsQueueModel,
                        SeleniumQueueModel,
                    ])
            except Exception:
                logger.pexc(LOG_WARNING,
                            category=DatabaseOperaionFailed,
                            line='DB.create_tables([HostnameQueueModel, ...]')
                continue
            break

    if SAVE_DB:
        while True:
            try:
                with DB_WEB:
                    _db_operation(DB_WEB.create_tables, [
                        HostnameModel,
                        URLModel,
                        URLThroughModel,
                        RobotsModel,
                        SitemapModel,
                        HostsModel,
                        RequestsModel,
                        RequestsHistoryModel,
                        SeleniumModel,
                    ])
            except Exception:
                logger.pexc(LOG_WARNING,
                            category=DatabaseOperaionFailed,
                            line='DB.create_tables([HostnameModel, ...]')
                continue
            break

    logger.debug('-*- Initialisation -*-')
    if DEBUG and not FLAG_DB:
        # nuke the db
        _redis_command('delete', 'queue_hostname')
        _redis_command('delete', 'queue_requests')
        _redis_command('delete', 'queue_selenium')

    link_list = []
    for link in filter(
            None, map(lambda s: s.strip(),
                      args.link)):  # type: ignore[name-defined,var-annotated]
        logger.pline(LOG_DEBUG, link)
        link_list.append(link)

    if args.file is not None:
        for path in args.file:
            with open(path) as file:
                for line in filter(None, map(lambda s: s.strip(), file)):
                    if line.startswith('#'):
                        continue
                    logger.pline(LOG_DEBUG, line)
                    link_list.append(line)

    # write to database
    link_pool = [parse_link(link, backref=None) for link in link_list]
    save_requests(link_pool, score=0, nx=True)
    logger.pline(LOG_DEBUG, logger.horizon)

    # init link file
    if not os.path.isfile(PATH_LN):
        with open(PATH_LN, 'w') as file:
            print('proxy,scheme,host,hash,link', file=file)

    try:
        process(args.type)
    except BaseException:
        traceback.print_exc()
    _exit()

    return 0
Ejemplo n.º 7
0
    if _system in ['Linux', 'Darwin']:
        _FREENET_ARGS = [
            'su', '-', DARC_USER,
            os.path.join(FREENET_PATH, 'run.sh'), 'start'
        ]
    else:
        _unsupported = True
        _FREENET_ARGS = []
else:
    _FREENET_ARGS = [os.path.join(FREENET_PATH, 'run.sh'), 'start']
_FREENET_ARGS.extend(FREENET_ARGS)

if _unsupported:
    if DEBUG:
        logger.debug('-*- FREENET PROXY -*-')
        logger.pline(LOG_ERROR, 'unsupported system: %s', platform.system())
        logger.pline(LOG_DEBUG, logger.horizon)
else:
    logger.plog(LOG_DEBUG, '-*- FREENET PROXY -*-', object=_FREENET_ARGS)


def launch_freenet() -> 'Popen[bytes]':
    """Launch Freenet process.

    See Also:
        This function mocks the behaviour of :func:`stem.process.launch_tor`.

    """
    pidfile = os.path.join(FREENET_PATH, 'Freenet.pid')
    with contextlib.suppress(OSError):
        os.remove(pidfile)