Skip to content

feat(dvc): add DvcChannelListener for multi-instance DVC support#1142

Open
uchouT (uchouT) wants to merge 6 commits intoDevolutions:masterfrom
uchouT:refactor/dvc
Open

feat(dvc): add DvcChannelListener for multi-instance DVC support#1142
uchouT (uchouT) wants to merge 6 commits intoDevolutions:masterfrom
uchouT:refactor/dvc

Conversation

@uchouT
Copy link

@uchouT uchouT (uchouT) commented Mar 3, 2026

Resolves #1135

  • implement the client-side without breaking the current API signatures by introducing OnceListener wrapper for pre-registered DVCs.
  • implement server side with a new method create_channel for DrdynvcServer.

older discussion

I try to implement the client-side without breaking the current API signatures by introducing OnceListener wrapper for pre-registered DVCs. But get_dvc_by_type_id's behavior has changed, it returns None until CreateRequest arrives.

This is unavoidable — the old 1:1 name→channel mapping cannot support multiple channels with the same name. The ChannelId is assigned by the server at CreateRequest time, so the DVC cannot exist before that point. And this behavior follows the RDPEDYC's expectation.

Marc-Andre Lureau (@elmarco) Benoît Cortier (@CBenoit) Does this approach acceptable and make sense?

@uchouT uchouT (uchouT) changed the title Refactor/dvc feat(dvc): add DvcChannelListener for multi-instance DVC support Mar 3, 2026
@elmarco
Copy link
Contributor

uchouT (@uchouT) lgtm, perhaps squash or reorganize some of your changes (PERF, ..)

Signed-off-by: uchouT <i@uchout.moe>
Introduce DvcChannelListener trait and OnceListener to support same-name
multi-instance dynamic virtual channels. DVCs are now created on-demand
via try_create_channel() when the server sends a CreateRequest, rather
than pre-allocated at registration. The existing with_dynamic_channel()
API is preserved via OnceListener.

BREAKING: get_dvc_by_type_id() now returns None until the server sends a
CreateRequest for the channel. Previously it returned Some immediately
after registration.

Signed-off-by: uchouT <i@uchout.moe>

perf(dvc): reduce another btreemap search

Signed-off-by: uchouT <i@uchout.moe>

perf(dvc): reduce needless allocation in OnceListener

Signed-off-by: uchouT <i@uchout.moe>
@uchouT
Copy link
Author

uchouT (uchouT (@uchouT)) lgtm, perhaps squash or reorganize some of your changes (PERF, ..)

Squashed, thanks for reminding.

I found that ironrdp-session would be affected by this, but I didn't go further.

pub fn get_dvc<T: DvcProcessor + 'static>(&self) -> Option<&DynamicVirtualChannel> {
self.get_svc_processor::<DrdynvcClient>()?.get_dvc_by_type_id::<T>()
}

If this is acceptable, I will try the server-side implementation.

@glamberson
Copy link
Contributor

If this is acceptable, I will try the server-side implementation.

This is good work. The listener/factory pattern is exactly the right approach for multi-instance DVCs. The OnceListener wrapper preserving backward compatibility for single-instance channels is a nice touch.

We're using IronRDP on the server side (lamco-rdp-server) and this direction aligns well with what we'll need for URBDRC support down the road. The encode_dvc_messages() and DvcProcessor trait being untouched means our current code should be unaffected by the client-side refactor.

Looking forward to the server-side implementation with take_new_channels(). Happy to help test once that lands.

Regards,
Greg Lamberson
Lamco Development

@uchouT
Copy link
Author

Looking forward to the server-side implementation with take_new_channels(). Happy to help test once that lands.

Thanks for the review, the positive feedback, and your willingness to help test, Greg Lamberson (@glamberson)!

Regarding the take_new_channels() approach, I still have some hesitations about the implementation details. I left my thoughts here #1135 (comment) , would love to hear your input.

Unlike `with_dynamic_channel`, this method is designed for runtime use
and doesn't record a TypeId mapping.

Signed-off-by: uchouT <i@uchout.moe>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements multi-instance DVC (Dynamic Virtual Channel) support by introducing a DvcChannelListener factory trait that produces a new DvcClientProcessor instance per DYNVC_CREATE_REQ. It preserves the existing single-instance API by internally wrapping pre-registered DvcProcessor instances in an OnceListener. On the server side, a new create_channel method is added to DrdynvcServer to allow opening new DVC channels mid-session.

Changes:

  • Introduces DvcChannelListener trait and OnceListener adapter, refactors DynamicChannelSet (moved from lib.rs to client.rs) to key active channels by DynamicChannelId rather than by name
  • Adds DrdynvcServer::create_channel() for mid-session server-side DVC channel creation
  • Removes the now-obsolete DynamicChannelSet struct from lib.rs, replacing DynamicVirtualChannel::new with from_boxed

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
crates/ironrdp-dvc/src/client.rs Adds DvcChannelListener trait + OnceListener, refactors DynamicChannelSet to support multi-instance channels, updates process() to use new listener-based creation flow
crates/ironrdp-dvc/src/lib.rs Removes DynamicChannelSet, changes DynamicVirtualChannel constructor to from_boxed
crates/ironrdp-dvc/src/server.rs Adds create_channel() for mid-session DVC channel creation; removes stale FIXME comment

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

uchouT (uchouT) and others added 2 commits March 5, 2026 14:51
Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Author

@uchouT uchouT (uchouT) left a comment

Choose a reason for hiding this comment

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

Addressed Copilot's review. Benoît Cortier (@CBenoit)

Signed-off-by: uchouT <i@uchout.moe>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

[ironrdp-dvc] Support multiple DVC channel instances with the same name

4 participants