1+ import * as fs from "fs" ;
2+ import * as path from "path" ;
13import * as vscode from "vscode" ;
24
35const REPO = "DivineDragonFanClub/engage-il2cpp" ;
@@ -58,7 +60,7 @@ async function checkForUpdates(context: vscode.ExtensionContext, output: vscode.
5860 }
5961
6062 if ( autoApply ) {
61- await applyUpdate ( vsix . browser_download_url , output ) ;
63+ await applyUpdate ( context , vsix . browser_download_url , output ) ;
6264 return ;
6365 }
6466
@@ -69,7 +71,7 @@ async function checkForUpdates(context: vscode.ExtensionContext, output: vscode.
6971 ) ;
7072
7173 if ( choice === "Update" ) {
72- await applyUpdate ( vsix . browser_download_url , output ) ;
74+ await applyUpdate ( context , vsix . browser_download_url , output ) ;
7375 }
7476}
7577
@@ -105,15 +107,31 @@ async function fetchLatestRelease(etag: string | undefined): Promise<FetchedRele
105107 return { release, etag : newEtag } ;
106108}
107109
108- async function applyUpdate ( vsixUrl : string , output : vscode . OutputChannel ) : Promise < void > {
109- output . appendLine ( `installing update from ${ vsixUrl } ` ) ;
110+ async function applyUpdate ( context : vscode . ExtensionContext , vsixUrl : string , output : vscode . OutputChannel ) : Promise < void > {
111+ output . appendLine ( `downloading update from ${ vsixUrl } ` ) ;
112+
113+ let localPath : string ;
114+
115+ try {
116+ localPath = await downloadVsix ( context , vsixUrl ) ;
117+ } catch ( err ) {
118+ const message = err instanceof Error ? err . message : String ( err ) ;
119+
120+ output . appendLine ( `download failed: ${ message } ` ) ;
121+ vscode . window . showErrorMessage ( `engage: download failed. ${ message } ` ) ;
122+
123+ return ;
124+ }
125+
126+ output . appendLine ( `installing from ${ localPath } ` ) ;
110127
111128 try {
112- await vscode . commands . executeCommand ( "workbench.extensions.installExtension" , vscode . Uri . parse ( vsixUrl ) ) ;
129+ await vscode . commands . executeCommand ( "workbench.extensions.installExtension" , vscode . Uri . file ( localPath ) ) ;
113130 } catch ( err ) {
114131 const message = err instanceof Error ? err . message : String ( err ) ;
115132
116133 vscode . window . showErrorMessage ( `engage: install failed. ${ message } ` ) ;
134+
117135 return ;
118136 }
119137
@@ -124,6 +142,43 @@ async function applyUpdate(vsixUrl: string, output: vscode.OutputChannel): Promi
124142 }
125143}
126144
145+ async function downloadVsix ( context : vscode . ExtensionContext , url : string ) : Promise < string > {
146+ const cacheDir = path . join ( context . globalStorageUri . fsPath , "updates" ) ;
147+ await fs . promises . mkdir ( cacheDir , { recursive : true } ) ;
148+
149+ const filename = inferFilename ( url ) ;
150+ const target = path . join ( cacheDir , filename ) ;
151+
152+ const response = await fetch ( url , {
153+ redirect : "follow" ,
154+ headers : { "User-Agent" : "engage-vscode" } ,
155+ } ) ;
156+
157+ if ( ! response . ok ) {
158+ throw new Error ( `HTTP ${ response . status } fetching ${ url } ` ) ;
159+ }
160+
161+ const data = Buffer . from ( await response . arrayBuffer ( ) ) ;
162+ await fs . promises . writeFile ( target , data ) ;
163+
164+ return target ;
165+ }
166+
167+ function inferFilename ( url : string ) : string {
168+ try {
169+ const u = new URL ( url ) ;
170+ const last = u . pathname . split ( "/" ) . filter ( ( p ) => p . length > 0 ) . pop ( ) ;
171+
172+ if ( last && last . endsWith ( ".vsix" ) ) {
173+ return last ;
174+ }
175+ } catch {
176+ // ignore
177+ }
178+
179+ return `engage-update-${ Date . now ( ) } .vsix` ;
180+ }
181+
127182function matchesPlatform ( assetName : string ) : boolean {
128183 const platform = process . platform ;
129184 const arch = process . arch ;
0 commit comments