1- import { injectable } from 'inversify' ;
1+ import { injectable , inject } from 'inversify' ;
22import * as createPaths from './create-paths' ;
3- import { posix , splitSketchPath } from './create-paths' ;
3+ import { posix } from './create-paths' ;
44import { AuthenticationClientService } from '../auth/authentication-client-service' ;
55import { ArduinoPreferences } from '../arduino-preferences' ;
6+ import { SketchCache } from '../widgets/cloud-sketchbook/cloud-sketch-cache' ;
67
78export interface ResponseResultProvider {
89 ( response : Response ) : Promise < any > ;
@@ -15,10 +16,11 @@ export namespace ResponseResultProvider {
1516
1617type ResourceType = 'f' | 'd' ;
1718
18- export let sketchCache : Create . Sketch [ ] = [ ] ;
19-
2019@injectable ( )
2120export class CreateApi {
21+ @inject ( SketchCache )
22+ protected readonly sketchCache : SketchCache ;
23+
2224 protected authenticationService : AuthenticationClientService ;
2325 protected arduinoPreferences : ArduinoPreferences ;
2426
@@ -32,48 +34,24 @@ export class CreateApi {
3234 return this ;
3335 }
3436
35- public sketchCompareByPath = ( param : string ) => {
36- return ( sketch : Create . Sketch ) => {
37- const [ , spath ] = splitSketchPath ( sketch . path ) ;
38- return param === spath ;
39- } ;
40- } ;
41-
42- async findSketchInCache (
43- compareFn : ( sketch : Create . Sketch ) => boolean ,
44- trustCache = true
45- ) : Promise < Create . Sketch | undefined > {
46- const sketch = sketchCache . find ( ( sketch ) => compareFn ( sketch ) ) ;
47- if ( trustCache ) {
48- return Promise . resolve ( sketch ) ;
49- }
50- return await this . sketch ( { id : sketch ?. id } ) ;
37+ public wipeCache ( ) : void {
38+ this . sketchCache . init ( ) ;
5139 }
5240
5341 getSketchSecretStat ( sketch : Create . Sketch ) : Create . Resource {
5442 return {
5543 href : `${ sketch . href } ${ posix . sep } ${ Create . arduino_secrets_file } ` ,
5644 modified_at : sketch . modified_at ,
45+ created_at : sketch . created_at ,
5746 name : `${ Create . arduino_secrets_file } ` ,
5847 path : `${ sketch . path } ${ posix . sep } ${ Create . arduino_secrets_file } ` ,
5948 mimetype : 'text/x-c++src; charset=utf-8' ,
6049 type : 'file' ,
61- sketchId : sketch . id ,
6250 } ;
6351 }
6452
65- async sketch ( opt : {
66- id ?: string ;
67- path ?: string ;
68- } ) : Promise < Create . Sketch | undefined > {
69- let url ;
70- if ( opt . id ) {
71- url = new URL ( `${ this . domain ( ) } /sketches/byID/${ opt . id } ` ) ;
72- } else if ( opt . path ) {
73- url = new URL ( `${ this . domain ( ) } /sketches/byPath${ opt . path } ` ) ;
74- } else {
75- return ;
76- }
53+ async sketch ( id : string ) : Promise < Create . Sketch | undefined > {
54+ const url = new URL ( `${ this . domain ( ) } /sketches/byID/${ id } ` ) ;
7755
7856 url . searchParams . set ( 'user_id' , 'me' ) ;
7957 const headers = await this . headers ( ) ;
@@ -92,7 +70,7 @@ export class CreateApi {
9270 method : 'GET' ,
9371 headers,
9472 } ) ;
95- sketchCache = result . sketches ;
73+ result . sketches . forEach ( ( sketch ) => this . sketchCache . addSketch ( sketch ) ) ;
9674 return result . sketches ;
9775 }
9876
@@ -118,7 +96,7 @@ export class CreateApi {
11896
11997 async readDirectory (
12098 posixPath : string ,
121- options : { recursive ?: boolean ; match ?: string ; secrets ?: boolean } = { }
99+ options : { recursive ?: boolean ; match ?: string } = { }
122100 ) : Promise < Create . Resource [ ] > {
123101 const url = new URL (
124102 `${ this . domain ( ) } /files/d/$HOME/sketches_v2${ posixPath } `
@@ -131,58 +109,21 @@ export class CreateApi {
131109 }
132110 const headers = await this . headers ( ) ;
133111
134- const sketchProm = options . secrets
135- ? this . sketches ( )
136- : Promise . resolve ( sketchCache ) ;
137-
138- return Promise . all ( [
139- this . run < Create . RawResource [ ] > ( url , {
140- method : 'GET' ,
141- headers,
142- } ) ,
143- sketchProm ,
144- ] )
145- . then ( async ( [ result , sketches ] ) => {
146- if ( options . secrets ) {
147- // for every sketch with secrets, create a fake arduino_secrets.h
148- result . forEach ( async ( res ) => {
149- if ( res . type !== 'sketch' ) {
150- return ;
151- }
152-
153- const [ , spath ] = createPaths . splitSketchPath ( res . path ) ;
154- const sketch = await this . findSketchInCache (
155- this . sketchCompareByPath ( spath )
156- ) ;
157- if ( sketch && sketch . secrets && sketch . secrets . length > 0 ) {
158- result . push ( this . getSketchSecretStat ( sketch ) ) ;
159- }
160- } ) ;
161-
162- if ( posixPath !== posix . sep ) {
163- const sketch = await this . findSketchInCache (
164- this . sketchCompareByPath ( posixPath )
165- ) ;
166- if ( sketch && sketch . secrets && sketch . secrets . length > 0 ) {
167- result . push ( this . getSketchSecretStat ( sketch ) ) ;
168- }
112+ return this . run < Create . RawResource [ ] > ( url , {
113+ method : 'GET' ,
114+ headers,
115+ } )
116+ . then ( async ( result ) => {
117+ // add arduino_secrets.h to the results, when reading a sketch main folder
118+ if ( posixPath . length && posixPath !== posix . sep ) {
119+ const sketch = this . sketchCache . getSketch ( posixPath ) ;
120+
121+ if ( sketch && sketch . secrets && sketch . secrets . length > 0 ) {
122+ result . push ( this . getSketchSecretStat ( sketch ) ) ;
169123 }
170124 }
171- const sketchesMap : Record < string , Create . Sketch > = sketches . reduce (
172- ( prev , curr ) => {
173- return { ...prev , [ curr . path ] : curr } ;
174- } ,
175- { }
176- ) ;
177125
178- // add the sketch id and isPublic to the resource
179- return result . map ( ( resource ) => {
180- return {
181- ...resource ,
182- sketchId : sketchesMap [ resource . path ] ?. id || '' ,
183- isPublic : sketchesMap [ resource . path ] ?. is_public || false ,
184- } ;
185- } ) ;
126+ return result ;
186127 } )
187128 . catch ( ( reason ) => {
188129 if ( reason ?. status === 404 ) return [ ] as Create . Resource [ ] ;
@@ -214,18 +155,16 @@ export class CreateApi {
214155
215156 let resources ;
216157 if ( basename === Create . arduino_secrets_file ) {
217- const sketch = await this . findSketchInCache (
218- this . sketchCompareByPath ( parentPosixPath )
219- ) ;
158+ const sketch = this . sketchCache . getSketch ( parentPosixPath ) ;
220159 resources = sketch ? [ this . getSketchSecretStat ( sketch ) ] : [ ] ;
221160 } else {
222161 resources = await this . readDirectory ( parentPosixPath , {
223162 match : basename ,
224163 } ) ;
225164 }
226-
227- resources . sort ( ( left , right ) => left . path . length - right . path . length ) ;
228- const resource = resources . find ( ( { name } ) => name === basename ) ;
165+ const resource = resources . find (
166+ ( { path } ) => createPaths . splitSketchPath ( path ) [ 1 ] === posixPath
167+ ) ;
229168 if ( ! resource ) {
230169 throw new CreateError ( `Not found: ${ posixPath } .` , 404 ) ;
231170 }
@@ -248,10 +187,7 @@ export class CreateApi {
248187 return data ;
249188 }
250189
251- const sketch = await this . findSketchInCache ( ( sketch ) => {
252- const [ , spath ] = splitSketchPath ( sketch . path ) ;
253- return spath === createPaths . parentPosix ( path ) ;
254- } , true ) ;
190+ const sketch = this . sketchCache . getSketch ( createPaths . parentPosix ( path ) ) ;
255191
256192 if (
257193 sketch &&
@@ -273,14 +209,25 @@ export class CreateApi {
273209
274210 if ( basename === Create . arduino_secrets_file ) {
275211 const parentPosixPath = createPaths . parentPosix ( posixPath ) ;
276- const sketch = await this . findSketchInCache (
277- this . sketchCompareByPath ( parentPosixPath ) ,
278- false
279- ) ;
212+
213+ //retrieve the sketch id from the cache
214+ const cacheSketch = this . sketchCache . getSketch ( parentPosixPath ) ;
215+ if ( ! cacheSketch ) {
216+ throw new Error ( `Unable to find sketch ${ parentPosixPath } in cache` ) ;
217+ }
218+
219+ // get a fresh copy of the sketch in order to guarantee fresh secrets
220+ const sketch = await this . sketch ( cacheSketch . id ) ;
221+ if ( ! sketch ) {
222+ throw new Error (
223+ `Unable to get a fresh copy of the sketch ${ cacheSketch . id } `
224+ ) ;
225+ }
226+ this . sketchCache . addSketch ( sketch ) ;
280227
281228 let file = '' ;
282229 if ( sketch && sketch . secrets ) {
283- for ( const item of sketch ? .secrets ) {
230+ for ( const item of sketch . secrets ) {
284231 file += `#define ${ item . name } "${ item . value } "\r\n` ;
285232 }
286233 }
@@ -310,9 +257,9 @@ export class CreateApi {
310257
311258 if ( basename === Create . arduino_secrets_file ) {
312259 const parentPosixPath = createPaths . parentPosix ( posixPath ) ;
313- const sketch = await this . findSketchInCache (
314- this . sketchCompareByPath ( parentPosixPath )
315- ) ;
260+
261+ const sketch = this . sketchCache . getSketch ( parentPosixPath ) ;
262+
316263 if ( sketch ) {
317264 const url = new URL ( `${ this . domain ( ) } /sketches/${ sketch . id } ` ) ;
318265 const headers = await this . headers ( ) ;
@@ -357,8 +304,7 @@ export class CreateApi {
357304 } ;
358305
359306 // replace the sketch in the cache, so other calls will not overwrite each other
360- sketchCache = sketchCache . filter ( ( skt ) => skt . id !== sketch . id ) ;
361- sketchCache . push ( { ...sketch , secrets } ) ;
307+ this . sketchCache . addSketch ( sketch ) ;
362308
363309 const init = {
364310 method : 'POST' ,
@@ -543,8 +489,9 @@ export namespace Create {
543489 */
544490 readonly path : string ;
545491 readonly type : ResourceType ;
546- readonly sketchId : string ;
492+ readonly sketchId ? : string ;
547493 readonly modified_at : string ; // As an ISO-8601 formatted string: `YYYY-MM-DDTHH:mm:ss.sssZ`
494+ readonly created_at : string ; // As an ISO-8601 formatted string: `YYYY-MM-DDTHH:mm:ss.sssZ`
548495 readonly children ?: number ; // For 'sketch' and 'folder' types.
549496 readonly size ?: number ; // For 'sketch' type only.
550497 readonly isPublic ?: boolean ; // For 'sketch' type only.
0 commit comments