Salve, compagni. Nei miei server di gioco è fantastico è attivo dal 2006 e nel corso degli anni di amministrazione ho accumulato molti config e template. Ho lodato molto nginx e in qualche modo ho iniziato anche un hub nginx su Habr, giusto per dire.
Gli amici mi hanno chiesto di allestire un farm di sviluppo e, invece di portare loro i miei template specifici, ho pensato a un progetto interessante , che distribuisce i config in modo ordinato e prepara tutto per lets encrypt, e così via. Ho pensato, perché no? Tuttavia, mi infastidiva il fatto che nginxconfig mi offrisse di scaricare un archivio zip nel browser, senza permettermi di trasferirlo direttamente sul server tramite wget/fetch/curl. Che assurdità, perché dovrebbe servirmi nel browser? Ne ho bisogno sul server dalla console. Infuriato, sono andato su GitHub per esaminare le viscere del progetto, il che ha portato a un fork e, di conseguenza, a una pull request. Di cui non avrei scritto se non fosse stato interessante 😉
Certo, prima di mettere mano al codice sorgente, ho controllato da dove Chrome scaricava l'archivio zip generato con i config, e lì mi aspettava un indirizzo che iniziava con «blob:», eccoci. Era chiaro che il servizio non generava nulla, in effetti era tutto gestito da javascript. In effetti, l'archivio zip viene generato dal client, dal browser, da javascript. Cioè, la bellezza è che il progetto può essere semplicemente salvato come pagina HTML, caricato su un qualsiasi e funzionerà :) È una soluzione molto divertente e interessante, tuttavia, è terribilmente scomoda per la configurazione dei server, proprio per ciò per cui è stato creato questo progetto. Scaricare un archivio generato attraverso il browser e poi trasferirlo sul server usando nc… nel 2019? Ho deciso di trovare un modo per scaricare direttamente il config sul server.
Dopo aver fatto il fork del progetto, ho iniziato a pensare alle mie opzioni. La sfida era complicata dal fatto che non volevo discostarmi dalla condizione che il progetto dovesse rimanere un puro front-end, senza alcun back-end. Certo, la soluzione più semplice sarebbe stata quella di utilizzare nodejs e costringerlo a generare l'archivio con i config tramite link diretti.
In effetti, le opzioni non erano molte. Piuttosto, mi è venuta in mente solo una. Dobbiamo configurare i config e ottenere un link che possiamo copiare nella console del server per ricevere l'archivio zip.
Alcuni file di testo nell'archivio zip ricevuto pesavano davvero poco, solo alcuni kilobyte. La soluzione ovvia era ottenere una stringa base64 dall'archivio zip generato e metterla negli appunti, mentre sul server tramite il comando nel terminale
echo 'base64string' | base64 --decode > config.zipavremmo potuto creare proprio quel file zip.
era scritto in AngularJS, non riesco neanche a immaginare quanti chilometri di codice sarebbero stati necessari se l'autore non avesse scelto un framework js reattivo. Ma immagino perfettamente quanto sarebbe stato più semplice e bello realizzare tutto ciò in VueJS, anche se questa è un'altra storia.
Nei sorgenti del progetto vediamo il metodo di generazione dell'archivio zip:
$scope.downloadZip = function() {
var zip = new JSZip();
var sourceCodes = $window.document.querySelectorAll('main .file .code.source');
for (var i = 0; i < sourceCodes.length; i++) {
var sourceCode = sourceCodes[i];
var name = sourceCode.dataset.filename;
var content = sourceCode.children[0].children[0].innerText;
if (!$scope.isSymlink() && name.match(/^sites-available\/\/)) {
name = name.replace(/^sites-available\/\/, 'sites-enabled/');
}
zip.file(name, content);
if (name.match(/^sites-available\/\/)) {
zip.file(name.replace(/^sites-available\/\/, 'sites-enabled\/'), '..\/ ' + name, {
unixPermissions: parseInt('120755', 8),
});
}
}
zip.generateAsync({
type: 'blob',
platform: 'UNIX',
}).then(function(content) {
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
});
gtag('event', $scope.getDomains().join(','), {
event_category: 'download_zip',
});
};
è tutto abbastanza semplice, grazie alla libreria viene creato un zip in cui sono inseriti i file di configurazione. Dopo la creazione dell'archivio zip, js lo passa al browser usando la libreria :
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
dove content è l'oggetto blob dell'archivio zip ricevuto.
Ok, tutto ciò che dovevo fare era aggiungere un altro pulsante accanto e, al suo clic, non salvare l'archivio zip ricevuto nel browser, ma ottenere il codice base64 da esso. Dopo averci lavorato un po', ho ottenuto 2 metodi, invece di uno solo downloadZip:
$scope.downloadZip = function() {
generateZip(function (content) {
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
});
gtag('event', $scope.getDomains().join(','), {
event_category: 'download_zip',
});
};
$scope.downloadBase64 = function() {
generateZip(function (content) {
var reader = new FileReader();
reader.readAsDataURL(content);
reader.onloadend = function() {
var base64 = reader.result.replace(/^data:.+;base64,/, '');
// nella variabile base64 c'è proprio l'archivio zip di cui ho bisogno sotto forma di stringa base64
}
});
gtag('event', $scope.getDomains().join(','), {
event_category: 'download_base64',
});
};
Come avete notato, ho spostato la generazione del file zip in un metodo privato chiamato generateZip, e dato che si tratta di AngularJS, e l'autore utilizza i callback, non ho implementato questa funzionalità tramite le promesse. downloadZip continua a utilizzare saveAs, mentre downloadBase64 fa qualcosa di diverso. Creiamo un oggetto FileReader, arrivato con l'html5, e già piuttosto pronto per l'uso. Questo, a suo tempo, è capace di trasformare un blob in una stringa base64, precisamente crea una stringa DataURL, ma non è così rilevante per noi, dato che il DataURL contiene esattamente ciò di cui abbiamo bisogno. Bingo, un piccolo grattacapo mi aspettava nel tentativo di mettere tutto questo negli appunti. L'autore ha utilizzato nella sua progettazione una libreria , che consente di lavorare con gli appunti senza oggetti flash, basandosi sul testo selezionato. Inizialmente, avevo deciso di mettere il mio base64 in un elemento con display:none;, ma in quel modo non riuscivo a copiarlo negli appunti, poiché non si crea alcuna selezione. Quindi, invece di display:none;, ho impostato
position: absolute;
z-index: -1;
opacity: 0;
il che mi ha permesso di nascondere l'elemento dalla vista, pur mantenendolo effettivamente sulla pagina. Voilà, compito completato, quando premi il mio pulsante, la stringa risultante veniva copiata negli appunti come:
echo 'base64string' | base64 --decode > config.zipche semplicemente incollavo nella console del server e ricevevo immediatamente un file zip con tutte le configurazioni.
E, naturalmente, ho inviato una pull request all'autore, dato che il progetto è attivo e vive, mi piacerebbe vedere anche gli aggiornamenti dell'autore e avere il mio pulsante ) Per chi fosse interessato, ecco del progetto e il link , dove puoi vedere ciò che ho corretto/aggiunto.
Buona sviluppo a tutti )
Fonte: habr.com
