@@ -5,6 +5,10 @@ import * as config from '../../config';
55import * as path from 'node:path' ;
66import * as vscode from 'vscode' ;
77import * as fs from 'node:fs' ;
8+ import { downloadWithBackupRecovery } from './downloader-utils' ;
9+
10+ const VERSION_CHECK_TIMEOUT_MS = 10_000 ;
11+ const DOWNLOAD_TIMEOUT_MS = 120_000 ;
812
913const versionFileName = 'clojure-lsp-version' ;
1014
@@ -56,39 +60,23 @@ export async function readVersionFile(extensionPath: string) {
5660
5761async function getLatestVersion ( ) : Promise < string > {
5862 try {
59- const releasesJSON = await util . fetchFromUrl (
60- 'https://api.github.com/repos/clojure-lsp/clojure-lsp/releases'
61- ) ;
63+ const releasesJSON = await Promise . race ( [
64+ util . fetchFromUrl ( 'https://api.github.com/repos/clojure-lsp/clojure-lsp/releases' ) ,
65+ new Promise < never > ( ( _ , reject ) =>
66+ setTimeout ( ( ) => reject ( new Error ( 'Version check timed out' ) ) , VERSION_CHECK_TIMEOUT_MS )
67+ ) ,
68+ ] ) ;
6269 const releases = JSON . parse ( releasesJSON ) ;
6370 return releases [ 0 ] . tag_name ;
6471 } catch ( err ) {
6572 return '' ;
6673 }
6774}
6875
69- async function backupExistingFile ( clojureLspPath : string ) : Promise < string > {
70- const backupDir = path . join ( path . dirname ( clojureLspPath ) , 'backup' ) ;
71- const backupPath = path . join ( backupDir , path . basename ( clojureLspPath ) ) ;
72-
73- if ( fs . existsSync ( clojureLspPath ) ) {
74- try {
75- await fs . promises . mkdir ( backupDir , {
76- recursive : true ,
77- } ) ;
78- console . log ( 'Backing up existing clojure-lsp to' , backupPath ) ;
79- await fs . promises . rename ( clojureLspPath , backupPath ) ;
80- } catch ( e ) {
81- console . log ( 'Error while backing up existing clojure-lsp file.' , e . message ) ;
82- }
83- }
84-
85- return fs . existsSync ( backupPath ) ? backupPath : null ;
86- }
87-
8876function downloadArtifact ( url : string , filePath : string ) : Promise < void > {
8977 console . log ( 'Downloading clojure-lsp from' , url ) ;
9078 return new Promise ( ( resolve , reject ) => {
91- https
79+ const request = https
9280 . get ( url , ( response ) => {
9381 if ( response . statusCode === 200 ) {
9482 const writeStream = fs . createWriteStream ( filePath ) ;
@@ -100,11 +88,14 @@ function downloadArtifact(url: string, filePath: string): Promise<void> {
10088 } )
10189 . pipe ( writeStream ) ;
10290 } else {
103- response . resume ( ) ; // Consume response to free up memory
91+ response . resume ( ) ;
10492 reject ( new Error ( response . statusMessage ) ) ;
10593 }
10694 } )
10795 . on ( 'error' , reject ) ;
96+ request . setTimeout ( DOWNLOAD_TIMEOUT_MS , ( ) => {
97+ request . destroy ( new Error ( 'Download timed out' ) ) ;
98+ } ) ;
10899 } ) ;
109100}
110101
@@ -135,8 +126,8 @@ async function downloadClojureLsp(extensionPath: string, version: string): Promi
135126 : `https://github.com/clojure-lsp/clojure-lsp-dev-builds/releases/latest/download/${ artifactName } ` ;
136127 const downloadPath = path . join ( extensionPath , artifactName ) ;
137128 const clojureLspPath = getClojureLspPath ( extensionPath ) ;
138- const backupPath = await backupExistingFile ( clojureLspPath ) ;
139- try {
129+
130+ const result = await downloadWithBackupRecovery ( clojureLspPath , async ( ) => {
140131 await downloadArtifact ( url , downloadPath ) ;
141132 if ( path . extname ( downloadPath ) === '.zip' ) {
142133 await unzipFile ( downloadPath , extensionPath ) ;
@@ -145,19 +136,14 @@ async function downloadClojureLsp(extensionPath: string, version: string): Promi
145136 await fs . promises . chmod ( clojureLspPath , 0o775 ) ;
146137 }
147138 writeVersionFile ( extensionPath , version ) ;
148- } catch ( e ) {
149- console . log ( `Error downloading clojure-lsp, version: ${ version } , from ${ url } ` , e ) ;
150- if ( backupPath ) {
151- console . log ( 'Using backup clojure-lsp' ) ;
152- void vscode . window . showWarningMessage (
153- `Error downloading clojure-lsp, version: ${ version } , from ${ url } . Using backup clojure-lsp`
154- ) ;
155- return backupPath ;
156- } else {
157- throw new Error ( `Error downloading clojure-lsp, version: ${ version } , from ${ url } ` ) ;
158- }
139+ } ) ;
140+
141+ if ( result . restored ) {
142+ void vscode . window . showWarningMessage (
143+ `Error downloading clojure-lsp, version: ${ version } . Using previously downloaded clojure-lsp`
144+ ) ;
159145 }
160- return clojureLspPath ;
146+ return result . path ;
161147}
162148
163149export const ensureServerDownloaded = async (
0 commit comments