mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
626 lines
20 KiB
TypeScript
626 lines
20 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
import * as crypto from 'crypto';
|
|
import Log from './common/logger';
|
|
import { getVSCodeServerConfig } from './serverConfig';
|
|
import SSHConnection from './ssh/sshConnection';
|
|
|
|
export interface ServerInstallOptions {
|
|
id: string;
|
|
quality: string;
|
|
commit: string;
|
|
version: string;
|
|
release?: string; // void specific
|
|
extensionIds: string[];
|
|
envVariables: string[];
|
|
useSocketPath: boolean;
|
|
serverApplicationName: string;
|
|
serverDataFolderName: string;
|
|
serverDownloadUrlTemplate: string;
|
|
}
|
|
|
|
export interface ServerInstallResult {
|
|
exitCode: number;
|
|
listeningOn: number | string;
|
|
connectionToken: string;
|
|
logFile: string;
|
|
osReleaseId: string;
|
|
arch: string;
|
|
platform: string;
|
|
tmpDir: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
export class ServerInstallError extends Error {
|
|
constructor(message: string) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
const DEFAULT_DOWNLOAD_URL_TEMPLATE = 'https://github.com/voideditor/binaries/releases/download/${version}.${release}/void-reh-${os}-${arch}-${version}.${release}.tar.gz';
|
|
|
|
export async function installCodeServer(conn: SSHConnection, serverDownloadUrlTemplate: string | undefined, extensionIds: string[], envVariables: string[], platform: string | undefined, useSocketPath: boolean, logger: Log): Promise<ServerInstallResult> {
|
|
let shell = 'powershell';
|
|
|
|
// detect platform and shell for windows
|
|
if (!platform || platform === 'windows') {
|
|
const result = await conn.exec('uname -s');
|
|
|
|
if (result.stdout) {
|
|
if (result.stdout.includes('windows32')) {
|
|
platform = 'windows';
|
|
} else if (result.stdout.includes('MINGW64')) {
|
|
platform = 'windows';
|
|
shell = 'bash';
|
|
}
|
|
} else if (result.stderr) {
|
|
if (result.stderr.includes('FullyQualifiedErrorId : CommandNotFoundException')) {
|
|
platform = 'windows';
|
|
}
|
|
|
|
if (result.stderr.includes('is not recognized as an internal or external command')) {
|
|
platform = 'windows';
|
|
shell = 'cmd';
|
|
}
|
|
}
|
|
|
|
if (platform) {
|
|
logger.trace(`Detected platform: ${platform}, ${shell}`);
|
|
}
|
|
}
|
|
|
|
const scriptId = crypto.randomBytes(12).toString('hex');
|
|
|
|
const vscodeServerConfig = await getVSCodeServerConfig();
|
|
const installOptions: ServerInstallOptions = {
|
|
id: scriptId,
|
|
version: vscodeServerConfig.version,
|
|
commit: vscodeServerConfig.commit,
|
|
quality: vscodeServerConfig.quality,
|
|
release: vscodeServerConfig.release,
|
|
extensionIds,
|
|
envVariables,
|
|
useSocketPath,
|
|
serverApplicationName: vscodeServerConfig.serverApplicationName,
|
|
serverDataFolderName: vscodeServerConfig.serverDataFolderName,
|
|
serverDownloadUrlTemplate: serverDownloadUrlTemplate ?? vscodeServerConfig.serverDownloadUrlTemplate ?? DEFAULT_DOWNLOAD_URL_TEMPLATE,
|
|
};
|
|
|
|
let commandOutput: { stdout: string; stderr: string };
|
|
if (platform === 'windows') {
|
|
const installServerScript = generatePowerShellInstallScript(installOptions);
|
|
|
|
logger.trace('Server install command:', installServerScript);
|
|
|
|
const installDir = `$HOME\\${vscodeServerConfig.serverDataFolderName}\\install`;
|
|
const installScript = `${installDir}\\${vscodeServerConfig.commit}.ps1`;
|
|
const endRegex = new RegExp(`${scriptId}: end`);
|
|
// investigate if it's possible to use `-EncodedCommand` flag
|
|
// https://devblogs.microsoft.com/powershell/invoking-powershell-with-complex-expressions-using-scriptblocks/
|
|
let command = '';
|
|
if (shell === 'powershell') {
|
|
command = `md -Force ${installDir}; echo @'\n${installServerScript}\n'@ | Set-Content ${installScript}; powershell -ExecutionPolicy ByPass -File "${installScript}"`;
|
|
} else if (shell === 'bash') {
|
|
command = `mkdir -p ${installDir.replace(/\\/g, '/')} && echo '\n${installServerScript.replace(/'/g, '\'"\'"\'')}\n' > ${installScript.replace(/\\/g, '/')} && powershell -ExecutionPolicy ByPass -File "${installScript}"`;
|
|
} else if (shell === 'cmd') {
|
|
const script = installServerScript.trim()
|
|
// remove comments
|
|
.replace(/^#.*$/gm, '')
|
|
// remove empty lines
|
|
.replace(/\n{2,}/gm, '\n')
|
|
// remove leading spaces
|
|
.replace(/^\s*/gm, '')
|
|
// escape double quotes (from powershell/cmd)
|
|
.replace(/"/g, '"""')
|
|
// escape single quotes (from cmd)
|
|
.replace(/'/g, `''`)
|
|
// escape redirect (from cmd)
|
|
.replace(/>/g, `^>`)
|
|
// escape new lines (from powershell/cmd)
|
|
.replace(/\n/g, '\'`n\'');
|
|
|
|
command = `powershell "md -Force ${installDir}" && powershell "echo '${script}'" > ${installScript.replace('$HOME', '%USERPROFILE%')} && powershell -ExecutionPolicy ByPass -File "${installScript.replace('$HOME', '%USERPROFILE%')}"`;
|
|
|
|
logger.trace('Command length (8191 max):', command.length);
|
|
|
|
if (command.length > 8191) {
|
|
throw new ServerInstallError(`Command line too long`);
|
|
}
|
|
} else {
|
|
throw new ServerInstallError(`Not supported shell: ${shell}`);
|
|
}
|
|
|
|
commandOutput = await conn.execPartial(command, (stdout: string) => endRegex.test(stdout));
|
|
} else {
|
|
const installServerScript = generateBashInstallScript(installOptions);
|
|
|
|
logger.trace('Server install command:', installServerScript);
|
|
// Fish shell does not support heredoc so let's workaround it using -c option,
|
|
// also replace single quotes (') within the script with ('\'') as there's no quoting within single quotes, see https://unix.stackexchange.com/a/24676
|
|
commandOutput = await conn.exec(`bash -c '${installServerScript.replace(/'/g, `'\\''`)}'`);
|
|
}
|
|
|
|
if (commandOutput.stderr) {
|
|
logger.trace('Server install command stderr:', commandOutput.stderr);
|
|
}
|
|
logger.trace('Server install command stdout:', commandOutput.stdout);
|
|
|
|
const resultMap = parseServerInstallOutput(commandOutput.stdout, scriptId);
|
|
if (!resultMap) {
|
|
throw new ServerInstallError(`Failed parsing install script output`);
|
|
}
|
|
|
|
const exitCode = parseInt(resultMap.exitCode, 10);
|
|
if (exitCode !== 0) {
|
|
throw new ServerInstallError(`Couldn't install vscode server on remote server, install script returned non-zero exit status`);
|
|
}
|
|
|
|
const listeningOn = resultMap.listeningOn.match(/^\d+$/)
|
|
? parseInt(resultMap.listeningOn, 10)
|
|
: resultMap.listeningOn;
|
|
|
|
const remoteEnvVars = Object.fromEntries(Object.entries(resultMap).filter(([key,]) => envVariables.includes(key)));
|
|
|
|
return {
|
|
exitCode,
|
|
listeningOn,
|
|
connectionToken: resultMap.connectionToken,
|
|
logFile: resultMap.logFile,
|
|
osReleaseId: resultMap.osReleaseId,
|
|
arch: resultMap.arch,
|
|
platform: resultMap.platform,
|
|
tmpDir: resultMap.tmpDir,
|
|
...remoteEnvVars
|
|
};
|
|
}
|
|
|
|
function parseServerInstallOutput(str: string, scriptId: string): { [k: string]: string } | undefined {
|
|
const startResultStr = `${scriptId}: start`;
|
|
const endResultStr = `${scriptId}: end`;
|
|
|
|
const startResultIdx = str.indexOf(startResultStr);
|
|
if (startResultIdx < 0) {
|
|
return undefined;
|
|
}
|
|
|
|
const endResultIdx = str.indexOf(endResultStr, startResultIdx + startResultStr.length);
|
|
if (endResultIdx < 0) {
|
|
return undefined;
|
|
}
|
|
|
|
const installResult = str.substring(startResultIdx + startResultStr.length, endResultIdx);
|
|
|
|
const resultMap: { [k: string]: string } = {};
|
|
const resultArr = installResult.split(/\r?\n/);
|
|
for (const line of resultArr) {
|
|
const [key, value] = line.split('==');
|
|
resultMap[key] = value;
|
|
}
|
|
|
|
return resultMap;
|
|
}
|
|
|
|
function generateBashInstallScript({ id, quality, version, commit, release, extensionIds, envVariables, useSocketPath, serverApplicationName, serverDataFolderName, serverDownloadUrlTemplate }: ServerInstallOptions) {
|
|
const extensions = extensionIds.map(id => '--install-extension ' + id).join(' ');
|
|
return `
|
|
# Server installation script
|
|
|
|
TMP_DIR="\${XDG_RUNTIME_DIR:-"/tmp"}"
|
|
|
|
DISTRO_VERSION="${version}"
|
|
DISTRO_COMMIT="${commit}"
|
|
DISTRO_QUALITY="${quality}"
|
|
DISTRO_VOID_RELEASE="${release ?? ''}"
|
|
|
|
SERVER_APP_NAME="${serverApplicationName}"
|
|
SERVER_INITIAL_EXTENSIONS="${extensions}"
|
|
SERVER_LISTEN_FLAG="${useSocketPath ? `--socket-path="$TMP_DIR/vscode-server-sock-${crypto.randomUUID()}"` : '--port=0'}"
|
|
SERVER_DATA_DIR="$HOME/${serverDataFolderName}"
|
|
SERVER_DIR="$SERVER_DATA_DIR/bin/$DISTRO_COMMIT"
|
|
SERVER_SCRIPT="$SERVER_DIR/bin/$SERVER_APP_NAME"
|
|
SERVER_LOGFILE="$SERVER_DATA_DIR/.$DISTRO_COMMIT.log"
|
|
SERVER_PIDFILE="$SERVER_DATA_DIR/.$DISTRO_COMMIT.pid"
|
|
SERVER_TOKENFILE="$SERVER_DATA_DIR/.$DISTRO_COMMIT.token"
|
|
SERVER_ARCH=
|
|
SERVER_CONNECTION_TOKEN=
|
|
SERVER_DOWNLOAD_URL=
|
|
|
|
LISTENING_ON=
|
|
OS_RELEASE_ID=
|
|
ARCH=
|
|
PLATFORM=
|
|
|
|
# Mimic output from logs of remote-ssh extension
|
|
print_install_results_and_exit() {
|
|
echo "${id}: start"
|
|
echo "exitCode==$1=="
|
|
echo "listeningOn==$LISTENING_ON=="
|
|
echo "connectionToken==$SERVER_CONNECTION_TOKEN=="
|
|
echo "logFile==$SERVER_LOGFILE=="
|
|
echo "osReleaseId==$OS_RELEASE_ID=="
|
|
echo "arch==$ARCH=="
|
|
echo "platform==$PLATFORM=="
|
|
echo "tmpDir==$TMP_DIR=="
|
|
${envVariables.map(envVar => `echo "${envVar}==$${envVar}=="`).join('\n')}
|
|
echo "${id}: end"
|
|
exit 0
|
|
}
|
|
|
|
# Check if platform is supported
|
|
KERNEL="$(uname -s)"
|
|
case $KERNEL in
|
|
Darwin)
|
|
PLATFORM="darwin"
|
|
;;
|
|
Linux)
|
|
PLATFORM="linux"
|
|
;;
|
|
FreeBSD)
|
|
PLATFORM="freebsd"
|
|
;;
|
|
DragonFly)
|
|
PLATFORM="dragonfly"
|
|
;;
|
|
*)
|
|
echo "Error platform not supported: $KERNEL"
|
|
print_install_results_and_exit 1
|
|
;;
|
|
esac
|
|
|
|
# Check machine architecture
|
|
ARCH="$(uname -m)"
|
|
case $ARCH in
|
|
x86_64 | amd64)
|
|
SERVER_ARCH="x64"
|
|
;;
|
|
armv7l | armv8l)
|
|
SERVER_ARCH="armhf"
|
|
;;
|
|
arm64 | aarch64)
|
|
SERVER_ARCH="arm64"
|
|
;;
|
|
ppc64le)
|
|
SERVER_ARCH="ppc64le"
|
|
;;
|
|
riscv64)
|
|
SERVER_ARCH="riscv64"
|
|
;;
|
|
loongarch64)
|
|
SERVER_ARCH="loong64"
|
|
;;
|
|
s390x)
|
|
SERVER_ARCH="s390x"
|
|
;;
|
|
*)
|
|
echo "Error architecture not supported: $ARCH"
|
|
print_install_results_and_exit 1
|
|
;;
|
|
esac
|
|
|
|
# https://www.freedesktop.org/software/systemd/man/os-release.html
|
|
OS_RELEASE_ID="$(grep -i '^ID=' /etc/os-release 2>/dev/null | sed 's/^ID=//gi' | sed 's/"//g')"
|
|
if [[ -z $OS_RELEASE_ID ]]; then
|
|
OS_RELEASE_ID="$(grep -i '^ID=' /usr/lib/os-release 2>/dev/null | sed 's/^ID=//gi' | sed 's/"//g')"
|
|
if [[ -z $OS_RELEASE_ID ]]; then
|
|
OS_RELEASE_ID="unknown"
|
|
fi
|
|
fi
|
|
|
|
# Create installation folder
|
|
if [[ ! -d $SERVER_DIR ]]; then
|
|
mkdir -p $SERVER_DIR
|
|
if (( $? > 0 )); then
|
|
echo "Error creating server install directory"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
fi
|
|
|
|
# adjust platform for void download, if needed
|
|
if [[ $OS_RELEASE_ID = alpine ]]; then
|
|
PLATFORM=$OS_RELEASE_ID
|
|
fi
|
|
|
|
SERVER_DOWNLOAD_URL="$(echo "${serverDownloadUrlTemplate.replace(/\$\{/g, '\\${')}" | sed "s/\\\${quality}/$DISTRO_QUALITY/g" | sed "s/\\\${version}/$DISTRO_VERSION/g" | sed "s/\\\${commit}/$DISTRO_COMMIT/g" | sed "s/\\\${os}/$PLATFORM/g" | sed "s/\\\${arch}/$SERVER_ARCH/g" | sed "s/\\\${release}/$DISTRO_VOID_RELEASE/g")"
|
|
|
|
# Check if server script is already installed
|
|
if [[ ! -f $SERVER_SCRIPT ]]; then
|
|
case "$PLATFORM" in
|
|
darwin | linux | alpine )
|
|
;;
|
|
*)
|
|
echo "Error '$PLATFORM' needs manual installation of remote extension host"
|
|
print_install_results_and_exit 1
|
|
;;
|
|
esac
|
|
|
|
pushd $SERVER_DIR > /dev/null
|
|
|
|
if [[ ! -z $(which wget) ]]; then
|
|
wget --tries=3 --timeout=10 --continue --no-verbose -O vscode-server.tar.gz $SERVER_DOWNLOAD_URL
|
|
elif [[ ! -z $(which curl) ]]; then
|
|
curl --retry 3 --connect-timeout 10 --location --show-error --silent --output vscode-server.tar.gz $SERVER_DOWNLOAD_URL
|
|
else
|
|
echo "Error no tool to download server binary"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
|
|
if (( $? > 0 )); then
|
|
echo "Error downloading server from $SERVER_DOWNLOAD_URL"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
|
|
tar -xf vscode-server.tar.gz --strip-components 1
|
|
if (( $? > 0 )); then
|
|
echo "Error while extracting server contents"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
|
|
if [[ ! -f $SERVER_SCRIPT ]]; then
|
|
echo "Error server contents are corrupted"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
|
|
rm -f vscode-server.tar.gz
|
|
|
|
popd > /dev/null
|
|
else
|
|
echo "Server script already installed in $SERVER_SCRIPT"
|
|
fi
|
|
|
|
# Try to find if server is already running
|
|
if [[ -f $SERVER_PIDFILE ]]; then
|
|
SERVER_PID="$(cat $SERVER_PIDFILE)"
|
|
SERVER_RUNNING_PROCESS="$(ps -o pid,args -p $SERVER_PID | grep $SERVER_SCRIPT)"
|
|
else
|
|
SERVER_RUNNING_PROCESS="$(ps -o pid,args -A | grep $SERVER_SCRIPT | grep -v grep)"
|
|
fi
|
|
|
|
if [[ -z $SERVER_RUNNING_PROCESS ]]; then
|
|
if [[ -f $SERVER_LOGFILE ]]; then
|
|
rm $SERVER_LOGFILE
|
|
fi
|
|
if [[ -f $SERVER_TOKENFILE ]]; then
|
|
rm $SERVER_TOKENFILE
|
|
fi
|
|
|
|
touch $SERVER_TOKENFILE
|
|
chmod 600 $SERVER_TOKENFILE
|
|
SERVER_CONNECTION_TOKEN="${crypto.randomUUID()}"
|
|
echo $SERVER_CONNECTION_TOKEN > $SERVER_TOKENFILE
|
|
|
|
$SERVER_SCRIPT --start-server --host=127.0.0.1 $SERVER_LISTEN_FLAG $SERVER_INITIAL_EXTENSIONS --connection-token-file $SERVER_TOKENFILE --telemetry-level off --enable-remote-auto-shutdown --accept-server-license-terms &> $SERVER_LOGFILE &
|
|
echo $! > $SERVER_PIDFILE
|
|
else
|
|
echo "Server script is already running $SERVER_SCRIPT"
|
|
fi
|
|
|
|
if [[ -f $SERVER_TOKENFILE ]]; then
|
|
SERVER_CONNECTION_TOKEN="$(cat $SERVER_TOKENFILE)"
|
|
else
|
|
echo "Error server token file not found $SERVER_TOKENFILE"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
|
|
if [[ -f $SERVER_LOGFILE ]]; then
|
|
for i in {1..5}; do
|
|
LISTENING_ON="$(cat $SERVER_LOGFILE | grep -E 'Extension host agent listening on .+' | sed 's/Extension host agent listening on //')"
|
|
if [[ -n $LISTENING_ON ]]; then
|
|
break
|
|
fi
|
|
sleep 0.5
|
|
done
|
|
|
|
if [[ -z $LISTENING_ON ]]; then
|
|
echo "Error server did not start successfully"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
else
|
|
echo "Error server log file not found $SERVER_LOGFILE"
|
|
print_install_results_and_exit 1
|
|
fi
|
|
|
|
# Finish server setup
|
|
print_install_results_and_exit 0
|
|
`;
|
|
}
|
|
|
|
function generatePowerShellInstallScript({ id, quality, version, commit, release, extensionIds, envVariables, useSocketPath, serverApplicationName, serverDataFolderName, serverDownloadUrlTemplate }: ServerInstallOptions) {
|
|
const extensions = extensionIds.map(id => '--install-extension ' + id).join(' ');
|
|
const downloadUrl = serverDownloadUrlTemplate
|
|
.replace(/\$\{quality\}/g, quality)
|
|
.replace(/\$\{version\}/g, version)
|
|
.replace(/\$\{commit\}/g, commit)
|
|
.replace(/\$\{os\}/g, 'win32')
|
|
.replace(/\$\{arch\}/g, 'x64')
|
|
.replace(/\$\{release\}/g, release ?? '');
|
|
|
|
return `
|
|
# Server installation script
|
|
|
|
$TMP_DIR="$env:TEMP\\$([System.IO.Path]::GetRandomFileName())"
|
|
$ProgressPreference = "SilentlyContinue"
|
|
|
|
$DISTRO_VERSION="${version}"
|
|
$DISTRO_COMMIT="${commit}"
|
|
$DISTRO_QUALITY="${quality}"
|
|
$DISTRO_VOID_RELEASE="${release ?? ''}"
|
|
|
|
$SERVER_APP_NAME="${serverApplicationName}"
|
|
$SERVER_INITIAL_EXTENSIONS="${extensions}"
|
|
$SERVER_LISTEN_FLAG="${useSocketPath ? `--socket-path="$TMP_DIR/vscode-server-sock-${crypto.randomUUID()}"` : '--port=0'}"
|
|
$SERVER_DATA_DIR="$(Resolve-Path ~)\\${serverDataFolderName}"
|
|
$SERVER_DIR="$SERVER_DATA_DIR\\bin\\$DISTRO_COMMIT"
|
|
$SERVER_SCRIPT="$SERVER_DIR\\bin\\$SERVER_APP_NAME.cmd"
|
|
$SERVER_LOGFILE="$SERVER_DATA_DIR\\.$DISTRO_COMMIT.log"
|
|
$SERVER_PIDFILE="$SERVER_DATA_DIR\\.$DISTRO_COMMIT.pid"
|
|
$SERVER_TOKENFILE="$SERVER_DATA_DIR\\.$DISTRO_COMMIT.token"
|
|
$SERVER_ARCH=
|
|
$SERVER_CONNECTION_TOKEN=
|
|
$SERVER_DOWNLOAD_URL=
|
|
|
|
$LISTENING_ON=
|
|
$OS_RELEASE_ID=
|
|
$ARCH=
|
|
$PLATFORM="win32"
|
|
|
|
function printInstallResults($code) {
|
|
"${id}: start"
|
|
"exitCode==$code=="
|
|
"listeningOn==$LISTENING_ON=="
|
|
"connectionToken==$SERVER_CONNECTION_TOKEN=="
|
|
"logFile==$SERVER_LOGFILE=="
|
|
"osReleaseId==$OS_RELEASE_ID=="
|
|
"arch==$ARCH=="
|
|
"platform==$PLATFORM=="
|
|
"tmpDir==$TMP_DIR=="
|
|
${envVariables.map(envVar => `"${envVar}==$${envVar}=="`).join('\n')}
|
|
"${id}: end"
|
|
}
|
|
|
|
# Check machine architecture
|
|
$ARCH=$env:PROCESSOR_ARCHITECTURE
|
|
# Use x64 version for ARM64, as it's not yet available.
|
|
if(($ARCH -eq "AMD64") -or ($ARCH -eq "IA64") -or ($ARCH -eq "ARM64")) {
|
|
$SERVER_ARCH="x64"
|
|
}
|
|
else {
|
|
"Error architecture not supported: $ARCH"
|
|
printInstallResults 1
|
|
exit 0
|
|
}
|
|
|
|
# Create installation folder
|
|
if(!(Test-Path $SERVER_DIR)) {
|
|
try {
|
|
ni -it d $SERVER_DIR -f -ea si
|
|
} catch {
|
|
"Error creating server install directory - $($_.ToString())"
|
|
exit 1
|
|
}
|
|
|
|
if(!(Test-Path $SERVER_DIR)) {
|
|
"Error creating server install directory"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
cd $SERVER_DIR
|
|
|
|
# Check if server script is already installed
|
|
if(!(Test-Path $SERVER_SCRIPT)) {
|
|
del vscode-server.tar.gz
|
|
|
|
$REQUEST_ARGUMENTS = @{
|
|
Uri="${downloadUrl}"
|
|
TimeoutSec=20
|
|
OutFile="vscode-server.tar.gz"
|
|
UseBasicParsing=$True
|
|
}
|
|
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
|
|
Invoke-RestMethod @REQUEST_ARGUMENTS
|
|
|
|
if(Test-Path "vscode-server.tar.gz") {
|
|
tar -xf vscode-server.tar.gz --strip-components 1
|
|
|
|
del vscode-server.tar.gz
|
|
}
|
|
|
|
if(!(Test-Path $SERVER_SCRIPT)) {
|
|
"Error while installing the server binary"
|
|
exit 1
|
|
}
|
|
}
|
|
else {
|
|
"Server script already installed in $SERVER_SCRIPT"
|
|
}
|
|
|
|
# Try to find if server is already running
|
|
if(Get-Process node -ErrorAction SilentlyContinue | Where-Object Path -Like "$SERVER_DIR\\*") {
|
|
echo "Server script is already running $SERVER_SCRIPT"
|
|
}
|
|
else {
|
|
if(Test-Path $SERVER_LOGFILE) {
|
|
del $SERVER_LOGFILE
|
|
}
|
|
if(Test-Path $SERVER_PIDFILE) {
|
|
del $SERVER_PIDFILE
|
|
}
|
|
if(Test-Path $SERVER_TOKENFILE) {
|
|
del $SERVER_TOKENFILE
|
|
}
|
|
|
|
$SERVER_CONNECTION_TOKEN="${crypto.randomUUID()}"
|
|
[System.IO.File]::WriteAllLines($SERVER_TOKENFILE, $SERVER_CONNECTION_TOKEN)
|
|
|
|
$SCRIPT_ARGUMENTS="--start-server --host=127.0.0.1 $SERVER_LISTEN_FLAG $SERVER_INITIAL_EXTENSIONS --connection-token-file $SERVER_TOKENFILE --telemetry-level off --enable-remote-auto-shutdown --accept-server-license-terms *> '$SERVER_LOGFILE'"
|
|
|
|
$START_ARGUMENTS = @{
|
|
FilePath = "powershell.exe"
|
|
WindowStyle = "hidden"
|
|
ArgumentList = @(
|
|
"-ExecutionPolicy", "Unrestricted", "-NoLogo", "-NoProfile", "-NonInteractive", "-c", "$SERVER_SCRIPT $SCRIPT_ARGUMENTS"
|
|
)
|
|
PassThru = $True
|
|
}
|
|
|
|
$SERVER_ID = (start @START_ARGUMENTS).ID
|
|
|
|
if($SERVER_ID) {
|
|
[System.IO.File]::WriteAllLines($SERVER_PIDFILE, $SERVER_ID)
|
|
}
|
|
}
|
|
|
|
if(Test-Path $SERVER_TOKENFILE) {
|
|
$SERVER_CONNECTION_TOKEN="$(cat $SERVER_TOKENFILE)"
|
|
}
|
|
else {
|
|
"Error server token file not found $SERVER_TOKENFILE"
|
|
printInstallResults 1
|
|
exit 0
|
|
}
|
|
|
|
sleep -Milliseconds 500
|
|
|
|
$SELECT_ARGUMENTS = @{
|
|
Path = $SERVER_LOGFILE
|
|
Pattern = "Extension host agent listening on (\\d+)"
|
|
}
|
|
|
|
for($I = 1; $I -le 5; $I++) {
|
|
if(Test-Path $SERVER_LOGFILE) {
|
|
$GROUPS = (Select-String @SELECT_ARGUMENTS).Matches.Groups
|
|
|
|
if($GROUPS) {
|
|
$LISTENING_ON = $GROUPS[1].Value
|
|
break
|
|
}
|
|
}
|
|
|
|
sleep -Milliseconds 500
|
|
}
|
|
|
|
if(!(Test-Path $SERVER_LOGFILE)) {
|
|
"Error server log file not found $SERVER_LOGFILE"
|
|
printInstallResults 1
|
|
exit 0
|
|
}
|
|
|
|
# Finish server setup
|
|
printInstallResults 0
|
|
|
|
if($SERVER_ID) {
|
|
while($True) {
|
|
if(!(gps -Id $SERVER_ID)) {
|
|
"server died, exit"
|
|
exit 0
|
|
}
|
|
|
|
sleep 30
|
|
}
|
|
}
|
|
`;
|
|
}
|