<commit_before>import collections
import enum
import queue
import socket
import threading


User = collections.namedtuple("User", ["nick", "user", "host"])
Server = collections.namedtuple("Server", ["name"])
_Message = collections.namedtuple(
    "_Message", ["sender", "sender_is_server", "command", "args"])

# from rfc1459
RPL_ENDOFMOTD = '376'


class IrcEvent(enum.Enum):
    # The comments above each enum value represent the parameters they should
    # come with.

    # (channel)
    self_joined = enum.auto()

    # (channel, reason)
    self_parted = enum.auto()

    # ()
    self_quit = enum.auto()

    # (sender_nick, channel)
    user_joined = enum.auto()

    # (sender_nick, channel, reason)
    # reason can be None
    user_parted = enum.auto()

    # (sender_nick, reason)
    # reason can be None
    user_quit = enum.auto()

    # (recipient, text)
    sent_privmsg = enum.auto()

    # (sender, recipient, text)
    recieved_privmsg = enum.auto()

    # (sender_server, command, args)
    server_message = enum.auto()

    # (sender_nick, command, args)
    # if you want to handle some of these, add the code to this file
    # not so that this creates an unknown_message that is parsed elsewhere
    # currently AT LEAST these things cause unknown messages:
    #    * KICK
    #    * MODE (ban, op, voice etc)
    #    * INVITE
    unknown_message = enum.auto()


class _IrcInternalEvent(enum.Enum):
    got_message = enum.auto()

    should_join = enum.auto()
    should_part = enum.auto()
    should_quit = enum.auto()
    should_send_privmsg = enum.auto()


class IrcCore:
    def __init__(self, host, port, nick):
        self.host = host
        self.port = port
        self._running = True
        self.nick = nick

        self._sock = socket.socket()

        self._linebuffer = collections.deque()

        self._internal_queue = queue.Queue()
        self.event_queue = queue.Queue()

    def _send(self, *parts):
        data = " ".join(parts).encode("utf-8") + b"\r\n"
        self._sock.sendall(data)

    def _recv_line(self):
        if not self._linebuffer:
            data = bytearray()
            while not data.endswith(b"\r\n"):
                chunk = self._sock.recv(4096)
                if chunk:
                    data += chunk
                else:
                    raise RuntimeError("Server closed the connection!")
            lines = data.decode("utf-8", errors='replace').split("\r\n")
            self._linebuffer.extend(lines)
        return self._linebuffer.popleft()

    def _add_messages_to_internal_queue(self):
        # We need to have this function because it would be very complicated to
        # wait on two different queues, one for requests to send stuff and one
        # recieved messages.
        while self._running:
            line = self._recv_line()
            if not line:
                # i'm not sure when this runs, but it runs sometimes
                continue
            if line.startswith("PING"):<commit_msg>support servers that send LF instead of CRLF<commit_after>import collections
import enum
import queue
import socket
import threading


User = collections.namedtuple("User", ["nick", "user", "host"])
Server = collections.namedtuple("Server", ["name"])
_Message = collections.namedtuple(
    "_Message", ["sender", "sender_is_server", "command", "args"])

# from rfc1459
RPL_ENDOFMOTD = '376'


class IrcEvent(enum.Enum):
    # The comments above each enum value represent the parameters they should
    # come with.

    # (channel)
    self_joined = enum.auto()

    # (channel, reason)
    self_parted = enum.auto()

    # ()
    self_quit = enum.auto()

    # (sender_nick, channel)
    user_joined = enum.auto()

    # (sender_nick, channel, reason)
    # reason can be None
    user_parted = enum.auto()

    # (sender_nick, reason)
    # reason can be None
    user_quit = enum.auto()

    # (recipient, text)
    sent_privmsg = enum.auto()

    # (sender, recipient, text)
    recieved_privmsg = enum.auto()

    # (sender_server, command, args)
    server_message = enum.auto()

    # (sender_nick, command, args)
    # if you want to handle some of these, add the code to this file
    # not so that this creates an unknown_message that is parsed elsewhere
    # currently AT LEAST these things cause unknown messages:
    #    * KICK
    #    * MODE (ban, op, voice etc)
    #    * INVITE
    unknown_message = enum.auto()


class _IrcInternalEvent(enum.Enum):
    got_message = enum.auto()

    should_join = enum.auto()
    should_part = enum.auto()
    should_quit = enum.auto()
    should_send_privmsg = enum.auto()


class IrcCore:
    def __init__(self, host, port, nick):
        self.host = host
        self.port = port
        self._running = True
        self.nick = nick

        self._sock = socket.socket()
        self._linebuffer = collections.deque()

        self._internal_queue = queue.Queue()
        self.event_queue = queue.Queue()

    def _send(self, *parts):
        data = " ".join(parts).encode("utf-8") + b"\r\n"
        self._sock.sendall(data)

    def _recv_line(self):
        if not self._linebuffer:
            data = bytearray()

            # this accepts both \r\n and \n because b'blah blah\r\n' ends
            # with b'\n'
            while not data.endswith(b"\n"):
                chunk = self._sock.recv(4096)
                if chunk:
                    data += chunk
                else:
                    raise RuntimeError("Server closed the connection!")

            lines = data.decode("utf-8", errors='replace').splitlines()
            self._linebuffer.extend(lines)

        return self._linebuffer.popleft()

    def _add_messages_to_internal_queue(self):
        # We need to have this function because it would be very complicated to
        # wait on two different queues, one for requests to send stuff and one
        # recieved messages.
        while self._running:
            line = self._recv_line()
            if not line:
                # i'm not sure when this runs, but it runs sometimes
                continue
            if line.startswith("PING"):
{'fraction_non_alphanumeric': 0.10720676752887587, 'fraction_numerical': 0.004229705547421507, 'mean_word_length': 2.3142857142857145, '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': '3845998', 'n_tokens_mistral': 1866, 'n_tokens_neox': 1782, 'n_words': 524}