From f60d82a7fa20f23664c6990f94b33b5cff38b92b Mon Sep 17 00:00:00 2001 From: Kinin-Code-Offical <125186556+Kinin-Code-Offical@users.noreply.github.com> Date: Mon, 22 Dec 2025 06:17:48 +0300 Subject: [PATCH] fix(p2): service-aware proxy install/update --- src/commands/install.ts | 20 ++++++++++++++++++++ src/commands/update.ts | 20 ++++++++++++++++++++ src/core/updater.ts | 31 +++++++++++++++++-------------- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/commands/install.ts b/src/commands/install.ts index dee36fa..59df311 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -2,12 +2,23 @@ import { Command } from 'commander'; import { getLatestVersion, downloadProxy } from '../core/updater.js'; import { logger } from '../core/logger.js'; import { isRunning, stopProxy } from '../core/proxy.js'; +import { isServiceInstalled, isServiceRunning, startService, stopService } from '../system/service.js'; export const installCommand = new Command('install') .description('Download and install Cloud SQL Proxy') .option('-v, --version ', 'Specific version to install') .action(async (options) => { + const serviceInstalled = await isServiceInstalled(); + const serviceWasRunning = serviceInstalled && await isServiceRunning(); + let serviceStopped = false; + try { + if (serviceWasRunning) { + logger.info('Stopping Windows Service before installation...'); + await stopService(); + serviceStopped = true; + } + if (await isRunning()) { logger.info('Stopping running proxy before installation...'); await stopProxy(); @@ -25,5 +36,14 @@ export const installCommand = new Command('install') } catch (error) { logger.error('Installation failed', error); process.exit(1); + } finally { + if (serviceStopped) { + try { + logger.info('Restarting Windows Service...'); + await startService(); + } catch (error) { + logger.warn('Failed to restart Windows Service after installation attempt', error); + } + } } }); diff --git a/src/commands/update.ts b/src/commands/update.ts index e4c03b6..1944e64 100644 --- a/src/commands/update.ts +++ b/src/commands/update.ts @@ -2,11 +2,22 @@ import { Command } from 'commander'; import { getLatestVersion, downloadProxy } from '../core/updater.js'; import { logger } from '../core/logger.js'; import { isRunning, stopProxy } from '../core/proxy.js'; +import { isServiceInstalled, isServiceRunning, startService, stopService } from '../system/service.js'; export const updateCommand = new Command('update') .description('Update Cloud SQL Proxy to the latest version') .action(async () => { + const serviceInstalled = await isServiceInstalled(); + const serviceWasRunning = serviceInstalled && await isServiceRunning(); + let serviceStopped = false; + try { + if (serviceWasRunning) { + logger.info('Stopping Windows Service before update...'); + await stopService(); + serviceStopped = true; + } + if (await isRunning()) { logger.info('Stopping running proxy before update...'); await stopProxy(); @@ -20,5 +31,14 @@ export const updateCommand = new Command('update') } catch (error) { logger.error('Update failed', error); process.exit(1); + } finally { + if (serviceStopped) { + try { + logger.info('Restarting Windows Service...'); + await startService(); + } catch (error) { + logger.warn('Failed to restart Windows Service after update attempt', error); + } + } } }); diff --git a/src/core/updater.ts b/src/core/updater.ts index f1ff534..c47aa75 100644 --- a/src/core/updater.ts +++ b/src/core/updater.ts @@ -58,34 +58,37 @@ export async function downloadProxy(version: string, targetPath: string = PATHS. // Ensure directory exists await fs.ensureDir(path.dirname(targetPath)); - const writer = fs.createWriteStream(targetPath); + const tmpPath = `${targetPath}.download`; + await fs.remove(tmpPath); + + const writer = fs.createWriteStream(tmpPath); const responseStream = await axios({ url: downloadUrl, method: 'GET', responseType: 'stream' }); - responseStream.data.pipe(writer); - - await new Promise((resolve, reject) => { - writer.on('finish', resolve); - writer.on('error', reject); - }); + try { + responseStream.data.pipe(writer); - logger.info('Download complete.'); + await new Promise((resolve, reject) => { + writer.on('finish', resolve); + writer.on('error', reject); + }); - logger.info('Verifying checksum...'); - try { - const isValid = await verifyChecksum(targetPath, expectedChecksum); + logger.info('Download complete.'); + logger.info('Verifying checksum...'); + const isValid = await verifyChecksum(tmpPath, expectedChecksum); if (!isValid) { throw new Error('Checksum verification failed'); } logger.info('Checksum verified.'); + + await fs.move(tmpPath, targetPath, { overwrite: true }); } catch (err) { - logger.warn('Failed to verify checksum', err); - // If verification fails, we should probably remove the file - await fs.remove(targetPath); + logger.warn('Failed to download/verify proxy', err); + await fs.remove(tmpPath); throw err; }