@@ -2,6 +2,7 @@ import { FirmwareOption } from '../constants'
2
2
import { defaultFirmwareOptions } from '../constants'
3
3
import { DeviceService } from './DeviceService' ;
4
4
// const { Octokit } = require('@octokit/rest');
5
+ import { unzipit } from 'unzipit' ;
5
6
6
7
export class FirmwareService {
7
8
private firmwareString : string | null = null ;
@@ -16,15 +17,6 @@ export class FirmwareService {
16
17
// Get the firmware options from GitHub (or local files).
17
18
// Maybe we'll add an explicit button for updating the firmware options in the future...
18
19
// We'll initialize our private firmwareOptions here with the reqFirmwareOptionsGitHub() method.
19
- // console.log("In the constructor about to fetch firmware options from GitHub...");
20
- // this.reqFirmwareOptionsGitHub().then((res) => {
21
- // // log the res
22
- // console.log('Firmware options response:', res);
23
- // this.firmwareOptions = res;
24
- // })
25
-
26
- // Log the firmware options to the console for debugging.
27
- // console.log('Firmware options:', this.firmwareOptions);
28
20
29
21
// Initialize firmware options with defaultFirmwareOptions.
30
22
this . firmwareOptions = defaultFirmwareOptions ;
@@ -36,6 +28,27 @@ export class FirmwareService {
36
28
}
37
29
}
38
30
31
+ private async unzipStreamToVariable ( stream : ReadableStream < Uint8Array > ) : Promise < { [ filename : string ] : Uint8Array } > {
32
+ const reader = stream . getReader ( ) ;
33
+ let chunks = [ ] ;
34
+ while ( true ) {
35
+ const { done, value } = await reader . read ( ) ;
36
+ if ( done ) {
37
+ break ;
38
+ }
39
+ chunks . push ( value ) ;
40
+ }
41
+ const allChunks = new Uint8Array ( chunks . flatMap ( chunk => [ ...chunk ] ) ) ;
42
+ const { entries } = await unzipit . unzip ( allChunks ) ;
43
+
44
+ const unzippedData : { [ filename : string ] : Uint8Array } = { } ;
45
+ for ( const entry of Object . values ( entries ) as { name : string ; arrayBuffer : ( ) => Promise < Uint8Array > } [ ] ) {
46
+ unzippedData [ entry . name ] = new Uint8Array ( await entry . arrayBuffer ( ) ) ;
47
+ }
48
+ return unzippedData ;
49
+ }
50
+
51
+
39
52
// We'll use this method to fetch the firmware options from GitHub.
40
53
// We could alternatively use local files in ../binaries/ so we aren't sending a request to GitHub every time.
41
54
private async reqFirmwareOptionsGitHub ( ) : Promise < Record < string , FirmwareOption > > {
@@ -67,25 +80,9 @@ export class FirmwareService {
67
80
firmwareId = 'm-' + firmwareId . replace ( 'minimal-' , '' ) ;
68
81
}
69
82
70
-
71
- // curl method to download based on ID:
72
- // curl -L \
73
- // -H "Accept: application/vnd.github+json" \
74
- // -H "Authorization: Bearer <YOUR-TOKEN>" \
75
- // -H "X-GitHub-Api-Version: 2022-11-28" \
76
- // https://api.github.com/repos/OWNER/REPO/releases/assets/ASSET_ID
77
-
78
83
//method 1: use the browser_download_url from the asset object.
79
84
const firmwareUrl = asset . browser_download_url ;
80
85
81
- //method 2: use the asset ID to formulate a GET request to the GitHub API with octokit.
82
- // Instead let's use the asset ID to formulate an GitHub API URL.
83
- // We'll still use the 'URL' var for now but it's actually a formatted GET req
84
- //const firmwareUrl = 'GET /repos/sparkfun/micropython/releases/assets/' + asset.id;
85
-
86
- //method 3: use the asset ID to formulate a direct url to fetch the asset from with similar method as curl.
87
- // const firmwareUrl = `https://api.github.com/repos/sparkfun/micropython/releases/assets/${asset.id}`;
88
-
89
86
// log the asset object
90
87
console . log ( 'Asset:' , asset ) ;
91
88
@@ -189,6 +186,8 @@ export class FirmwareService {
189
186
throw new Error ( `Invalid firmware selection or no URL for: ${ firmwareId } ` ) ;
190
187
}
191
188
189
+ // GitHub requires a CORS proxy to fetch files from their API. We'll use a public CORS proxy for now.
190
+ // See: https://github.com/orgs/community/discussions/106849
192
191
const cors_proxy = "https://corsproxy.io/?url=" ;
193
192
console . log ( "Performing fetch for firmware:" , cors_proxy + selectedFirmware . url ) ;
194
193
@@ -200,98 +199,27 @@ export class FirmwareService {
200
199
} ,
201
200
} ) ;
202
201
203
- // console.log('Firmware fetch result:', result);
204
-
205
- // method 2: use the asset ID to formulate a GET request to the GitHub API with octokit.
206
- // const octokit = new Octokit({});
207
-
208
- // firmware URLs from above: const firmwareUrl = 'GET /repos/sparkfun/micropython/releases/assets/' + asset.id;
209
- // const response = await octokit.request(selectedFirmware.url, {
210
- // owner: 'sparkfun',
211
- // repo: 'micropython',
212
- // asset_id: selectedFirmware.url.split('/').pop(), // Extract the asset ID from the URL
213
- // headers: {
214
- // 'X-GitHub-Api-Version': '2022-11-28'
215
- // }
216
- // });
217
-
218
- // console.log('Response from GitHub:', response);
219
- // throw new Error('Purposeful error out during testing.'); // TODO: Remove this line when done testing.
220
-
221
- // method 3: use the asset ID to formulate a direct url to fetch the asset from with similar method as curl.
222
- // we can look at the headers in the curl command to see what we need to add to our fetch request.
223
- // const headers = new Headers({
224
- // 'Accept': 'application/vnd.github+json',
225
- // 'X-GitHub-Api-Version': '2022-11-28',
226
- // });
227
-
228
- // Since we are getting cors errors,
229
- // const result = await fetch(selectedFirmware.url, {
230
- // headers:{
231
- // // 'Accept': 'application/vnd.github+json',
232
- // 'Accept': 'application/octet-stream',
233
- // 'X-GitHub-Api-Version': '2022-11-28',
234
- // // 'Authorization': `Bearer ${import.meta.env.VITE_GITHUB_TOKEN}` // Use your GitHub token here.
235
- // }
236
- // });
237
-
238
- // console.log('Result:', result);
239
-
240
- // // Now we check the result to see if it's ok and then we can actually read from the body.
241
- // if (!result.ok) {
242
- // console.log("Error fetching firmware:", result.status, result.statusText);
243
- // }
244
-
245
- // // stream the response
246
- // const reader = result.body?.getReader();
247
- // if (!reader) {
248
- // throw new Error('Failed to get reader from response body.');
249
- // }
250
-
251
- // let receivedLength = 0; // received bytes
252
- // const chunks: Uint8Array[] = []; // chunks of received data
253
-
254
- // while (true) {
255
- // const { done, value } = await reader.read();
256
- // if (done) {
257
- // break;
258
- // }
259
- // chunks.push(value);
260
- // receivedLength += value.length;
261
- // console.log(`Received ${receivedLength} bytes`);
262
- // }
263
-
264
- // console.log('All chunks received:', chunks);
265
-
266
- // // Combine all chunks into a single Uint8Array
267
- // const chunksAll = new Uint8Array(receivedLength);
268
- // let position = 0;
269
- // for (const chunk of chunks) {
270
- // chunksAll.set(chunk, position); // copy chunk to the final array
271
- // position += chunk.length; // update position
272
- // }
273
- // console.log('All chunks combined:', chunksAll);
274
-
275
-
276
- // // Convert the Uint8Array to a string
277
- // const firmwareString = Array.from(chunksAll)
278
- // .map(byte => String.fromCharCode(byte))
279
- // .join('');
280
-
281
- // console.log('Firmware string:', firmwareString);
282
-
283
- // throw new Error('Purposeful error out during testing.'); // TODO: Remove this line when done testing.
284
-
285
202
if ( ! result . ok ) {
286
203
console . log ( "Error fetching firmware:" , result . status , result . statusText ) ;
287
204
throw new Error ( `Failed to fetch firmware: ${ result . status } ${ result . statusText } ` ) ;
288
205
}
289
206
290
- this . firmwareBlob = await result . blob ( ) ;
291
- const uint8Array = new Uint8Array ( await this . firmwareBlob . arrayBuffer ( ) ) ;
292
- this . firmwareString = Array . from ( uint8Array )
207
+ const firmwareData = await this . unzipStreamToVariable ( result . body ! ) ;
208
+
209
+ const firmwareDataMP = firmwareData [ 'micropython.bin' ] ;
210
+
211
+ this . firmwareString = Array . from ( firmwareDataMP )
293
212
. map ( byte => String . fromCharCode ( byte ) )
294
213
. join ( '' ) ;
214
+
215
+ // Log the raw firmware data for debugging.
216
+ console . log ( 'Raw firmware data:' , this . firmwareString ) ;
217
+
218
+ // this.firmwareBlob = await result.blob();
219
+ // const uint8Array = new Uint8Array(await this.firmwareBlob.arrayBuffer());
220
+ // this.firmwareString = Array.from(uint8Array)
221
+ // .map(byte => String.fromCharCode(byte))
222
+ // .join('');
295
223
296
224
console . log ( 'Downloaded SFE FIRMWARE. Firmware string size:' , this . firmwareString . length ) ;
297
225
return this . firmwareString ;
0 commit comments