-
Notifications
You must be signed in to change notification settings - Fork 10
Update the configure logic #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Dima Dorezyuk <ddo@qwello.eu>
Signed-off-by: Dima Dorezyuk <ddo@qwello.eu>
7d4e408 to
a173fd5
Compare
| #[error("TID not activated")] | ||
| /// Note: This does **not** mean that we have to activate the tid on the | ||
| /// payment terminal side. | ||
| TidNotActivated = 0x3a, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this has been verified with lavego
| /// Messages as defined under chapter 11. | ||
| #[derive(Debug, PartialEq, FromPrimitive, Clone, Copy, Error)] | ||
| #[repr(u8)] | ||
| pub enum TerminalStatusCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we act on only a fraction of the error codes right now - but we would need to observe which ones we really see from feig
| constants::TerminalStatusCode::PtReady => { | ||
| log::debug!("Terminal is ready"); | ||
| } | ||
| constants::TerminalStatusCode::ReconciliationRequired => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note - this is not identical with the emails we receive regarding eod jobs - this would only fire if the pt itself thinks we need to run eod
hovinen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might need you to walk me through some of these changes, since I'm not so familiar with all of the components involved.
| } | ||
|
|
||
| impl FromStr for StatusType { | ||
| type Err = String; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this project is using anyhow anyway, would it make sense to use anyhow::Error here?
| match s.to_lowercase().as_str() { | ||
| "feig" => Ok(StatusType::Feig), | ||
| "zvt" => Ok(StatusType::Zvt), | ||
| _ => Err(format!("'{}' is not a valid StatusType (feig | zvt)", s)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could inline s in the format string: {s}. I see this elsewhere so I guess there's no concern about supporting older rustc version which don't have that yet.
| pub async fn configure(&mut self) -> Result<()> { | ||
| if self.successfully_configured { | ||
| return Ok(()); | ||
| // Get the status inquiry so we can reason on the terminal_status_code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to understand this function. It seems that it's doing two distinct things: fetching the terminal status code via a kind of RPC and evaluating that to possibly issue some commands. What would you say about extracting those parts into separate, appropriately named functions to make the steps clearer?
| match response? { | ||
| CVendFunctionsEnhancedSystemInformationCompletion(data) => log::info!("{data:#?}"), | ||
| Abort(_) => bail!("Failed to get system info. Received Abort."), | ||
| async fn status( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having trouble understanding how these changes here map to what's in the PR description. This seems to be modifying the CLI tool to log some data in response to a command. How does that relate to the rest of the changes?
| StatusType::Zvt => { | ||
| let request = packets::StatusEnquiry { | ||
| password: Some(password), | ||
| service_byte: service_byte, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed: since this can cause deserialization to fail for certain values, consider detecting those cases and printing at least a warning.
| SystemError = 0xff, | ||
| } | ||
|
|
||
| /// Messages as defined under chapter 11. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit - to make the comment clearer, maybe add:
/// Messages as defined under chapter 11 of the ZVT specifications, under "Terminal Status Codes".
| CompletionData(packets::CompletionData), | ||
| /// 2.55.5. The possible tags in the status enquiry correspond to the | ||
| /// ReceiptPrintoutCompletion. | ||
| CompletionData(packets::ReceiptPrintoutCompletion), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I understand - until now did we misread status responses?
| }; | ||
|
|
||
| let mut stream = sequences::StatusEnquiry::into_stream(&request, socket); | ||
| while let Some(response) = stream.next().await { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also get an Abort here from the stream? Would we likewise want to bail if we get it?
| /// We're doing the following based on the terminal status code: | ||
| /// * If PtReady - return | ||
| /// * If ReconciliationRequired - run end-of-day | ||
| /// * If InitialisationRequired or DiagnosisRequired - set terminal id and run emv diagnostics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's incomplete here - If InitialisationRequired or DiagnosisRequired or TerminalActivationRequired - set terminal id and run emv diagnostics, and initialize the terminal.
|
|
||
| match status { | ||
| constants::TerminalStatusCode::PtReady => { | ||
| log::debug!("Terminal is ready"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit - I think this can be info, since this only happens on new and reconnect
| terminal_status_code = Some(completion_data.terminal_status_code); | ||
| } | ||
| other => { | ||
| log::debug!("{other:#?}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is unexpected behavior, I think this can likewise be info / warning.
| } | ||
| constants::TerminalStatusCode::ReconciliationRequired => { | ||
| info!("Reconciliation required, running end of day"); | ||
| self.end_of_day().await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We wouldn't know a failure occurred here, since end_of_day doesn't log failure. Do we want to add some failure log there, here, or log the error when calling configure? Same goes for failure of set_terminal_id, initialize, and run_diagnosis below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better yet - since if this function fails we won't have a working PT on a pole, better log it in the calling function and add an alert for this failure to track it
| self.set_terminal_id().await?; | ||
| self.run_diagnosis(packets::DiagnosisType::EmvConfiguration) | ||
| .await?; | ||
| self.initialize().await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit - We can safely return after this line, we don't need to check if the TID was changed again since we've just set it.
hovinen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM based on our discussion yesterday. Please see also my comments.
Currently we run init and diagnostics on every start up - until the
successfully_configureflag is set. While being a simple logic this results in lots of unnecessary transactions (inti and diagnostics are transactions from the view of the payment provider backend and 1. cost money and 2. can overload the payment provider backend).The idea is to query the payment terminal (status inquiry, which is fast and does not result in calls to the payment provider backend) and based on the return code to reason if we need to run the aforementioned commands.
The status inquiry returns the terminal_status_code, which is defined under chapter 11 of zvt.