style(web-client): run prettier

This commit is contained in:
Benoît CORTIER 2023-11-04 00:45:10 -04:00 committed by Benoît Cortier
parent dff3f307eb
commit d4ea558da0
52 changed files with 1346 additions and 1302 deletions

View file

@ -12,30 +12,30 @@
root: true root: true
plugins: plugins:
- "@typescript-eslint" - '@typescript-eslint'
extends: extends:
- "eslint:recommended" - 'eslint:recommended'
- "plugin:@typescript-eslint/recommended" - 'plugin:@typescript-eslint/recommended'
- "plugin:svelte/prettier" # Turns off rules that may conflict with Prettier - 'plugin:svelte/prettier' # Turns off rules that may conflict with Prettier
- "plugin:prettier/recommended" - 'plugin:prettier/recommended'
parser: "@typescript-eslint/parser" parser: '@typescript-eslint/parser'
parserOptions: parserOptions:
project: ./tsconfig.json project: ./tsconfig.json
sourceType: module sourceType: module
ecmaVersion: 2020 ecmaVersion: 2020
extraFileExtensions: extraFileExtensions:
- ".svelte" - '.svelte'
ignorePatterns: ignorePatterns:
- "*.cjs" - '*.cjs'
overrides: overrides:
- files: "*.svelte" - files: '*.svelte'
parser: svelte-eslint-parser parser: svelte-eslint-parser
parserOptions: parserOptions:
parser: "@typescript-eslint/parser" parser: '@typescript-eslint/parser'
env: env:
browser: true browser: true
@ -44,10 +44,10 @@ env:
rules: rules:
strict: 2 strict: 2
"@typescript-eslint/no-unused-vars": '@typescript-eslint/no-unused-vars':
- "error" - 'error'
- argsIgnorePattern: '^_' - argsIgnorePattern: '^_'
"@typescript-eslint/strict-boolean-expressions": '@typescript-eslint/strict-boolean-expressions':
- 2 - 2
- allowString: false - allowString: false
allowNumber: false allowNumber: false

View file

@ -15,7 +15,7 @@ Run `npm run build`
As member of the Devolutions organization, you can import the Web Component from JFrog Artifactory by running the following npm command: As member of the Devolutions organization, you can import the Web Component from JFrog Artifactory by running the following npm command:
```shell ```shell
$ npm install @devolutions/iron-remote-gui $ npm install @devolutions/iron-remote-gui
``` ```
Otherwise, you can run `npm install` targeting the `dist/` folder directly. Otherwise, you can run `npm install` targeting the `dist/` folder directly.
@ -33,10 +33,10 @@ Call the `connect` method on this object.
For now, we didn't make the enums used by some method directly available (I didn't find the good way to export them directly with the component.). For now, we didn't make the enums used by some method directly available (I didn't find the good way to export them directly with the component.).
You need to recreate them on your application for now (it will be improved in future version); You need to recreate them on your application for now (it will be improved in future version);
Also, even if the connection to RDP work there is still a lot of improvement to do. Also, even if the connection to RDP work there is still a lot of improvement to do.
As of now, you can expect, mouse movement and click (4 buttons) - no scroll, Keyboard for at least the standard. As of now, you can expect, mouse movement and click (4 buttons) - no scroll, Keyboard for at least the standard.
Windows and CTRL+ALT+DEL can be called by method on `UserInteractionService`. Windows and CTRL+ALT+DEL can be called by method on `UserInteractionService`.
Lock keys (like caps lock), have a partial support. Lock keys (like caps lock), have a partial support.
Other advanced functionalities (sharing / copy past...) are not implemented yet. Other advanced functionalities (sharing / copy past...) are not implemented yet.
## Component parameters ## Component parameters
@ -59,19 +59,18 @@ You can add some parameters for default initialization on the component `<iron-r
> `authtoken` is the authentication token to send to the Devolutions Gateway. > `authtoken` is the authentication token to send to the Devolutions Gateway.
> `ctrlAltDel()` > `ctrlAltDel()`
> >
> Sends the ctrl+alt+del key to server. > Sends the ctrl+alt+del key to server.
> `metaKey()` > `metaKey()`
> >
> Sends the meta key event to remote host (i.e.: Windows key). > Sends the meta key event to remote host (i.e.: Windows key).
> `setVisibility(value: bool)` > `setVisibility(value: bool)`
> >
> Shows or hides rendering canvas. > Shows or hides rendering canvas.
> `setScale(scale: ScreenScale)` > `setScale(scale: ScreenScale)`
> >
> Sets the scale behavior of the canvas. > Sets the scale behavior of the canvas.
> See the [ScreenScale](./src/services/user-interaction-service.ts) enum for possible values. > See the [ScreenScale](./src/services/user-interaction-service.ts) enum for possible values.

View file

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
@ -7,12 +7,12 @@
</head> </head>
<body> <body>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
<iron-remote-gui isvisible="false" desktopwidth="600" desktopheight="400"/> <iron-remote-gui isvisible="false" desktopwidth="600" desktopheight="400" />
<script> <script>
var el = document.querySelector('iron-remote-gui'); var el = document.querySelector('iron-remote-gui');
el.addEventListener('ready', (e) => { el.addEventListener('ready', (e) => {
console.log("WebComponent Loaded"); console.log('WebComponent Loaded');
e.detail.irgUserInteraction.setVisibility(true); e.detail.irgUserInteraction.setVisibility(true);
}); });
</script> </script>

View file

@ -16,14 +16,11 @@
"build-alone": "vite build", "build-alone": "vite build",
"pre-build": "node ./pre-build.js", "pre-build": "node ./pre-build.js",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json", "check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "npm run lint:prettier && npm run lint:eslint", "lint": "npm run lint:prettier && npm run lint:eslint",
"lint:prettier": "prettier . --check", "lint:prettier": "prettier . --check",
"lint:eslint": "eslint src/**", "lint:eslint": "eslint src/**",
"format": "prettier . --write ." "format": "prettier . --write ."
}, },
"devDependencies": { "devDependencies": {

View file

@ -1,8 +1,8 @@
import {spawn} from "child_process"; import { spawn } from 'child_process';
let run = async function (command, cwd) { let run = async function (command, cwd) {
return new Promise(resolve => { return new Promise((resolve) => {
const buildCommand = spawn(command, {stdio: "pipe", shell: true, cwd: cwd}); const buildCommand = spawn(command, { stdio: 'pipe', shell: true, cwd: cwd });
buildCommand.stdout.on('data', (data) => { buildCommand.stdout.on('data', (data) => {
console.log(`${data}`); console.log(`${data}`);
@ -16,7 +16,7 @@ let run = async function (command, cwd) {
console.log(`child process exited with code ${code}`); console.log(`child process exited with code ${code}`);
resolve(); resolve();
}); });
}) });
} };
await run('wasm-pack build --target web', '../../crates/ironrdp-web'); await run('wasm-pack build --target web', '../../crates/ironrdp-web');

View file

@ -1,19 +1,19 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test</title> <title>Test</title>
</head> </head>
<body> <body>
<script type="module" src="./iron-remote-gui.js"></script> <script type="module" src="./iron-remote-gui.js"></script>
<iron-remote-gui isvisible="false" desktopwidth="600" desktopheight="400"/> <iron-remote-gui isvisible="false" desktopwidth="600" desktopheight="400" />
<script> <script>
var el = document.querySelector('iron-remote-gui'); var el = document.querySelector('iron-remote-gui');
el.addEventListener('ready', (e) => { el.addEventListener('ready', (e) => {
e.detail.irgUserInteraction.setVisibility(true); e.detail.irgUserInteraction.setVisibility(true);
}); });
</script> </script>
</body> </body>
</html> </html>

View file

@ -1,10 +1,10 @@
export enum LockKey { export enum LockKey {
CAPS_LOCK = "CapsLock", CAPS_LOCK = 'CapsLock',
NUM_LOCK = "NumLock", NUM_LOCK = 'NumLock',
SCROLL_LOCK = "ScrollLock", SCROLL_LOCK = 'ScrollLock',
KANA_MODE = "KanaMode", KANA_MODE = 'KanaMode',
"CapsLock" = CAPS_LOCK, 'CapsLock' = CAPS_LOCK,
"ScrollLock" = SCROLL_LOCK, 'ScrollLock' = SCROLL_LOCK,
"NumLock" = NUM_LOCK, 'NumLock' = NUM_LOCK,
"KanaMode" = KANA_MODE 'KanaMode' = KANA_MODE,
} }

View file

@ -1,8 +1,8 @@
export enum LogType { export enum LogType {
OFF = "OFF", OFF = 'OFF',
ERROR = "ERROR", ERROR = 'ERROR',
WARN = "WARN", WARN = 'WARN',
INFO = "INFO", INFO = 'INFO',
DEBUG = "DEBUG", DEBUG = 'DEBUG',
TRACE = "TRACE" TRACE = 'TRACE',
} }

View file

@ -1,14 +1,14 @@
export enum ModifierKey { export enum ModifierKey {
CTRL_LEFT = "ControlLeft", CTRL_LEFT = 'ControlLeft',
SHIFT_LEFT = "ShiftLeft", SHIFT_LEFT = 'ShiftLeft',
SHIFT_RIGHT = "ShiftRight", SHIFT_RIGHT = 'ShiftRight',
ALT_LEFT = "AltLeft", ALT_LEFT = 'AltLeft',
CTRL_RIGHT = "ControlRight", CTRL_RIGHT = 'ControlRight',
ALT_RIGHT = "AltRight", ALT_RIGHT = 'AltRight',
"ControlLeft" = CTRL_LEFT, 'ControlLeft' = CTRL_LEFT,
"ShiftLeft" = SHIFT_LEFT, 'ShiftLeft' = SHIFT_LEFT,
"ShiftRight" = SHIFT_RIGHT, 'ShiftRight' = SHIFT_RIGHT,
"AltLeft" = ALT_LEFT, 'AltLeft' = ALT_LEFT,
"ControlRight" = CTRL_RIGHT, 'ControlRight' = CTRL_RIGHT,
"AltRight" = ALT_RIGHT, 'AltRight' = ALT_RIGHT,
} }

View file

@ -3,5 +3,5 @@
MIDDLE = 1, MIDDLE = 1,
RIGHT = 2, RIGHT = 2,
BROWSER_BACK = 3, BROWSER_BACK = 3,
BROWSER_FORWARD = 4 BROWSER_FORWARD = 4,
} }

View file

@ -1,4 +1,4 @@
export enum MouseButtonState { export enum MouseButtonState {
MOUSE_DOWN, MOUSE_DOWN,
MOUSE_UP MOUSE_UP,
} }

View file

@ -1,5 +1,5 @@
export enum OS { export enum OS {
WINDOWS = 'windows', WINDOWS = 'windows',
LINUX = 'linux', LINUX = 'linux',
ANDROID = 'android' ANDROID = 'android',
} }

View file

@ -1,5 +1,5 @@
export enum ScreenScale { export enum ScreenScale {
Fit = 1, Fit = 1,
Full = 2, Full = 2,
Real = 3 Real = 3,
} }

View file

@ -1,5 +1,5 @@
export enum SessionEventType { export enum SessionEventType {
STARTED, STARTED,
TERMINATED, TERMINATED,
ERROR ERROR,
} }

View file

@ -1,4 +1,4 @@
export enum SpecialCombination { export enum SpecialCombination {
CTRL_ALT_DEL, CTRL_ALT_DEL,
META META,
} }

View file

@ -1,4 +1,4 @@
export interface DesktopSize { export interface DesktopSize {
width: number, width: number;
height: number height: number;
} }

View file

@ -1,7 +1,7 @@
import type {DesktopSize} from './DesktopSize'; import type { DesktopSize } from './DesktopSize';
export interface NewSessionInfo { export interface NewSessionInfo {
session_id: number, session_id: number;
websocket_port: number, websocket_port: number;
initial_desktop_size: DesktopSize, initial_desktop_size: DesktopSize;
} }

View file

@ -1,6 +1,6 @@
import type {DesktopSize} from './DesktopSize'; import type { DesktopSize } from './DesktopSize';
export interface ResizeEvent { export interface ResizeEvent {
session_id: number, session_id: number;
desktop_size: DesktopSize, desktop_size: DesktopSize;
} }

View file

@ -1,20 +1,29 @@
import type {ScreenScale} from '../enums/ScreenScale'; import type { ScreenScale } from '../enums/ScreenScale';
import type {Observable} from 'rxjs'; import type { Observable } from 'rxjs';
import type {NewSessionInfo} from './NewSessionInfo'; import type { NewSessionInfo } from './NewSessionInfo';
import type {SessionEvent} from './session-event'; import type { SessionEvent } from './session-event';
import type {DesktopSize} from './DesktopSize'; import type { DesktopSize } from './DesktopSize';
export interface UserInteraction { export interface UserInteraction {
setVisibility(state: boolean): void; setVisibility(state: boolean): void;
setScale(scale: ScreenScale): void; setScale(scale: ScreenScale): void;
connect(username: string, password: string, destination: string, proxyAddress: string, serverDomain: string, authToken: string, desktopSize?: DesktopSize, preConnectionBlob?: string): Observable<NewSessionInfo>; connect(
username: string,
password: string,
destination: string,
proxyAddress: string,
serverDomain: string,
authToken: string,
desktopSize?: DesktopSize,
preConnectionBlob?: string,
): Observable<NewSessionInfo>;
ctrlAltDel(): void; ctrlAltDel(): void;
metaKey(): void; metaKey(): void;
shutdown(): void; shutdown(): void;
sessionListener: Observable<SessionEvent>; sessionListener: Observable<SessionEvent>;

View file

@ -1,7 +1,7 @@
import type {SessionEventType} from '../enums/SessionEventType'; import type { SessionEventType } from '../enums/SessionEventType';
import type { IronRdpError } from '../../../../crates/ironrdp-web/pkg/ironrdp_web'; import type { IronRdpError } from '../../../../crates/ironrdp-web/pkg/ironrdp_web';
export interface SessionEvent { export interface SessionEvent {
type: SessionEventType, type: SessionEventType;
data?: IronRdpError | string data?: IronRdpError | string;
} }

View file

@ -1,18 +1,18 @@
<svelte:options tag="iron-remote-gui"/> <svelte:options tag="iron-remote-gui" />
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte'; import { onMount } from 'svelte';
import {get_current_component} from "svelte/internal"; import { get_current_component } from 'svelte/internal';
import {loggingService} from "./services/logging.service"; import { loggingService } from './services/logging.service';
import {WasmBridgeService} from './services/wasm-bridge.service'; import { WasmBridgeService } from './services/wasm-bridge.service';
import {LogType} from './enums/LogType'; import { LogType } from './enums/LogType';
import type {ResizeEvent} from './interfaces/ResizeEvent'; import type { ResizeEvent } from './interfaces/ResizeEvent';
import {PublicAPI} from './services/PublicAPI'; import { PublicAPI } from './services/PublicAPI';
import {ScreenScale} from './enums/ScreenScale'; import { ScreenScale } from './enums/ScreenScale';
export let scale = 'real'; export let scale = 'real';
export let verbose = 'false'; export let verbose = 'false';
export let debugwasm: "OFF" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" = 'INFO'; export let debugwasm: 'OFF' | 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' = 'INFO';
export let flexcenter = 'true'; export let flexcenter = 'true';
let isVisible = false; let isVisible = false;
@ -24,7 +24,7 @@
let viewerStyle: string; let viewerStyle: string;
let wrapperStyle: string; let wrapperStyle: string;
let wasmService = new WasmBridgeService(); let wasmService = new WasmBridgeService();
let publicAPI = new PublicAPI(wasmService); let publicAPI = new PublicAPI(wasmService);
@ -49,9 +49,9 @@
if (flexcenter === 'true') { if (flexcenter === 'true') {
if (!full) { if (!full) {
currentComponent.style.flexGrow = 1; currentComponent.style.flexGrow = 1;
currentComponent.style.display = "flex"; currentComponent.style.display = 'flex';
currentComponent.style.justifyContent = "center"; currentComponent.style.justifyContent = 'center';
currentComponent.style.alignItems = "center"; currentComponent.style.alignItems = 'center';
} else { } else {
currentComponent.style.flexGrow = 1; currentComponent.style.flexGrow = 1;
} }
@ -86,16 +86,16 @@
scaleSession(scale); scaleSession(scale);
}); });
wasmService.scaleObserver.subscribe(s => { wasmService.scaleObserver.subscribe((s) => {
loggingService.info("Change scale!"); loggingService.info('Change scale!');
scaleSession(s); scaleSession(s);
}); });
wasmService.changeVisibilityObservable.subscribe(val => { wasmService.changeVisibilityObservable.subscribe((val) => {
isVisible = val; isVisible = val;
if (val) { if (val) {
//Enforce first scaling and delay the call to scaleSession to ensure Dom is ready. //Enforce first scaling and delay the call to scaleSession to ensure Dom is ready.
setWrapperStyle("100%", "100%", "hidden"); setWrapperStyle('100%', '100%', 'hidden');
setTimeout(() => scaleSession(scale), 150); setTimeout(() => scaleSession(scale), 150);
} }
}); });
@ -107,22 +107,22 @@
switch (currentSize) { switch (currentSize) {
case 'fit': case 'fit':
case ScreenScale.Fit: case ScreenScale.Fit:
loggingService.info("Size to fit"); loggingService.info('Size to fit');
scale = 'fit'; scale = 'fit';
fitResize(); fitResize();
break; break;
case 'full': case 'full':
case ScreenScale.Full: case ScreenScale.Full:
loggingService.info("Size to full"); loggingService.info('Size to full');
fullResize(); fullResize();
scale = 'full'; scale = 'full';
break; break;
case 'real': case 'real':
case ScreenScale.Real: case ScreenScale.Real:
loggingService.info("Size to real"); loggingService.info('Size to real');
realResize(); realResize();
scale = 'real'; scale = 'real';
break break;
} }
} }
} }
@ -181,7 +181,11 @@
const containerHeight = windowSize.y - wrapperBoundingBox.y; const containerHeight = windowSize.y - wrapperBoundingBox.y;
if (containerWidth < canvas.width || containerHeight < canvas.height) { if (containerWidth < canvas.width || containerHeight < canvas.height) {
setWrapperStyle(`${Math.min(containerHeight, canvas.height)}px`, `${Math.min(containerWidth, canvas.width)}px`, 'auto'); setWrapperStyle(
`${Math.min(containerHeight, canvas.height)}px`,
`${Math.min(containerWidth, canvas.width)}px`,
'auto',
);
} else { } else {
setWrapperStyle('initial', 'initial', 'initial'); setWrapperStyle('initial', 'initial', 'initial');
} }
@ -197,7 +201,7 @@
const coord = { const coord = {
x: Math.round((evt.clientX - rect.left) * scaleX), x: Math.round((evt.clientX - rect.left) * scaleX),
y: Math.round((evt.clientY - rect.top) * scaleY) y: Math.round((evt.clientY - rect.top) * scaleY),
}; };
wasmService.updateMousePosition(coord); wasmService.updateMousePosition(coord);
@ -232,11 +236,11 @@
body = doc.getElementsByTagName('body')[0], body = doc.getElementsByTagName('body')[0],
x = win.innerWidth ?? docElem.clientWidth ?? body.clientWidth, x = win.innerWidth ?? docElem.clientWidth ?? body.clientWidth,
y = win.innerHeight ?? docElem.clientHeight ?? body.clientHeight; y = win.innerHeight ?? docElem.clientHeight ?? body.clientHeight;
return {x, y}; return { x, y };
} }
async function initcanvas() { async function initcanvas() {
loggingService.info('Start canvas initialization.') loggingService.info('Start canvas initialization.');
canvas = currentComponent.shadowRoot.getElementById('renderer'); canvas = currentComponent.shadowRoot.getElementById('renderer');
// Set a default canvas size. Need more test to know if i can remove it. // Set a default canvas size. Need more test to know if i can remove it.
@ -250,11 +254,11 @@
initListeners(); initListeners();
let result = { let result = {
irgUserInteraction: publicAPI.getExposedFunctions() irgUserInteraction: publicAPI.getExposedFunctions(),
}; };
loggingService.info('Component ready'); loggingService.info('Component ready');
currentComponent.dispatchEvent(new CustomEvent("ready", {detail: result})); currentComponent.dispatchEvent(new CustomEvent('ready', { detail: result }));
} }
onMount(async () => { onMount(async () => {
@ -264,26 +268,28 @@
}); });
</script> </script>
<div bind:this={wrapper} class="screen-wrapper scale-{scale}" class:hidden="{!isVisible}" <div
class:capturing-inputs="{capturingInputs}" bind:this={wrapper}
style="{wrapperStyle}"> class="screen-wrapper scale-{scale}"
<div class="screen-viewer" style="{viewerStyle}"> class:hidden={!isVisible}
class:capturing-inputs={capturingInputs}
style={wrapperStyle}
>
<div class="screen-viewer" style={viewerStyle}>
<canvas <canvas
on:mousemove={getMousePos} on:mousemove={getMousePos}
on:mousedown={(event) => setMouseButtonState(event, true)} on:mousedown={(event) => setMouseButtonState(event, true)}
on:mouseup={(event) => setMouseButtonState(event, false)} on:mouseup={(event) => setMouseButtonState(event, false)}
on:mouseleave={(event) => { on:mouseleave={(event) => {
setMouseButtonState(event, false); setMouseButtonState(event, false);
setMouseOut(event); setMouseOut(event);
} }}
} on:mouseenter={(event) => {
on:mouseenter={(event) => { setMouseIn(event);
setMouseIn(event); }}
} on:contextmenu={(event) => event.preventDefault()}
} on:wheel={mouseWheel}
on:contextmenu={(event) => event.preventDefault()} id="renderer"
on:wheel={mouseWheel}
id="renderer"
/> />
</div> </div>
</div> </div>
@ -294,7 +300,7 @@
} }
.capturing-inputs { .capturing-inputs {
outline: 1px solid rgba(0, 97, 166, .7); outline: 1px solid rgba(0, 97, 166, 0.7);
outline-offset: -1px; outline-offset: -1px;
} }

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,9 @@
export * as default from './iron-remote-gui.svelte'; export * as default from './iron-remote-gui.svelte';
export type {UserInteraction} from './interfaces/UserInteraction'; export type { UserInteraction } from './interfaces/UserInteraction';
export type {ResizeEvent} from './interfaces/ResizeEvent'; export type { ResizeEvent } from './interfaces/ResizeEvent';
export type {NewSessionInfo} from './interfaces/NewSessionInfo'; export type { NewSessionInfo } from './interfaces/NewSessionInfo';
export type {ServerRect} from './interfaces/ServerRect'; export type { ServerRect } from './interfaces/ServerRect';
export type {DesktopSize} from './interfaces/DesktopSize'; export type { DesktopSize } from './interfaces/DesktopSize';
export type {SessionEvent} from './interfaces/session-event'; export type { SessionEvent } from './interfaces/session-event';
export type {SessionEventType} from './enums/SessionEventType'; export type { SessionEventType } from './enums/SessionEventType';

View file

@ -1,11 +1,11 @@
import {loggingService} from './logging.service'; import { loggingService } from './logging.service';
import type {NewSessionInfo} from '../interfaces/NewSessionInfo'; import type { NewSessionInfo } from '../interfaces/NewSessionInfo';
import {SpecialCombination} from '../enums/SpecialCombination'; import { SpecialCombination } from '../enums/SpecialCombination';
import type {WasmBridgeService} from './wasm-bridge.service'; import type { WasmBridgeService } from './wasm-bridge.service';
import type {UserInteraction} from '../interfaces/UserInteraction'; import type { UserInteraction } from '../interfaces/UserInteraction';
import type {ScreenScale} from '../enums/ScreenScale'; import type { ScreenScale } from '../enums/ScreenScale';
import type {Observable} from 'rxjs'; import type { Observable } from 'rxjs';
import type {DesktopSize} from '../interfaces/DesktopSize'; import type { DesktopSize } from '../interfaces/DesktopSize';
export class PublicAPI { export class PublicAPI {
private wasmService: WasmBridgeService; private wasmService: WasmBridgeService;
@ -14,9 +14,27 @@ export class PublicAPI {
this.wasmService = wasmService; this.wasmService = wasmService;
} }
private connect(username: string, password: string, destination: string, proxyAddress: string, serverDomain: string, authToken: string, desktopSize?: DesktopSize, preConnectionBlob?: string): Observable<NewSessionInfo> { private connect(
username: string,
password: string,
destination: string,
proxyAddress: string,
serverDomain: string,
authToken: string,
desktopSize?: DesktopSize,
preConnectionBlob?: string,
): Observable<NewSessionInfo> {
loggingService.info('Initializing connection.'); loggingService.info('Initializing connection.');
return this.wasmService.connect(username, password, destination, proxyAddress, serverDomain, authToken, desktopSize, preConnectionBlob); return this.wasmService.connect(
username,
password,
destination,
proxyAddress,
serverDomain,
authToken,
desktopSize,
preConnectionBlob,
);
} }
private ctrlAltDel() { private ctrlAltDel() {
@ -35,8 +53,8 @@ export class PublicAPI {
private setScale(scale: ScreenScale) { private setScale(scale: ScreenScale) {
this.wasmService.setScale(scale); this.wasmService.setScale(scale);
} }
private shutdown() { private shutdown() {
this.wasmService.shutdown(); this.wasmService.shutdown();
} }
@ -48,8 +66,7 @@ export class PublicAPI {
sessionListener: this.wasmService.sessionObserver, sessionListener: this.wasmService.sessionObserver,
ctrlAltDel: this.ctrlAltDel.bind(this), ctrlAltDel: this.ctrlAltDel.bind(this),
metaKey: this.metaKey.bind(this), metaKey: this.metaKey.bind(this),
shutdown: this.shutdown.bind(this) shutdown: this.shutdown.bind(this),
} };
} }
} }

View file

@ -1,12 +1,12 @@
export class LoggingService { export class LoggingService {
verbose: boolean = false; verbose: boolean = false;
info(description: string) { info(description: string) {
if (this.verbose) { if (this.verbose) {
console.log(description); console.log(description);
} }
} }
error(description: string, object?: unknown) { error(description: string, object?: unknown) {
if (this.verbose) { if (this.verbose) {
console.error(description, object); console.error(description, object);
@ -14,4 +14,4 @@
} }
} }
export const loggingService = new LoggingService(); export const loggingService = new LoggingService();

View file

@ -1,26 +1,34 @@
import {BehaviorSubject, from, Observable, of, Subject} from 'rxjs'; import { BehaviorSubject, from, Observable, of, Subject } from 'rxjs';
import init, {DesktopSize, DeviceEvent, InputTransaction, ironrdp_init, IronRdpError, Session, SessionBuilder} from '../../../../crates/ironrdp-web/pkg/ironrdp_web'; import init, {
import {loggingService} from './logging.service'; DesktopSize,
import {catchError, filter, map} from 'rxjs/operators'; DeviceEvent,
import {scanCode} from '../lib/scancodes'; InputTransaction,
import {LogType} from '../enums/LogType'; ironrdp_init,
import {OS} from '../enums/OS'; IronRdpError,
import {ModifierKey} from '../enums/ModifierKey'; Session,
import {LockKey} from '../enums/LockKey'; SessionBuilder,
import {SessionEventType} from '../enums/SessionEventType'; } from '../../../../crates/ironrdp-web/pkg/ironrdp_web';
import type {NewSessionInfo} from '../interfaces/NewSessionInfo'; import { loggingService } from './logging.service';
import {SpecialCombination} from '../enums/SpecialCombination'; import { catchError, filter, map } from 'rxjs/operators';
import type {ResizeEvent} from '../interfaces/ResizeEvent'; import { scanCode } from '../lib/scancodes';
import {ScreenScale} from '../enums/ScreenScale'; import { LogType } from '../enums/LogType';
import type {MousePosition} from '../interfaces/MousePosition'; import { OS } from '../enums/OS';
import type {SessionEvent} from '../interfaces/session-event'; import { ModifierKey } from '../enums/ModifierKey';
import type {DesktopSize as IDesktopSize} from '../interfaces/DesktopSize'; import { LockKey } from '../enums/LockKey';
import { SessionEventType } from '../enums/SessionEventType';
import type { NewSessionInfo } from '../interfaces/NewSessionInfo';
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 } from '../interfaces/session-event';
import type { DesktopSize as IDesktopSize } from '../interfaces/DesktopSize';
export class WasmBridgeService { export class WasmBridgeService {
private _resize: Subject<ResizeEvent> = new Subject<ResizeEvent>(); private _resize: Subject<ResizeEvent> = new Subject<ResizeEvent>();
private mousePosition: BehaviorSubject<MousePosition> = new BehaviorSubject<MousePosition>({ private mousePosition: BehaviorSubject<MousePosition> = new BehaviorSubject<MousePosition>({
x: 0, x: 0,
y: 0 y: 0,
}); });
private changeVisibility: Subject<boolean> = new Subject(); private changeVisibility: Subject<boolean> = new Subject();
private sessionEvent: Subject<SessionEvent> = new Subject(); private sessionEvent: Subject<SessionEvent> = new Subject();
@ -82,8 +90,16 @@ export class WasmBridgeService {
this.mousePosition.next(position); this.mousePosition.next(position);
} }
connect(
connect(username: string, password: string, destination: string, proxyAddress: string, serverDomain: string, authToken: string, desktopSize?: IDesktopSize, preConnectionBlob?: string): Observable<NewSessionInfo> { username: string,
password: string,
destination: string,
proxyAddress: string,
serverDomain: string,
authToken: string,
desktopSize?: IDesktopSize,
preConnectionBlob?: string,
): Observable<NewSessionInfo> {
const sessionBuilder = SessionBuilder.new(); const sessionBuilder = SessionBuilder.new();
sessionBuilder.proxy_address(proxyAddress); sessionBuilder.proxy_address(proxyAddress);
sessionBuilder.destination(destination); sessionBuilder.destination(destination);
@ -114,26 +130,28 @@ export class WasmBridgeService {
catchError((err: IronRdpError) => { catchError((err: IronRdpError) => {
this.raiseSessionEvent({ this.raiseSessionEvent({
type: SessionEventType.ERROR, type: SessionEventType.ERROR,
data: err data: err,
}); });
return of(err); return of(err);
}), }),
filter(isSession), filter(isSession),
map((session: Session) => { map((session: Session) => {
from(session.run()).pipe( from(session.run())
catchError(err => { .pipe(
this.setVisibility(false); catchError((err) => {
this.raiseSessionEvent({ this.setVisibility(false);
type: SessionEventType.ERROR, this.raiseSessionEvent({
data: err.backtrace() type: SessionEventType.ERROR,
}); data: err.backtrace(),
this.raiseSessionEvent({ });
type: SessionEventType.TERMINATED, this.raiseSessionEvent({
data: 'Session was terminated.' type: SessionEventType.TERMINATED,
}); data: 'Session was terminated.',
return of(err); });
}), return of(err);
).subscribe(); }),
)
.subscribe();
return session; return session;
}), }),
map((session: Session) => { map((session: Session) => {
@ -141,17 +159,17 @@ export class WasmBridgeService {
this.session = session; this.session = session;
this._resize.next({ this._resize.next({
desktop_size: session.desktop_size(), desktop_size: session.desktop_size(),
session_id: 0 session_id: 0,
}); });
this.raiseSessionEvent({ this.raiseSessionEvent({
type: SessionEventType.STARTED, type: SessionEventType.STARTED,
data: 'Session started' data: 'Session started',
}); });
return { return {
session_id: 0, session_id: 0,
initial_desktop_size: session.desktop_size(), initial_desktop_size: session.desktop_size(),
websocket_port: 0 websocket_port: 0,
} };
}), }),
); );
} }
@ -167,14 +185,12 @@ export class WasmBridgeService {
} }
} }
mouseWheel(event: WheelEvent) { mouseWheel(event: WheelEvent) {
const vertical = event.deltaY !== 0; const vertical = event.deltaY !== 0;
const rotation = vertical ? event.deltaY : event.deltaX; const rotation = vertical ? event.deltaY : event.deltaX;
this.doTransactionFromDeviceEvents([DeviceEvent.new_wheel_rotations(vertical, -rotation)]); this.doTransactionFromDeviceEvents([DeviceEvent.new_wheel_rotations(vertical, -rotation)]);
} }
setVisibility(state: boolean) { setVisibility(state: boolean) {
this.changeVisibility.next(state); this.changeVisibility.next(state);
} }
@ -234,7 +250,12 @@ export class WasmBridgeService {
const syncScrollLockActive = evt.getModifierState(LockKey.SCROLL_LOCK); const syncScrollLockActive = evt.getModifierState(LockKey.SCROLL_LOCK);
const syncKanaModeActive = evt.getModifierState(LockKey.KANA_MODE); const syncKanaModeActive = evt.getModifierState(LockKey.KANA_MODE);
this.session?.synchronize_lock_keys(syncScrollLockActive, syncNumsLockActive, syncCapsLockActive, syncKanaModeActive); this.session?.synchronize_lock_keys(
syncScrollLockActive,
syncNumsLockActive,
syncCapsLockActive,
syncKanaModeActive,
);
} }
private raiseSessionEvent(event: SessionEvent) { private raiseSessionEvent(event: SessionEvent) {
@ -253,7 +274,7 @@ export class WasmBridgeService {
private doTransactionFromDeviceEvents(deviceEvents: DeviceEvent[]) { private doTransactionFromDeviceEvents(deviceEvents: DeviceEvent[]) {
const transaction = InputTransaction.new(); const transaction = InputTransaction.new();
deviceEvents.forEach(event => transaction.add_event(event)); deviceEvents.forEach((event) => transaction.add_event(event));
this.session?.apply_inputs(transaction); this.session?.apply_inputs(transaction);
} }

View file

@ -1,10 +1,10 @@
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default { export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors // for more information about preprocessors
compilerOptions: { compilerOptions: {
customElement: true customElement: true,
}, },
preprocess: vitePreprocess(), preprocess: vitePreprocess(),
} };

View file

@ -14,7 +14,7 @@
"allowJs": false, "allowJs": false,
"checkJs": false, "checkJs": false,
"isolatedModules": true, "isolatedModules": true,
"strict": true, "strict": true,
"strictNullChecks": true, "strictNullChecks": true,
"noImplicitAny": true "noImplicitAny": true
}, },

View file

@ -1,22 +1,22 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte' import { svelte } from '@sveltejs/vite-plugin-svelte';
import wasm from "vite-plugin-wasm"; import wasm from 'vite-plugin-wasm';
import topLevelAwait from "vite-plugin-top-level-await"; import topLevelAwait from 'vite-plugin-top-level-await';
import dtsPlugin from "vite-plugin-dts"; import dtsPlugin from 'vite-plugin-dts';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
build: { build: {
lib: { lib: {
entry: './src/main.ts', entry: './src/main.ts',
name: 'IronRemoteGui', name: 'IronRemoteGui',
formats: ["umd", "es"], formats: ['umd', 'es'],
} },
}, },
server: { server: {
fs: { fs: {
strict: false strict: false,
} },
}, },
plugins: [svelte(), wasm(), topLevelAwait(), dtsPlugin()], plugins: [svelte(), wasm(), topLevelAwait(), dtsPlugin()],
}) });

View file

@ -12,31 +12,31 @@
root: true root: true
plugins: plugins:
- "@typescript-eslint" - '@typescript-eslint'
- 'html' - 'html'
extends: extends:
- "eslint:recommended" - 'eslint:recommended'
- "plugin:@typescript-eslint/recommended" - 'plugin:@typescript-eslint/recommended'
- "plugin:svelte/prettier" # Turns off rules that may conflict with Prettier - 'plugin:svelte/prettier' # Turns off rules that may conflict with Prettier
- "plugin:prettier/recommended" - 'plugin:prettier/recommended'
parser: "@typescript-eslint/parser" parser: '@typescript-eslint/parser'
parserOptions: parserOptions:
project: ./tsconfig.json project: ./tsconfig.json
sourceType: module sourceType: module
ecmaVersion: 2020 ecmaVersion: 2020
extraFileExtensions: extraFileExtensions:
- ".svelte" - '.svelte'
ignorePatterns: ignorePatterns:
- "*.cjs" - '*.cjs'
overrides: overrides:
- files: "*.svelte" - files: '*.svelte'
parser: svelte-eslint-parser parser: svelte-eslint-parser
parserOptions: parserOptions:
parser: "@typescript-eslint/parser" parser: '@typescript-eslint/parser'
env: env:
browser: true browser: true
@ -45,10 +45,10 @@ env:
rules: rules:
strict: 2 strict: 2
"@typescript-eslint/no-unused-vars": '@typescript-eslint/no-unused-vars':
- "error" - 'error'
- argsIgnorePattern: '^_' - argsIgnorePattern: '^_'
"@typescript-eslint/strict-boolean-expressions": '@typescript-eslint/strict-boolean-expressions':
- 2 - 2
- allowString: false - allowString: false
allowNumber: false allowNumber: false

View file

@ -97,7 +97,7 @@ $ New-DGatewayToken -Type ASSOCIATION -PrivateKeyFile <PRIVATE KEY PATH> -Destin
First, run `npm install` in the [iron-remote-gui](../iron-remote-gui/) folder, First, run `npm install` in the [iron-remote-gui](../iron-remote-gui/) folder,
and then `npm install` in [iron-svelte-client](./) folder. and then `npm install` in [iron-svelte-client](./) folder.
You can then start the dev server with either: You can then start the dev server with either:
- `npm run dev` - Runs only the final application. - `npm run dev` - Runs only the final application.
- `npm run dev-all` - Builds WASM module and `iron-remote-gui` prior to starting the dev server. - `npm run dev-all` - Builds WASM module and `iron-remote-gui` prior to starting the dev server.

View file

@ -11,14 +11,11 @@
"build": "npm run pre-build && vite build", "build": "npm run pre-build && vite build",
"build-no-wasm": "npm run pre-build-no-wasm && vite build", "build-no-wasm": "npm run pre-build-no-wasm && vite build",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "npm run lint:prettier && npm run lint:eslint", "lint": "npm run lint:prettier && npm run lint:eslint",
"lint:prettier": "prettier . --check", "lint:prettier": "prettier . --check",
"lint:eslint": "eslint src/**", "lint:eslint": "eslint src/**",
"format": "prettier . --write ." "format": "prettier . --write ."
}, },
"devDependencies": { "devDependencies": {

View file

@ -1,7 +1,7 @@
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import {spawn} from 'child_process'; import { spawn } from 'child_process';
import * as path from 'path'; import * as path from 'path';
import {fileURLToPath} from 'url'; import { fileURLToPath } from 'url';
import { argv } from 'node:process'; import { argv } from 'node:process';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
@ -18,8 +18,8 @@ argv.forEach((val, index) => {
}); });
let run = async function (command, cwd) { let run = async function (command, cwd) {
return new Promise(resolve => { return new Promise((resolve) => {
const buildCommand = spawn(command, {stdio: "pipe", shell: true, cwd: cwd}); const buildCommand = spawn(command, { stdio: 'pipe', shell: true, cwd: cwd });
buildCommand.stdout.on('data', (data) => { buildCommand.stdout.on('data', (data) => {
console.log(`${data}`); console.log(`${data}`);
@ -39,7 +39,7 @@ let run = async function (command, cwd) {
let copyCoreFiles = async function () { let copyCoreFiles = async function () {
console.log('Copying core files…'); console.log('Copying core files…');
await fs.remove(assetIronRemoteGuiFolder); await fs.remove(assetIronRemoteGuiFolder);
return new Promise(resolve => { return new Promise((resolve) => {
let source = '../iron-remote-gui/dist'; let source = '../iron-remote-gui/dist';
let destination = assetIronRemoteGuiFolder; let destination = assetIronRemoteGuiFolder;
@ -51,8 +51,8 @@ let copyCoreFiles = async function () {
console.log('Core files were copied successfully'); console.log('Core files were copied successfully');
resolve(); resolve();
}); });
}) });
} };
let buildCommand = 'npm run build'; let buildCommand = 'npm run build';
if (noWasm) { if (noWasm) {

View file

@ -2,8 +2,8 @@
// for information about these interfaces // for information about these interfaces
// and what to do when importing types // and what to do when importing types
declare namespace App { declare namespace App {
// interface Locals {} // interface Locals {}
// interface PageData {} // interface PageData {}
// interface Error {} // interface Error {}
// interface Platform {} // interface Platform {}
} }

View file

@ -1,19 +1,19 @@
<!DOCTYPE html> <!doctype html>
<html lang="en" style="height: 100%; margin: 0; padding: 0;"> <html lang="en" style="height: 100%; margin: 0; padding: 0">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link href="%sveltekit.assets%/material-icons/index.css" rel="stylesheet"> <link href="%sveltekit.assets%/material-icons/index.css" rel="stylesheet" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,600,700" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,600,700" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono" />
<link href="%sveltekit.assets%/beercss/beer.min.css" rel="stylesheet" /> <link href="%sveltekit.assets%/beercss/beer.min.css" rel="stylesheet" />
<link href="%sveltekit.assets%/theme.css" rel="stylesheet" /> <link href="%sveltekit.assets%/theme.css" rel="stylesheet" />
<script src="%sveltekit.assets%/beercss/beer.min.js" type="text/javascript"></script> <script src="%sveltekit.assets%/beercss/beer.min.js" type="text/javascript"></script>
<script type="module" src="%sveltekit.assets%/iron-remote-gui/iron-remote-gui.js"></script> <script type="module" src="%sveltekit.assets%/iron-remote-gui/iron-remote-gui.js"></script>
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
%sveltekit.head% %sveltekit.head%
</head> </head>
<body class="light" style="height: 100%; margin: 0; padding: 0;"> <body class="light" style="height: 100%; margin: 0; padding: 0">
<div style="display: contents" class="mdc-typography--font-family">%sveltekit.body%</div> <div style="display: contents" class="mdc-typography--font-family">%sveltekit.body%</div>
</body> </body>
</html> </html>

View file

@ -1,3 +1,3 @@
import {writable} from 'svelte/store'; import { writable } from 'svelte/store';
export const showLogin = writable(true); export const showLogin = writable(true);

View file

@ -1,4 +1,4 @@
.wrapper { .wrapper {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }

View file

@ -1,27 +1,28 @@
<script lang="ts"> <script lang="ts">
import {currentSession, userInteractionService} from '../../services/session.service'; import { currentSession, userInteractionService } from '../../services/session.service';
import {catchError, filter} from "rxjs/operators"; import { catchError, filter } from 'rxjs/operators';
import type {UserInteraction, NewSessionInfo} from '../../../static/iron-remote-gui'; import type { UserInteraction, NewSessionInfo } from '../../../static/iron-remote-gui';
import {of} from 'rxjs'; import { of } from 'rxjs';
import {toast} from '$lib/messages/message-store'; import { toast } from '$lib/messages/message-store';
import {showLogin} from '$lib/login/login-store'; import { showLogin } from '$lib/login/login-store';
import type {DesktopSize} from '../../models/desktop-size'; import type { DesktopSize } from '../../models/desktop-size';
let username = "Administrator"; let username = 'Administrator';
let password = "DevoLabs123!"; let password = 'DevoLabs123!';
let gatewayAddress = "ws://localhost:7171/jet/rdp"; let gatewayAddress = 'ws://localhost:7171/jet/rdp';
let hostname = "10.10.0.3:3389"; let hostname = '10.10.0.3:3389';
let domain = ""; let domain = '';
let authtoken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkFTU09DSUFUSU9OIn0.eyJkc3RfaHN0IjoiMTkyLjE2OC41Ni4xMDE6MzM4OSIsImV4cCI6MTY5MzQyMzY1NSwiamV0X2FpZCI6IjMwNzZjZGIwLWYxNTctNDJlNy1iOWMzLThhMTdlNDFkYjYwNyIsImpldF9hcCI6InJkcCIsImpldF9jbSI6ImZ3ZCIsImp0aSI6IjAwYjY4OTY2LWJiYjAtNDU0NS05ZDZiLWRjNmFmMjAzNjY5MiIsIm5iZiI6MTY5MzQyMjc1NX0.SYQv4HtWQbdHMHgoCLYejCfO3TtsMAyjjILB6-Nir3mBznKiSad3POeLf02n05JFc5QhCeSGxspAaoNU7-znQFhHr0Tt0MnZJ1YMQt4UoR3PR2fTuUqv8M5TKdm4lKwCIjh73tTD001glTkXHaxuCQBTFCUSzfZhXDIqq5-CQueKtCrgJfYepJLmlvgH-ujGcxfXoGJGmeUy3Fmaijiy0uaC98j9GNCfnAd6JENmSAOkxfroMFhq601PSEizRbPzq2exDakfJ0EkaANz15udBX1a7NP-RyANHWQb8hp0rj6hyuyg1-vfUKYusw5qNUjAGXaWOjHC5bLgnqfE2V8Xnw"; let authtoken =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkFTU09DSUFUSU9OIn0.eyJkc3RfaHN0IjoiMTkyLjE2OC41Ni4xMDE6MzM4OSIsImV4cCI6MTY5MzQyMzY1NSwiamV0X2FpZCI6IjMwNzZjZGIwLWYxNTctNDJlNy1iOWMzLThhMTdlNDFkYjYwNyIsImpldF9hcCI6InJkcCIsImpldF9jbSI6ImZ3ZCIsImp0aSI6IjAwYjY4OTY2LWJiYjAtNDU0NS05ZDZiLWRjNmFmMjAzNjY5MiIsIm5iZiI6MTY5MzQyMjc1NX0.SYQv4HtWQbdHMHgoCLYejCfO3TtsMAyjjILB6-Nir3mBznKiSad3POeLf02n05JFc5QhCeSGxspAaoNU7-znQFhHr0Tt0MnZJ1YMQt4UoR3PR2fTuUqv8M5TKdm4lKwCIjh73tTD001glTkXHaxuCQBTFCUSzfZhXDIqq5-CQueKtCrgJfYepJLmlvgH-ujGcxfXoGJGmeUy3Fmaijiy0uaC98j9GNCfnAd6JENmSAOkxfroMFhq601PSEizRbPzq2exDakfJ0EkaANz15udBX1a7NP-RyANHWQb8hp0rj6hyuyg1-vfUKYusw5qNUjAGXaWOjHC5bLgnqfE2V8Xnw';
let desktopSize: DesktopSize = { let desktopSize: DesktopSize = {
width: 1280, width: 1280,
height: 768 height: 768,
}; };
let pcb: string; let pcb: string;
let userInteraction: UserInteraction; let userInteraction: UserInteraction;
userInteractionService.subscribe(val => { userInteractionService.subscribe((val) => {
userInteraction = val; userInteraction = val;
if (val != null) { if (val != null) {
initListeners(); initListeners();
@ -29,9 +30,9 @@
}); });
const initListeners = () => { const initListeners = () => {
userInteraction.sessionListener.subscribe(event => { userInteraction.sessionListener.subscribe((event) => {
if (event.type === 2) { if (event.type === 2) {
console.log("Error event", event.data); console.log('Error event', event.data);
toast.set({ toast.set({
type: 'error', type: 'error',
@ -40,27 +41,28 @@
} else { } else {
toast.set({ toast.set({
type: 'info', type: 'info',
message: event.data ?? "No info", message: event.data ?? 'No info',
}); });
} }
}); });
} };
const StartSession = () => { const StartSession = () => {
toast.set({ toast.set({
type: 'info', type: 'info',
message: 'Connection in progress...' message: 'Connection in progress...',
}); });
userInteraction.connect(username, password, hostname, gatewayAddress, domain, authtoken, desktopSize, pcb) userInteraction
.connect(username, password, hostname, gatewayAddress, domain, authtoken, desktopSize, pcb)
.pipe( .pipe(
catchError(err => { catchError((err) => {
toast.set({ toast.set({
type: 'info', type: 'info',
message: err.backtrace() message: err.backtrace(),
}); });
return of(null); return of(null);
}), }),
filter(result => !!result) filter((result) => !!result),
) )
.subscribe((start_info: NewSessionInfo | null) => { .subscribe((start_info: NewSessionInfo | null) => {
if (start_info != null && start_info.initial_desktop_size !== null) { if (start_info != null && start_info.initial_desktop_size !== null) {
@ -68,11 +70,13 @@
type: 'info', type: 'info',
message: 'Success', message: 'Success',
}); });
currentSession.update(session => Object.assign(session, { currentSession.update((session) =>
sessionId: start_info.session_id, Object.assign(session, {
desktopSize: start_info.initial_desktop_size, sessionId: start_info.session_id,
active: true, desktopSize: start_info.initial_desktop_size,
})); active: true,
}),
);
showLogin.set(false); showLogin.set(false);
} else { } else {
toast.set({ toast.set({
@ -85,48 +89,48 @@
</script> </script>
<main class="responsive"> <main class="responsive">
<div class="large-space"/> <div class="large-space" />
<div class="grid"> <div class="grid">
<div class="s2"/> <div class="s2" />
<div class="s8"> <div class="s8">
<article class="primary-container"> <article class="primary-container">
<h5>Login</h5> <h5>Login</h5>
<div class="medium-space"/> <div class="medium-space" />
<div> <div>
<div class="field label border"> <div class="field label border">
<input id="hostname" type="text" bind:value={hostname}/> <input id="hostname" type="text" bind:value={hostname} />
<label for="hostname">Hostname</label> <label for="hostname">Hostname</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="domain" type="text" bind:value={domain}/> <input id="domain" type="text" bind:value={domain} />
<label for="domain">Domain</label> <label for="domain">Domain</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="username" type="text" bind:value={username}/> <input id="username" type="text" bind:value={username} />
<label for="username">Username</label> <label for="username">Username</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="password" type="password" bind:value={password}/> <input id="password" type="password" bind:value={password} />
<label for="password">Password</label> <label for="password">Password</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="gatewayAddress" type="text" bind:value={gatewayAddress}/> <input id="gatewayAddress" type="text" bind:value={gatewayAddress} />
<label for="gatewayAddress">Gateway Address</label> <label for="gatewayAddress">Gateway Address</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="authtoken" type="text" bind:value={authtoken}/> <input id="authtoken" type="text" bind:value={authtoken} />
<label for="authtoken">AuthToken</label> <label for="authtoken">AuthToken</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="pcb" type="text" bind:value={pcb}/> <input id="pcb" type="text" bind:value={pcb} />
<label for="pcb">Pre Connection Blob</label> <label for="pcb">Pre Connection Blob</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="desktopSizeW" type="text" bind:value={desktopSize.width}/> <input id="desktopSizeW" type="text" bind:value={desktopSize.width} />
<label for="desktopSizeW">Desktop Width</label> <label for="desktopSizeW">Desktop Width</label>
</div> </div>
<div class="field label border"> <div class="field label border">
<input id="desktopSizeH" type="text" bind:value={desktopSize.height}/> <input id="desktopSizeH" type="text" bind:value={desktopSize.height} />
<label for="desktopSizeH">Desktop Height</label> <label for="desktopSizeH">Desktop Height</label>
</div> </div>
</div> </div>
@ -135,11 +139,10 @@
</nav> </nav>
</article> </article>
</div> </div>
<div class="s2"/> <div class="s2" />
</div> </div>
</main> </main>
<style> <style>
@import './login.css'; @import './login.css';
</style> </style>

View file

@ -1,8 +1,8 @@
import type {Writable} from 'svelte/store'; import type { Writable } from 'svelte/store';
import {writable} from 'svelte/store'; import { writable } from 'svelte/store';
type ToastMessage = { type ToastMessage = {
message: string, message: string;
type: 'info' | 'error' type: 'info' | 'error';
}; };
export const toast: Writable<ToastMessage> = writable(); export const toast: Writable<ToastMessage> = writable();

View file

@ -1,9 +1,9 @@
<script lang="ts"> <script lang="ts">
import {toast} from '$lib/messages/message-store'; import { toast } from '$lib/messages/message-store';
let toastMessage: string; let toastMessage: string;
toast.subscribe(t => { toast.subscribe((t) => {
if (t != null) { if (t != null) {
toastMessage = t.message; toastMessage = t.message;
switch (t.type) { switch (t.type) {
@ -24,7 +24,6 @@
} }
} }
}); });
</script> </script>
<div id="toast" class="toast blue white-text"> <div id="toast" class="toast blue white-text">

View file

@ -1,25 +1,22 @@
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte'; import { onMount } from 'svelte';
import { import { setCurrentSessionActive, userInteractionService } from '../../services/session.service';
setCurrentSessionActive, import { showLogin } from '$lib/login/login-store';
userInteractionService
} from '../../services/session.service';
import {showLogin} from '$lib/login/login-store';
import type { UserInteraction } from '../../../static/iron-remote-gui/main'; import type { UserInteraction } from '../../../static/iron-remote-gui/main';
let uiService: UserInteraction; let uiService: UserInteraction;
userInteractionService.subscribe(uis => { userInteractionService.subscribe((uis) => {
if (uis != null) { if (uis != null) {
uiService = uis uiService = uis;
uiService.sessionListener.subscribe(event => { uiService.sessionListener.subscribe((event) => {
if (event.type === 0) { if (event.type === 0) {
uiService.setVisibility(true); uiService.setVisibility(true);
} else if (event.type === 1) { } else if (event.type === 1) {
setCurrentSessionActive(false); setCurrentSessionActive(false);
showLogin.set(true); showLogin.set(true);
} }
}) });
} }
}); });
@ -27,7 +24,7 @@
let el = document.querySelector('iron-remote-gui'); let el = document.querySelector('iron-remote-gui');
if (el == null) { if (el == null) {
throw "`iron-remote-gui` element not found"; throw '`iron-remote-gui` element not found';
} }
el.addEventListener('ready', (e) => { el.addEventListener('ready', (e) => {
@ -36,28 +33,30 @@
}); });
}); });
</script> </script>
<div style="display: flex; height: 100%; flex-direction: column; background-color: #2e2e2e;" class:hideall={$showLogin}> <div style="display: flex; height: 100%; flex-direction: column; background-color: #2e2e2e;" class:hideall={$showLogin}>
<div style="text-align: center; padding: 10px; background: black;"> <div style="text-align: center; padding: 10px; background: black;">
<button on:click={() => uiService.setScale(1)}>Fit</button> <button on:click={() => uiService.setScale(1)}>Fit</button>
<button on:click={() => uiService.setScale(2)}>Full</button> <button on:click={() => uiService.setScale(2)}>Full</button>
<button on:click={() => uiService.setScale(3)}>Real</button> <button on:click={() => uiService.setScale(3)}>Real</button>
<button on:click={() => uiService.ctrlAltDel()}>Ctrl+Alt+Del</button> <button on:click={() => uiService.ctrlAltDel()}>Ctrl+Alt+Del</button>
<button on:click={() => uiService.metaKey()}>Meta <button on:click={() => uiService.metaKey()}
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 512 512"><title> >Meta
ionicons-v5_logos</title> <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 512 512"
<path d="M480,265H232V444l248,36V265Z"/> ><title> ionicons-v5_logos</title>
<path d="M216,265H32V415l184,26.7V265Z"/> <path d="M480,265H232V444l248,36V265Z" />
<path d="M480,32,232,67.4V249H480V32Z"/> <path d="M216,265H32V415l184,26.7V265Z" />
<path d="M216,69.7,32,96V249H216V69.7Z"/> <path d="M480,32,232,67.4V249H480V32Z" />
<path d="M216,69.7,32,96V249H216V69.7Z" />
</svg> </svg>
</button> </button>
<button on:click={() => uiService.shutdown()}>Terminate Session</button> <button on:click={() => uiService.shutdown()}>Terminate Session</button>
</div> </div>
<iron-remote-gui debugwasm="INFO" verbose="true" scale="fit" flexcenter="true"/> <iron-remote-gui debugwasm="INFO" verbose="true" scale="fit" flexcenter="true" />
</div> </div>
<style> <style>
.hideall { .hideall {
display: none !important; display: none !important;
} }
</style> </style>

View file

@ -1,4 +1,4 @@
export class DesktopSize { export class DesktopSize {
width!: number; width!: number;
height!: number; height!: number;
} }

View file

@ -1,7 +1,7 @@
export class Rect { export class Rect {
top!: number; top!: number;
left!: number; left!: number;
width!: number; width!: number;
height!: number; height!: number;
buffer!: ArrayBuffer buffer!: ArrayBuffer;
} }

View file

@ -1,16 +1,16 @@
import {Guid} from "guid-typescript"; import { Guid } from 'guid-typescript';
import type { DesktopSize } from "./desktop-size"; import type { DesktopSize } from './desktop-size';
export class Session { export class Session {
id:Guid; id: Guid;
sessionId!: number; sessionId!: number;
name?:string; name?: string;
active!: boolean; active!: boolean;
desktopSize!: DesktopSize; desktopSize!: DesktopSize;
constructor(name?: string) { constructor(name?: string) {
this.id = Guid.create(); this.id = Guid.create();
this.name = name; this.name = name;
this.active = false; this.active = false;
} }
} }

View file

@ -1,4 +1,4 @@
<script> <script>
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
goto("/session"); goto('/session');
</script> </script>

View file

@ -2,14 +2,12 @@
import Login from '$lib/login/login.svelte'; import Login from '$lib/login/login.svelte';
import RemoteScreen from '$lib/remote-screen/remote-screen.svelte'; import RemoteScreen from '$lib/remote-screen/remote-screen.svelte';
import Message from '$lib/messages/message.svelte'; import Message from '$lib/messages/message.svelte';
import {showLogin} from "$lib/login/login-store"; import { showLogin } from '$lib/login/login-store';
</script> </script>
{#if $showLogin} {#if $showLogin}
<Login/> <Login />
{/if} {/if}
<RemoteScreen/> <RemoteScreen />
<Message></Message> <Message></Message>

View file

@ -1,39 +1,38 @@
import type {Observable} from "rxjs"; import type { Observable } from 'rxjs';
export interface ServerRect { export interface ServerRect {
free(): void; free(): void;
clone_buffer(): Uint8Array; clone_buffer(): Uint8Array;
bottom: number; bottom: number;
left: number; left: number;
right: number; right: number;
top: number; top: number;
} }
export interface NewSessionInfo { export interface NewSessionInfo {
session_id: number, session_id: number;
websocket_port: number, websocket_port: number;
initial_desktop_size: DesktopSize, initial_desktop_size: DesktopSize;
} }
export interface DesktopSize { export interface DesktopSize {
width: number, width: number;
height: number height: number;
} }
export interface ResizeEvent { export interface ResizeEvent {
session_id: number, session_id: number;
desktop_size: DesktopSize, desktop_size: DesktopSize;
} }
export abstract class ServerBridgeService { export abstract class ServerBridgeService {
abstract init(): void; abstract init(): void;
abstract connect(username: string, password: string, address: string): Observable<NewSessionInfo>; abstract connect(username: string, password: string, address: string): Observable<NewSessionInfo>;
abstract resize: Observable<ResizeEvent>; abstract resize: Observable<ResizeEvent>;
abstract updateMouse(mouse_x: number, mouse_y: number, click_state: number): void; abstract updateMouse(mouse_x: number, mouse_y: number, click_state: number): void;
} }

View file

@ -1,8 +1,8 @@
import type {Guid} from "guid-typescript"; import type { Guid } from 'guid-typescript';
import type {Writable} from "svelte/store"; import type { Writable } from 'svelte/store';
import {writable} from "svelte/store"; import { writable } from 'svelte/store';
import {Session} from "../models/session"; import { Session } from '../models/session';
import type {UserInteraction} from '../../static/iron-remote-gui'; import type { UserInteraction } from '../../static/iron-remote-gui';
export const userInteractionService: Writable<UserInteraction> = writable(); export const userInteractionService: Writable<UserInteraction> = writable();
export const currentSession: Writable<Session> = writable(); export const currentSession: Writable<Session> = writable();
@ -23,14 +23,14 @@ export function getCurrentSession(): Session {
} }
export function setCurrentSessionActive(active: boolean) { export function setCurrentSessionActive(active: boolean) {
currentSession.update(session => { currentSession.update((session) => {
session.active = active; session.active = active;
return session; return session;
}); });
} }
export function setCurrentSessionById(id: Guid) { export function setCurrentSessionById(id: Guid) {
const session = sessions.find(session => session.id.equals(id)); const session = sessions.find((session) => session.id.equals(id));
if (session) { if (session) {
setCurrentSession(session); setCurrentSession(session);
} }
@ -47,7 +47,7 @@ export function addSession(name: string) {
export function closeSession(id: Guid) { export function closeSession(id: Guid) {
sessionCounter--; sessionCounter--;
sessions = sessions.filter(session => !session.id.equals(id)); sessions = sessions.filter((session) => !session.id.equals(id));
if (sessionCounter == 1) { if (sessionCounter == 1) {
setCurrentSession(sessions[0]); setCurrentSession(sessions[0]);
} }

View file

@ -1,59 +1,59 @@
body.light { body.light {
--primary: #0061a6; --primary: #0061a6;
--on-primary: #ffffff; --on-primary: #ffffff;
--primary-container: #d0e4ff; --primary-container: #d0e4ff;
--on-primary-container: #001d36; --on-primary-container: #001d36;
--secondary: #535f70; --secondary: #535f70;
--on-secondary: #ffffff; --on-secondary: #ffffff;
--secondary-container: #d6e3f7; --secondary-container: #d6e3f7;
--on-secondary-container: #101c2b; --on-secondary-container: #101c2b;
--tertiary: #6b5778; --tertiary: #6b5778;
--on-tertiary: #ffffff; --on-tertiary: #ffffff;
--tertiary-container: #f3daff; --tertiary-container: #f3daff;
--on-tertiary-container: #251432; --on-tertiary-container: #251432;
--error: #ba1b1b; --error: #ba1b1b;
--error-container: #ffdad4; --error-container: #ffdad4;
--on-error: #ffffff; --on-error: #ffffff;
--on-error-container: #410001; --on-error-container: #410001;
--background: #fdfcff; --background: #fdfcff;
--on-background: #1b1b1b; --on-background: #1b1b1b;
--surface: #fdfcff; --surface: #fdfcff;
--on-surface: #1b1b1b; --on-surface: #1b1b1b;
--surface-variant: #dfe2eb; --surface-variant: #dfe2eb;
--on-surface-variant: #42474e; --on-surface-variant: #42474e;
--outline: #73777f; --outline: #73777f;
--inverse-on-surface: #f1f0f4; --inverse-on-surface: #f1f0f4;
--inverse-surface: #2f3033; --inverse-surface: #2f3033;
--inverse-primary: #9ccaff; --inverse-primary: #9ccaff;
--shadow: #000000; --shadow: #000000;
} }
body.dark { body.dark {
--primary: #9ccaff; --primary: #9ccaff;
--on-primary: #00325a; --on-primary: #00325a;
--primary-container: #00497f; --primary-container: #00497f;
--on-primary-container: #d0e4ff; --on-primary-container: #d0e4ff;
--secondary: #bbc8db; --secondary: #bbc8db;
--on-secondary: #253140; --on-secondary: #253140;
--secondary-container: #3c4858; --secondary-container: #3c4858;
--on-secondary-container: #d6e3f7; --on-secondary-container: #d6e3f7;
--tertiary: #d6bee4; --tertiary: #d6bee4;
--on-tertiary: #3b2948; --on-tertiary: #3b2948;
--tertiary-container: #523f5f; --tertiary-container: #523f5f;
--on-tertiary-container: #f3daff; --on-tertiary-container: #f3daff;
--error: #ffb4a9; --error: #ffb4a9;
--error-container: #930006; --error-container: #930006;
--on-error: #680003; --on-error: #680003;
--on-error-container: #ffdad4; --on-error-container: #ffdad4;
--background: #1b1b1b; --background: #1b1b1b;
--on-background: #e2e2e6; --on-background: #e2e2e6;
--surface: #1b1b1b; --surface: #1b1b1b;
--on-surface: #e2e2e6; --on-surface: #e2e2e6;
--surface-variant: #42474e; --surface-variant: #42474e;
--on-surface-variant: #c3c7d0; --on-surface-variant: #c3c7d0;
--outline: #8d9199; --outline: #8d9199;
--inverse-on-surface: #1b1b1b; --inverse-on-surface: #1b1b1b;
--inverse-surface: #e2e2e6; --inverse-surface: #e2e2e6;
--inverse-primary: #0061a6; --inverse-primary: #0061a6;
--shadow: #000000; --shadow: #000000;
} }

View file

@ -3,19 +3,19 @@ import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
// Consult https://github.com/sveltejs/svelte-preprocess // Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors // for more information about preprocessors
preprocess: preprocess(), preprocess: preprocess(),
kit: { kit: {
adapter: adapter({ adapter: adapter({
pages: 'build/browser', pages: 'build/browser',
assets: 'build/browser', assets: 'build/browser',
fallback: null, fallback: null,
precompress: false, precompress: false,
strict: true strict: true,
}) }),
} },
}; };
export default config; export default config;

View file

@ -1,19 +1,19 @@
{ {
"extends": "./.svelte-kit/tsconfig.json", "extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"allowJs": false, "allowJs": false,
"checkJs": false, "checkJs": false,
"esModuleInterop": true, "esModuleInterop": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"strictNullChecks": true, "strictNullChecks": true,
"noImplicitAny": true "noImplicitAny": true
}, }
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
// //
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in // from the referenced tsconfig.json - TypeScript does not merge them in
} }

View file

@ -4,8 +4,8 @@ import wasm from 'vite-plugin-wasm';
import topLevelAwait from 'vite-plugin-top-level-await'; import topLevelAwait from 'vite-plugin-top-level-await';
const config: UserConfig = { const config: UserConfig = {
mode: 'process.env.MODE' || 'development', mode: 'process.env.MODE' || 'development',
plugins: [sveltekit(), wasm(), topLevelAwait()], plugins: [sveltekit(), wasm(), topLevelAwait()],
}; };
export default config; export default config;