def Propagate_Withdraw(self, request_id, amount): MyLog( logger, f'Propagate {get_operation_name(banking_pb2.WITHDRAW)} id {request_id} amount {amount} to other branches' ) if not self.stubList: self.Populate_Stub_List() for stub in self.stubList: response = stub.MsgDelivery( banking_pb2.MsgDeliveryRequest( S_ID=request_id, OP=banking_pb2.WITHDRAW, Amount=amount, D_ID= DO_NOT_PROPAGATE, # Sets DO_NOT_PROPAGATE for receiving branches )) MyLog( logger, f'Branch {self.id} sent request {request_id} to other Branches -' f'operation {get_operation_name(banking_pb2.WITHDRAW)} result {get_result_name(response.RC)} ' f'money {response.Amount}')
def executeEvents(self, output_file): """Execute customer events.""" # DEBUG #MyLog(logger,f'Executing events for Customer #{self.id}') record = {'id': self.id, 'recv': []} for event in self.events: request_id = event['id'] request_operation = get_operation(event['interface']) request_amount = event['money'] response = self.stub.MsgDelivery( banking_pb2.MsgDeliveryRequest( S_ID=request_id, OP=request_operation, Amount=request_amount, D_ID=self.id, )) MyLog( logger, f'Customer {self.id} sent request {request_id} to Branch {response.ID} ' f'interface {get_operation_name(request_operation)} result {get_result_name(response.RC)} ' f'money {response.Amount}') 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')
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)
def executeEvents(self, output_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: request_id = event['id'] request_operation = get_operation(event['interface']) request_amount = event['money'] try: LogMessage = ( f'[Customer {self.id}] Executing request: ID {request_id} against Branch - ' f'Operation: {get_operation_name(request_operation)} - ' f'Initial balance: {request_amount}') MyLog(logger, LogMessage, self) # The customer's clock is not used in gRPC and Lampard's algorithm, but will be # likely used in the Client Consistency's exercise. # In the logical clock assignment (Lampars's algorithm), it is checked, but the configuration # file for customers does not allow setting it anyway. response = self.stub.MsgDelivery( banking_pb2.MsgDeliveryRequest(REQ_ID=request_id, OP=request_operation, Amount=request_amount, D_ID=self.id, Clock=0)) LogMessage = ( f'[Customer {self.id}] Received response to request ID {request_id} from Branch - ' f'Operation: {get_operation_name(request_operation)} - Result: {get_result_name(response.RC)} - ' f'New balance: {response.Amount}') values = { 'interface': get_operation_name(request_operation), 'result': get_result_name(response.RC), } MyLog(logger, LogMessage, self) 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)