Skip to content

Conversation

@atomgardner
Copy link
Collaborator

@atomgardner atomgardner commented Oct 3, 2020

Another step toward #255.

@casey
Copy link
Owner

casey commented Oct 3, 2020

I think that FromStr is too general for MagnetLink, perhaps it should be TryFrom<URL>? I would also make a separate error type, since it seems there are a lot of ways that magnet link parsing can fail, perhaps MagnetLinkParseError?

Copy link
Owner

@casey casey left a comment

Choose a reason for hiding this comment

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

Also, it would be good to add tests that check that the expected errors are returned when malformed magnet links are parsed.

});
}
let xt = v
.trim_start_matches("urn:bti")
Copy link
Owner

Choose a reason for hiding this comment

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

If these aren't present it should return an error.

@atomgardner
Copy link
Collaborator Author

I think FromStr was suggested so the subcommand would be nice and clean:

#[derive(StructOpt)]
#[structopt(...)]
pub(crate) struct FromLink {
  link : MagnetLink
}

Is StructOpt smart enough to walk the &str -> URL -> MagnetLink parser lattice without any guidance?

@casey
Copy link
Owner

casey commented Oct 4, 2020

Ahh, you're right. In that case, I think FromStr is fine.

@casey
Copy link
Owner

casey commented Oct 4, 2020

Also, just thought of this, I think it's allowed for a magnet link to have multiple exact topics. There are different xt types for different networks, and you're allowed to have multiple xts:

http://wiki.depthstrike.com/wiki/P2P:Protocol:Specifications:Magnet#xt_-_eXact_Topic

I think the right behavior is to just grab the first xt key where the value starts with urn:btih:.

@atomgardner atomgardner force-pushed the magnet-link-parsing branch 2 times, most recently from de37e74 to 0bbb097 Compare October 10, 2020 09:30
@atomgardner
Copy link
Collaborator Author

have sent a band-aid patch (#485) for the linting failures

@casey
Copy link
Owner

casey commented Oct 11, 2020

I just merged #485, although with some changes. Let me know when this is ready to review!

Copy link
Owner

@casey casey left a comment

Choose a reason for hiding this comment

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

Added a bunch of comments, mostly about error messages and formatting.

src/error.rs Outdated
#[snafu(display("Invalid glob: {}", source))]
GlobParse { source: globset::Error },
#[snafu(display("Failed to parse hex string `{}`: {}", text, source))]
HexParse {
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 that HexParse and InfohashParse should be moved into MagnetLinkParseError. HexParse on its own is not informative enough on the top level for a user to figure out what to do. If eventually multiple parts of the code parse infohashes, InfohashParse can be be moved back into Error. (But actually, if multiple parts of the code are parsing infohashes, then a generic Error::InfohashParse will not be specific enough for the user to know what to do, and will need separate error types.)

I'm thinking how these errors will be reported to the user, and I think in all cases the text that was being parsed should be printed. That way, the user sees the text of the magnet link that failed to parse, in addition to the error.

There are a few ways to do this. One is to have the error be a struct with a kind member that shows the actual error:

struct MagnetLinkParseError {
  text: String, // magnet link that we attempted to parse
  kind: MagnetLinkParseKind, // the actual error that occurred
}

enum MagnetLinkParseKind {
  Url { source: url::Error},
  // …
}

Another is to move the text into the Error variant:

enum Error {
  MagnetLinkParse {
    text: String, // magnet link we attempted to parse
    source: MagnetLinkParseError,
  },
  // …
}

I think the latter approach probably the right way to go for now. It's less annoying, and if it's eventually insufficient, it can be refactored into the former.

The variant can look like this:

#[snafu(display("Failed to parse magnet link `{}`: {}", text, source))]
MagnetLinkParse { text: String, source: MagnetLinkParseError},

Copy link
Collaborator Author

@atomgardner atomgardner Oct 14, 2020

Choose a reason for hiding this comment

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

I can see why you want MagnetLinkParse to have access to the link URL. But I think it's cleaner to put it inside every variant of MagnetLinkParseError---otherwise, we'd lose the From conversions.

I see what to do 💯

Copy link
Owner

Choose a reason for hiding this comment

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

I'm also cool with putting it inside of the MagnetLinkParserError, I was thinking it be annoying.

text: String,
source: HostPortParseError,
},
#[snafu(display("Magnet links must begin with `magnet:`"))]
Copy link
Owner

Choose a reason for hiding this comment

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

Invalid scheme `{}`, magnet links must use the `magnet:` scheme

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Something about the comma looks strange. Sure you want this exact message?

Copy link
Owner

Choose a reason for hiding this comment

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

I'm not wedded to the exact message, as long as it contains the invalid scheme. (Since I'm not sure if all users will know what a URL scheme is.)


#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub(crate) enum MagnetLinkParseError {
Copy link
Owner

Choose a reason for hiding this comment

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

Some of these messages will be redundant when printed in context, i.e. with Failed to parse magnet link: from the outer Error message.

Copy link
Owner

Choose a reason for hiding this comment

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

Tests should be added that use malformed magnet links to trigger all of these error variants, and check that their contents are correct.

@atomgardner atomgardner requested a review from casey October 16, 2020 09:17
@casey
Copy link
Owner

casey commented Oct 17, 2020

Looks good! Can you flip the switch that lets me push to this branch? I need to push a version with my PGP signature attached in order to merge it.

@casey
Copy link
Owner

casey commented Oct 17, 2020

I just realized a couple things that could be improved:

  1. There's an assert_matches macro that can be used to clean up the tests. You can do assert_matches!(VALUE, PATTERN if CONDITION).

  2. I think all the logic inside the fromstr implementation could be moved into MagnetLink::parse(text: &str) -> Result<MagnetLink, MagnetLinkParseError> and then from_str could just be Self::parse(text).context(error::MagnetLinkParse{text}), to avoid a bunch of .context calls.

Feel free to do these, or I can do them before I merge.

@atomgardner atomgardner force-pushed the magnet-link-parsing branch 2 times, most recently from 316b102 to f354199 Compare October 17, 2020 23:54
@atomgardner
Copy link
Collaborator Author

...to avoid a bunch of context calls.

excellent! 💯 💯

Also, you now have permission to clobber this branch.

@casey casey force-pushed the magnet-link-parsing branch 2 times, most recently from d33fc51 to 97ab785 Compare October 18, 2020 00:27
@casey casey merged commit 97ab785 into casey:master Oct 18, 2020
@casey
Copy link
Owner

casey commented Oct 18, 2020

Sweet, merged! Thank you!

@atomgardner atomgardner deleted the magnet-link-parsing branch December 1, 2022 07:42
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.

2 participants