@@ -2,6 +2,7 @@ import { FirmwareOption } from '../constants'
22import { defaultFirmwareOptions } from '../constants'
33import { DeviceService } from './DeviceService' ;
44// const { Octokit } = require('@octokit/rest');
5+ import { unzipit } from 'unzipit' ;
56
67export class FirmwareService {
78 private firmwareString : string | null = null ;
@@ -16,15 +17,6 @@ export class FirmwareService {
1617 // Get the firmware options from GitHub (or local files).
1718 // Maybe we'll add an explicit button for updating the firmware options in the future...
1819 // 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);
2820
2921 // Initialize firmware options with defaultFirmwareOptions.
3022 this . firmwareOptions = defaultFirmwareOptions ;
@@ -36,6 +28,27 @@ export class FirmwareService {
3628 }
3729 }
3830
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+
3952 // We'll use this method to fetch the firmware options from GitHub.
4053 // We could alternatively use local files in ../binaries/ so we aren't sending a request to GitHub every time.
4154 private async reqFirmwareOptionsGitHub ( ) : Promise < Record < string , FirmwareOption > > {
@@ -67,25 +80,9 @@ export class FirmwareService {
6780 firmwareId = 'm-' + firmwareId . replace ( 'minimal-' , '' ) ;
6881 }
6982
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-
7883 //method 1: use the browser_download_url from the asset object.
7984 const firmwareUrl = asset . browser_download_url ;
8085
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-
8986 // log the asset object
9087 console . log ( 'Asset:' , asset ) ;
9188
@@ -189,6 +186,8 @@ export class FirmwareService {
189186 throw new Error ( `Invalid firmware selection or no URL for: ${ firmwareId } ` ) ;
190187 }
191188
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
192191 const cors_proxy = "https://corsproxy.io/?url=" ;
193192 console . log ( "Performing fetch for firmware:" , cors_proxy + selectedFirmware . url ) ;
194193
@@ -200,98 +199,27 @@ export class FirmwareService {
200199 } ,
201200 } ) ;
202201
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-
285202 if ( ! result . ok ) {
286203 console . log ( "Error fetching firmware:" , result . status , result . statusText ) ;
287204 throw new Error ( `Failed to fetch firmware: ${ result . status } ${ result . statusText } ` ) ;
288205 }
289206
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 )
293212 . map ( byte => String . fromCharCode ( byte ) )
294213 . 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('');
295223
296224 console . log ( 'Downloaded SFE FIRMWARE. Firmware string size:' , this . firmwareString . length ) ;
297225 return this . firmwareString ;
0 commit comments