Skip to content
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

Add custom error handling #104

Merged
merged 44 commits into from
Mar 1, 2020
Merged

Add custom error handling #104

merged 44 commits into from
Mar 1, 2020

Conversation

captain-yossarian
Copy link
Contributor

@captain-yossarian captain-yossarian commented Jan 9, 2020

Regarding #73 issue
It is only prototype.
@imsnif Which cases I have to consider in custom error trait?

@imsnif
Copy link
Owner

imsnif commented Jan 9, 2020

So, what we're trying to do here is forward all errors to the user and provide useful hints about what to do about the ones we know. Which is currently only the permission error. We also throw a custom error for an unknown interface (because pnet doesn't do it for us).

So essentially, what we'd like to get to is a generic error type that would wrap or mirror the io error, and allow us to slap on our own "unknown interface error".

Makes sense? (sorry if the explanation is not 100%, I'm a little tired and didn't want to keep you stuck until I have more time :) ).

src/os/shared.rs Outdated
)),
Err(e) => Err(e),
Ok(_) => {
let error = MyError::new(MyErrorKind::PermissionError("Please do something".to_string()));
Copy link
Contributor Author

@captain-yossarian captain-yossarian Jan 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsnif What do you think about this approach? Here we can define our own kind of error along with error message.
GItHub warns about files conflict, but I have no clue how to fix it. There is no conflicts on my local GitBash.

Copy link
Collaborator

@ebroto ebroto Jan 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @SerhiiBilyk, the conflicts appear because GitHub merges your work with the current master. To reproduce this locally, you need the latest changes.

You will have to add this repo (as opposed to your fork) as a remote if you didn't do it already. See here for instructions. After that, you can either rebase your branch on top of the current master, or merge master with your branch.

I hope this helps!

@captain-yossarian
Copy link
Contributor Author

@ebroto Thank you very much!

@captain-yossarian captain-yossarian changed the title [WIP]Add custom error handling Add custom error handling Jan 13, 2020
@imsnif
Copy link
Owner

imsnif commented Jan 14, 2020

Hey @SerhiiBilyk - is this ready for a review?

@captain-yossarian
Copy link
Contributor Author

Hey @imsnif , yes

Copy link
Owner

@imsnif imsnif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, good progress! I like the approach - just be sure to place the errors in the right place. :) You can check with the permission error (the most important to us right now) locally as I wrote in the comments.

Otherwise, could we change the name from MyError to something like GetInterfaceError?

src/os/shared.rs Outdated
let error = MyError::new(MyErrorKind::PermissionError("Please do something".to_string()));
Err(error)
},
Err(e) => Err(MyError::new(MyErrorKind::OtherError(e.to_string()))),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The permission error actually happens here. You can test for it locally by running without sudo and seeing where the error comes from.

@captain-yossarian
Copy link
Contributor Author

@imsnif I've changed error name. It is looks like it work. Could you please check?

Copy link
Owner

@imsnif imsnif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for changing the name. Good progress - I left some comments about what needs to be changed. Please let me know if it's unclear and I'll try to explain further.

src/os/shared.rs Outdated
)),
Err(e) => Err(e),
Ok(_) => {
let error = GetInterfaceError::new(GetInterfaceErrorKind::OtherError("Please do something".to_string()));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here we can go with "Unsupported interface type" as it was before

src/os/shared.rs Outdated
let error = GetInterfaceError::new(GetInterfaceErrorKind::OtherError("Please do something".to_string()));
Err(error)
},
Err(e) => Err(GetInterfaceError::new(GetInterfaceErrorKind::PermissionError("Permission error".to_string()))),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Permission error is only one error type we can get here. Essentially, we would like to forward all of these errors to the user, and if the error is a permission error, display the "use sudo" string below. Does this make sense?

@captain-yossarian
Copy link
Contributor Author

@imsnif could you please check if everything is ok ?

@imsnif
Copy link
Owner

imsnif commented Feb 5, 2020

Hey @SerhiiBilyk - correct me if I'm wrong, but I think even after the changes we still send a permission error for whatever error we get, don't we?

@captain-yossarian
Copy link
Contributor Author

@imsnif if you mean this line (shared.rs, 48 line) then - yes. Do I need to check if this error is permission error ?
Maybe I did not understand you. I thought here we can get only permission error.

Could you please highlight those line of code which I have to change ? Thank you for your patient ;)

@imsnif
Copy link
Owner

imsnif commented Feb 6, 2020

@imsnif if you mean this line (shared.rs, 48 line) then - yes. Do I need to check if this error is permission error ?

Yes, exactly.

Maybe I did not understand you. I thought here we can get only permission error.

Ah, sorry. I think I wrote that quickly and I wasn't very clear. We want to handle only the permission error (by suggesting to the user to user sudo). All the rest we just want to forward to them.

src/os/shared.rs Outdated
ErrorKind::PermissionDenied => Err(GetInterfaceError::new(
GetInterfaceErrorKind::PermissionError(format!("{}. Try running with sudo.", e)),
)),
_ => Err(GetInterfaceError::new(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsnif I did not find Result error type which will allow to return here simple std::io::Error Err(e)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we might be able to store its text in the GetInterfaceError you created, so that we can display it to the user?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsnif If user will run cargo build without sudo, he will see Permission error (sudo).
If you comment 46-48 lines and run cargo build without sudo, you will see Failed to find any network, because in this case we throw our custom error only in case of Permission Error.

If you want print to user other error Err(e) , we should change this failure::bail!("Failed to find any network interface to listen on.");

Answer on your question: yes.
Check this 35 line of errors.rs

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you think we should change it, let's do that. :)
The final end goal is:

  1. If it's a permission error, the user should get a permission error and have sudo suggested to them.
  2. If there's another error, let's forward it to the user.
  3. If we get several other errors, we can forward all of them to the user. Maybe one per line with the name of the network interface in front of it.

How does that sound?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I will do that

Copy link
Contributor Author

@captain-yossarian captain-yossarian Feb 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsnif done.
I made a small refactor to reduce boilerplate

P.S. Could you please look at this comment ? I did all my best

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, this is great! I'm good to go with this, just one little nitpick:
With this, if there is more than 1 interface that has an error, we will bail and show the error for just the first one.
Would you like to fix this, or shall we leave it for next time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsnif I will do it in scope of this PR

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Just another addition: if there is at least one permission error, let's just show the permission message. I think that would be clearer. Sounds good?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@imsnif Could you please check ?

@imsnif
Copy link
Owner

imsnif commented Mar 1, 2020

Hey @captain-yossarian.

First let me start by apologizing for my spotty availability over the past few weeks.

I really liked the changes you made for displaying multiple errors. I also learned about the .. spread syntax which was totally new to me. Thank you for that :)

I made some minor changes, mainly in order to display the network interface name on all errors, and to make sure all the errors we get are displayed in some edge cases (eg. permission errors on multiple interfaces).

In order to find these edge cases, I mostly just started hacking away at the get_datalink_channel method in os/shared.rs. By making it return different error types (eg. one permission error and one "other" error, two permission errors, two "other" errors, etc.) I could see how we behave in those situations and which errors we display.

I found, for example, that if we get a permission error, we get a nice explanation for it, but then afterwards we just get the printed errors from the interfaces (sometimes without the interface names). I thought that output could be friendlier, so I added an "Additional Errors" display.

Thank you for all your work on this, and your persistence even when I wasn't 100% available to assist. I hope to see more contributions from you in the future.

@imsnif imsnif merged commit c45b3c8 into imsnif:master Mar 1, 2020
@captain-yossarian
Copy link
Contributor Author

@imsnif Hi, thank you for your feedback. I have learn a lot from your codebase! This is my first Rust PR. So thank you very much for your patient and guidance.
I'm definitely will contribute to your project in the future!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants