Skip to content

refactor(web-client): refactor iron-remote-gui into iron-remote-desktop #722

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

Merged
merged 23 commits into from
Apr 11, 2025

Conversation

RRRadicalEdward
Copy link
Collaborator

@RRRadicalEdward RRRadicalEdward commented Mar 25, 2025

This is the first part of the "Modularize the remote desktop WebComponent" ticket.
PR changes the web-client of the IronRDP:

  • Renamed some of the structures on the Rust side
  • Removed the iron-remote-gui package
  • Added the iron-remote-desktop package with the TypeScript interfaces and exposed more interfaces from the WASM bindings
  • Added iron-remote-desktop-rdp package which combines WASM bindings and the TypeScript interfaces from the iron-remote-desktop to create an iron-remote-desktop HTML tag which is responsible for the RDP connection.
  • Updated xtask

Although GitHub says that there are 5K changes, most of the things are just file moves/renaming from iron-remote-gui to iron-remote-desktop and iron-remote-desktop-rdp. It doesn't seem to be able to diff it properly.

@RRRadicalEdward RRRadicalEdward self-assigned this Mar 25, 2025
@RRRadicalEdward RRRadicalEdward requested a review from CBenoit March 25, 2025 10:41
@CBenoit
Copy link
Member

CBenoit commented Mar 26, 2025

I think you are aware of this yourself as far as I can see in your own comments, but this is not really what I imagined when I talked about dependency injection.

To clarify: the new iron-remote-desktop package should contain ALL the logic that is found in the previous iron-remote-gui package.
The iron-remote-desktop-rdp package should only re-export the WASM module API, and nothing more. No additional logic. (Mostly? It’s fine to have a few helpers in addition to the rest.)
The architectural invariant is that these packages do not contain any common logic, and no code is duplicated.

I’m not very good at JavaScript/TypeScript, so let me illustrate what I mean using Rust:

// -- iron-remote-desktop --
// Implements all the backend-agnostic logic, based on a given "remote desktop interface".

trait RemoteDesktopApi {
    fn remote_desktop_init(&self);
}

fn run(api: Box<dyn RemoteDesktopApi>) {
    // The logic is calling the remote desktop API, and does not know whether this is RDP or VNC.
    api.remote_desktop_init();
}

// -- ironrdp-web --
// This is what actually implements the interface.
// But TypeScript is kind of working in a duck-typed way,
// so unlike Rust you don’t need to import the interface definition in order to implement it!

pub struct Api;

impl RemoteDesktopApi for Api {
    fn remote_desktop_init(&self) {
        // do stuff
    }
}

// -- iron-remote-desktop-rdp --
// The purpose is to inline the WASM module in base64,
// but essentially, it exposes the exact same things as ironrdp-web.

pub use ironrdp_web::Api;

// -- iron-svelte-client --
// Injects the dependency (IronRDP) into the web component (iron-remote-desktop), and uses it.
// It knows that its IronRDP behind the scenes, and may inject additional extensions (future improvement).

iron_remote_desktop::run(Box::new(iron_remote_desktop_rdp::Api));

Because of the way JavaScript/TypeScript works, we don’t need iron-remote-desktop-rdp to know about the interface defined in iron-remote-desktop.

Keep in mind that I’m only trying to illustrate what I meant for dependency injection. I do not ask you to modify drastically any Rust code (ideally ironrdp-web should stay the way it is, and there is no issue with the way you updated it in this PR.)
It’s not possible to directly translate this Rust code into TypeScript, and you will likely not define a "TypeScript interface" for the module itself.
My understanding is that when building ironrdp_web using wasmpack, we get a module exporting a few items such as SessionBuilder. SessionBuilder in turns implements a specific "typescript interface" (as defined in the Slack canvas).

My expectation is that iron-remote-desktop-rdp should basically end up being this:

export * as default from './path/to/wasm/module'

= Re-export the whole interface of the WASM module.

You can then import this module in iron-svelte-client, and inject it into the iron-remote-desktop component.

import * as rdp from '@devolutions/iron-remote-desktop-rdp'

// I think we have something called "userInteraction" somewhere?
// Use it to inject the module ("dependency").
userInteraction.setBackend(rdp);

// Or maybe it’s `userInteractionService` which wraps the `userInteraction`?
// Try to look for the `onMount` function.
// We retrieve the `userInteraction` (`event.detail.irgUserInteraction`) and
// store it in a `writeable` that is accessible globally.

(Also refer to this section.)

If you hit a problem, let me know in Slack so we can think through this together. I never implemented such a thing myself, so I don’t know all the problems you may encounter beforehand in details, but I have a solid idea of what it should looks like.

@RRRadicalEdward
Copy link
Collaborator Author

RRRadicalEdward commented Mar 27, 2025

#722 (comment)

Let's clarify: iron-remote-desktop-rdp has to re-export WASM and provide extension types. The next step is to modify the UserInteraction to accept the "backend" which will be either RDP or VNC and implements an interface (I have really missed the fact that JS/TS has a duck types). The next step should be the refactoring of the connect function into a builder (or I will leave it to a follow-up PR if there won't be a direct need in it right now).

@CBenoit
Copy link
Member

CBenoit commented Mar 27, 2025

#722 (comment)

Let's clarify: iron-remote-desktop-rdp has to re-export WASM and provide extension types. The next step is to modify the UserInteraction to accept the "backend" which will be either RDP or VNC and implements an interface (I have really missed the fact that JS/TS has a duck types). The next step should be the refactoring of the connect function into a builder (or I will leave it to a follow-up PR if there won't be a direct need in it right now).

Exactly!
For this PR, really focus on the core architectural refactoring.
Anything that can be a follow up should be a follow up 🙂

@RRRadicalEdward RRRadicalEdward force-pushed the modularize-remote-desktop branch from 3a4a47a to f7a4b86 Compare March 28, 2025 13:25
@RRRadicalEdward RRRadicalEdward requested a review from CBenoit March 28, 2025 13:27
Copy link

github-actions bot commented Mar 28, 2025

Coverage Report 🤖 ⚙️

Past:
Total lines: 30423
Covered lines: 19493 (64.07%)

New:
Total lines: 30423
Covered lines: 19493 (64.07%)

Diff: +0.00%

[this comment will be updated automatically]

Copy link
Member

@CBenoit CBenoit left a comment

Choose a reason for hiding this comment

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

Really good work so far. Remaining comments are "minor" 🙂
That was a big refactoring, but we are almost done!

@RRRadicalEdward RRRadicalEdward requested a review from CBenoit April 11, 2025 10:18
Copy link
Member

@CBenoit CBenoit left a comment

Choose a reason for hiding this comment

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

LGTM! Excellent work. Let’s follow up with small incremental changes in separate PRs 🙂

@CBenoit CBenoit merged commit 0ff1ed8 into master Apr 11, 2025
10 checks passed
@CBenoit CBenoit deleted the modularize-remote-desktop branch April 11, 2025 12:28
RRRadicalEdward added a commit that referenced this pull request Apr 14, 2025
CBenoit pushed a commit that referenced this pull request Apr 14, 2025
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.

2 participants