<commit_before># encoding=utf8
#
# Copyright 2015 <NAME>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import, division, print_function, \
    with_statement


import time
import socket
import struct
from miserable.log import *
from miserable.utils import *
from miserable.exception import *
from miserable.eventloop import *
from miserable.protocol import *
from miserable.encrypt import Encryptor

from miserable.tcp.client import ClientState, Client
from miserable.tcp.remote import Remote
from miserable.config import LocalConfigManager


def stop_transfer_if_fail(f):
    """stop transfer if unexpected exception occurs"""
    def wrapper(transfer, *args, **kwargs):
        try:
            return f(transfer, *args, **kwargs)
        except Exception as e:
            transfer.stop(warning='%s closed because of %s' %
                          (transfer.display_name, str(e)))
            import traceback
            traceback.print_exc()
    return wrapper


class LocalTransfer(object):
    """
    client <==> local <==> remote
    """

    def __init__(self, loop, sock, addr, dns_resolver):
        cfg = LocalConfigManager.get_config()

        self._encryptor = Encryptor(cfg['password'], cfg['method'])
        self._loop = loop
        self._client = Client(sock, addr, loop, self._encryptor)
        self._remote = None
        self._server_address = None
        self._dns_resolver = dns_resolver
        self._last_active = time.time()
        self._remote_address = cfg['remote_address']
        self._local_address = cfg['local_address']

    @property
    def closed(self):
        return self._client is None

    @property
    def last_active(self):
        return self._last_active

    @property
    def display_name(self):
        client = '%s:%s' % (self._client.ipaddr, self._client.port)
        if self._server_address:
            server = '%s:%s' % (self._server_address.ipaddr,
                                self._server_address.port)
        else:
            server = 'None'
        return '%s <==> %s' % (client, server)

    def start(self):
        self._client.start(POLL_IN | POLL_ERR, self)

    def handle_event(self, sock, fd, event):
        self._last_active = time.time()
        if sock == self._client.socket:
            if event & POLL_ERR:
                self.stop(info='client %s:%s error' %
                          (self._client.ipaddr, self._client.port))
                return
            self._handle_client(event)
        elif sock == self._remote.socket:
            if event & POLL_ERR:
                self.stop(info='remote %s:%s error' %
                          (self._client.ipaddr, self._client.port))
                return
            self._handle_remote(event)

    @stop_transfer_if_fail
    def _handle_client(self, event):
        """handle the client events"""
        data = None
        if event & POLL_IN:
            data = self._client.read()
            if data == b'':
                self.stop(info='client %s:%s closed' %
                          (self._client.ipaddr, self._client.port))
                return

        if self._client.state == ClientState.UDP_ASSOC:
            return
        elif self._client.state in (ClientState.INIT, ClientState.ADDR)\
                and not data:
            """in state INIT or ADDR, supposed to receive data from client"""
            self.stop(info='client %s:%s closed' %<commit_msg>warning<commit_after># encoding=utf8
#
# Copyright 2015 <NAME>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import, division, print_function, \
    with_statement


import time
import socket
import struct
from miserable.log import *
from miserable.utils import *
from miserable.exception import *
from miserable.eventloop import *
from miserable.protocol import *
from miserable.encrypt import Encryptor

from miserable.tcp.client import ClientState, Client
from miserable.tcp.remote import Remote
from miserable.config import LocalConfigManager


def stop_transfer_if_fail(f):
    """stop transfer if unexpected exception occurs"""
    def wrapper(transfer, *args, **kwargs):
        try:
            return f(transfer, *args, **kwargs)
        except Exception as e:
            transfer.stop(warning='%s closed because of %s' %
                          (transfer.display_name, str(e)))
            import traceback
            traceback.print_exc()
    return wrapper


class LocalTransfer(object):
    """
    client <==> local <==> remote
    """

    def __init__(self, loop, sock, addr, dns_resolver):
        cfg = LocalConfigManager.get_config()

        self._encryptor = Encryptor(cfg['password'], cfg['method'])
        self._loop = loop
        self._client = Client(sock, addr, loop, self._encryptor)
        self._remote = None
        self._server_address = None
        self._dns_resolver = dns_resolver
        self._last_active = time.time()
        self._remote_address = cfg['remote_address']
        self._local_address = cfg['local_address']

    @property
    def closed(self):
        return self._client is None

    @property
    def last_active(self):
        return self._last_active

    @property
    def display_name(self):
        client = '%s:%s' % (self._client.ipaddr, self._client.port)
        if self._server_address:
            server = '%s:%s' % (self._server_address.ipaddr,
                                self._server_address.port)
        else:
            server = 'None'
        return '%s <==> %s' % (client, server)

    def start(self):
        self._client.start(POLL_IN | POLL_ERR, self)

    def handle_event(self, sock, fd, event):
        self._last_active = time.time()
        if sock == self._client.socket:
            if event & POLL_ERR:
                self.stop(warning='client %s:%s error' %
                          (self._client.ipaddr, self._client.port))
                return
            self._handle_client(event)
        elif sock == self._remote.socket:
            if event & POLL_ERR:
                self.stop(warning='remote %s:%s error' %
                          (self._client.ipaddr, self._client.port))
                return
            self._handle_remote(event)

    @stop_transfer_if_fail
    def _handle_client(self, event):
        """handle the client events"""
        data = None
        if event & POLL_IN:
            data = self._client.read()
            if data == b'':
                self.stop(info='client %s:%s closed' %
                          (self._client.ipaddr, self._client.port))
                return

        if self._client.state == ClientState.UDP_ASSOC:
            return
        elif self._client.state in (ClientState.INIT, ClientState.ADDR)\
                and not data:
            """in state INIT or ADDR, supposed to receive data from client"""
            self.stop(info='client %s:%s closed' %
{'fraction_non_alphanumeric': 0.09858442871587463, 'fraction_numerical': 0.002275025278058645, 'mean_word_length': 2.306727956539908, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '4300722', 'n_tokens_mistral': 2179, 'n_tokens_neox': 2120, 'n_words': 634}