refactor(web): follow-up to #722 (#747)

This commit is contained in:
Alex Yusiuk
2025-04-14 14:05:19 +00:00
committed by GitHub
parent cc3dbf124f
commit fe676eeac5
18 changed files with 72 additions and 73 deletions
@@ -1,9 +1,7 @@
use core::{cmp, fmt};
use ironrdp_pdu::{
fast_path::{EncryptionFlags, FastPathHeader, FastPathUpdatePdu, Fragmentation, UpdateCode},
Encode, WriteCursor,
};
use ironrdp_pdu::fast_path::{EncryptionFlags, FastPathHeader, FastPathUpdatePdu, Fragmentation, UpdateCode};
use ironrdp_pdu::{Encode, WriteCursor};
// this is the maximum amount of data (not including headers) we can send in a single TS_FP_UPDATE_PDU
const MAX_FASTPATH_UPDATE_SIZE: usize = 16_374;
@@ -100,9 +98,10 @@ impl UpdateFragmenter {
#[cfg(test)]
mod tests {
use super::*;
use ironrdp_core::{decode_cursor, ReadCursor};
use super::*;
#[test]
fn test_single_fragment() {
let data = vec![1, 2, 3, 4];
+2 -2
View File
@@ -137,7 +137,7 @@ impl WasmClipboard {
pub(crate) fn new(message_proxy: WasmClipboardMessageProxy, js_callbacks: JsClipboardCallbacks) -> Self {
Self {
local_clipboard: None,
remote_clipboard: ClipboardTransaction::construct(),
remote_clipboard: ClipboardTransaction::init(),
proxy: message_proxy,
js_callbacks,
@@ -505,7 +505,7 @@ impl WasmClipboard {
} else {
// If no initial clipboard callback was set, send empty format list instead
return self.process_event(WasmClipboardBackendMessage::LocalClipboardChanged(
ClipboardTransaction::construct(),
ClipboardTransaction::init(),
));
}
}
@@ -19,7 +19,7 @@ impl ClipboardTransaction {
#[wasm_bindgen]
impl ClipboardTransaction {
pub fn construct() -> Self {
pub fn init() -> Self {
Self { contents: Vec::new() }
}
+16 -16
View File
@@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*;
#[wasm_bindgen]
#[derive(Clone, Copy)]
pub enum RemoteDesktopErrorKind {
pub enum IronErrorKind {
/// Catch-all error kind
General,
/// Incorrect password used
@@ -19,30 +19,30 @@ pub enum RemoteDesktopErrorKind {
}
#[wasm_bindgen]
pub struct RemoteDesktopError {
kind: RemoteDesktopErrorKind,
pub struct IronError {
kind: IronErrorKind,
source: anyhow::Error,
}
impl RemoteDesktopError {
pub fn with_kind(mut self, kind: RemoteDesktopErrorKind) -> Self {
impl IronError {
pub fn with_kind(mut self, kind: IronErrorKind) -> Self {
self.kind = kind;
self
}
}
#[wasm_bindgen]
impl RemoteDesktopError {
impl IronError {
pub fn backtrace(&self) -> String {
format!("{:?}", self.source)
}
pub fn kind(&self) -> RemoteDesktopErrorKind {
pub fn kind(&self) -> IronErrorKind {
self.kind
}
}
impl From<connector::ConnectorError> for RemoteDesktopError {
impl From<connector::ConnectorError> for IronError {
fn from(e: connector::ConnectorError) -> Self {
use sspi::credssp::NStatusCode;
@@ -50,13 +50,13 @@ impl From<connector::ConnectorError> for RemoteDesktopError {
ConnectorErrorKind::Credssp(sspi::Error {
nstatus: Some(NStatusCode::WRONG_PASSWORD),
..
}) => RemoteDesktopErrorKind::WrongPassword,
}) => IronErrorKind::WrongPassword,
ConnectorErrorKind::Credssp(sspi::Error {
nstatus: Some(NStatusCode::LOGON_FAILURE),
..
}) => RemoteDesktopErrorKind::LogonFailure,
ConnectorErrorKind::AccessDenied => RemoteDesktopErrorKind::AccessDenied,
_ => RemoteDesktopErrorKind::General,
}) => IronErrorKind::LogonFailure,
ConnectorErrorKind::AccessDenied => IronErrorKind::AccessDenied,
_ => IronErrorKind::General,
};
Self {
@@ -66,19 +66,19 @@ impl From<connector::ConnectorError> for RemoteDesktopError {
}
}
impl From<ironrdp::session::SessionError> for RemoteDesktopError {
impl From<ironrdp::session::SessionError> for IronError {
fn from(e: ironrdp::session::SessionError) -> Self {
Self {
kind: RemoteDesktopErrorKind::General,
kind: IronErrorKind::General,
source: anyhow::Error::new(e),
}
}
}
impl From<anyhow::Error> for RemoteDesktopError {
impl From<anyhow::Error> for IronError {
fn from(e: anyhow::Error) -> Self {
Self {
kind: RemoteDesktopErrorKind::General,
kind: IronErrorKind::General,
source: e,
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ pub struct InputTransaction(pub(crate) SmallVec<[Operation; 3]>);
#[wasm_bindgen]
impl InputTransaction {
pub fn construct() -> Self {
pub fn init() -> Self {
Self(SmallVec::new())
}
+1 -1
View File
@@ -69,7 +69,7 @@ pub struct DesktopSize {
#[wasm_bindgen]
impl DesktopSize {
pub fn construct(width: u16, height: u16) -> Self {
pub fn init(width: u16, height: u16) -> Self {
DesktopSize { width, height }
}
}
+20 -20
View File
@@ -37,7 +37,7 @@ use web_sys::HtmlCanvasElement;
use crate::canvas::Canvas;
use crate::clipboard::{ClipboardTransaction, WasmClipboard, WasmClipboardBackend, WasmClipboardBackendMessage};
use crate::error::{RemoteDesktopError, RemoteDesktopErrorKind};
use crate::error::{IronError, IronErrorKind};
use crate::image::extract_partial_image;
use crate::input::InputTransaction;
use crate::network_client::WasmNetworkClient;
@@ -103,7 +103,7 @@ impl Default for SessionBuilderInner {
#[wasm_bindgen]
impl SessionBuilder {
pub fn construct() -> SessionBuilder {
pub fn init() -> SessionBuilder {
Self(Rc::new(RefCell::new(SessionBuilderInner::default())))
}
@@ -220,7 +220,7 @@ impl SessionBuilder {
self.clone()
}
pub async fn connect(&self) -> Result<Session, RemoteDesktopError> {
pub async fn connect(&self) -> Result<Session, IronError> {
let (
username,
destination,
@@ -295,11 +295,11 @@ impl SessionBuilder {
loop {
match ws.state() {
websocket::State::Closing | websocket::State::Closed => {
return Err(RemoteDesktopError::from(anyhow::anyhow!(
return Err(IronError::from(anyhow::anyhow!(
"failed to connect to {proxy_address} (WebSocket is `{:?}`)",
ws.state()
))
.with_kind(RemoteDesktopErrorKind::ProxyConnect));
.with_kind(IronErrorKind::ProxyConnect));
}
websocket::State::Connecting => {
trace!("WebSocket is connecting to proxy at {proxy_address}...");
@@ -417,7 +417,7 @@ pub struct Session {
#[wasm_bindgen]
impl Session {
pub async fn run(&self) -> Result<SessionTerminationInfo, RemoteDesktopError> {
pub async fn run(&self) -> Result<SessionTerminationInfo, IronError> {
let rdp_reader = self
.rdp_reader
.borrow_mut()
@@ -712,17 +712,17 @@ impl Session {
}
}
pub fn apply_inputs(&self, transaction: InputTransaction) -> Result<(), RemoteDesktopError> {
pub fn apply_inputs(&self, transaction: InputTransaction) -> Result<(), IronError> {
let inputs = self.input_database.borrow_mut().apply(transaction);
self.h_send_inputs(inputs)
}
pub fn release_all_inputs(&self) -> Result<(), RemoteDesktopError> {
pub fn release_all_inputs(&self) -> Result<(), IronError> {
let inputs = self.input_database.borrow_mut().release_all();
self.h_send_inputs(inputs)
}
fn h_send_inputs(&self, inputs: smallvec::SmallVec<[FastPathInputEvent; 2]>) -> Result<(), RemoteDesktopError> {
fn h_send_inputs(&self, inputs: smallvec::SmallVec<[FastPathInputEvent; 2]>) -> Result<(), IronError> {
if !inputs.is_empty() {
trace!("Inputs: {inputs:?}");
@@ -740,7 +740,7 @@ impl Session {
num_lock: bool,
caps_lock: bool,
kana_lock: bool,
) -> Result<(), RemoteDesktopError> {
) -> Result<(), IronError> {
use ironrdp::pdu::input::fast_path::FastPathInput;
let event = ironrdp::input::synchronize_event(scroll_lock, num_lock, caps_lock, kana_lock);
@@ -755,7 +755,7 @@ impl Session {
Ok(())
}
pub fn shutdown(&self) -> Result<(), RemoteDesktopError> {
pub fn shutdown(&self) -> Result<(), IronError> {
self.input_events_tx
.unbounded_send(RdpInputEvent::TerminateSession)
.context("failed to send terminate session event to writer task")?;
@@ -763,7 +763,7 @@ impl Session {
Ok(())
}
pub async fn on_clipboard_paste(&self, content: ClipboardTransaction) -> Result<(), RemoteDesktopError> {
pub async fn on_clipboard_paste(&self, content: ClipboardTransaction) -> Result<(), IronError> {
self.input_events_tx
.unbounded_send(RdpInputEvent::ClipboardBackend(
WasmClipboardBackendMessage::LocalClipboardChanged(content),
@@ -773,7 +773,7 @@ impl Session {
Ok(())
}
fn set_cursor_style(&self, style: CursorStyle) -> Result<(), RemoteDesktopError> {
fn set_cursor_style(&self, style: CursorStyle) -> Result<(), IronError> {
let (kind, data, hotspot_x, hotspot_y) = match style {
CursorStyle::Default => ("default", None, None, None),
CursorStyle::Hidden => ("hidden", None, None, None),
@@ -824,7 +824,7 @@ impl Session {
false
}
pub fn extension_call(_value: JsValue) -> Result<JsValue, RemoteDesktopError> {
pub fn extension_call(_value: JsValue) -> Result<JsValue, IronError> {
Ok(JsValue::null())
}
}
@@ -922,7 +922,7 @@ async fn connect(
clipboard_backend,
use_display_control,
}: ConnectParams,
) -> Result<(connector::ConnectionResult, WebSocket), RemoteDesktopError> {
) -> Result<(connector::ConnectionResult, WebSocket), IronError> {
let mut framed = ironrdp_futures::LocalFuturesFramed::new(ws);
let mut connector = ClientConnector::new(config);
@@ -969,7 +969,7 @@ async fn connect_rdcleanpath<S>(
destination: String,
proxy_auth_token: String,
pcb: Option<String>,
) -> Result<(ironrdp_futures::Upgraded, Vec<u8>), RemoteDesktopError>
) -> Result<(ironrdp_futures::Upgraded, Vec<u8>), IronError>
where
S: ironrdp_futures::FramedRead + FramedWrite,
{
@@ -1048,10 +1048,10 @@ where
server_addr,
} => (x224_connection_response, server_cert_chain, server_addr),
ironrdp_rdcleanpath::RDCleanPath::Err(error) => {
return Err(RemoteDesktopError::from(
anyhow::Error::new(error).context("received an RDCleanPath error"),
)
.with_kind(RemoteDesktopErrorKind::RDCleanPath));
return Err(
IronError::from(anyhow::Error::new(error).context("received an RDCleanPath error"))
.with_kind(IronErrorKind::RDCleanPath),
);
}
};
@@ -3,7 +3,7 @@ import init, {
DesktopSize,
DeviceEvent,
InputTransaction,
RemoteDesktopError,
IronError,
Session,
SessionBuilder,
SessionTerminationInfo,
@@ -17,7 +17,7 @@ export default {
DesktopSize,
DeviceEvent,
InputTransaction,
RemoteDesktopError,
IronError,
SessionBuilder,
ClipboardTransaction,
ClipboardContent,
@@ -1,7 +1,7 @@
import type { ClipboardContent } from './ClipboardContent';
export interface ClipboardTransaction {
construct(): ClipboardTransaction;
init(): ClipboardTransaction;
add_content(content: ClipboardContent): void;
is_empty(): boolean;
content(): Array<ClipboardContent>;
@@ -2,5 +2,5 @@
width: number;
height: number;
construct(width: number, height: number): DesktopSize;
init(width: number, height: number): DesktopSize;
}
@@ -1,6 +1,6 @@
import type { DeviceEvent } from './DeviceEvent';
export interface InputTransaction {
construct(): InputTransaction;
init(): InputTransaction;
add_event(event: DeviceEvent): void;
}
@@ -1,7 +1,7 @@
import type { DesktopSize } from './DesktopSize';
import type { DeviceEvent } from './DeviceEvent';
import type { InputTransaction } from './InputTransaction';
import type { RemoteDesktopError } from './session-event';
import type { IronError } from './session-event';
import type { Session } from './Session';
import type { SessionBuilder } from './SessionBuilder';
import type { SessionTerminationInfo } from './SessionTerminationInfo';
@@ -14,7 +14,7 @@ export interface RemoteDesktopModule {
DesktopSize: DesktopSize;
DeviceEvent: DeviceEvent;
InputTransaction: InputTransaction;
RemoteDesktopError: RemoteDesktopError;
RemoteDesktopError: IronError;
Session: Session;
SessionBuilder: SessionBuilder;
SessionTerminationInfo: SessionTerminationInfo;
@@ -3,7 +3,7 @@ import type { DesktopSize } from './DesktopSize';
import type { ClipboardTransaction } from './ClipboardTransaction';
export interface SessionBuilder {
construct(): SessionBuilder;
init(): SessionBuilder;
/**
* Required
*/
@@ -63,8 +63,6 @@ export interface SessionBuilder {
*/
force_clipboard_update_callback(callback: ForceClipboardUpdateCallback): SessionBuilder;
extension(value: unknown): SessionBuilder;
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
extension_call(_ident: string, _call: Function): SessionBuilder;
connect(): Promise<Session>;
}
@@ -1,6 +1,6 @@
import type { SessionEventType } from '../enums/SessionEventType';
export enum RemoteDesktopErrorKind {
export enum IronErrorKind {
General = 0,
WrongPassword = 1,
LogonFailure = 2,
@@ -8,12 +8,13 @@ export enum RemoteDesktopErrorKind {
RDCleanPath = 4,
ProxyConnect = 5,
}
export interface RemoteDesktopError {
export interface IronError {
backtrace: () => string;
kind: () => RemoteDesktopErrorKind;
kind: () => IronErrorKind;
}
export interface SessionEvent {
type: SessionEventType;
data: RemoteDesktopError | string;
data: IronError | string;
}
+1 -1
View File
@@ -3,7 +3,7 @@ export type { ResizeEvent } from './interfaces/ResizeEvent';
export type { NewSessionInfo } from './interfaces/NewSessionInfo';
export type { ServerRect } from './interfaces/ServerRect';
export type { DesktopSize } from './interfaces/DesktopSize';
export type { SessionEvent, RemoteDesktopError, RemoteDesktopErrorKind } from './interfaces/session-event';
export type { SessionEvent, IronError, IronErrorKind } from './interfaces/session-event';
export type { SessionEventType } from './enums/SessionEventType';
export type { SessionTerminationInfo } from './interfaces/SessionTerminationInfo';
export type { ClipboardTransaction } from './interfaces/ClipboardTransaction';
@@ -12,7 +12,7 @@ import { SpecialCombination } from '../enums/SpecialCombination';
import type { ResizeEvent } from '../interfaces/ResizeEvent';
import { ScreenScale } from '../enums/ScreenScale';
import type { MousePosition } from '../interfaces/MousePosition';
import type { SessionEvent, RemoteDesktopErrorKind, RemoteDesktopError } from '../interfaces/session-event';
import type { SessionEvent, IronErrorKind, IronError } from '../interfaces/session-event';
import type { DesktopSize } from '../interfaces/DesktopSize';
import type { ClipboardTransaction } from '../interfaces/ClipboardTransaction';
import type { ClipboardContent } from '../interfaces/ClipboardContent';
@@ -65,7 +65,7 @@ export class RemoteDesktopService {
}
constructClipboardTransaction(): ClipboardTransaction {
return this.module.ClipboardTransaction.construct();
return this.module.ClipboardTransaction.init();
}
constructClipboardContentFromText(mime_type: string, text: string): ClipboardContent {
@@ -147,7 +147,7 @@ export class RemoteDesktopService {
kdc_proxy_url?: string,
use_display_control = true,
): Observable<NewSessionInfo> {
const sessionBuilder = this.module.SessionBuilder.construct();
const sessionBuilder = this.module.SessionBuilder.init();
sessionBuilder.proxy_address(proxyAddress);
sessionBuilder.destination(destination);
@@ -177,22 +177,22 @@ export class RemoteDesktopService {
}
if (desktopSize != null) {
sessionBuilder.desktop_size(this.module.DesktopSize.construct(desktopSize.width, desktopSize.height));
sessionBuilder.desktop_size(this.module.DesktopSize.init(desktopSize.width, desktopSize.height));
}
// Type guard to filter out errors
function isSession(result: RemoteDesktopError | Session): result is Session {
function isSession(result: IronError | Session): result is Session {
// Check whether function exists. To make it more robust we can check every method.
return (<Session>result).run !== undefined;
}
return from(sessionBuilder.connect()).pipe(
catchError((err: RemoteDesktopError) => {
catchError((err: IronError) => {
this.raiseSessionEvent({
type: SessionEventType.ERROR,
data: {
backtrace: () => err.backtrace(),
kind: () => err.kind() as number as RemoteDesktopErrorKind,
kind: () => err.kind() as number as IronErrorKind,
},
});
return of(err);
@@ -201,7 +201,7 @@ export class RemoteDesktopService {
map((session: Session) => {
from(session.run())
.pipe(
catchError((err: RemoteDesktopError) => {
catchError((err: IronError) => {
this.setVisibility(false);
this.raiseSessionEvent({
type: SessionEventType.ERROR,
@@ -289,7 +289,7 @@ export class RemoteDesktopService {
onClipboardChangedEmpty(): Promise<void> {
const onClipboardChangedPromise = async () => {
await this.session?.on_clipboard_paste(this.module.ClipboardTransaction.construct());
await this.session?.on_clipboard_paste(this.module.ClipboardTransaction.init());
};
return onClipboardChangedPromise();
}
@@ -469,7 +469,7 @@ export class RemoteDesktopService {
}
private doTransactionFromDeviceEvents(deviceEvents: DeviceEvent[]) {
const transaction = this.module.InputTransaction.construct();
const transaction = this.module.InputTransaction.init();
deviceEvents.forEach((event) => transaction.add_event(event));
this.session?.apply_inputs(transaction);
}
@@ -5,7 +5,7 @@ export class DesktopSize implements IDesktopSize {
this.height = height;
}
construct(width: number, height: number): DesktopSize {
init(width: number, height: number): DesktopSize {
return new DesktopSize(width, height);
}
+2 -1
View File
@@ -1,6 +1,7 @@
use crate::prelude::*;
use std::fs;
use crate::prelude::*;
const IRON_REMOTE_DESKTOP_PATH: &str = "./web-client/iron-remote-desktop";
const IRON_REMOTE_DESKTOP_RDP_PATH: &str = "./web-client/iron-remote-desktop-rdp";
const IRON_SVELTE_CLIENT_PATH: &str = "./web-client/iron-svelte-client";