Merge pull request #2 from orus-dev/simple-working-mvp
Simple working mvp
This commit is contained in:
Generated
+146
@@ -9,8 +9,11 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/diff-match-patch": "^1.0.36",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
|
"axios": "^1.13.5",
|
||||||
"cors": "^2.8.6",
|
"cors": "^2.8.6",
|
||||||
|
"diff-match-patch": "^1.0.5",
|
||||||
"express": "^5.2.1"
|
"express": "^5.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -301,6 +304,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/diff-match-patch": {
|
||||||
|
"version": "1.0.36",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
|
||||||
|
"integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/express": {
|
"node_modules/@types/express": {
|
||||||
"version": "5.0.6",
|
"version": "5.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz",
|
||||||
@@ -769,6 +778,23 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.13.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
|
||||||
|
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.11",
|
||||||
|
"form-data": "^4.0.5",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -1063,6 +1089,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@@ -1186,6 +1224,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
@@ -1205,6 +1252,12 @@
|
|||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/diff-match-patch": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/dir-glob": {
|
"node_modules/dir-glob": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
@@ -1304,6 +1357,21 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||||
@@ -1717,6 +1785,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||||
|
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/foreground-child": {
|
"node_modules/foreground-child": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||||
@@ -1734,6 +1822,43 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data/node_modules/mime-db": {
|
||||||
|
"version": "1.52.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/form-data/node_modules/mime-types": {
|
||||||
|
"version": "2.1.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.52.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
@@ -1972,6 +2097,21 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
@@ -3090,6 +3230,12 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
|||||||
+34
-1
@@ -31,7 +31,37 @@
|
|||||||
"command": "devrun-vscode.stopServer",
|
"command": "devrun-vscode.stopServer",
|
||||||
"title": "DevRun: Stop the run server (for quick run starts)"
|
"title": "DevRun: Stop the run server (for quick run starts)"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"menus": {
|
||||||
|
"commandPalette": [
|
||||||
|
{
|
||||||
|
"command": "devrun-vscode.startRun",
|
||||||
|
"when": "!devrun.runActive"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "devrun-vscode.stopRun",
|
||||||
|
"when": "devrun.runActive"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "devrun-vscode.startServer",
|
||||||
|
"when": "!devrun.serverActive"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "devrun-vscode.stopServer",
|
||||||
|
"when": "devrun.serverActive"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"title": "DevRun",
|
||||||
|
"properties": {
|
||||||
|
"devrun.autoStartServer": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Automatically start the server when vscode starts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"vscode:prepublish": "npm run compile",
|
"vscode:prepublish": "npm run compile",
|
||||||
@@ -54,8 +84,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cors": "^2.8.19",
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/diff-match-patch": "^1.0.36",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
|
"axios": "^1.13.5",
|
||||||
"cors": "^2.8.6",
|
"cors": "^2.8.6",
|
||||||
|
"diff-match-patch": "^1.0.5",
|
||||||
"express": "^5.2.1"
|
"express": "^5.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-10
@@ -1,13 +1,57 @@
|
|||||||
export interface LiveRunMove {
|
import axios from "axios";
|
||||||
latency: number;
|
import { LiveRunMove } from "./types";
|
||||||
cursor: number;
|
|
||||||
changes?: {
|
var cookies: string | undefined;
|
||||||
from: number;
|
|
||||||
to: number;
|
export function getCookies(): string | undefined {
|
||||||
insert: string;
|
return cookies;
|
||||||
};
|
}
|
||||||
|
export function setCookies(c: string) {
|
||||||
|
cookies = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitRun() {}
|
export async function addRun(problem: string, mode: string): Promise<string> {
|
||||||
|
return (
|
||||||
|
await axios.put(
|
||||||
|
"http://localhost:3000/api/run",
|
||||||
|
{
|
||||||
|
problem,
|
||||||
|
category: mode,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: cookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
).data.runId;
|
||||||
|
}
|
||||||
|
|
||||||
export async function addRunMoves() {}
|
export async function submitRun(runId: string) {
|
||||||
|
await axios.post(
|
||||||
|
"http://localhost:3000/api/run",
|
||||||
|
{
|
||||||
|
runId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: cookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addRunMoves(runId: string, moves: LiveRunMove[]) {
|
||||||
|
await axios.post(
|
||||||
|
"http://localhost:3000/api/run/move",
|
||||||
|
{
|
||||||
|
runId,
|
||||||
|
moves,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: cookies,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
+97
-2
@@ -1,10 +1,12 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { currentRun, startRun, stopRun } from "./run";
|
import { currentRun, startRun, stopRun } from "./run";
|
||||||
import { startServer, stopServer } from "./server";
|
import { startServer, stopServer } from "./server";
|
||||||
|
import os from "os";
|
||||||
|
import { exec } from "child_process";
|
||||||
|
import net from "net";
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
console.log("dev-run Activated");
|
const config = vscode.workspace.getConfiguration("devrun");
|
||||||
|
|
||||||
const statusBarItem = vscode.window.createStatusBarItem(
|
const statusBarItem = vscode.window.createStatusBarItem(
|
||||||
vscode.StatusBarAlignment.Left,
|
vscode.StatusBarAlignment.Left,
|
||||||
10,
|
10,
|
||||||
@@ -49,8 +51,101 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
stopServer(statusBarItem),
|
stopServer(statusBarItem),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
console.log("dev-run Activated");
|
||||||
|
|
||||||
|
// Security check - Make sure there aren't any malicious servers currently running
|
||||||
|
const autoStart = config.get<boolean>("autoStartServer");
|
||||||
|
|
||||||
|
canConnect(63780)
|
||||||
|
.then((canConnect) => {
|
||||||
|
if (canConnect) {
|
||||||
|
console.error(
|
||||||
|
"Unable to start due to another process listening on port 63780",
|
||||||
|
);
|
||||||
|
|
||||||
|
console.error("Possible malicious dev-run instance running");
|
||||||
|
|
||||||
|
vscode.window
|
||||||
|
.showErrorMessage(
|
||||||
|
"Possible malicious dev-run instance running",
|
||||||
|
"Kill the process listening on port 63780",
|
||||||
|
)
|
||||||
|
.then(async (response) => {
|
||||||
|
if (!response) return;
|
||||||
|
|
||||||
|
if (response === "Kill the process listening on port 63780") {
|
||||||
|
await killProcessOnPort(63780);
|
||||||
|
|
||||||
|
if (autoStart) {
|
||||||
|
startServer(statusBarItem);
|
||||||
|
console.log("dev-run server auto started!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoStart) {
|
||||||
|
startServer(statusBarItem);
|
||||||
|
console.log("dev-run server auto started!");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {
|
export function deactivate() {
|
||||||
stopRun();
|
stopRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function canConnect(
|
||||||
|
port: number,
|
||||||
|
host = "127.0.0.1",
|
||||||
|
timeout = 1000,
|
||||||
|
): Promise<boolean> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const socket = new net.Socket();
|
||||||
|
|
||||||
|
socket.setTimeout(timeout);
|
||||||
|
|
||||||
|
socket.once("connect", () => {
|
||||||
|
socket.destroy();
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.once("timeout", () => {
|
||||||
|
socket.destroy();
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.once("error", () => {
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.connect(port, host);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function killProcessOnPort(port: number): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const platform = os.platform();
|
||||||
|
|
||||||
|
let cmd: string;
|
||||||
|
|
||||||
|
if (platform === "win32") {
|
||||||
|
// Windows
|
||||||
|
cmd = `for /f "tokens=5" %a in ('netstat -ano ^| findstr :${port}') do taskkill /PID %a /F`;
|
||||||
|
} else {
|
||||||
|
// macOS / Linux
|
||||||
|
cmd = `lsof -ti tcp:${port} | xargs kill -9`;
|
||||||
|
}
|
||||||
|
|
||||||
|
exec(cmd, (error) => {
|
||||||
|
if (error) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
import * as vscode from "vscode";
|
||||||
|
import { diff_match_patch, Diff } from "diff-match-patch";
|
||||||
|
import { LiveRunMove } from "./types";
|
||||||
|
import { addRunMoves } from "./client";
|
||||||
|
|
||||||
|
export function startMonitoring(runId: string) {
|
||||||
|
const dmp = new diff_match_patch();
|
||||||
|
|
||||||
|
let moveId = 0;
|
||||||
|
let moves: LiveRunMove[] = [];
|
||||||
|
|
||||||
|
let lastText = "";
|
||||||
|
let lastEventTime = Date.now();
|
||||||
|
let idleTimeout: NodeJS.Timeout | undefined;
|
||||||
|
let isSending = false;
|
||||||
|
|
||||||
|
const IDLE_MS = 350;
|
||||||
|
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor) {
|
||||||
|
lastText = editor.document.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function flush() {
|
||||||
|
if (!moves.length || isSending) return;
|
||||||
|
|
||||||
|
isSending = true;
|
||||||
|
const batch = moves;
|
||||||
|
moves = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await addRunMoves(runId, batch);
|
||||||
|
} finally {
|
||||||
|
isSending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const readInterval = setInterval(() => {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (!editor) return;
|
||||||
|
|
||||||
|
const newText = editor.document.getText();
|
||||||
|
if (newText === lastText) return;
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const latency = capLatency(now - lastEventTime, IDLE_MS);
|
||||||
|
lastEventTime = now;
|
||||||
|
|
||||||
|
const diffs = dmp.diff_main(lastText, newText);
|
||||||
|
dmp.diff_cleanupEfficiency(diffs);
|
||||||
|
|
||||||
|
const changes = diffsToChanges(diffs);
|
||||||
|
|
||||||
|
lastText = newText;
|
||||||
|
|
||||||
|
for (const change of changes) {
|
||||||
|
moves.push({
|
||||||
|
moveId: moveId++,
|
||||||
|
latency,
|
||||||
|
cursor: editor.document.offsetAt(editor.selection.active),
|
||||||
|
changes: change,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idleTimeout) clearTimeout(idleTimeout);
|
||||||
|
idleTimeout = setTimeout(flush, IDLE_MS);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(readInterval);
|
||||||
|
if (idleTimeout) clearTimeout(idleTimeout);
|
||||||
|
flush();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function diffsToChanges(diffs: Diff[]) {
|
||||||
|
const changes: {
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
insert: string;
|
||||||
|
}[] = [];
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
for (const [op, text] of diffs) {
|
||||||
|
if (op === 0) {
|
||||||
|
// equal
|
||||||
|
offset += text.length;
|
||||||
|
} else if (op === -1) {
|
||||||
|
// delete
|
||||||
|
changes.push({
|
||||||
|
from: offset,
|
||||||
|
to: offset + text.length,
|
||||||
|
insert: "",
|
||||||
|
});
|
||||||
|
} else if (op === 1) {
|
||||||
|
// insert
|
||||||
|
changes.push({
|
||||||
|
from: offset,
|
||||||
|
to: offset,
|
||||||
|
insert: text,
|
||||||
|
});
|
||||||
|
offset += text.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function capLatency(value: number, max: number) {
|
||||||
|
return value > max ? 0 : value;
|
||||||
|
}
|
||||||
+15
-1
@@ -1,9 +1,13 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
import { addRun, submitRun } from "./client";
|
||||||
|
import { startMonitoring } from "./move";
|
||||||
|
|
||||||
export var currentRun: {
|
export var currentRun: {
|
||||||
interval: NodeJS.Timeout;
|
interval: NodeJS.Timeout;
|
||||||
|
stopMonitoring: () => void;
|
||||||
problemId: string;
|
problemId: string;
|
||||||
start: Date;
|
start: Date;
|
||||||
|
id: string;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
|
|
||||||
export async function startRun(
|
export async function startRun(
|
||||||
@@ -36,11 +40,15 @@ export async function startRun(
|
|||||||
|
|
||||||
if (!mode) return;
|
if (!mode) return;
|
||||||
|
|
||||||
|
const runId = await addRun(problemId, mode);
|
||||||
|
|
||||||
let start = Date.now();
|
let start = Date.now();
|
||||||
|
|
||||||
currentRun = {
|
currentRun = {
|
||||||
|
id: runId,
|
||||||
problemId,
|
problemId,
|
||||||
start: new Date(),
|
start: new Date(),
|
||||||
|
stopMonitoring: startMonitoring(runId),
|
||||||
interval: setInterval(() => {
|
interval: setInterval(() => {
|
||||||
const elapsed = Date.now() - start;
|
const elapsed = Date.now() - start;
|
||||||
|
|
||||||
@@ -53,11 +61,17 @@ export async function startRun(
|
|||||||
.padStart(2, "0")}`;
|
.padStart(2, "0")}`;
|
||||||
}, 50),
|
}, 50),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await vscode.commands.executeCommand("setContext", "devrun.runActive", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function stopRun() {
|
export async function stopRun() {
|
||||||
if (currentRun) {
|
if (currentRun) {
|
||||||
clearTimeout(currentRun.interval);
|
clearInterval(currentRun.interval);
|
||||||
|
submitRun(currentRun.id);
|
||||||
|
|
||||||
currentRun = null;
|
currentRun = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await vscode.commands.executeCommand("setContext", "devrun.runActive", false);
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-3
@@ -2,15 +2,16 @@ import * as vscode from "vscode";
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
|
import { getCookies, setCookies } from "./client";
|
||||||
|
|
||||||
let server: http.Server | undefined;
|
var server: http.Server | undefined;
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
app.use(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
origin: (origin, callback) => {
|
origin: (origin, callback) => {
|
||||||
// allow requests with no origin (e.g., direct curl)
|
|
||||||
if (
|
if (
|
||||||
!origin ||
|
!origin ||
|
||||||
origin.includes("localhost") ||
|
origin.includes("localhost") ||
|
||||||
@@ -25,10 +26,19 @@ app.use(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.post("/auth", (req, res) => {
|
||||||
|
const { saveCookies } = req.body;
|
||||||
|
|
||||||
|
setCookies(saveCookies);
|
||||||
|
|
||||||
|
res.json({ ok: true });
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/start-run/:problemId", (req, res) => {
|
app.get("/start-run/:problemId", (req, res) => {
|
||||||
const { problemId } = req.params;
|
const { problemId } = req.params;
|
||||||
|
|
||||||
// trigger VS Code command
|
if (!getCookies()) return res.json({ ok: false, code: "auth" });
|
||||||
|
|
||||||
vscode.commands.executeCommand("devrun-vscode.startRun", problemId);
|
vscode.commands.executeCommand("devrun-vscode.startRun", problemId);
|
||||||
|
|
||||||
res.json({ ok: true, problemId });
|
res.json({ ok: true, problemId });
|
||||||
@@ -42,6 +52,12 @@ export async function startServer(statusBarItem: vscode.StatusBarItem) {
|
|||||||
server = app.listen(63780, "127.0.0.1", () => {
|
server = app.listen(63780, "127.0.0.1", () => {
|
||||||
setTimeout(() => (statusBarItem.text = "$(clock) No active run"), 500);
|
setTimeout(() => (statusBarItem.text = "$(clock) No active run"), 500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await vscode.commands.executeCommand(
|
||||||
|
"setContext",
|
||||||
|
"devrun.serverActive",
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function stopServer(statusBarItem: vscode.StatusBarItem) {
|
export async function stopServer(statusBarItem: vscode.StatusBarItem) {
|
||||||
@@ -57,4 +73,10 @@ export async function stopServer(statusBarItem: vscode.StatusBarItem) {
|
|||||||
|
|
||||||
server = undefined;
|
server = undefined;
|
||||||
setTimeout(() => (statusBarItem.text = "$(clock) No active run"), 500);
|
setTimeout(() => (statusBarItem.text = "$(clock) No active run"), 500);
|
||||||
|
|
||||||
|
await vscode.commands.executeCommand(
|
||||||
|
"setContext",
|
||||||
|
"devrun.serverActive",
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export interface LiveRunMove {
|
||||||
|
latency: number;
|
||||||
|
cursor: number;
|
||||||
|
changes?: {
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
insert: string;
|
||||||
|
};
|
||||||
|
moveId: number;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user