Conversation
feat(req,rep,pub,sub): support custom connection hooks
Code ReviewI found 2 issues during the code review: 1. Compilation Error: Field name mismatch in SubOptions::default()File: The Default implementation uses See the struct definition around line 56: pub struct SubOptions {
/// The maximum amount of incoming messages that will be buffered before being dropped due to
/// a slow consumer.
ingress_queue_size: usize,But the Default impl at line 104 uses the wrong name: impl Default for SubOptions {
fn default() -> Self {
Self {
ingress_buffer_size: DEFAULT_QUEUE_SIZE, // Should be ingress_queue_sizeFix: Change 2. CLAUDE.md not updated to reflect architecture changesFile: The PR completely replaces the
Since CLAUDE.md provides guidance about the architecture and key design patterns of the project, these references should be updated to reflect the new Suggested changes:
See: Line 53 in f14e578 Line 96 in f14e578 |
|
@claude please review again |
|
Claude finished @Karrq's task in 1m 36s —— View job Code Review CompleteGreat work on this refactoring! The previous issues have been fixed: ✅ Fixed: Overall AssessmentThis is a well-executed refactoring that successfully replaces the authentication system with a more flexible What's Good
Minor ObservationsThese are not bugs, just observations for potential future improvements:
Test CoverageThe examples demonstrate the hooks working correctly:
Consider adding integration tests in
Code Quality
SummaryThis PR successfully achieves its goal of replacing the authentication system with a more flexible hook-based approach. The implementation is solid, well-tested through examples, and maintains consistency across all socket types. The design allows users to implement custom authentication, handshakes, or protocol negotiation while providing convenient built-in token-based auth. Recommendation: ✅ Approve with the understanding that the minor observations above are not blockers. |
msg-socket/src/hooks/mod.rs
Outdated
| @@ -0,0 +1,160 @@ | |||
| //! Connection hooks for customizing connection setup. | |||
There was a problem hiding this comment.
Nit but if the folder is for connection hooks only, I'd rename it as such, since this might hint there are some other type of hooks that could be implemented. Otherwise, these docs can be adjusted slightly.
There was a problem hiding this comment.
Hmmm, maybe I can move it under connection? so it's even more explicit?
tbh I didn't leave out other hook types, but at the same time we can refactor if/when we do that
There was a problem hiding this comment.
I made it explicit in the doc that this could be expanded to other hook types
msg-socket/src/hooks/mod.rs
Outdated
| /// A custom hook-specific error. | ||
| Custom(Box<dyn StdError + Send + Sync + 'static>), |
There was a problem hiding this comment.
Isn't it a bit too loose? Have you thought about adding a generic?
There was a problem hiding this comment.
Originally I wanted the generic too, but it was a pain to propagate everywhere
We already type erase the hook itself, and tbh we don't really use this error so far.
It's mostly to differentiate it from the underlying io error
There was a problem hiding this comment.
Now we still have hooks::Error accepting a generic arg, and then we have the type erased one for internal use
| let mut pub_socket = | ||
| PubSocket::new(Tcp::default()).with_connection_hook(ServerHook::accept_all()); |
There was a problem hiding this comment.
Is it necessary to be specified if it's an accept_all policy? Same for other occurrences here.
There was a problem hiding this comment.
This replaces the logic of the test that was there before, which I think was just showing how you'd do auth, but the implementation actually didn't verify anything.
So here we are showing that we could do authentication using a connection hook
msg-socket/src/sub/driver.rs
Outdated
| /// A joinset of connection tasks. | ||
| pub(super) connection_tasks: JoinMap<A, Result<T::Io, HookError>>, |
There was a problem hiding this comment.
Why now connection tasks may return HookError? Should this be renamed?
There was a problem hiding this comment.
Split the join map so we avoid this
msg-socket/src/sub/socket.rs
Outdated
| // Take the transport from the existing driver and rebuild with the hook | ||
| if let Some(mut driver) = self.driver.take() { | ||
| driver.hook = Some(hook_arc.clone()); | ||
| self.driver = Some(driver); | ||
| } |
There was a problem hiding this comment.
I would expect it to make clear that this should be run before the driver is taken and spawn by connecting.
There was a problem hiding this comment.
Yes this is what I mentioned in the standup today: there's a bit of unclarity in how we want to handle this pattern, where realistically items like hook (and compression as it stands today) shouldn't be able to be changed after, and in general a socket shouldn't be able to spawn multiple drivers
I decided that this decision should be made in another PR
fix: better hook task spans docs: consistent "connection hook" phrasing refactor(sub): split connection and (old auth) hooks task sets fix: ensure connection hook not set when driver is running
mempirate
left a comment
There was a problem hiding this comment.
Very nice! Could you add a more involved example of like a negotiation?
| ) -> Pin<Box<dyn Future<Output = ErasedHookResult<Io>> + Send + 'static>>; | ||
| } | ||
|
|
||
| impl<T, Io> ConnectionHookErased<Io> for T |
There was a problem hiding this comment.
Nice pattern! Simplifies implementation for any consumers of this API
docs(hook): remove specific socket type mention
Closes #172 with a new
ConnectionHooktrait, which allows users of the library to inject custom custom logic when a connection is established.The authentication system we implemented before was redone in form of a hook, and is provided in it's own module