diff --git a/web-client/iron-remote-desktop-rdp/package-lock.json b/web-client/iron-remote-desktop-rdp/package-lock.json index e3ee0b29f..9b89a3d7d 100644 --- a/web-client/iron-remote-desktop-rdp/package-lock.json +++ b/web-client/iron-remote-desktop-rdp/package-lock.json @@ -8,7 +8,6 @@ "name": "@devolutions/iron-remote-desktop-rdp", "version": "0.0.0", "dependencies": { - "rxjs": "^6.6.7", "ua-parser-js": "^1.0.33" }, "devDependencies": { @@ -3525,24 +3524,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", diff --git a/web-client/iron-remote-desktop-rdp/package.json b/web-client/iron-remote-desktop-rdp/package.json index 009ae4f59..1b18e4a39 100644 --- a/web-client/iron-remote-desktop-rdp/package.json +++ b/web-client/iron-remote-desktop-rdp/package.json @@ -41,7 +41,6 @@ "vite-plugin-wasm": "^3.1.0" }, "dependencies": { - "rxjs": "^6.6.7", "ua-parser-js": "^1.0.33" } } diff --git a/web-client/iron-remote-desktop-rdp/public/package.json b/web-client/iron-remote-desktop-rdp/public/package.json index b0df2a159..f434f15cb 100644 --- a/web-client/iron-remote-desktop-rdp/public/package.json +++ b/web-client/iron-remote-desktop-rdp/public/package.json @@ -12,8 +12,5 @@ "files": [ "iron-remote-desktop-rdp.js", "index.d.ts" - ], - "dependencies": { - "rxjs": "^6.6.7" - } + ] } diff --git a/web-client/iron-remote-desktop/package-lock.json b/web-client/iron-remote-desktop/package-lock.json index dd51b3be3..244d3bc3c 100644 --- a/web-client/iron-remote-desktop/package-lock.json +++ b/web-client/iron-remote-desktop/package-lock.json @@ -8,7 +8,6 @@ "name": "@devolutions/iron-remote-desktop", "version": "0.0.0", "dependencies": { - "rxjs": "^6.6.7", "svelte-eslint-parser": "^1.0.0", "ua-parser-js": "^1.0.33" }, @@ -3959,24 +3958,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", diff --git a/web-client/iron-remote-desktop/package.json b/web-client/iron-remote-desktop/package.json index 5677b147c..1e9012622 100644 --- a/web-client/iron-remote-desktop/package.json +++ b/web-client/iron-remote-desktop/package.json @@ -49,7 +49,6 @@ "vite-plugin-wasm": "^3.1.0" }, "dependencies": { - "rxjs": "^6.6.7", "svelte-eslint-parser": "^1.0.0", "ua-parser-js": "^1.0.33" } diff --git a/web-client/iron-remote-desktop/public/package.json b/web-client/iron-remote-desktop/public/package.json index fbf30948f..40bef8a92 100644 --- a/web-client/iron-remote-desktop/public/package.json +++ b/web-client/iron-remote-desktop/public/package.json @@ -16,8 +16,5 @@ "files": [ "iron-remote-desktop.js", "index.d.ts" - ], - "dependencies": { - "rxjs": "^6.6.7" - } + ] } diff --git a/web-client/iron-remote-desktop/src/interfaces/UserInteraction.ts b/web-client/iron-remote-desktop/src/interfaces/UserInteraction.ts index 7f3649ef1..19c1e2517 100644 --- a/web-client/iron-remote-desktop/src/interfaces/UserInteraction.ts +++ b/web-client/iron-remote-desktop/src/interfaces/UserInteraction.ts @@ -3,8 +3,8 @@ import type { NewSessionInfo } from './NewSessionInfo'; import type { SessionEvent } from './session-event'; import { ConfigBuilder } from '../services/ConfigBuilder'; import type { Config } from '../services/Config'; -import type { PartialObserver } from 'rxjs'; import type { Extension } from './Extension'; +import type { Callback } from '../lib/Observable'; export interface UserInteraction { setVisibility(state: boolean): void; @@ -25,7 +25,7 @@ export interface UserInteraction { setCursorStyleOverride(style: string | null): void; - onSessionEvent(partialObserver: PartialObserver): void; + onSessionEvent(callback: Callback): void; resize(width: number, height: number, scale?: number): void; diff --git a/web-client/iron-remote-desktop/src/iron-remote-desktop.svelte b/web-client/iron-remote-desktop/src/iron-remote-desktop.svelte index 0c845d3cf..7144c662a 100644 --- a/web-client/iron-remote-desktop/src/iron-remote-desktop.svelte +++ b/web-client/iron-remote-desktop/src/iron-remote-desktop.svelte @@ -456,7 +456,7 @@ } function serverBridgeListeners() { - remoteDesktopService.resize.subscribe((evt: ResizeEvent) => { + remoteDesktopService.resizeObservable.subscribe((evt: ResizeEvent) => { loggingService.info(`Resize canvas to: ${evt.desktopSize.width}x${evt.desktopSize.height}`); canvas.width = evt.desktopSize.width; canvas.height = evt.desktopSize.height; @@ -469,12 +469,12 @@ scaleSession(scale); }); - remoteDesktopService.scaleObserver.subscribe((s) => { + remoteDesktopService.scaleObservable.subscribe((s) => { loggingService.info('Change scale!'); scaleSession(s); }); - remoteDesktopService.dynamicResize.subscribe((evt) => { + remoteDesktopService.dynamicResizeObservable.subscribe((evt) => { loggingService.info(`Dynamic resize!, width: ${evt.width}, height: ${evt.height}`); setViewerStyle(evt.height.toString(), evt.width.toString(), true); }); diff --git a/web-client/iron-remote-desktop/src/lib/Observable.ts b/web-client/iron-remote-desktop/src/lib/Observable.ts new file mode 100644 index 000000000..2e9948e22 --- /dev/null +++ b/web-client/iron-remote-desktop/src/lib/Observable.ts @@ -0,0 +1,19 @@ +export type Callback = (_: T) => void; + +export class Observable { + constructor() { + this.subscribers = []; + } + + subscribers: Array>; + + subscribe(cb: Callback) { + this.subscribers.push(cb); + } + + publish(value: T) { + for (const cb of this.subscribers) { + cb(value); + } + } +} diff --git a/web-client/iron-remote-desktop/src/services/PublicAPI.ts b/web-client/iron-remote-desktop/src/services/PublicAPI.ts index 582f02f69..bea105845 100644 --- a/web-client/iron-remote-desktop/src/services/PublicAPI.ts +++ b/web-client/iron-remote-desktop/src/services/PublicAPI.ts @@ -21,9 +21,7 @@ export class PublicAPI { private connect(config: Config): Promise { loggingService.info('Initializing connection.'); - const resultObservable = this.remoteDesktopService.connect(config); - - return resultObservable.toPromise(); + return this.remoteDesktopService.connect(config); } private ctrlAltDel() { @@ -73,8 +71,8 @@ export class PublicAPI { configBuilder: this.configBuilder.bind(this), connect: this.connect.bind(this), setScale: this.setScale.bind(this), - onSessionEvent: (partialObserver) => { - this.remoteDesktopService.sessionObserver.subscribe(partialObserver); + onSessionEvent: (callback) => { + this.remoteDesktopService.sessionEventObservable.subscribe(callback); }, ctrlAltDel: this.ctrlAltDel.bind(this), metaKey: this.metaKey.bind(this), diff --git a/web-client/iron-remote-desktop/src/services/remote-desktop.service.ts b/web-client/iron-remote-desktop/src/services/remote-desktop.service.ts index e4e3518ee..97dc11320 100644 --- a/web-client/iron-remote-desktop/src/services/remote-desktop.service.ts +++ b/web-client/iron-remote-desktop/src/services/remote-desktop.service.ts @@ -1,6 +1,4 @@ -import { BehaviorSubject, from, Observable, of, Subject } from 'rxjs'; import { loggingService } from './logging.service'; -import { catchError, filter, map } from 'rxjs/operators'; import { scanCode } from '../lib/scancodes'; import { OS } from '../enums/OS'; import { ModifierKey } from '../enums/ModifierKey'; @@ -11,30 +9,28 @@ 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, IronErrorKind, IronError } from '../interfaces/session-event'; +import type { IronError, IronErrorKind, SessionEvent } from '../interfaces/session-event'; import type { ClipboardData } from '../interfaces/ClipboardData'; import type { Session } from '../interfaces/Session'; import type { DeviceEvent } from '../interfaces/DeviceEvent'; -import type { SessionTerminationInfo } from '../interfaces/SessionTerminationInfo'; import type { RemoteDesktopModule } from '../interfaces/RemoteDesktopModule'; import { ConfigBuilder } from './ConfigBuilder'; import type { Config } from './Config'; import type { Extension } from '../interfaces/Extension'; +import { Observable } from '../lib/Observable'; type OnRemoteClipboardChanged = (data: ClipboardData) => void; type OnRemoteReceivedFormatsList = () => void; type OnForceClipboardUpdate = () => void; +const isIronError = (error: unknown): error is IronError => + typeof error === 'object' && + error !== null && + typeof (error as IronError).backtrace === 'function' && + typeof (error as IronError).kind === 'function'; + export class RemoteDesktopService { private module: RemoteDesktopModule; - private _resize: Subject = new Subject(); - private mousePosition: BehaviorSubject = new BehaviorSubject({ - x: 0, - y: 0, - }); - private changeVisibility: Subject = new Subject(); - private sessionEvent: Subject = new Subject(); - private scale: BehaviorSubject = new BehaviorSubject(ScreenScale.Fit as ScreenScale); private canvas?: HTMLCanvasElement; private keyboardUnicodeMode: boolean = false; private backendSupportsUnicodeKeyboardShortcuts: boolean | undefined = undefined; @@ -45,21 +41,19 @@ export class RemoteDesktopService { private lastCursorStyle: string = 'default'; private enableClipboard: boolean = true; - resize: Observable; + resizeObservable: Observable = new Observable(); + session?: Session; modifierKeyPressed: ModifierKey[] = []; - mousePositionObservable: Observable = this.mousePosition.asObservable(); - changeVisibilityObservable: Observable = this.changeVisibility.asObservable(); - sessionObserver: Observable = this.sessionEvent.asObservable(); - scaleObserver: Observable = this.scale.asObservable(); - dynamicResize = new Subject<{ - width: number; - height: number; - }>(); + mousePositionObservable: Observable = new Observable(); + changeVisibilityObservable: Observable = new Observable(); + sessionEventObservable: Observable = new Observable(); + scaleObservable: Observable = new Observable(); + + dynamicResizeObservable: Observable<{ width: number; height: number }> = new Observable(); constructor(module: RemoteDesktopModule) { - this.resize = this._resize.asObservable(); this.module = module; loggingService.info('Web bridge initialized.'); } @@ -113,14 +107,14 @@ export class RemoteDesktopService { updateMousePosition(position: MousePosition) { this.doTransactionFromDeviceEvents([this.module.DeviceEvent.mouseMove(position.x, position.y)]); - this.mousePosition.next(position); + this.mousePositionObservable.publish(position); } configBuilder(): ConfigBuilder { return new ConfigBuilder(); } - connect(config: Config): Observable { + async connect(config: Config): Promise { const sessionBuilder = new this.module.SessionBuilder(); sessionBuilder.proxyAddress(config.proxyAddress); @@ -153,68 +147,66 @@ export class RemoteDesktopService { ); } - // Type guard to filter out errors - function isSession(result: IronError | Session): result is Session { - // Check whether function exists. To make it more robust we can check every method. - return (result).run !== undefined; - } + const session = await sessionBuilder.connect().catch((err: IronError) => { + this.raiseSessionEvent({ + type: SessionEventType.ERROR, + data: { + backtrace: () => err.backtrace(), + kind: () => err.kind() as number as IronErrorKind, + }, + }); + throw new Error('could not connect to the session'); + }); + + await this.run(session); + + loggingService.info('Session started.'); + + this.session = session; + + this.resizeObservable.publish({ + desktopSize: session.desktopSize(), + sessionId: 0, + }); + this.raiseSessionEvent({ + type: SessionEventType.STARTED, + data: 'Session started', + }); + + return { + sessionId: 0, + initialDesktopSize: session.desktopSize(), + websocketPort: 0, + }; + } + + async run(session: Session): Promise { + try { + const termination_info = await session.run(); + + this.setVisibility(false); + this.raiseSessionEvent({ + type: SessionEventType.TERMINATED, + data: 'Session was terminated: ' + termination_info.reason() + '.', + }); + + return session; + } catch (err) { + if (isIronError(err)) { + this.setVisibility(false); - return from(sessionBuilder.connect()).pipe( - catchError((err: IronError) => { this.raiseSessionEvent({ type: SessionEventType.ERROR, - data: { - backtrace: () => err.backtrace(), - kind: () => err.kind() as number as IronErrorKind, - }, - }); - return of(err); - }), - filter(isSession), - map((session: Session) => { - from(session.run()) - .pipe( - catchError((err: IronError) => { - this.setVisibility(false); - this.raiseSessionEvent({ - type: SessionEventType.ERROR, - data: err.backtrace(), - }); - this.raiseSessionEvent({ - type: SessionEventType.TERMINATED, - data: 'Session was terminated.', - }); - throw err; - }), - map((termination_info: SessionTerminationInfo) => { - this.setVisibility(false); - this.raiseSessionEvent({ - type: SessionEventType.TERMINATED, - data: 'Session was terminated: ' + termination_info.reason() + '.', - }); - }), - ) - .subscribe(); - return session; - }), - map((session: Session) => { - loggingService.info('Session started.'); - this.session = session; - this._resize.next({ - desktopSize: session.desktopSize(), - sessionId: 0, + data: err.backtrace(), }); this.raiseSessionEvent({ - type: SessionEventType.STARTED, - data: 'Session started', + type: SessionEventType.TERMINATED, + data: 'Session was terminated.', }); - return { - sessionId: 0, - initialDesktopSize: session.desktopSize(), - websocketPort: 0, - }; - }), - ); + } + + throw new Error('could not run the session.'); + } } sendSpecialCombination(specialCombination: SpecialCombination): void { @@ -235,11 +227,11 @@ export class RemoteDesktopService { } setVisibility(state: boolean) { - this.changeVisibility.next(state); + this.changeVisibilityObservable.publish(state); } setScale(scale: ScreenScale) { - this.scale.next(scale); + this.scaleObservable.publish(scale); } setCanvas(canvas: HTMLCanvasElement) { @@ -247,7 +239,7 @@ export class RemoteDesktopService { } resizeDynamic(width: number, height: number, scale?: number) { - this.dynamicResize.next({ width, height }); + this.dynamicResizeObservable.publish({ width, height }); this.session?.resize(width, height, scale); } @@ -432,7 +424,7 @@ export class RemoteDesktopService { } private raiseSessionEvent(event: SessionEvent) { - this.sessionEvent.next(event); + this.sessionEventObservable.publish(event); } private updateModifierKeyState(evt: KeyboardEvent) { diff --git a/web-client/iron-svelte-client/package-lock.json b/web-client/iron-svelte-client/package-lock.json index b90104798..332afa21b 100644 --- a/web-client/iron-svelte-client/package-lock.json +++ b/web-client/iron-svelte-client/package-lock.json @@ -26,7 +26,6 @@ "guid-typescript": "^1.0.9", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0", - "rxjs": "^6.6.7", "svelte": "^3.44.0", "svelte-check": "^2.7.1", "svelte-preprocess": "^4.10.6", @@ -3516,24 +3515,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", diff --git a/web-client/iron-svelte-client/package.json b/web-client/iron-svelte-client/package.json index 21fb47619..b3632aca8 100644 --- a/web-client/iron-svelte-client/package.json +++ b/web-client/iron-svelte-client/package.json @@ -32,7 +32,6 @@ "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0", "@rollup/plugin-replace": "^5.0.1", - "rxjs": "^6.6.7", "svelte": "^3.44.0", "svelte-check": "^2.7.1", "@sveltejs/adapter-auto": "^2.0.0", diff --git a/web-client/iron-svelte-client/src/lib/login/login.svelte b/web-client/iron-svelte-client/src/lib/login/login.svelte index 7dc19cf05..22e725cdb 100644 --- a/web-client/iron-svelte-client/src/lib/login/login.svelte +++ b/web-client/iron-svelte-client/src/lib/login/login.svelte @@ -1,9 +1,8 @@