• Non ci sono risultati.

3.4 Il codice - Lato server

3.4.9 serverFota.js

cui viene effettuata la richiesta di generazione e sull’indirizzo ethernet del dispositivo in cui è stato generato. Questa associazione di valori rende de facto impossibile avere due nomi identici. [27]

Come nel caso del service middleware dell’API getAvailableFirmware, an-che qui è stato inserito un costruttore an-che setti un parametro containerClient per l’oggetto omonimo passato in ingresso. Il metodo asincrono upload pro-cessa la richiesta ed in particolare salva in tre costanti le informazioni rice-vute riguardanti il nome del file, la classe del dispositivo e la data di rilascio dell’aggiornamento. Per rendere il nome del file univoco all’interno dell’intero sistema, viene accodato al nome del file comunicato un ID univoco generato con la libreria uuidv1. Si procede dunque a spostare il file ricevuto in un path locale per preparare l’upload al blob storage: al rigo 39 si richiama il metodo createBlob a cui vengono passati l’attributo containerClient, il nome del file univoco e il path locale in cui è salvato il file. Il metodo ritornerà, come già discusso nella sezione dedicata, l’URL in cui è stata creata la nuova risorsa. Il nuovo URL viene quindi passato al metodo newFirmware che lo andrà a caricare nel database assieme alle altre informazioni sul nuovo codice.

Viene quindi stampato un messaggio a video in cui si segnala la creazione della risorsa all’URL indicato e si invia di risposta al client un codice 201, Created.

3.4 – Il codice - Lato server

7 c o n s t r e g i s t r y D e v i c e S v c = r e q u i r e (’ ./ S e r v i c e / r e g i s t r y D e v i c e S v c . js ’) ;

8 c o n s t i n i t i a l i z e D e v i c e s V a l = r e q u i r e (’ ./ V a l i d a t o r s / i n i t i a l i z e D e v i c e s V a l . js ’) ;

9 c o n s t i n i t i a l i z e D e v i c e s S v c = r e q u i r e (’ ./ S e r v i c e / i n i t i a l i z e D e v i c e s S v c . js ’) ;

10 c o n s t g e t A v a i l a b l e F i r m w a r e S v c = r e q u i r e (’ ./ S e r v i c e / g e t A v a i l a b l e F i r m w a r e S v c . js ’) ;

11 c o n s t g e t A v a i l a b l e F i r m w a r e V a l = r e q u i r e (’ ./ V a l i d a t o r s / g e t A v a i l a b l e F i r m w a r e V a l . js ’) ;

12 c o n s t s a v e N e w F i r m w a r e S v c = r e q u i r e (’ ./ S e r v i c e / s a v e N e w F i r m w a r e S v c . js ’) ;

13 c o n s t s a v e N e w F i r m w a r e V a l = r e q u i r e (’ ./ V a l i d a t o r s / s a v e N e w F i r m w a r e V a l . js ’) ;

14 15 16

17 // E x e c u t e s e r v e r 18 s e r v e r () ;

19

20 a s y n c f u n c t i o n s e r v e r () { 21 try {

22 // I n i t i a l i z e the c o n t a i n e r in the b l o b s t o r a g e 23 // If it not a l r e a d y e x i s t s

24 var c o n t a i n e r C l i e n t = a w a i t b l o b . c r e a t e C o n t a i n e r ( c o n f i g . C O N T A I N E R _ N A M E ) ;

25 // C r e a t e the s e r v i c e and v a l i d a t o r s for 26 // The A P I s

27 t h i s. s e r v e r = r e s t i f y . c r e a t e S e r v e r ({ n a m e : ’ f o t a ’}) ; 28 t h i s. r e g i s t r y D e v i c e V a l = new r e g i s t r y D e v i c e V a l () ; 29 t h i s. r e g i s t r y D e v i c e S v c = new r e g i s t r y D e v i c e S v c () ;

30 t h i s. i n i t i a l i z e D e v i c e s V a l = new i n i t i a l i z e D e v i c e s V a l () ; 31 t h i s. i n i t i a l i z e D e v i c e s S v c = new i n i t i a l i z e D e v i c e s S v c () ; 32 t h i s. s a v e N e w F i r m w a r e S v c = new s a v e N e w F i r m w a r e S v c (

c o n t a i n e r C l i e n t ) ;

33 t h i s. s a v e N e w F i r m w a r e V a l = new s a v e N e w F i r m w a r e V a l () ;

34 t h i s. g e t A v a i l a b l e F i r m w a r e S v c = new g e t A v a i l a b l e F i r m w a r e S v c ( c o n t a i n e r C l i e n t ) ;

35 t h i s. g e t A v a i l a b l e F i r m w a r e V a l = new g e t A v a i l a b l e F i r m w a r e V a l () ;

36

37 // M i d d l e w a r e s

38 t h i s. s e r v e r . use ( r e s t i f y . p l u g i n s . a c c e p t P a r s e r ([’ a p p l i c a t i o n / j s o n ’]) ) ;

39 t h i s. s e r v e r . use ( r e s t i f y . p l u g i n s . q u e r y P a r s e r () ) ; 40 t h i s. s e r v e r . use ( r e s t i f y . p l u g i n s . r e q u e s t L o g g e r () ) ;

41 t h i s. s e r v e r . use ( r e s t i f y . p l u g i n s . b o d y P a r s e r () ) ; 42

43 // P r e v e n t r e s p o n s e c a c h i n g

44 t h i s. s e r v e r . use (f u n c t i o n ( req , res , n e x t ) { 45 res . h e a d e r (’ Cache - C o n t r o l ’, ’ no - s t o r e ’) ; 46 res . h e a d e r (’ P r a g m a ’, ’ no - c a c h e ’) ;

47 r e t u r n n e x t () ; 48 }) ;

49

50 // L i s t e n to p o r t 3 0 0 0

51 t h i s. s e r v e r . l i s t e n ( c o n f i g . PORT , a s y n c f u n c t i o n() {

52 try {

53 c o n s o l e . log (’ S e r v e r is l i s t e n i n g at p o r t : ’ , c o n f i g . P O R T ) ;

54 }

55 c a t c h( err ) {

56 c o n s o l e . log ( c h a l k . red (’ U n e x p e c t e d e r r o r : ’ + err ) ) ;

57 }

58 }) ; 59

60 // D e v i c e n e e d s to r e g i s t e r to the iot hub API 61 t h i s. s e r v e r . p o s t (’ / r e g i s t r y D e v i c e ’,

62 a w a i t t h i s. r e g i s t r y D e v i c e V a l . r e g i s t r y , 63 a w a i t t h i s. r e g i s t r y D e v i c e S v c . r e g i s t r y ) ; 64

65 // New d e v i c e s a v a i l a b l e API

66 t h i s. s e r v e r . p o s t (’ / i n i t i a l i z e D e v i c e s ’, 67 a w a i t t h i s. i n i t i a l i z e D e v i c e s V a l . compile , 68 a w a i t t h i s. i n i t i a l i z e D e v i c e s S v c . c o m p i l e ) ; 69

70 // S a v e F i r m w a r e API

71 t h i s. s e r v e r . p o s t (’ / s a v e N e w F i r m w a r e ’, 72 a w a i t t h i s. s a v e N e w F i r m w a r e V a l . upload , 73 a w a i t t h i s. s a v e N e w F i r m w a r e S v c . u p l o a d ) ; 74

75 // Get the m o s t r e c e n t f i r m w a r e a v a i l a b l e API 76 t h i s. s e r v e r . get (’ / g e t A v a i l a b l e F i r m w a r e ’, 77 a w a i t t h i s. g e t A v a i l a b l e F i r m w a r e V a l . list , 78 a w a i t t h i s. g e t A v a i l a b l e F i r m w a r e S v c . l i s t ) ; 79

80 c o n s o l e . log (’ S e r v e r is r u n n i n g ’) ;

81 }

82 c a t c h( err ) {

83 c o n s o l e . log ( c h a l k . g r e e n B r i g h t (’ U n e x p e c t e d e r r o r in the s e r v e r : ’ + err . t o S t r i n g () ) ) ;

84 }

3.4 – Il codice - Lato server

85 }

Listing 3.13. Codice Javascript per il file serverFota.js

Oltre alla libreria restify, tra gli import si possono individuare il file di configurazione che è stato utilizzato anche per gli altri moduli, da cui si attingerà per prelevare il nome utilizzato per il contenitore sull’account di storage e la porta utilizzata per hostare la connessione, il file blob.js utilizzato per la creazione dell’oggetto contenitore, necessario per il service delle API getAvailableFirmware e saveNewFirmware, i quattro services ed i quattro validators delle API ed una libreria grafica chalk utilizzata per enfatizzare la scrittura dei messaggi a video all’interno del server.

Al rigo 17 avviene il lancio del server, ma si vuole prima mostrare la strut-tura interna definita alle righe successive. La funzione server viene dichiarata al rigo 19 in modo asincrono, così da poter eseguire altre funzioni asincrone al suo interno; la prima che si incontra è la createContainer a cui si passa il nome del contenitore e si avrà come ritorno l’oggetto contenitore associato.

Si passa dunque alla definizione delle proprietà del server (righe 26-34).

Attraverso il metodo di restify createServer, si restituisce un oggetto di tipo server con il nome passato come parametro al metodo (fota in questo caso);

inoltre si è impostato un attributo per ognuno dei services e validators andan-do a richiamare gli oggetti omonimi e instanzianandan-doli attraverso la keyword new. Per impostare gli altri middlewares necessari, si è utilizzato il metodo use (righe 37-40) dell’oggetto server che verranno attivati soltanto quando le richieste saranno indirizzate ad una route disponibile:

• restify.plugins.acceptParser(’application/json’) è il middleware che imposta l’accept header che indica al client che tipo di contenuto il server si aspetta dalla richiesta (in questo caso un tipo JSON).

• this.server.use (restify.plugins.queryParser()) permette di tradur-re una query indicata nella richiesta.

• restify.plugins.requestLogger() registra l’ID di ogni client che effetua una richiesta al server.

• restify.plugins.bodyParser() si occupa di leggere e tradurre automa-ticamente il body della richiesta ricevuta.

Alle righe 44-47 si è scelto di utilizzare un sistema non-cachable per pre-venire il salvataggio della risposta server nella cache del client; così facendo ogni nuova richiesta del client sarà scorrellata da quella precedente. Questo

fatto permette di soddisfare i requisiti RESTful e di non occupare cache nella memoria dei dispositivi, considerando la non critica frequenza degli aggiorna-menti e quindi delle loro richieste. Vengono utilizzati due header per settare queste impostazioni: Cache-Control e Pragma. Entrambe le impostazioni prevengono il salvataggio nella cache del client e la scelta di utilizzarne due è dovuta alla retrocompatibilità con protocolli HTTP più vecchi che supporta l’header Pragma.

Si procede al rigo 51 a richiamare il metodo listen del server sulla porta 3000 a cui il server rimarrà in ascolto fino all’arrivo di una richiesta da servire.

Si sono quindi create le route alle quali il server può rispondere andando ad impostare i metodi accettati per ogni route. Al rigo 61 si è costruita una route /registryDevice a cui un client può accedere con un metodo POST:

se il routing avviene con successo, la richiesta dovrà passare attraverso il validator dell’API, richiamata come attributo della route dell’oggetto server, attraverso il metodo registry. Il metodo omonimo del service lavorerà per servire la richiesta in caso la validazione sia andata a buon fine.

La route /initializeDevices viene costruita al rigo 66 attraverso un metodo POST dell’oggetto server: se il routing ha successo, il metodo compile del validator si occupa della validazione della richiesta. Se la validazione è andata a buon fine, il metodo omonimo del service servirà la richiesta.

Al rigo 71 si crea la route /saveNewFirmware, la quale accetta un metodo POST: in caso di successo del routing, il metodo upload del validator si occuperà della validazione della richiesta. Se la richiesta è valida, verrà servita dal metodo omonimo del service.

Al rigo 76 viene costruita la route per l’API /getAvailableFirmware attra-verso un metodo GET: anche in questo caso, se l’instradamento avviene in maniera corretta, la richiesta sarà analizzata dal metodo list del validator.

Se anche la validazione ha avuto successo, il metodo omonimo si occuperà di servire la richiesta.

Infine alle righe 80-83 si stampa a video un avviso di esecuzione del server e, in caso di criticità impreviste durante l’esecuzione, si gestiscono gli errori con un catch e si stampa a schermo il messaggio d’errore.

Documenti correlati