#!/usr/bin/env python3

import argparse
import base64
import logging
import multiprocessing
import os
import pathlib
import sys
import time

import stem.descriptor
import stem.control
import stem.process

OFFICE = pathlib.Path(__file__).parent.absolute()

CONTROL_SOCKET = 'sockets/control.socket'
SOCKS_SOCKET = 'sockets/socks.socket'
SOCKS_PORT = 7654
LOG_LEVEL = 'INFO'
LOG_PATH = 'logs'
DATA_PATH = 'data'
SERVICE_KEY_PATH = 'service.key'
SERVICE_PORTS = {
        22 : 'localhost:22',
        80 : 'uj.edu.pl:80',
        443 : 'uj.edu.pl:443',
    }

DUCKDUCKGO_ONION_V2 = '3g2upl4pq6kufc4m.onion'
DUCKDUCKGO_ONION_V3 = 'duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion'

def get_tor():
    control_socket_path = OFFICE / CONTROL_SOCKET
    control_socket_path.parent.mkdir(parents=True, exist_ok=True)
    control_socket_path.parent.chmod(0o700)
    socks_socket_path = OFFICE / SOCKS_SOCKET
    socks_socket_path.parent.mkdir(parents=True, exist_ok=True)
    log_path = OFFICE / LOG_PATH
    log_path.parent.mkdir(parents=True, exist_ok=True)
    data_path = OFFICE / DATA_PATH
    data_path.mkdir(parents=True, exist_ok=True)

    config = {
        'ControlPort': f'unix:{control_socket_path} RelaxDirModeCheck',
        'SocksPort': [f'unix:{socks_socket_path}', f'localhost:{SOCKS_PORT}',],
        'DataDirectory': f'{data_path}',
        'Log': f'{LOG_LEVEL} file {log_path}',
    }

    return stem.process.launch_tor_with_config(config=config)

def get_controller():
    control_socket_path = OFFICE / CONTROL_SOCKET
    logging.debug(f'Connecting TOR Control socket at {control_socket_path}')
    return stem.control.Controller.from_socket_file(str(control_socket_path))

def get_service_key(controller):
    key_path = OFFICE / SERVICE_KEY_PATH
    if not key_path.exists():
        service = controller.create_ephemeral_hidden_service(SERVICE_PORTS)
        logging.info(f'Created new service {service.service_id}')
        with key_path.open('w') as key_file:
            key_file.write(f'{service.private_key_type}:{service.private_key}\n')
        return (service.private_key_type, service.private_key)
    else:
        with key_path.open('r') as key_file:
            return tuple([ field.strip() for field in key_file.read().split(':') ])

def get_service(controller, key_type=None, key_content=None):
    if key_type is None or key_content is None:
        key_type, key_content = get_service_key(controller)
    service = controller.create_ephemeral_hidden_service(SERVICE_PORTS, key_type=key_type, key_content=key_content, await_publication=True)
    logging.info(f'Started service {service.service_id}')
    return service

def get_descriptor(controller, service_id):
    desc = controller.get_hidden_service_descriptor(service_id)
    if len(service_id) > 32:
        return stem.descriptor.hidden_service.HiddenServiceDescriptorV3.from_str(str(desc)).decrypt(service_id)
    else:
        return desc

def nice_link(link_specifier):
    if isinstance(link_specifier, (stem.client.datatype.LinkByIPv4, stem.client.datatype.LinkByIPv6)):
        return f'{link_specifier.address}:{link_specifier.port}'
    if isinstance(link_specifier, (stem.client.datatype.LinkByFingerprint, stem.client.datatype.LinkByEd25519)):
        return f'#'
    return '?'

tor = get_tor()
try:
    with get_controller() as controller:
        controller.authenticate()

        service = get_service(controller)

        print(service.service_id)

        time.sleep(60*90)
finally:
    tor.kill()
