<filename>homeworks/02 - occurrence/processing.py
#!/usr/bin/env python3

import argparse
import csv
import io
import os
import pathlib
import server
import signal
import socket
import sys

from data import Data


def count_word_occurrences(content):
    '''
    Count the occurrence of the words in "content".

    Args:
        content (str): The received content from a requested file.

    Returns:
        dict: Contains the words as keys and their ocurrences as values.
    '''

    count = dict()
    for word in content.split():
        count[word] = count.get(word, 0) + 1

    return count

def encode_word_occurrences_to_csv(count):
    '''
    Encodes a received dict to a CSV.

    Args:
        count (dict): Contains the words as keys and their ocurrences as values.

    Returns:
        csv: The count is just reestructured as a CSV, without nothing additional.
    '''

    r = io.StringIO()

    writer = csv.writer(r)
    for word in count:
        writer.writerow([word, count[word]])

    return r.getvalue()


class Processing(server.Server):
    '''
    Reimplements the Server Class.
    '''

    def __init__(self, data_address = 'localhost', data_port = 8080, threads = 2, payload_size = 1024):
        super().__init__(threads = threads, payload_size = payload_size)

        self.data_address = data_address
        self.data_port = data_port

    def handle_connection(self, worker_id, peer_conn, peer_address):
        data = peer_conn.recv(self.payload_size)
        if not data:
            print(f'worker #{worker_id}: {peer_address[0]}:{peer_address[1]} sent no data, closing connection', file = sys.stderr)
            return

        filename = str(data, encoding = 'utf-8').rstrip(os.linesep)
        print(f'worker #{worker_id}: {peer_address[0]}:{peer_address[1]} has requested the {filename} file', file = sys.stderr)

        content = self.get_file_content(worker_id, filename)

        response = ''

        if Data.is_error(content):
            response = content
        else:
            response = encode_word_occurrences_to_csv(count_word_occurrences(content))

        peer_conn.send(response.encode())

    def get_file_content(self, worker_id, filename):
        '''
        Connects with Data Server and sends the received file name.

        Args:
            filename (str): The requested file name.

        Returns:
            str: The content of the file name requested to the Data Server.
        '''
        content = ''

        with socket.socket() as data_conn:
            print(f'worker #{worker_id}: connecting to data service at {self.data_address}:{self.data_port}', file = sys.stderr)
            data_conn.connect((self.data_address, self.data_port))

            data_conn.sendall(filename.encode())
            print(f'worker #{worker_id}: requesting the content of {filename} on data service', file = sys.stderr)

            while True:
                raw = data_conn.recv(self.payload_size)
                if not raw:
                    break

                content += str(raw, encoding = 'utf-8')

        return content


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description = 'starts the processing server')

    parser.add_argument('--host', '-H', type = str, default = 'localhost', help = 'local address (default localhost)')
    parser.add_argument('--port', '-p', type = int, default = 8080, help = 'local port (default 8080)')
    parser.add_argument('--threads', '-t', type = int, default = 2, help = 'max number of simultaneous clients (default 2)')
    parser.add_argument('--data-address', type = str, default = 'localhost', help = 'data server\'s address (default localhost)')
    parser.add_argument('--data-port', type = int, default = 8080, help = 'data server\'s port (default 8080)')

    args = parser.parse_args()

    server = Processing(data_address = args.data_address, data_port = args.data_port, threads = args.threads)

    for ss in [signal.SIGINT, signal.SIGTERM]:
        signal.signal(ss, lambda received_signal, frame: server.stop())

    server.start(host = args.host, port = args.port)
<filename>homeworks/02 - occurrence/processing.py
#!/usr/bin/env python3

import argparse
import csv
import io
import os
import pathlib
import server
import signal
import socket
import sys

from data import Data


def count_word_occurrences(content):
    '''
    Count the occurrence of the words in "content".

    Args:
        content (str): The received content from a requested file.

    Returns:
        dict: Contains the words as keys and their ocurrences as values.
    '''

    count = dict()
    for word in content.split():
        count[word] = count.get(word, 0) + 1

    return count

def encode_word_occurrences_to_csv(count):
    '''
    Encodes a received dict to a CSV.

    Args:
        count (dict): Contains the words as keys and their ocurrences as values.

    Returns:
        csv: The count is just reestructured as a CSV, without nothing additional.
    '''

    r = io.StringIO()

    writer = csv.writer(r)
    for word in count:
        writer.writerow([word, count[word]])

    return r.getvalue()


class Processing(server.Server):
    '''
    Reimplements the Server Class.
    '''

    def __init__(self, data_address = 'localhost', data_port = 8080, threads = 2, payload_size = 1024):
        super().__init__(threads = threads, payload_size = payload_size)

        self.data_address = data_address
        self.data_port = data_port

    def handle_connection(self, worker_id, peer_conn, peer_address):
        data = peer_conn.recv(self.payload_size)
        if not data:
            print(f'worker #{worker_id}: {peer_address[0]}:{peer_address[1]} sent no data, closing connection', file = sys.stderr)
            return

        filename = str(data, encoding = 'utf-8').rstrip(os.linesep)
        print(f'worker #{worker_id}: {peer_address[0]}:{peer_address[1]} has requested the {filename} file', file = sys.stderr)

        content = self.get_file_content(worker_id, filename)

        response = ''

        if Data.is_error(content):
            response = content
        else:
            response = encode_word_occurrences_to_csv(count_word_occurrences(content))

        peer_conn.send(response.encode())

    def get_file_content(self, worker_id, filename):
        '''
        Connects with Data Server and sends the received file name.

        Args:
            filename (str): The requested file name.

        Returns:
            str: The content of the file name requested to the Data Server.
        '''
        content = ''

        with socket.socket() as data_conn:
            print(f'worker #{worker_id}: connecting to data service at {self.data_address}:{self.data_port}', file = sys.stderr)
            data_conn.connect((self.data_address, self.data_port))

            data_conn.sendall(filename.encode())
            print(f'worker #{worker_id}: requesting the content of {filename} on data service', file = sys.stderr)

            while True:
                raw = data_conn.recv(self.payload_size)
                if not raw:
                    break

                content += str(raw, encoding = 'utf-8')

        return content


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description = 'starts the processing server')

    parser.add_argument('--host', '-H', type = str, default = 'localhost', help = 'local address (default localhost)')
    parser.add_argument('--port', '-p', type = int, default = 8080, help = 'local port (default 8080)')
    parser.add_argument('--threads', '-t', type = int, default = 2, help = 'max number of simultaneous clients (default 2)')
    parser.add_argument('--data-address', type = str, default = 'localhost', help = 'data server\'s address (default localhost)')
    parser.add_argument('--data-port', type = int, default = 8080, help = 'data server\'s port (default 8080)')

    args = parser.parse_args()

    server = Processing(data_address = args.data_address, data_port = args.data_port, threads = args.threads)

    for ss in [signal.SIGINT, signal.SIGTERM]:
        signal.signal(ss, lambda received_signal, frame: server.stop())

    server.start(host = args.host, port = args.port)
#!/usr/bin/env python3 Count the occurrence of the words in "content".      Args:         content (str): The received content from a requested file.      Returns:         dict: Contains the words as keys and their ocurrences as values. Encodes a received dict to a CSV.      Args:         count (dict): Contains the words as keys and their ocurrences as values.      Returns:         csv: The count is just reestructured as a CSV, without nothing additional. Reimplements the Server Class. #{worker_id}: {peer_address[0]}:{peer_address[1]} sent no data, closing connection', file = sys.stderr) #{worker_id}: {peer_address[0]}:{peer_address[1]} has requested the {filename} file', file = sys.stderr) Connects with Data Server and sends the received file name.          Args:             filename (str): The requested file name.          Returns:             str: The content of the file name requested to the Data Server. #{worker_id}: connecting to data service at {self.data_address}:{self.data_port}', file = sys.stderr) #{worker_id}: requesting the content of {filename} on data service', file = sys.stderr)