<commit_before># -*- coding: utf-8 -*-
"""
If you call sender.py from the command line, it will send 3 test packets.
See argparse for options.

Otherwise, this module is loaded to provide the ServerSender class.
"""

from __future__ import print_function

import socket
import argparse
import time
from contextlib import closing
import errno

from auxiliaries import set_verbosity, Config, PublicKey
from globalvalues import DEFAULT_HOSTNAME, DEFAULT_SENDER_MODE
from globalvalues import DEFAULT_UDP_PORT, DEFAULT_TCP_PORT
from globalvalues import DEFAULT_CONFIG, DEFAULT_PUBLICKEY

TCP_TIMEOUT = 5


class ServerSender(object):
    """
    Provides ServerSender.send_cpm() for sending UDP packets to the DoseNet
    server.
    """

    def __init__(self,
                 manager=None,
                 address=DEFAULT_HOSTNAME,
                 port=None,
                 config=None,
                 publickey=None,
                 verbosity=1,
                 logfile=None,
                 mode=None,
                 ):
        """
        network_status, config, publickey loaded from manager if not provided.
        address and port take system defaults, although without config and
          publickey, address and port will not be used.
        """

        self.v = verbosity
        if manager and logfile is None:
            set_verbosity(self, logfile=manager.logfile)
        else:
            set_verbosity(self, logfile=logfile)

        self.address = address
        self.handle_input(
            manager, mode, port, config, publickey)

    def handle_input(
            self, manager, mode, port, config, publickey):

        # TODO: this stuff is messy. Is there a cleaner way using exceptions?
        if manager is None:
            self.vprint(1, 'ServerSender starting without Manager object')
        self.manager = manager

        try:
            if mode is None:
                self.mode = DEFAULT_SENDER_MODE
            elif mode.lower() == 'udp':
                self.mode = 'udp'
            elif mode.lower() == 'tcp':
                self.mode = 'tcp'
            else:
                raise RuntimeError(
                    'Invalid ServerSender mode (choose TCP or UDP)')
        except AttributeError:
            # if mode is not a string or None, then mode.lower() raises this
            raise RuntimeError('Invalid ServerSender mode (choose TCP or UDP)')

        if self.mode == 'udp':
            if port is None:
                self.port = DEFAULT_UDP_PORT
            else:
                self.port = port
            self.vprint(3, 'ServerSender using UDP for {}:{}'.format(
                self.address, self.port))
        elif self.mode == 'tcp':
            if port is None:
                self.port = DEFAULT_TCP_PORT
            else:
                self.port = port
            self.vprint(3, 'ServerSender using TCP for {}:{}'.format(
                self.address, self.port))

        if config is None:
            if manager is None:
                self.vprint(1, 'ServerSender starting without config file')
                self.config = None
            else:
                self.config = manager.config
        else:
            self.config = config

        if publickey is None:
            if manager is None:
                self.vprint(1, 'ServerSender starting without publickey file')
                self.encrypter = None
            elif manager.publickey is None:
                self.vprint(1, 'ServerSender starting without publickey file')
                self.encrypter = None
            else:
                self.encrypter = manager.publickey.encrypter
        else:
            self.encrypter = publickey.encrypter

    def construct_packet(self, cpm, cpm_error, error_code=0):
        """
        Construct the raw packet string. (basically copied from old code)

        hash,ID,cpm,cpm_error,error_code
        """

        c = ','
        try:
            raw_packet = (
                str(self.config.hash) + c +
                str(self.config.ID) + c +
                str(cpm) + c +
                str(cpm_error) + c +
                str(error_code))
        except AttributeError:      # on self.config.hash
            raise MissingFile('Missing or broken Config object')
        else:
            self.vprint(3, 'Constructed packet')
            return raw_packet

    def construct_packet_new(self, timestamp, cpm, cpm_error, error_code=0):
        """
        New protocol version of construct packet.

        hash,ID,timestamp,cpm,cpm_error,error_code
        """

        c = ','
        try:
            raw_packet = (
                str(self.config.hash) + c +
                str(self.config.ID) + c +
                str(timestamp) + c +
                str(cpm) + c +
                str(cpm_error) + c +
                str(error_code))
        except AttributeError:      # on self.config.hash
            raise MissingFile('Missing or broken Config object')
        else:
            self.vprint(3, 'Constructed packet')
            return raw_packet

    def construct_log_packet(self, msg_code, msg_text):
        """
        Send a message to be recorded in the server log database.

        hash,ID,"LOG",msg_code,msg_text
        """

        c = ','
        if not isinstance(msg_code, int):
            raise TypeError('msg_code should be an int')
        try:
            raw_packet = (
                str(self.config.hash) + c +
                str(self.config.ID) + c +
                'LOG' + c +
                str(msg_code) + c +
                str(msg_text))
        except AttributeError:      # on self.config.hash
            raise MissingFile('Missing or broken Config object')
        else:
            self.vprint(3, 'Constructed log packet')
            return raw_packet

    def encrypt_packet(self, raw_packet):
        """Encrypt the raw packet"""
<commit_msg>sender.construct_packet*: use ','.join()<commit_after># -*- coding: utf-8 -*-
"""
If you call sender.py from the command line, it will send 3 test packets.
See argparse for options.

Otherwise, this module is loaded to provide the ServerSender class.
"""

from __future__ import print_function

import socket
import argparse
import time
from contextlib import closing
import errno

from auxiliaries import set_verbosity, Config, PublicKey
from globalvalues import DEFAULT_HOSTNAME, DEFAULT_SENDER_MODE
from globalvalues import DEFAULT_UDP_PORT, DEFAULT_TCP_PORT
from globalvalues import DEFAULT_CONFIG, DEFAULT_PUBLICKEY

TCP_TIMEOUT = 5


class ServerSender(object):
    """
    Provides ServerSender.send_cpm() for sending UDP packets to the DoseNet
    server.
    """

    def __init__(self,
                 manager=None,
                 address=DEFAULT_HOSTNAME,
                 port=None,
                 config=None,
                 publickey=None,
                 verbosity=1,
                 logfile=None,
                 mode=None,
                 ):
        """
        network_status, config, publickey loaded from manager if not provided.
        address and port take system defaults, although without config and
          publickey, address and port will not be used.
        """

        self.v = verbosity
        if manager and logfile is None:
            set_verbosity(self, logfile=manager.logfile)
        else:
            set_verbosity(self, logfile=logfile)

        self.address = address
        self.handle_input(
            manager, mode, port, config, publickey)

    def handle_input(
            self, manager, mode, port, config, publickey):

        # TODO: this stuff is messy. Is there a cleaner way using exceptions?
        if manager is None:
            self.vprint(1, 'ServerSender starting without Manager object')
        self.manager = manager

        try:
            if mode is None:
                self.mode = DEFAULT_SENDER_MODE
            elif mode.lower() == 'udp':
                self.mode = 'udp'
            elif mode.lower() == 'tcp':
                self.mode = 'tcp'
            else:
                raise RuntimeError(
                    'Invalid ServerSender mode (choose TCP or UDP)')
        except AttributeError:
            # if mode is not a string or None, then mode.lower() raises this
            raise RuntimeError('Invalid ServerSender mode (choose TCP or UDP)')

        if self.mode == 'udp':
            if port is None:
                self.port = DEFAULT_UDP_PORT
            else:
                self.port = port
            self.vprint(3, 'ServerSender using UDP for {}:{}'.format(
                self.address, self.port))
        elif self.mode == 'tcp':
            if port is None:
                self.port = DEFAULT_TCP_PORT
            else:
                self.port = port
            self.vprint(3, 'ServerSender using TCP for {}:{}'.format(
                self.address, self.port))

        if config is None:
            if manager is None:
                self.vprint(1, 'ServerSender starting without config file')
                self.config = None
            else:
                self.config = manager.config
        else:
            self.config = config

        if publickey is None:
            if manager is None:
                self.vprint(1, 'ServerSender starting without publickey file')
                self.encrypter = None
            elif manager.publickey is None:
                self.vprint(1, 'ServerSender starting without publickey file')
                self.encrypter = None
            else:
                self.encrypter = manager.publickey.encrypter
        else:
            self.encrypter = publickey.encrypter

    def construct_packet(self, cpm, cpm_error, error_code=0):
        """
        Construct the raw packet string. (basically copied from old code)

        hash,ID,cpm,cpm_error,error_code
        """

        try:
            raw_packet = ','.join(
                [str(self.config.hash),
                 str(self.config.ID),
                 str(cpm),
                 str(cpm_error),
                 str(error_code)]
            )
        except AttributeError:      # on self.config.hash
            raise MissingFile('Missing or broken Config object')
        else:
            self.vprint(3, 'Constructed packet')
            return raw_packet

    def construct_packet_new(self, timestamp, cpm, cpm_error, error_code=0):
        """
        New protocol version of construct packet.

        hash,ID,timestamp,cpm,cpm_error,error_code
        """

        try:
            raw_packet = ','.join(
                [str(self.config.hash),
                 str(self.config.ID),
                 str(timestamp),
                 str(cpm),
                 str(cpm_error),
                 str(error_code)]
            )
        except AttributeError:      # on self.config.hash
            raise MissingFile('Missing or broken Config object')
        else:
            self.vprint(3, 'Constructed packet')
            return raw_packet

    def construct_log_packet(self, msg_code, msg_text):
        """
        Send a message to be recorded in the server log database.

        hash,ID,"LOG",msg_code,msg_text
        """

        if not isinstance(msg_code, int):
            raise TypeError('msg_code should be an int')
        try:
            raw_packet = ','.join(
                [str(self.config.hash),
                 str(self.config.ID),
                 'LOG',
                 str(msg_code),
                 str(msg_text)]
            )
        except AttributeError:      # on self.config.hash
            raise MissingFile('Missing or broken Config object')
        else:
            self.vprint(3, 'Constructed log packet')
            return raw_packet

    def encrypt_packet(self, raw_packet):
        """Encrypt the raw packet"""

{'fraction_non_alphanumeric': 0.08205041448147521, 'fraction_numerical': 0.002537641684994079, 'mean_word_length': 1.6402411790978115, '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': '1134145', 'n_tokens_mistral': 3168, 'n_tokens_neox': 3038, 'n_words': 921}