<commit_before>import threading
import asyncore

from astral.net.tunnel import Tunnel
from astral.models import Ticket
from astral.models.ticket import TUNNEL_QUEUE

import logging
log = logging.getLogger(__name__)


class TunnelControlThread(threading.Thread):
    def __init__(self):
        super(TunnelControlThread, self).__init__()
        self.daemon = True

    def run(self):
        while True:
            ticket_id = TUNNEL_QUEUE.get()
            ticket = Ticket.get_by(id=ticket_id)
            log.debug("Found %s in tunnel queue", ticket)
            port = self.create_tunnel(ticket.source.ip_address, ticket.source_port,
                    ticket.destination.ip_address, ticket.destination_port)
            TUNNEL_QUEUE.task_done()
            ticket.source_port = port
            self.close_expired_tunnels()

    def create_tunnel(self, ticket_id, source_ip, source_port,
            destination_ip, destination_port):
        tunnel = Tunnel(destination_ip, destination_port)
        log.info("Starting %s", tunnel)
        self.tunnels[ticket_id] = tunnel
        return tunnel.source_port()

    def destroy_tunnel(self, ticket_id):
        tunnel = self.tunnels.pop(ticket_id)
        log.info("Stopping %s", tunnel)
        tunnel.handle_close()

    def close_expired_tunnels(self):
        for ticket_id, tunnel in self.tunnels.values():
            if not Ticket.get_by(id=ticket_id):
                self.destroy_tunnel(ticket_id)


class TunnelLoopThread(threading.Thread):
    def __init__(self):
        super(TunnelLoopThread, self).__init__()
        self.daemon = True
        self.tunnels = dict()

    def run(self):
        # TODO this is going to just spin when we first start up and have no
        # existing tunnels. we talked about having everyone with the rtmp server
        # access that not directly, but through a tunnel, so we could use that
        # to control the on/off. still need that?
        while True:
            asyncore.loop()<commit_msg>Workaround to avoid a CPU burning busy wait loop.<commit_after>import threading
import asyncore
import time

from astral.net.tunnel import Tunnel
from astral.models import Ticket
from astral.models.ticket import TUNNEL_QUEUE

import logging
log = logging.getLogger(__name__)


class TunnelControlThread(threading.Thread):
    def __init__(self):
        super(TunnelControlThread, self).__init__()
        self.daemon = True

    def run(self):
        while True:
            ticket_id = TUNNEL_QUEUE.get()
            ticket = Ticket.get_by(id=ticket_id)
            log.debug("Found %s in tunnel queue", ticket)
            port = self.create_tunnel(ticket.source.ip_address, ticket.source_port,
                    ticket.destination.ip_address, ticket.destination_port)
            TUNNEL_QUEUE.task_done()
            ticket.source_port = port
            self.close_expired_tunnels()

    def create_tunnel(self, ticket_id, source_ip, source_port,
            destination_ip, destination_port):
        tunnel = Tunnel(destination_ip, destination_port)
        log.info("Starting %s", tunnel)
        self.tunnels[ticket_id] = tunnel
        return tunnel.source_port()

    def destroy_tunnel(self, ticket_id):
        tunnel = self.tunnels.pop(ticket_id)
        log.info("Stopping %s", tunnel)
        tunnel.handle_close()

    def close_expired_tunnels(self):
        for ticket_id, tunnel in self.tunnels.values():
            if not Ticket.get_by(id=ticket_id):
                self.destroy_tunnel(ticket_id)


class TunnelLoopThread(threading.Thread):
    def __init__(self):
        super(TunnelLoopThread, self).__init__()
        self.daemon = True
        self.tunnels = dict()

    def run(self):
        # TODO this is going to just spin when we first start up and have no
        # existing tunnels. we talked about having everyone with the rtmp server
        # access that not directly, but through a tunnel, so we could use that
        # to control the on/off. still need that?
        while True:
            asyncore.loop()
            # TODO this is a little workaround to make sure we don't eat up 100%
            # CPU at the moment
            time.sleep(1)
{'fraction_non_alphanumeric': 0.08108752683043167, 'fraction_numerical': 0.0009539709038874314, 'mean_word_length': 2.5784982935153584, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3059754', 'n_tokens_mistral': 1244, 'n_tokens_neox': 1218, 'n_words': 326}