Ejemplo n.º 1
0
 def Populate_Stub_List(self):
     if len(self.stubList) == len(
             self.branches):  # stub list already initialized
         return
     for b in self.branches:
         if b != self.id:
             branch_address = self.bind_address
             MyLog(
                 logger,
                 f'Initializing branch to branch stub at {branch_address}')
             self.stubList.append(
                 banking_pb2_grpc.BankingStub(
                     grpc.insecure_channel(branch_address)))
Ejemplo n.º 2
0
    def createStub(self, Branch_address, THREAD_CONCURRENCY):
        """Start a client (customer) stub."""

        MyLog(
            logger,
            f'Initializing customer stub to branch stub at {Branch_address}')

        self.stub = banking_pb2_grpc.BankingStub(
            grpc.insecure_channel(Branch_address))

        client = grpc.server(
            futures.ThreadPoolExecutor(max_workers=THREAD_CONCURRENCY, ), )
        #banking_pb2_grpc.add_BankingServicer_to_server(Customer, client)
        client.start()
    def createStub(self,
                   Branch_address,
                   want_windows=False,
                   THREAD_CONCURRENCY=1):
        """
        Boots a client (customer) stub in a subprocess.
        If PySimpleGUI/TK are installed and in mode 2, launches a window in the Windows' Manager.

        Args:
            Self:               Customer class
            Branch_address:     TCP/IP address/port where to fund the Branch to connect to
            want_windows:       Boolean, True if graphical windows are desired as UX
            THREAD_CONCURRENCY: Integer, number of threads concurrency

        Returns:
            None

        """
        MyLog(
            logger,
            f'[Customer {self.id}] Initializing customer stub to branch stub at {Branch_address}'
        )

        self.stub = banking_pb2_grpc.BankingStub(
            grpc.insecure_channel(Branch_address))

        if ((sg != NotImplemented) and want_windows):
            layout = [[
                sg.Text("Operations Loaded:",
                        size=(60, 1),
                        justification="left")
            ], [sg.Listbox(values=self.events, size=(60, 3))],
                      [sg.Output(size=(80, 12))],
                      [
                          sg.Button("Run",
                                    tooltip='Start Customer\'s Operations')
                      ], [sg.Button("Close", tooltip='Terminate Customer')]]

            # Create the window
            sg.theme('Dark Green 5')
            w, h = sg.Window.get_screen_size()
            self.window = sg.Window(
                f"Customer #{self.id} -> To Branch @ {Branch_address}",
                layout,
                location=(50 * (self.id) + 10, h / 5 * (self.id - 1) + 50))

        client = grpc.server(
            futures.ThreadPoolExecutor(max_workers=THREAD_CONCURRENCY, ), )
        client.start()
Ejemplo n.º 4
0
    def Propagate_Withdraw(self, request_id, amount):
        """
        Implements the propagation of the withdraw to other branches.

        Args:
            Self:   Branch class
            request_id: the request ID of the event
            amount: the amount to be withdrawn from the balance

        Returns: The updated Branch balance after the amount withdrawn

        """
        #        with self.branch_lock:
        for stub in self.branchList:
            if self.id != stub[
                    0]:  # Do not propagate to itself (should not happen, added security)
                LogMessage = (
                    f'[Branch {self.id}] Propagate {get_operation_name(banking_pb2.WITHDRAW)} request ID {request_id} '
                    f'amount {amount} to Branch {stub[0]} @{stub[1]}')
                if (self.clock_events !=
                        None):  # Verify if in the logical clock case
                    LogMessage += (f' with clock {self.local_clock}')
                MyLog(logger, LogMessage, self)

                try:
                    msgStub = banking_pb2_grpc.BankingStub(
                        grpc.insecure_channel(stub[1]))

                    if (self.clock_events !=
                            None):  # Verify if in the logical clock case
                        response = msgStub.MsgDelivery(
                            banking_pb2.MsgDeliveryRequest(
                                REQ_ID=request_id,
                                OP=banking_pb2.WITHDRAW,
                                Amount=amount,
                                D_ID=
                                DO_NOT_PROPAGATE,  # Sets DO_NOT_PROPAGATE for receiving branches
                                Clock=self.local_clock))
                    else:
                        response = msgStub.MsgDelivery(
                            banking_pb2.MsgDeliveryRequest(
                                REQ_ID=request_id,
                                OP=banking_pb2.WITHDRAW,
                                Amount=amount,
                                D_ID=
                                DO_NOT_PROPAGATE,  # Sets DO_NOT_PROPAGATE for receiving branches
                            ))
                    LogMessage = (
                        f'[Branch {self.id}] received response to request ID {request_id} to Branch @{stub[1]} - '
                        f'Operation: {get_operation_name(banking_pb2.WITHDRAW)} - Result: {get_result_name(response.RC)} - '
                        f'New balance: {response.Amount}')
                    if (self.clock_events !=
                            None):  # Verify if in the logical clock case
                        LogMessage += (f' - Clock: {response.Clock}')

                    self.eventResponse()  # Call for eventResponse

                except grpc.RpcError as rpc_error_call:
                    code = rpc_error_call.code()
                    details = rpc_error_call.details()

                    if (code.name == "UNAVAILABLE"):
                        LogMessage = (
                            f'[Branch {self.id}] Error on request ID {request_id}: Branch {stub[0]} @{stub[1]} likely unavailable - Code: {code} - Details: {details}'
                        )
                    else:
                        LogMessage = (
                            f'[Branch {self.id}] Error on request ID {request_id}: Code: {code} - Details: {details}'
                        )

                MyLog(logger, LogMessage, self)
    def executeEvents(self, output_file, balance_file, want_windows=False):
        """
        Boots a client (customer) stub in a subprocess.
        If PySimpleGUI/TK are installed and in mode 2, launches a window in the Windows' Manager.

        Args:
            Self:               Customer class
            output_file:        Logging file where to save customer's events
            want_windows:       Boolean, True if graphical windows are desired as UX

        Returns:
            None

        """
        record = {'id': self.id, 'recv': []}
        for event in self.events:
            try:
                request_id = event['id']  # In case of client-consistency
            except KeyError:
                request_id = self.id
            request_operation = get_operation(event['interface'])
            try:
                request_amount = event['money']
            except KeyError:
                request_amount = 0  # In case of query
            try:
                request_dest = event['dest']  # In case of client-consistency
            except KeyError:
                request_dest = self.id

            try:
                if request_operation == banking_pb2.QUERY:
                    request_amount_string = ""
                else:
                    request_amount_string = str(event['money'])
                LogMessage = (
                    f'[Customer {self.id}] ID {request_id}: '
                    f'{get_operation_name(request_operation)} {request_amount_string}'
                    f' -> Branch {request_dest}')
                MyLog(logger, LogMessage, self)

                # Find the right Branch to send to
                msgStubClient = None
                for curr_branch in self.branchList:
                    if request_dest == curr_branch[0]:
                        msgStubClient = banking_pb2_grpc.BankingStub(
                            grpc.insecure_channel(curr_branch[1]))
                        break

                if msgStubClient == None:
                    LogMessage = (
                        f'[Customer {self.id}] Error on ID {request_id}: '
                        f'Branch {request_dest} not found in the list.  Not executed.'
                    )
                    MyLog(logger, LogMessage, self)
                else:
                    progr_request_id = request_id
                    if request_operation != banking_pb2.QUERY:
                        # First of all, request a WriteID to the Branch - if not a query.
                        # This is used to enforce "Monotonic Writes" and "Read Your Writes" client-centric consistency.
                        wid_response = msgStubClient.RequestWriteSet(
                            banking_pb2.WriteSetRequest(S_ID=self.id,
                                                        LAST_ID=request_id,
                                                        Clock=0))
                        self.writeSets.append(
                            WriteSet(self.id, wid_response.ProgrID, False))
                        progr_request_id = wid_response.ProgrID

                    # Execute the Client's request.
                    # The customer's clock is not used, but could be a future expansion.
                    # In the logical clock assignment (Lampars's algorithm), it is checked,
                    # but the configuration file for customers does not allow setting it anyway.
                    response = msgStubClient.MsgDelivery(
                        banking_pb2.MsgDeliveryRequest(
                            REQ_ID=request_id,
                            OP=request_operation,
                            Amount=request_amount,
                            S_TYPE=banking_pb2.
                            CUSTOMER,  # Source Type = Customer
                            S_ID=self.id,  # Source ID
                            D_ID=request_dest,
                            Clock=0,
                            ProgrID=progr_request_id))
                    if request_operation != banking_pb2.QUERY:
                        set_found = Set_WriteSet_Executed(
                            self, self.id, progr_request_id)
                        response_amount_string = f"New balance: {response.Amount}"
                    else:
                        response_amount_string = f"Balance: {response.Amount}"
                        # Output the final balance for the customer from the last query
                        with open(f'{balance_file}', 'a') as outfileb:
                            brecord = {
                                'id': self.id,
                                'balance': response.Amount
                            }
                            json.dump(brecord, outfileb)
                            #outfileb.write('\n')
                    LogMessage = (
                        f'[Customer {self.id}] ID {request_id}: {get_result_name(response.RC)} <- Branch {request_dest} - '
                        f'{response_amount_string}')
                    MyLog(logger, LogMessage, self)

                    values = {
                        'interface': get_operation_name(request_operation),
                        'result': get_result_name(response.RC),
                    }
                    if request_operation == banking_pb2.QUERY:
                        values['money'] = response.Amount
                    record['recv'].append(values)

                    if record['recv']:
                        # DEBUG
                        #MyLog(logger,f'Writing JSON file on #{output_file}')
                        with open(f'{output_file}', 'a') as outfile:
                            json.dump(record, outfile)
                            outfile.write('\n')

            except grpc.RpcError as rpc_error_call:
                code = rpc_error_call.code()
                details = rpc_error_call.details()

                if (code.name == "UNAVAILABLE"):
                    LogMessage = (
                        f'[Customer {self.id}] Error on Request #{request_id}: Branch {self.id} likely unavailable - Code: {code} - Details: {details}'
                    )
                else:
                    LogMessage = (
                        f'[Customer {self.id}] Error on Request #{request_id}: Code: {code} - Details: {details}'
                    )
                MyLog(logger, LogMessage, self)