Conversation
|
Currently every top-level item is in its own file, and I'd like to keep doing that. It use fzf-vim to navigate around the project, and it makes it very easy to jump between structs by filename, and not have to search within a file. What do you think about creating a It makes sense to put request/response pairs in the the same file, so, for example,
More comments in a second, but I wanted to start with that high level thought. |
casey
left a comment
There was a problem hiding this comment.
I didn't get to reviewing the meat of the code, but it's getting late so I'm going to leave it at this for now.
If you check continuous integration, there are a bunch of clippy lints, you can see them locally if your run cargo clippy --all or just clippy.
|
I also updated this branch with new commits from master, which I shouldn't have done, since it creates nasty merge commits. Feel free to rebase and force push. |
|
The only problem I see with your high level thought: all of the big Linux distros use https trackers. |
Sorry, I don't follow. If we add an HTTPS tracker later, can't the code be reorganized then? |
It totally can. I was stating the obvious fact that if |
100%! |
360ac58 to
d0f5b7d
Compare
|
This build pipeline is fastidious. Let's see if I can fix the book building. |
|
There's a lot of generated documentation, and a lot of checks that make sure that all the documentation is consistent and/or up-to-date. I think in this case it's complaining that https://github.com/casey/intermodal/blob/master/bin/gen/config.yaml#L5 |
8e3e73b to
b9ef0a3
Compare
|
Interesting failure on the Windows machine. You totally saw it coming |
|
That's interesting! I'm surpised it would work on macos/linux, but fail on Windows. |
885f949 to
6673c2b
Compare
|
I think Window is right to send back the error. Binding to |
|
Ahh, yeah, I guess the tests should bind to 127.0.0.1? |
670c69a to
4b00703
Compare
casey
left a comment
There was a problem hiding this comment.
Made a bunch of comments, let me know what you think. Have you tried this with different tracker implementations, both OpenTracker, and anything else out there that's popular.
| SymlinkRoot { root: PathBuf }, | ||
| #[snafu(display("Failed to retrieve system time: {}", source))] | ||
| SystemTime { source: SystemTimeError }, | ||
| #[snafu(display("The UDP tracker connection id has expired."))] |
There was a problem hiding this comment.
Hypothetically, shouldn't this not be a user-facing error, since the client is supposed to get a new connection ID if the old one expires?
For simplicity, I propose we deviate from the spec a little bit for now, instead of worrying about handling getting a new connection ID. For every request, let's do 4 attempts every 15 seconds, and if we don't get a response by the last attempt, we give up and return a TrackerTimeout error. This keeps us under the 60 second limit for our connection ID, and later we can implement exponential backoff and re-requesting new connection IDs.
| self.parse_compact_peer_list(&buf[mem::size_of::<announce::Response>()..len]) | ||
| } | ||
|
|
||
| fn roundtrip<T: Request>(&self, req: &T, rxbuf: &mut [u8]) -> Result<(T::Response, usize)> { |
There was a problem hiding this comment.
I think I like fn exchange a little better than roundtrip, round trip sounds to me like the same thing going in both directions.
There was a problem hiding this comment.
Instead of returning a usize, can send_and_retry_with_backoff and roundtrip return a &[u8], which is the written-to portion of the rxbuf? This would avoid needing to index into the rxbuf correctly.
There was a problem hiding this comment.
I'll do a little research on this. But it looks like I left myself a little comment about this:
src/client/response.rs:
pub(crate) trait Response {
// We leak the response length so that payloads can be parsed. This should be
// cleaner when associated types within traits can specify named lifetime
// parameters.
fn deserialize(buf: &[u8]) -> Result<(Self, &[u8])>
There was a problem hiding this comment.
Woah—looks like this is easily doable now!!
4b00703 to
e6b05c1
Compare
e6b05c1 to
292f9b0
Compare
|
Yo!! I've had a bunch of changes queued up for a while now, and I think this is getting closer to usable. Let me know how it's looking. I'm also planning to push the Peer Protocol stuff up in the next few days. |
|
Awesome! It might take me a little bit, but I'll definitely get to this within the next few days. |
casey
left a comment
There was a problem hiding this comment.
10 days is a few, right 😅 Sorry for taking so long! I did some initial review, just really minor stuff, because I realized that I don't remember where we were in the feature.
What's new that I should be focusing on?
| code: "imdl torrent --help" | ||
|
|
||
| - command: imdl torrent announce | ||
| text: "Announce a torrent to its trackers and print all peers returned:" |
There was a problem hiding this comment.
Minor reword: "Announce a torrent to trackers and print returned peers:"
| #[snafu(display("UDP tracker connection id has expired."))] | ||
| TrackerConnectionExpired, | ||
| #[snafu(display("UDP tracker resolved `{}` to no useable addresses.", host_port))] | ||
| TrackerNoHosts { host_port: HostPort }, |
There was a problem hiding this comment.
Do you happen to know under what circumstances this could happen? It isn't obvious to me why to_socket_addrs would return an empty iterator, even though the stdlib docs say that it could.
There was a problem hiding this comment.
My understanding of the DNS protocol is too shallow to know whether this behaviour is possible. It seems reasonable that whoever hatched to_socket_addrs probably spent some serious time thinking it all through.
| clippy::map_unwrap_or, | ||
| clippy::missing_docs_in_private_items, | ||
| clippy::missing_inline_in_public_items, | ||
| clippy::needless_lifetimes, |
There was a problem hiding this comment.
I added this in a diff I just merged, so there'll be a conflict here.
91a5ff8 to
c4237c0
Compare
|
Heya heya---when 10 days is a few days plus holidays, you don't count the holidays. I've pushed up your copy changes, but, I think, the "integration test" needs a look. And you should also try the command and confirm that it works. |
casey
left a comment
There was a problem hiding this comment.
Made a bunch of comments! Almost all of them requesting things that aren't tests. I created #490, to track things that don't belong in the initial PR.
I'm changing the tests to remove the one that generates the changelog, which means you also don't have to worry about adding a commit type to commits anymore. It was good for keeping the changelog up to date, but ultimately, I think, more annoying that it was worth.
If possible, could you push diffs instead of force pushing? This makes it easier to see what's changed since I last took a look. I think I might have said something about force pushing being preferable, but I take it all back.
| None => continue, | ||
| }; | ||
|
|
||
| let client = tracker::Client::connect(&hostport); |
There was a problem hiding this comment.
This can be:
let client = match tracker::Client::connect(&hostport) {
Err(e) => {
errln!(env, "Couldn't connect to tracker: {}", e)?;
continue;
}
Ok(client) => client,
};There was a problem hiding this comment.
(I wish Rust had let = … else { … } statements like swift.)
| continue; | ||
| } | ||
|
|
||
| let hostport = match HostPort::from_url(&tracker) { |
There was a problem hiding this comment.
If a URL in the torrent is malformed, we should print a warning.
There was a problem hiding this comment.
Also, there should be a test that such URLs are skipped.
| for result in metainfo.trackers() { | ||
| match result { | ||
| Ok(tracker) => trackers.push(tracker), | ||
| Err(err) => errln!(env, "Skipping malformed tracker URL: {}", err)?, |
There was a problem hiding this comment.
There should be a test that malformed tracker URLs are skipped.
| } | ||
|
|
||
| if trackers.is_empty() { | ||
| return Err(Error::MetainfoMissingTrackers); |
There was a problem hiding this comment.
There should be a test that elicits this error.
| } | ||
|
|
||
| for tracker in trackers { | ||
| if tracker.scheme() != "udp" { |
There was a problem hiding this comment.
There should be a test that non-UDP tracker URLs are skipped.
| impl super::Request for Request { | ||
| type Response = Response; | ||
|
|
||
| fn serialize(&self) -> Vec<u8> { |
There was a problem hiding this comment.
This could use a test. Just had a thought: Request/response pairs should all have tests that round trip a struct, where the struct is serialized, deserialized, and the output asserted to be equal to the input.
|
|
||
| impl super::Response for Request { | ||
| #[allow(dead_code)] | ||
| fn deserialize(buf: &[u8]) -> Result<(Self, usize)> { |
There was a problem hiding this comment.
This could use a test, and also one that elicits the error condition.
| } | ||
|
|
||
| impl super::Response for Response { | ||
| fn deserialize(buf: &[u8]) -> Result<(Self, usize)> { |
There was a problem hiding this comment.
This could use a test, including one for the error condition.
| type Response = Request; | ||
|
|
||
| #[allow(dead_code)] | ||
| fn serialize(&self) -> Vec<u8> { |
| @@ -0,0 +1,298 @@ | |||
| use super::*; | |||
There was a problem hiding this comment.
There should be tests that elicit all of the error conditions that are possible.
This command makes use of a partially-implemented UDP tracker client to announce an infohash and list the response. type: added
Switch `Into<X> for Y` to `From<Y> for X`.
Tidy up out-of-vogue `to_string()` usage.
Please MacOS by binding to `0.0.0.0`.
Tidy up exchange signature
Keep futzing with IP addresses in timeout tests.
Run `cargo +nightly fmt --all`
announce: print a warning when tracker URLs are malformed
announce: attempt to get a peer list from all trackers in the metainfo
Remove deadcode attribute
Follow clippy advice
Fix up bad diff from bad rebase.
|
I think this has gone stale 😅 |
Here's some alpha quality work towards #255
Please take note of the "popular repository" indelibly front and centre on my Microsoft Github profile page.