Skip to content

Commit f965d42

Browse files
authored
Merge pull request #181 from NewtonDer/fix_idle_shutdown_1-7
Fix: Move checkTerminalActivity to server side
2 parents 1ca5359 + d765707 commit f965d42

File tree

7 files changed

+105
-133
lines changed

7 files changed

+105
-133
lines changed

patched-vscode/extensions/sagemaker-idle-extension/src/extension.ts

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,14 @@ import * as vscode from "vscode";
22
import * as fs from "fs";
33
import * as path from "path";
44

5-
let idleFilePath: string
6-
let terminalActivityInterval: NodeJS.Timeout | undefined
7-
const LOG_PREFIX = "[sagemaker-idle-extension]"
8-
const CHECK_INTERVAL = 60000; // 60 seconds interval
5+
let idleFilePath: string;
96

107
export function activate(context: vscode.ExtensionContext) {
118
initializeIdleFilePath();
129
registerEventListeners(context);
13-
startMonitoringTerminalActivity();
1410
}
1511

16-
export function deactivate() {
17-
if(terminalActivityInterval) {
18-
clearInterval(terminalActivityInterval)
19-
}
20-
}
12+
export function deactivate() {}
2113

2214
/**
2315
* Initializes the file path where the idle timestamp will be stored.
@@ -28,7 +20,7 @@ function initializeIdleFilePath() {
2820
idleFilePath = path.join(tmpDirectory, ".sagemaker-last-active-timestamp");
2921

3022
// Set initial lastActivetimestamp
31-
updateLastActivityTimestamp()
23+
updateLastActivityTimestamp();
3224
}
3325

3426
/**
@@ -56,52 +48,6 @@ function registerEventListeners(context: vscode.ExtensionContext) {
5648
);
5749
}
5850

59-
/**
60-
* Starts monitoring terminal activity by setting an interval to check for activity in the /dev/pts directory.
61-
*/
62-
const startMonitoringTerminalActivity = () => {
63-
terminalActivityInterval = setInterval(checkTerminalActivity, CHECK_INTERVAL);
64-
};
65-
66-
67-
/**
68-
* Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files.
69-
*
70-
* The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices.
71-
* Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory.
72-
* When a terminal session has activity, such as when a user inputs commands or output is written to the terminal,
73-
* the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification
74-
* times of the files in the /dev/pts directory, we can detect terminal activity.
75-
*
76-
* If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function
77-
* updates the last activity timestamp.
78-
*/
79-
const checkTerminalActivity = () => {
80-
fs.readdir("/dev/pts", (err, files) => {
81-
if (err) {
82-
console.error(`${LOG_PREFIX} Error reading /dev/pts directory:`, err);
83-
return;
84-
}
85-
86-
const now = Date.now();
87-
const activityDetected = files.some((file) => {
88-
const filePath = path.join("/dev/pts", file);
89-
try {
90-
const stats = fs.statSync(filePath);
91-
const mtime = new Date(stats.mtime).getTime();
92-
return now - mtime < CHECK_INTERVAL;
93-
} catch (error) {
94-
console.error(`${LOG_PREFIX} Error reading file stats:`, error);
95-
return false;
96-
}
97-
});
98-
99-
if (activityDetected) {
100-
updateLastActivityTimestamp();
101-
}
102-
});
103-
};
104-
10551
/**
10652
* Updates the last activity timestamp by recording the current timestamp in the idle file and
10753
* refreshing the status bar. The timestamp should be in ISO 8601 format and set to the UTC timezone.

patched-vscode/src/vs/server/node/webClientServer.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,41 @@ export async function serveFile(filePath: string, cacheControl: CacheControl, lo
9999
}
100100
}
101101

102+
const CHECK_INTERVAL = 60000; // 60 seconds interval
102103
const APP_ROOT = dirname(FileAccess.asFileUri('').fsPath);
103104

105+
/**
106+
* Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files.
107+
*
108+
* The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices.
109+
* Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory.
110+
* When a terminal session has activity, such as when a user inputs commands or output is written to the terminal,
111+
* the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification
112+
* times of the files in the /dev/pts directory, we can detect terminal activity.
113+
*
114+
* If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function
115+
* updates the last activity timestamp.
116+
*/
117+
function checkTerminalActivity(idleFilePath: string) {
118+
try {
119+
const files: string[] = fs.readdirSync('/dev/pts');
120+
const now = new Date();
121+
122+
const activityDetected = files.some((file: string) => {
123+
const filePath = path.join('/dev/pts', file);
124+
const stats = fs.statSync(filePath);
125+
const mtime = new Date(stats.mtime).getTime();
126+
return now.getTime() - mtime < CHECK_INTERVAL;
127+
});
128+
129+
if (activityDetected) {
130+
fs.writeFileSync(idleFilePath, now.toISOString());
131+
}
132+
} catch (err) {
133+
console.error('Error checking terminal activity:', err);
134+
}
135+
}
136+
104137
export class WebClientServer {
105138

106139
private readonly _webExtensionResourceUrlTemplate: URI | undefined;
@@ -481,6 +514,8 @@ export class WebClientServer {
481514
writeFileSync(idleFilePath, timestamp);
482515
}
483516

517+
checkTerminalActivity(idleFilePath);
518+
484519
const data = await readFile(idleFilePath, 'utf8');
485520

486521
res.statusCode = 200;

patches/custom-extensions-marketplace.diff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ Index: sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
9898
===================================================================
9999
--- sagemaker-code-editor.orig/vscode/src/vs/server/node/webClientServer.ts
100100
+++ sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
101-
@@ -331,14 +331,7 @@ export class WebClientServer {
101+
@@ -364,14 +364,7 @@ export class WebClientServer {
102102
const productConfiguration = {
103103
rootEndpoint: base,
104104
embedderIdentifier: 'server-distro',

patches/display-language.patch

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ Index: sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
304304
import { CharCode } from 'vs/base/common/charCode';
305305
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
306306

307-
@@ -362,6 +363,8 @@ export class WebClientServer {
307+
@@ -395,6 +396,8 @@ export class WebClientServer {
308308
callbackRoute: this._callbackRoute
309309
};
310310

@@ -313,15 +313,15 @@ Index: sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
313313
const nlsBaseUrl = this._productService.extensionsGallery?.nlsBaseUrl;
314314
const values: { [key: string]: string } = {
315315
WORKBENCH_WEB_CONFIGURATION: asJSON(workbenchWebConfiguration),
316-
@@ -370,6 +373,7 @@ export class WebClientServer {
316+
@@ -403,6 +406,7 @@ export class WebClientServer {
317317
WORKBENCH_NLS_BASE_URL: vscodeBase + (nlsBaseUrl ? `${nlsBaseUrl}${!nlsBaseUrl.endsWith('/') ? '/' : ''}${this._productService.commit}/${this._productService.version}/` : ''),
318318
BASE: base,
319319
VS_BASE: vscodeBase,
320320
+ NLS_CONFIGURATION: asJSON(nlsConfiguration),
321321
};
322322

323323
if (useTestResolver) {
324-
@@ -401,7 +405,7 @@ export class WebClientServer {
324+
@@ -434,7 +438,7 @@ export class WebClientServer {
325325
`frame-src 'self' https://*.vscode-cdn.net data:;`,
326326
'worker-src \'self\' data: blob:;',
327327
'style-src \'self\' \'unsafe-inline\';',

patches/sagemaker-extensions-sync.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Index: sagemaker-code-editor/vscode/build/gulpfile.extensions.js
99
+ 'extensions/sagemaker-extensions-sync/tsconfig.json',
1010
'extensions/sagemaker-terminal-crash-mitigation/tsconfig.json',
1111
'extensions/sagemaker-open-notebook-extension/tsconfig.json',
12-
'extensions/tunnel-forwarding/tsconfig.json',
12+
'extensions/sagemaker-ui-dark-theme/tsconfig.json',
1313
Index: sagemaker-code-editor/vscode/build/npm/dirs.js
1414
===================================================================
1515
--- sagemaker-code-editor.orig/vscode/build/npm/dirs.js

patches/sagemaker-idle-extension.patch

Lines changed: 55 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -147,27 +147,19 @@ Index: sagemaker-code-editor/vscode/extensions/sagemaker-idle-extension/src/exte
147147
===================================================================
148148
--- /dev/null
149149
+++ sagemaker-code-editor/vscode/extensions/sagemaker-idle-extension/src/extension.ts
150-
@@ -0,0 +1,112 @@
150+
@@ -0,0 +1,58 @@
151151
+import * as vscode from "vscode";
152152
+import * as fs from "fs";
153153
+import * as path from "path";
154154
+
155-
+let idleFilePath: string
156-
+let terminalActivityInterval: NodeJS.Timeout | undefined
157-
+const LOG_PREFIX = "[sagemaker-idle-extension]"
158-
+const CHECK_INTERVAL = 60000; // 60 seconds interval
155+
+let idleFilePath: string;
159156
+
160157
+export function activate(context: vscode.ExtensionContext) {
161158
+ initializeIdleFilePath();
162159
+ registerEventListeners(context);
163-
+ startMonitoringTerminalActivity();
164160
+}
165161
+
166-
+export function deactivate() {
167-
+ if(terminalActivityInterval) {
168-
+ clearInterval(terminalActivityInterval)
169-
+ }
170-
+}
162+
+export function deactivate() {}
171163
+
172164
+/**
173165
+ * Initializes the file path where the idle timestamp will be stored.
@@ -178,7 +170,7 @@ Index: sagemaker-code-editor/vscode/extensions/sagemaker-idle-extension/src/exte
178170
+ idleFilePath = path.join(tmpDirectory, ".sagemaker-last-active-timestamp");
179171
+
180172
+ // Set initial lastActivetimestamp
181-
+ updateLastActivityTimestamp()
173+
+ updateLastActivityTimestamp();
182174
+}
183175
+
184176
+/**
@@ -207,52 +199,6 @@ Index: sagemaker-code-editor/vscode/extensions/sagemaker-idle-extension/src/exte
207199
+}
208200
+
209201
+/**
210-
+ * Starts monitoring terminal activity by setting an interval to check for activity in the /dev/pts directory.
211-
+ */
212-
+const startMonitoringTerminalActivity = () => {
213-
+ terminalActivityInterval = setInterval(checkTerminalActivity, CHECK_INTERVAL);
214-
+};
215-
+
216-
+
217-
+/**
218-
+ * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files.
219-
+ *
220-
+ * The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices.
221-
+ * Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory.
222-
+ * When a terminal session has activity, such as when a user inputs commands or output is written to the terminal,
223-
+ * the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification
224-
+ * times of the files in the /dev/pts directory, we can detect terminal activity.
225-
+ *
226-
+ * If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function
227-
+ * updates the last activity timestamp.
228-
+ */
229-
+const checkTerminalActivity = () => {
230-
+ fs.readdir("/dev/pts", (err, files) => {
231-
+ if (err) {
232-
+ console.error(`${LOG_PREFIX} Error reading /dev/pts directory:`, err);
233-
+ return;
234-
+ }
235-
+
236-
+ const now = Date.now();
237-
+ const activityDetected = files.some((file) => {
238-
+ const filePath = path.join("/dev/pts", file);
239-
+ try {
240-
+ const stats = fs.statSync(filePath);
241-
+ const mtime = new Date(stats.mtime).getTime();
242-
+ return now - mtime < CHECK_INTERVAL;
243-
+ } catch (error) {
244-
+ console.error(`${LOG_PREFIX} Error reading file stats:`, error);
245-
+ return false;
246-
+ }
247-
+ });
248-
+
249-
+ if (activityDetected) {
250-
+ updateLastActivityTimestamp();
251-
+ }
252-
+ });
253-
+};
254-
+
255-
+/**
256202
+ * Updates the last activity timestamp by recording the current timestamp in the idle file and
257203
+ * refreshing the status bar. The timestamp should be in ISO 8601 format and set to the UTC timezone.
258204
+ */
@@ -289,33 +235,77 @@ Index: sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
289235
===================================================================
290236
--- sagemaker-code-editor.orig/vscode/src/vs/server/node/webClientServer.ts
291237
+++ sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
292-
@@ -3,7 +3,8 @@
238+
@@ -3,8 +3,10 @@
293239
* Licensed under the MIT License. See License.txt in the project root for license information.
294240
*--------------------------------------------------------------------------------------------*/
295241

296242
-import { createReadStream } from 'fs';
297243
+import { createReadStream, existsSync, writeFileSync } from 'fs';
298244
+import {readFile } from 'fs/promises';
299245
import { Promises } from 'vs/base/node/pfs';
246+
+import * as fs from 'fs';
300247
import * as path from 'path';
301248
import * as http from 'http';
302-
@@ -100,6 +101,7 @@ export class WebClientServer {
249+
import * as url from 'url';
250+
@@ -91,8 +93,41 @@ export async function serveFile(filePath
251+
}
252+
}
253+
254+
+const CHECK_INTERVAL = 60000; // 60 seconds interval
255+
const APP_ROOT = dirname(FileAccess.asFileUri('').fsPath);
256+
257+
+/**
258+
+ * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files.
259+
+ *
260+
+ * The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices.
261+
+ * Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory.
262+
+ * When a terminal session has activity, such as when a user inputs commands or output is written to the terminal,
263+
+ * the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification
264+
+ * times of the files in the /dev/pts directory, we can detect terminal activity.
265+
+ *
266+
+ * If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function
267+
+ * updates the last activity timestamp.
268+
+ */
269+
+function checkTerminalActivity(idleFilePath: string) {
270+
+ try {
271+
+ const files: string[] = fs.readdirSync('/dev/pts');
272+
+ const now = new Date();
273+
+
274+
+ const activityDetected = files.some((file: string) => {
275+
+ const filePath = path.join('/dev/pts', file);
276+
+ const stats = fs.statSync(filePath);
277+
+ const mtime = new Date(stats.mtime).getTime();
278+
+ return now.getTime() - mtime < CHECK_INTERVAL;
279+
+ });
280+
+
281+
+ if (activityDetected) {
282+
+ fs.writeFileSync(idleFilePath, now.toISOString());
283+
+ }
284+
+ } catch (err) {
285+
+ console.error('Error checking terminal activity:', err);
286+
+ }
287+
+}
288+
+
289+
export class WebClientServer {
290+
291+
private readonly _webExtensionResourceUrlTemplate: URI | undefined;
292+
@@ -100,6 +135,7 @@ export class WebClientServer {
303293
private readonly _staticRoute: string;
304294
private readonly _callbackRoute: string;
305295
private readonly _webExtensionRoute: string;
306296
+ private readonly _idleRoute: string;
307297

308298
constructor(
309299
private readonly _connectionToken: ServerConnectionToken,
310-
@@ -115,6 +117,7 @@ export class WebClientServer {
300+
@@ -115,6 +151,7 @@ export class WebClientServer {
311301
this._staticRoute = `${serverRootPath}/static`;
312302
this._callbackRoute = `${serverRootPath}/callback`;
313303
this._webExtensionRoute = `${serverRootPath}/web-extension-resource`;
314304
+ this._idleRoute = '/api/idle';
315305
}
316306

317307
/**
318-
@@ -132,6 +135,9 @@ export class WebClientServer {
308+
@@ -132,6 +169,9 @@ export class WebClientServer {
319309
if (pathname === this._basePath) {
320310
return this._handleRoot(req, res, parsedUrl);
321311
}
@@ -325,7 +315,7 @@ Index: sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
325315
if (pathname === this._callbackRoute) {
326316
// callback support
327317
return this._handleCallback(res);
328-
@@ -451,6 +457,31 @@ export class WebClientServer {
318+
@@ -451,6 +491,33 @@ export class WebClientServer {
329319
});
330320
return void res.end(data);
331321
}
@@ -345,6 +335,8 @@ Index: sagemaker-code-editor/vscode/src/vs/server/node/webClientServer.ts
345335
+ writeFileSync(idleFilePath, timestamp);
346336
+ }
347337
+
338+
+ checkTerminalActivity(idleFilePath);
339+
+
348340
+ const data = await readFile(idleFilePath, 'utf8');
349341
+
350342
+ res.statusCode = 200;

0 commit comments

Comments
 (0)