Skip to content

Commit

Permalink
Adapt @eclipse-che/theia-activity-tracker for che-code
Browse files Browse the repository at this point in the history
Signed-off-by: David Kwon <dakwon@redhat.com>
  • Loading branch information
dkwon17 committed Jul 7, 2022
1 parent ca6784b commit 88a4955
Show file tree
Hide file tree
Showing 11 changed files with 2,908 additions and 3 deletions.
3 changes: 2 additions & 1 deletion build/scripts/entrypoint-volume.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ fi
ls -la /checode/

# Start the machine-exec component in background
nohup /checode/bin/machine-exec --url '0.0.0.0:3333' &
export MACHINE_EXEC_PORT=3333
nohup /checode/bin/machine-exec --url "0.0.0.0:${MACHINE_EXEC_PORT}" &
sleep 5

# Start the checode component based on musl or libc
Expand Down
7 changes: 7 additions & 0 deletions code/extensions/che-activity-tracker/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
build/**
tests/**
coverage/**
out/**
tsconfig.json
extension.webpack.config.js
yarn.lock
18 changes: 18 additions & 0 deletions code/extensions/che-activity-tracker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Eclipse Che Activity Tracker for Visual Studio Code

**Notice:** This extension is bundled with Eclipse Che. It can be disabled but not uninstalled.

## What types of activity are tracked?

This extension tracks the following events provided by the VS Code extension API:

* `vscode.workspace.onDidChangeTextDocument`
* `vscode.window.onDidChangeActiveTextEditor`
* `vscode.window.onDidChangeTextEditorSelection`
* `vscode.window.onDidChangeTextEditorViewColumn`
* `vscode.window.onDidChangeWindowState`
* `vscode.window.onDidChangeTerminalState`
* `vscode.window.onDidChangeActiveTerminal`

## How does this extension use the tracked data?
This extension does not save, collect, or store data. This extension detects and sends activity events to [che-machine-exec](https://github.com/eclipse-che/che-machine-exec) in order to determine and terminate inactive workspaces.
36 changes: 36 additions & 0 deletions code/extensions/che-activity-tracker/extension.webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**********************************************************************
* Copyright (c) 2022 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

/* eslint-disable header/header */

//@ts-check

'use strict';

const withDefaults = require('../shared.webpack.config');
const webpack = require('webpack');

module.exports = withDefaults({
context: __dirname,
resolve: {
mainFields: ['module', 'main']
},
entry: {
extension: './src/extension.ts',
},
plugins: [
new webpack.ContextReplacementPlugin(/keyv/), // needs to exclude the package to ignore warnings https://github.com/jaredwray/keyv/issues/45
],
externals: {
'bufferutil': 'commonjs bufferutil', // ignored
'utf-8-validate': 'commonjs utf-8-validate', // ignored
},

});
53 changes: 53 additions & 0 deletions code/extensions/che-activity-tracker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "che-activity-tracker",
"displayName": "che-activity-tracker",
"description": "",
"publisher": "eclipse-che",
"license": "EPL-2.0",
"version": "0.0.1",
"engines": {
"vscode": "^1.63.0"
},
"categories": [
"Other"
],
"activationEvents": [
"*"
],
"capabilities": {
"virtualWorkspaces": true,
"untrustedWorkspaces": {
"supported": true
}
},
"main": "./out/extension.js",
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "yarn run compile && yarn run lint",
"lint": "eslint src --ext ts",
"test": "node ./out/test/runTest.js"
},
"devDependencies": {
"@types/fs-extra": "^9.0.13",
"@types/jest": "^27.4.1",
"@types/js-yaml": "^4.0.5",
"@types/node": "14.x",
"add": "^2.0.6",
"jest": "27.3.1",
"ts-jest": "^27.1.4",
"yarn": "^1.22.18"
},
"dependencies": {
"axios": "0.21.2",
"inversify": "^6.0.1"
},
"repository": {
"type": "git",
"url": "https://github.com/che-incubator/che-code.git"
},
"extensionDependencies": [
"eclipse-che.api"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**********************************************************************
* Copyright (c) 2022 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

/**
* Receives activity updates and sends reset inactivity requests to the che-machine-exec /activity/tick endpoint.
* To avoid duplicate requests may send requests periodically. This means
* that, in the worst case, it might keep user's workspace alive for a longer period of time.
*/
export class ActivityTrackerService {
// Time before sending next request. If multiple requests are received during this period,
// only one request will be sent. A second request will be sent after this period ends.
private static REQUEST_PERIOD_MS = 1 * 60 * 1000;
// Time before resending request to che-machine-exec if a network error occurs.
private static RETRY_REQUEST_PERIOD_MS = 5 * 1000;
// Number of retries before give up if a network error occurs.
private static RETRY_COUNT = 5;

// Indicates state of the timer. If true timer is running.
private isTimerRunning: boolean;
// Flag which is used to check if new requests were received during timer awaiting.
private isNewRequest: boolean;

private workspaceService: any;

constructor(workspaceService: any) {
this.isTimerRunning = false;
this.isNewRequest = false;
this.workspaceService = workspaceService;
}

/**
* Invoked each time when a client sends an activity request.
*/
async resetTimeout(): Promise<void> {
if (this.isTimerRunning) {
this.isNewRequest = true;
return;
}
await this.sendRequestAndSetTimer();
}

private async sendRequestAndSetTimer(): Promise<void> {
this.sendRequest(ActivityTrackerService.RETRY_COUNT);
this.isNewRequest = false;

setTimeout(
() => this.checkNewRequestsTimerCallback(),
ActivityTrackerService.REQUEST_PERIOD_MS
);
this.isTimerRunning = true;
}

private checkNewRequestsTimerCallback(): void {
this.isTimerRunning = false;

if (this.isNewRequest) {
this.sendRequestAndSetTimer();
}
}

private sendRequest(
attemptsLeft: number = ActivityTrackerService.RETRY_COUNT,
): void {
try {
this.workspaceService.updateWorkspaceActivity();
} catch (error) {
if (attemptsLeft > 0) {
setTimeout(this.sendRequest, ActivityTrackerService.RETRY_REQUEST_PERIOD_MS, --attemptsLeft);
} else {
console.error('Activity tracker: Failed to ping che-machine-exec: ', error.message);
}
}
}
}
57 changes: 57 additions & 0 deletions code/extensions/che-activity-tracker/src/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**********************************************************************
* Copyright (c) 2022 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as vscode from "vscode";
import { ActivityTrackerService } from "./activity-tracker-service";

export async function activate(context: vscode.ExtensionContext) {

const eventsToTrack = [
vscode.workspace.onDidChangeTextDocument,
vscode.window.onDidChangeActiveTextEditor,
vscode.window.onDidChangeTextEditorSelection,
vscode.window.onDidChangeTextEditorViewColumn,
vscode.window.onDidChangeWindowState,
vscode.window.onDidChangeTerminalState,
vscode.window.onDidChangeActiveTerminal,
];

await track(eventsToTrack, context);
}

async function track(events: vscode.Event<any>[], context: vscode.ExtensionContext) {
const workspaceService = await getWorkspaceService();
const activityTracker = new ActivityTrackerService(workspaceService);
events.forEach((e: vscode.Event<any>) => {
context.subscriptions.push(
e(async () => {
await activityTracker.resetTimeout();
})
);
});
}

async function getWorkspaceService(): Promise<any> {
const CHE_API = 'eclipse-che.api';
const extensionApi = vscode.extensions.getExtension(CHE_API);
if (!extensionApi) {
throw Error(`Failed to get workspace service. Extension ${CHE_API} is not installed.`);
}

try {
await extensionApi.activate();
const cheApi: any = extensionApi?.exports;
return cheApi.getWorkspaceService();
} catch {
throw Error(`Failed to get workspace service. Could not activate and retrieve exports from extension ${CHE_API}.`);
}
}

export function deactivate() {}
15 changes: 15 additions & 0 deletions code/extensions/che-activity-tracker/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"outDir": "./out",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"types": [
"node",
]
},
"include": [
"src/**/*",
"../../src/vscode-dts/vscode.d.ts",
]
}
Loading

0 comments on commit 88a4955

Please sign in to comment.