Salve, compagni. Sui miei server di battaglia gira un ottimo dal 2006 e nel corso degli anni di amministrazione ho accumulato molti config e template. Ho sempre lodato nginx e in qualche modo ho finito per fondare anche il hub nginx su Хабр, parlando delle mie esperienze m/
Gli amici mi hanno chiesto di creare una farm per sviluppatori e invece di portare i miei template specifici, ho ricordato un progetto interessante , che organizza i config e prepara tutto per Let's Encrypt e così via. E ho pensato, perché no? Tuttavia, mi dava fastidio il fatto che nginxconfig mi chiedesse di scaricare un archivio zip nel browser, senza permettermi di trasferirlo subito sul server tramite wget/fetch/curl. Che assurdità, perché dovrei averlo nel browser? Ne ho bisogno sul server dalla console. In preda alla frustrazione, sono andato su GitHub per vedere le entra, il che ha portato a un fork e, di conseguenza, a un pull request. Non ne avrei scritto se non fosse stato interessante 😉
Certo, prima di immergermi nei sorgenti, ho controllato da dove Chrome estraesse l'archivio zip generato con le configurazioni, e lì mi aspettava un indirizzo che iniziava con «blob:», oppla. È diventato chiaro che, in sostanza, il servizio non genera nulla, tutto questo viene fatto da JavaScript. Infatti, l'archivio zip viene generato dal client stesso, dal browser, da JavaScript. Quindi, la bellezza è che il progetto può essere semplicemente salvato come pagina HTML, caricato su qualche e funzionerà ) È una soluzione molto divertente e interessante, tuttavia, è estremamente scomoda per la configurazione dei server, proprio per lo scopo per cui questo progetto è stato creato. Scaricare l'archivio generato tramite il browser e poi trasferirlo sul server usando nc... nel 2019? Mi sono posto l'obiettivo di trovare un modo per caricare la configurazione ottenuta direttamente sul server.
Fatto un fork del progetto, ho cominciato a pensare a quali opzioni avessi. La sfida si complicava perchè non volevo deviare dalla condizione che il progetto dovesse rimanere un front-end pulito, senza alcun back-end. Certo, la soluzione più semplice sarebbe stata tirare dentro Node.js e costringerlo a generare l'archivio con le configurazioni tramite link diretti.
Le opzioni, in effetti, erano poche. Anzi, mi è venuta in mente solo una. Dobbiamo configurare i file e ottenere il link che possiamo copiare nella console del server per ottenere l'archivio zip.
Alcuni file di testo nell'archivio zip risultante pesavano davvero poco, solo qualche kilobyte. Una soluzione ovvia era ottenere una stringa base64 dall'archivio zip generato e inserirla negli appunti, mentre sul server con il comando nella console
echo 'base64string' | base64 --decode > config.zipavremmo potuto creare proprio questo 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. Posso però immaginare quanto sarebbe stato più semplice e bello realizzare tutto ciò con VueJS, anche se questa è un'altra storia.
Nei sorgenti del progetto vediamo il metodo per generare l'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 si crea un zip, dove vengono inseriti i file di configurazione. Dopo la creazione dell'archivio zip, il js lo passa al browser tramite la libreria :
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
dove content è l'oggetto blob risultante dall'archivio zip.
Ok, tutto quello che dovevo fare era aggiungere un altro pulsante accanto e, quando viene premuto, non salvare l'archivio zip nel browser, ma ottenere il codice base64. Magari lavorando su questo, ho ottenuto 2 metodi, invece di uno, 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 abbiamo il file zip necessario come stringa base64
}
});
gtag('event', $scope.getDomains().join(','), {
event_category: 'download_base64',
});
};
Come avrete notato, ho spostato la generazione del file zip vero e proprio in un metodo privato generateZip. Poiché si tratta di AngularJS, e l'autore stesso utilizza i callback, non ho implementato questa funzione tramite le promesse. downloadZip continua a utilizzare saveAs, mentre downloadBase64 fa qualcosa di leggermente diverso. Creiamo un oggetto FileReader, introdotto con HTML5 e già utilizzabile. Questo oggetto è in grado, nel suo piccolo, di convertire un blob in una stringa base64, più precisamente crea una stringa DataURL, ma per noi non è così importante, poiché il DataURL contiene proprio ciò di cui abbiamo bisogno. Bingo, una piccola complicazione mi aspettava mentre cercavo di mettere tutto questo negli appunti. L'autore ha usato nel progetto la libreria , che consente di lavorare con il clipboard senza oggetti flash, basato sul testo selezionato. Inizialmente ho deciso di inserire il mio base64 in un elemento con display:none;, ma in tal caso non riuscivo a copiarlo negli appunti, poiché non si verificava la selezione. Così, invece di display:none;, ho realizzato
position: absolute;
z-index: -1;
opacity: 0;
, il che mi ha permesso di nascondere l'elemento dalla vista e, di fatto, lasciarlo sulla pagina. Voilà, compito riuscito, cliccando sul mio pulsante, la stringa veniva copiata negli appunti:
echo 'base64string' | base64 --decode > config.zip, che semplicemente incollavo nella console del server e ricevevo immediatamente un archivio zip con tutte le configurazioni.
E, naturalmente, ho inserito un pull request all'autore, poiché il progetto è attivo e vivo, mi piacerebbe vedere anche gli aggiornamenti dell'autore e avere il mio pulsante) A chi è interessato, ecco del progetto e il , dove si può vedere cosa ho corretto/aggiunto.
A tutti, buona programmazione )
Fonte: habr.com
