mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-25 09:25:50 +00:00
200 lines
7.1 KiB
JavaScript
200 lines
7.1 KiB
JavaScript
"use strict";
|
|
/**
|
|
* Simplified Windows terminal implementation without threading
|
|
* Removed ConoutSocketWorker and shared pipe architecture
|
|
*/
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || (function () {
|
|
var ownKeys = function(o) {
|
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
var ar = [];
|
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
return ar;
|
|
};
|
|
return ownKeys(o);
|
|
};
|
|
return function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
})();
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.WindowsTerminal = void 0;
|
|
const fs = __importStar(require("fs"));
|
|
const net_1 = require("net");
|
|
const terminal_1 = require("./terminal");
|
|
const utils_1 = require("./utils");
|
|
const DEFAULT_FILE = 'cmd.exe';
|
|
const DEFAULT_NAME = 'Windows Shell';
|
|
let conptyNative;
|
|
class WindowsTerminal extends terminal_1.Terminal {
|
|
get master() { return this._outSocket; }
|
|
get slave() { return this._inSocket; }
|
|
constructor(file, args, opt) {
|
|
super(opt);
|
|
this._isReady = false;
|
|
this._pid = 0;
|
|
this._innerPid = 0;
|
|
this._useConptyDll = false;
|
|
// Load native module
|
|
if (!conptyNative) {
|
|
try {
|
|
conptyNative = require('../build/Release/conpty.node');
|
|
}
|
|
catch (outerError) {
|
|
try {
|
|
conptyNative = require('../build/Debug/conpty.node');
|
|
}
|
|
catch (innerError) {
|
|
throw outerError;
|
|
}
|
|
}
|
|
}
|
|
this._ptyNative = conptyNative;
|
|
// Initialize arguments
|
|
args = args || [];
|
|
file = file || DEFAULT_FILE;
|
|
opt = opt || {};
|
|
opt.env = opt.env || process.env;
|
|
const env = (0, utils_1.assign)({}, opt.env);
|
|
this._cols = opt.cols || terminal_1.DEFAULT_COLS;
|
|
this._rows = opt.rows || terminal_1.DEFAULT_ROWS;
|
|
const cwd = opt.cwd || process.cwd();
|
|
const parsedEnv = this._parseEnv(env);
|
|
// Compose command line
|
|
const commandLine = this._argsToCommandLine(file, args);
|
|
// Start ConPTY process
|
|
const pipeName = this._generatePipeName();
|
|
const term = this._ptyNative.startProcess(file, this._cols, this._rows, false, pipeName, false, this._useConptyDll);
|
|
this._pty = term.pty;
|
|
this._fd = term.fd;
|
|
// Create direct socket connections without worker threads
|
|
this._setupDirectSockets(term);
|
|
// Connect the process
|
|
const connect = this._ptyNative.connect(this._pty, commandLine, cwd, parsedEnv, this._useConptyDll, (exitCode) => {
|
|
this._exitCode = exitCode;
|
|
this.emit('exit', exitCode);
|
|
this._close();
|
|
});
|
|
this._innerPid = connect.pid;
|
|
this._pid = connect.pid;
|
|
this._file = file;
|
|
this._name = opt.name || env.TERM || DEFAULT_NAME;
|
|
this._readable = true;
|
|
this._writable = true;
|
|
this._forwardEvents();
|
|
}
|
|
_setupDirectSockets(term) {
|
|
// Setup output socket - read directly from conout
|
|
const outFd = fs.openSync(term.conout, 'r');
|
|
this._outSocket = new net_1.Socket({ fd: outFd, readable: true, writable: false });
|
|
this._outSocket.setEncoding('utf8');
|
|
this._socket = this._outSocket;
|
|
// Setup input socket - write directly to conin
|
|
const inFd = fs.openSync(term.conin, 'w');
|
|
this._inSocket = new net_1.Socket({ fd: inFd, readable: false, writable: true });
|
|
this._inSocket.setEncoding('utf8');
|
|
// Forward events directly
|
|
this._outSocket.on('data', (data) => {
|
|
if (!this._isReady) {
|
|
this._isReady = true;
|
|
}
|
|
this.emit('data', data);
|
|
});
|
|
this._outSocket.on('error', (err) => {
|
|
if (err.code && (err.code.includes('EPIPE') || err.code.includes('EIO'))) {
|
|
// Expected errors when process exits
|
|
return;
|
|
}
|
|
this.emit('error', err);
|
|
});
|
|
this._outSocket.on('close', () => {
|
|
if (this._exitCode === undefined) {
|
|
this.emit('exit', 0);
|
|
}
|
|
this._close();
|
|
});
|
|
}
|
|
_write(data) {
|
|
if (this._inSocket && this._inSocket.writable) {
|
|
this._inSocket.write(data);
|
|
}
|
|
}
|
|
resize(cols, rows) {
|
|
if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
|
|
throw new Error('resizing must be done using positive cols and rows');
|
|
}
|
|
if (this._exitCode !== undefined) {
|
|
throw new Error('Cannot resize a pty that has already exited');
|
|
}
|
|
this._cols = cols;
|
|
this._rows = rows;
|
|
this._ptyNative.resize(this._pty, cols, rows, this._useConptyDll);
|
|
}
|
|
clear() {
|
|
this._ptyNative.clear(this._pty, this._useConptyDll);
|
|
}
|
|
kill(signal) {
|
|
this._close();
|
|
try {
|
|
process.kill(this._pid);
|
|
}
|
|
catch (e) {
|
|
// Ignore if process cannot be found
|
|
}
|
|
this._ptyNative.kill(this._pty, this._useConptyDll);
|
|
}
|
|
_close() {
|
|
if (this._inSocket) {
|
|
this._inSocket.destroy();
|
|
}
|
|
if (this._outSocket) {
|
|
this._outSocket.destroy();
|
|
}
|
|
}
|
|
_generatePipeName() {
|
|
return `\\\\.\\pipe\\conpty-${Date.now()}-${Math.random()}`;
|
|
}
|
|
_argsToCommandLine(file, args) {
|
|
if (typeof args === 'string') {
|
|
return `${file} ${args}`;
|
|
}
|
|
const argv = [file];
|
|
if (args) {
|
|
argv.push(...args);
|
|
}
|
|
return argv.map(arg => {
|
|
if (arg.includes(' ') || arg.includes('\t')) {
|
|
return `"${arg.replace(/"/g, '\\"')}"`;
|
|
}
|
|
return arg;
|
|
}).join(' ');
|
|
}
|
|
static open(options) {
|
|
throw new Error('open() not supported on windows, use spawn() instead.');
|
|
}
|
|
get process() { return this._name; }
|
|
get pid() { return this._pid; }
|
|
destroy() {
|
|
this.kill();
|
|
}
|
|
}
|
|
exports.WindowsTerminal = WindowsTerminal;
|