Skip to content
Snippets Groups Projects
client.py 2.87 KiB
Newer Older
WinJ's avatar
WinJ committed
import json
from multiprocessing.connection import Client
import pickle
import random
import socket
import sys

from message import *  # Can change this after testing done
from timers import ClientTimer, setTimer


class LockClient():
    def __init__(self) -> None:
        with open("config.json", encoding='utf-8') as f:
            json_dict = json.loads(f.read())
        server_addresses = json_dict["servers"]
        self.server_addresses = [(server_addresses[i], int(server_addresses[i + 1])) for i in range(0, len(server_addresses), 2)]

        # create a UDP socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(('', 0))
        self.client_addr = self.sock.getsockname()
        print(f"Starting client {self.client_addr}", file=sys.stdout)
        random.seed(0)
        # For client timer to know whether to resend message
        self.req_num = 0

    def execute(self):
        prompt_str = "Enter a command (e.g. lock 1 / unlock 1 / exit): "
        input_str = input(prompt_str)  # Input would be "lock 2" / "unlock 1", etc or "exit"
        try:
            while input_str != "exit":
                lock, val = input_str.split(" ", 2)
                paxos_req = PaxosRequest(self.client_addr, LockCommand(lock, val, self.req_num))
                data = pickle.dumps(paxos_req)

                server_address = random.choice(self.server_addresses)
                print(f"Sending command {paxos_req} to {server_address}", file=sys.stdout)
                self.sock.sendto(data, server_address)

                setTimer(ClientTimer(paxos_req, self.req_num), ClientTimer.CLIENT_RETRY_MILLIS, self.onClientTimer)

                # receive data back from the server
                res = pickle.loads(self.sock.recv(1024))
                while res.cmd.req_num != self.req_num:
                    res = pickle.loads(self.sock.recv(1024))

                self.req_num += 1

                print(f"Received response: {res}", file=sys.stdout)

                if res.value == True:
                    print("Command successfully ran", file=sys.stdout)
                else:
                    print("Command failed to run", file=sys.stdout)

                input_str = input(prompt_str)
        finally:
            # Close socket
            self.sock.close()

    def onClientTimer(self, client_timer: ClientTimer):
        # print(f"{client_timer}: Callback", file=sys.stdout)
        if self.req_num <= client_timer.req_num:
            server_address = random.choice(self.server_addresses)
            print(f"Resending command {client_timer.paxos_req} to {server_address}", file=sys.stdout)
            data = pickle.dumps(client_timer.paxos_req)
            self.sock.sendto(data, server_address)
            setTimer(client_timer, ClientTimer.CLIENT_RETRY_MILLIS, self.onClientTimer)


if __name__ == "__main__":
    client = LockClient()
    client.execute()