@@ -29,6 +29,7 @@ export class LanguageServerResolver {
2929 private readonly manifest : Manifest ,
3030 private readonly lsName : string ,
3131 private readonly versionRange : semver . Range ,
32+ private readonly manifestUrl : string ,
3233 /**
3334 * Custom message to show user when downloading, if undefined it will use the default.
3435 */
@@ -90,7 +91,22 @@ export class LanguageServerResolver {
9091
9192 /** Finds an older, cached version of the LSP server bundle. */
9293 private async getFallbackServer ( latestVersion : LspVersion ) : Promise < LspResult > {
93- const fallbackDirectory = await this . getFallbackDir ( latestVersion . serverVersion )
94+ const cachedVersions = await this . getCachedVersions ( )
95+ if ( cachedVersions . length === 0 ) {
96+ /**
97+ * at this point the latest version doesn't exist locally, lsp download (with retries) failed, and there are no cached fallback versions.
98+ * This _probably_ only happens when the user hit a firewall/proxy issue, since otherwise they would probably have at least
99+ * one other language server locally
100+ */
101+ throw new ToolkitError (
102+ `Unable to download dependencies from ${ this . manifestUrl } . Check your network connectivity or firewall configuration and then try again.` ,
103+ {
104+ code : 'NetworkConnectivityError' ,
105+ }
106+ )
107+ }
108+
109+ const fallbackDirectory = await this . getFallbackDir ( latestVersion . serverVersion , cachedVersions )
94110 if ( ! fallbackDirectory ) {
95111 throw new ToolkitError ( 'Unable to find a compatible version of the Language Server' , {
96112 code : 'IncompatibleVersion' ,
@@ -142,13 +158,22 @@ export class LanguageServerResolver {
142158 assetDirectory : cacheDirectory ,
143159 }
144160 } else {
161+ await this . cleanupVersion ( latestVersion . serverVersion )
145162 throw new ToolkitError ( 'Failed to download server from remote' , { code : 'RemoteDownloadFailed' } )
146163 }
147164 } finally {
148165 timeout . dispose ( )
149166 }
150167 }
151168
169+ private async cleanupVersion ( version : string ) {
170+ // clean up the X.X.X download directory since the download failed
171+ const downloadDirectory = this . getDownloadDirectory ( version )
172+ if ( await fs . existsDir ( downloadDirectory ) ) {
173+ await fs . delete ( downloadDirectory )
174+ }
175+ }
176+
152177 /** Gets the current local ("cached") LSP server bundle. */
153178 private async getLocalServer (
154179 cacheDirectory : string ,
@@ -178,16 +203,9 @@ export class LanguageServerResolver {
178203 /**
179204 * Returns the path to the most compatible cached LSP version that can serve as a fallback
180205 **/
181- private async getFallbackDir ( version : string ) {
206+ private async getFallbackDir ( version : string , cachedVersions : string [ ] ) {
182207 const compatibleLspVersions = this . compatibleManifestLspVersion ( )
183208
184- // determine all folders containing lsp versions in the fallback parent folder
185- const cachedVersions = ( await fs . readdir ( this . defaultDownloadFolder ( ) ) )
186- . filter ( ( [ _ , filetype ] ) => filetype === FileType . Directory )
187- . map ( ( [ pathName , _ ] ) => semver . parse ( pathName ) )
188- . filter ( ( ver ) : ver is semver . SemVer => ver !== null )
189- . map ( ( x ) => x . version )
190-
191209 const expectedVersion = semver . parse ( version )
192210 if ( ! expectedVersion ) {
193211 return undefined
@@ -203,6 +221,15 @@ export class LanguageServerResolver {
203221 return fallbackDir . length > 0 ? fallbackDir [ 0 ] : undefined
204222 }
205223
224+ private async getCachedVersions ( ) {
225+ // determine all folders containing lsp versions in the parent folder
226+ return ( await fs . readdir ( this . defaultDownloadFolder ( ) ) )
227+ . filter ( ( [ _ , filetype ] ) => filetype === FileType . Directory )
228+ . map ( ( [ pathName , _ ] ) => semver . parse ( pathName ) )
229+ . filter ( ( ver ) : ver is semver . SemVer => ver !== null )
230+ . map ( ( x ) => x . version )
231+ }
232+
206233 /**
207234 * Validate the local cache directory of the given lsp version (matches expected hash)
208235 * If valid return cache directory, else return undefined
0 commit comments