Skip to content

Commit e749900

Browse files
Create new RDP service (#3029)
* feat: 🎸 added a new RDP service * fix: πŸ› rdp test * refactor: πŸ’‘ update error handling for fetching rdp clients * refactor: πŸ’‘ addressed comments * fix: πŸ› revert private field * refactor: πŸ’‘ addressed comments * refactor: πŸ’‘ updated rdp clients to array of strings
1 parent 35ccaeb commit e749900

File tree

3 files changed

+194
-0
lines changed

3 files changed

+194
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: BUSL-1.1
4+
*/
5+
6+
import Service from '@ember/service';
7+
import { service } from '@ember/service';
8+
import { tracked } from '@glimmer/tracking';
9+
10+
const { __electronLog } = globalThis;
11+
12+
export default class RdpService extends Service {
13+
// =services
14+
15+
@service ipc;
16+
17+
// =properties
18+
19+
/**
20+
* The preferred RDP client set by the user.
21+
* @type {string|null}
22+
* @private
23+
*/
24+
@tracked preferredRdpClient = null;
25+
26+
/**
27+
* The list of available RDP clients fetched from the main process.
28+
* @type {Array<String>}
29+
* @private
30+
*/
31+
@tracked rdpClients = [];
32+
33+
// =attributes
34+
35+
/**
36+
* Helper to determine if a preferred RDP client is set and the value is not "none". This is used to
37+
* conditionally show the "Open" button for RDP targets only when a preferred
38+
* RDP client is configured.
39+
* @returns {boolean}
40+
*/
41+
get isPreferredRdpClientSet() {
42+
return (
43+
this.preferredRdpClient !== null && this.preferredRdpClient !== 'none'
44+
);
45+
}
46+
47+
// =methods
48+
49+
/**
50+
* Fetches the list of available RDP clients from the main process.
51+
*/
52+
async getRdpClients() {
53+
// Return cached clients if already fetched
54+
if (this.rdpClients.length > 0) {
55+
return this.rdpClients;
56+
}
57+
try {
58+
this.rdpClients = await this.ipc.invoke('getRdpClients');
59+
return this.rdpClients;
60+
} catch (error) {
61+
__electronLog?.error('Failed to fetch RDP clients', error.message);
62+
// default to 'none' option if it fails
63+
this.rdpClients = ['none'];
64+
return this.rdpClients;
65+
}
66+
}
67+
68+
/**
69+
* Fetches the preferred RDP client from the main process.
70+
* @returns {string} The preferred RDP client
71+
*/
72+
async getPreferredRdpClient() {
73+
// Return cached preferred RDP client if already fetched
74+
if (this.preferredRdpClient !== null) {
75+
return this.preferredRdpClient;
76+
}
77+
try {
78+
this.preferredRdpClient = await this.ipc.invoke('getPreferredRdpClient');
79+
return this.preferredRdpClient;
80+
} catch (error) {
81+
__electronLog?.error(
82+
'Failed to fetch preferred RDP client',
83+
error.message,
84+
);
85+
// default to 'none' if it fails
86+
this.preferredRdpClient = 'none';
87+
return this.preferredRdpClient;
88+
}
89+
}
90+
91+
/**
92+
* Sets the preferred RDP client by the user.
93+
* @param {string} rdpClient - The value of the preferred RDP client
94+
* @returns {Promise<string>} The updated preferred RDP client
95+
*/
96+
async setPreferredRdpClient(rdpClient) {
97+
try {
98+
await this.ipc.invoke('setPreferredRdpClient', rdpClient);
99+
this.preferredRdpClient = rdpClient;
100+
return this.preferredRdpClient;
101+
} catch (error) {
102+
__electronLog?.error('Failed to set preferred RDP client', error.message);
103+
// set to 'none' if it fails
104+
this.preferredRdpClient = 'none';
105+
}
106+
}
107+
108+
/**
109+
* Launches the RDP client for a given session.
110+
* The `sessionId` is passed to the main process, which securely retrieves
111+
* the proxy details and constructs the appropriate RDP connection parameters.
112+
* @param {string} sessionId - The ID of the active session
113+
*/
114+
async launchRdpClient(sessionId) {
115+
await this.ipc.invoke('launchRdpClient', sessionId);
116+
}
117+
}

β€Žui/desktop/electron-app/src/ipc/handlers.jsβ€Ž

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,28 @@ handle('getLogPath', () => {
269269
}
270270
});
271271

272+
/**
273+
* Returns the available RDP clients
274+
*/
275+
handle('getRdpClients', async () => []);
276+
277+
/**
278+
* Returns the preferred RDP client
279+
*/
280+
handle('getPreferredRdpClient', async () => 'none');
281+
282+
/**
283+
* Sets the preferred RDP client
284+
*/
285+
handle('setPreferredRdpClient', async (rdpClient) => rdpClient);
286+
287+
/**
288+
* Launches the RDP client with the provided session ID.
289+
*/
290+
handle('launchRdpClient', async (sessionId) => {
291+
return;
292+
});
293+
272294
/**
273295
* Handler to help create terminal windows. We don't use the helper `handle` method
274296
* as we need access to the event and don't need to be using `ipcMain.handle`.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Copyright (c) HashiCorp, Inc.
3+
* SPDX-License-Identifier: BUSL-1.1
4+
*/
5+
6+
import { module, test } from 'qunit';
7+
import { setupTest } from 'desktop/tests/helpers';
8+
import sinon from 'sinon';
9+
10+
module('Unit | Service | rdp', function (hooks) {
11+
setupTest(hooks);
12+
13+
let service, ipcService;
14+
15+
hooks.beforeEach(function () {
16+
service = this.owner.lookup('service:rdp');
17+
ipcService = this.owner.lookup('service:ipc');
18+
});
19+
20+
test('getRdpClients sets to fallback value on error', async function (assert) {
21+
sinon.stub(ipcService, 'invoke').withArgs('getRdpClients').rejects();
22+
await service.getRdpClients();
23+
assert.deepEqual(
24+
service.rdpClients,
25+
['none'],
26+
'rdpClients fallback is set correctly',
27+
);
28+
});
29+
30+
test('getPreferredRdpClient sets to fallback value on error', async function (assert) {
31+
sinon
32+
.stub(ipcService, 'invoke')
33+
.withArgs('getPreferredRdpClient')
34+
.rejects();
35+
await service.getPreferredRdpClient();
36+
assert.strictEqual(
37+
service.preferredRdpClient,
38+
'none',
39+
'preferredRdpClient fallback is set correctly',
40+
);
41+
});
42+
43+
test('setPreferredRdpClient sets to fallback value on error', async function (assert) {
44+
sinon
45+
.stub(ipcService, 'invoke')
46+
.withArgs('setPreferredRdpClient', 'mstsc')
47+
.rejects();
48+
await service.setPreferredRdpClient('mstsc');
49+
assert.strictEqual(
50+
service.preferredRdpClient,
51+
'none',
52+
'preferredRdpClient fallback is set correctly',
53+
);
54+
});
55+
});

0 commit comments

Comments
Β (0)