Hallo, Freunde. Auf meinen Produktionsservern lĂ€uft ein hervorragendes seit 2006 und wĂ€hrend meiner Jahre der Administration habe ich viele Konfigurationen und Vorlagen gesammelt. Ich habe nginx oft gelobt und irgendwie kam es dazu, dass ich sogar den nginx-Hub auf HabrĂ© gegrĂŒndet habe, ein bisschen Prahlerei m/
Freunde haben mich gebeten, ihnen eine Entwicklungsfarm aufzubauen, und anstatt meine spezifischen Vorlagen zu ihnen zu bringen, erinnerte ich mich an ein interessantes Projekt , das die Konfigurationen aufgliedert und alles fĂŒr Lets Encrypt vorbereitet usw. Ich dachte, warum nicht? Allerdings Ă€rgerte mich der Umstand, dass nginxconfig mir vorschlĂ€gt, das zip-Archiv im Browser herunterzuladen, ohne die Möglichkeit, es direkt auf den Server mit wget/fetch/curl zu ĂŒbertragen. Was fĂŒr ein Unsinn, warum brauche ich das im Browser, ich will es auf dem Server aus der Konsole. VerĂ€rgert sah ich mir auf GitHub die inneren AblĂ€ufe des Projekts an, was zu einem Fork und letztlich zu einem Pull Request fĂŒhrte. Ăber den ich nicht geschrieben hĂ€tte, hĂ€tte er nicht interessiert, đ
NatĂŒrlich schauten ich mir, bevor ich den Quellcode durchschaute, an, wo Chrome das generierte zip-Archiv mit Konfigurationen herunterlĂ€dt, und dort erwartete mich eine Adresse, die mit "blob:" begann, hoppla. Es wurde bereits klar, dass der Dienst anscheinend nichts generiert, sondern dass dies alles von js gemacht wird. TatsĂ€chlich generiert der Client selbst, also der Browser, das zip-Archiv durch JavaScript. Das bedeutet, dass das Projekt einfach als HTML-Seite gespeichert, auf irgendeinem hochgeladen werden kann und es trotzdem funktioniert ) Das ist eine sehr amĂŒsante und interessante Lösung, jedoch Ă€uĂerst unpraktisch fĂŒr die Serverkonfigurationen, fĂŒr die dieses Projekt tatsĂ€chlich geschaffen wurde. Ein generiertes Archiv mit dem Browser herunterzuladen und es dann ĂŒber nc auf den Server zu ĂŒbertragen... im Jahr 2019? Ich stellte mir die Aufgabe, einen Weg zu finden, die erhaltene Konfiguration direkt auf den Server herunterzuladen.
Nachdem ich das Projekt geforkt hatte, begann ich zu ĂŒberlegen, welche Optionen mir zur VerfĂŒgung standen. Die Herausforderung bestand darin, dass ich nicht vom Ziel abweichen wollte, dass das Projekt ein reines Front-End bleiben sollte, ohne jegliches Back-End. NatĂŒrlich wĂ€re die einfachste Lösung gewesen, nodejs zu nutzen und es dazu zu bringen, das Archiv mit den Konfigurationen ĂŒber direkte Links zu generieren.
Es gab nicht viele Optionen. Genauer gesagt, mir fiel nur eine ein. Wir mĂŒssen die Konfigurationen einrichten und einen Link erhalten, den wir in die Konsole des Servers kopieren können, um das zip-Archiv zu erhalten.
Einige Textdateien im erhaltenen Zip-Archiv wogen nur sehr wenig, buchstÀblich ein paar Kilobyte. Eine offensichtliche Lösung war, den Base64-String aus dem erzeugten Zip-Archiv zu erhalten und ihn in die Zwischenablage zu kopieren, wÀhrend auf dem Server mit einem Konsolenbefehl
echo 'base64string' | base64 --decode > config.zipwir diese Zip-Datei erstellen könnten.
wurde mit AngularJS geschrieben, ich kann mir nicht vorstellen, wie viele Kilometer Code erforderlich gewesen wĂ€ren, wenn der Autor sich nicht fĂŒr ein reaktives JS-Framework entschieden hĂ€tte. Ich kann mir jedoch gut vorstellen, wie viel einfacher und schöner das Ganze mit VueJS hĂ€tte umgesetzt werden können, obwohl das ein ganz anderes Thema ist.
Im Quellcode des Projekts sehen wir die Methode zur Generierung des Zip-Archivs:
$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',
});
};
alles ist ziemlich einfach, mit Hilfe der Bibliothek wird ein Zip erstellt, in das die Konfigurationsdateien gelegt werden. Nach der Erstellung des Zip-Archivs wird JS es dem Browser mit Hilfe der Bibliothek :
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
wobei content das erhaltene Blob-Objekt des Zip-Archivs ist.
Okay, alles, was ich tun musste, war, einen weiteren Button daneben hinzuzufĂŒgen und bei dessen BetĂ€tigung das erhaltene Zip-Archiv nicht im Browser zu speichern, sondern den Base64-Code daraus zu erhalten. Nach ein wenig TĂŒftelei erhielt ich 2 Methoden anstelle einer 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\/, '');
// in der Variable base64 befindet sich genau das Zip-Archiv, das ich in Form eines Base64-Strings benötige
}
});
gtag('event', $scope.getDomains().join(','), {
event_category: 'download_base64',
});
};
Wie Sie vielleicht bemerkt haben, habe ich die Generierung des eigentlichen Zip-Archivs in eine private Methode namens generateZip ausgelagert. Da dies AngularJS ist und der Autor Callback-Funktionen verwendet, habe ich mich entschieden, dies nicht mit Promises zu realisieren. downloadZip verwendet nach wie vor saveAs, wĂ€hrend downloadBase64 etwas anderes macht. Wir erstellen ein FileReader-Objekt, das uns in HTML5 zur VerfĂŒgung steht und bereits völlig ist. Dieses kann, damals, aus Blob eine Base64-Zeichenkette erzeugen; genauer gesagt, es erzeugt eine DataURL-Zeichenkette, aber das ist fĂŒr uns nicht so wichtig, da die DataURL genau das enthĂ€lt, was wir brauchen. Bingo, eine kleine HĂŒrde erwartete mich, als ich versuchte, all dies in die Zwischenablage zu legen. Der Autor verwendete in dem Projekt die Bibliothek , die es ermöglicht, ohne Flash-Objekte mit der Zwischenablage zu arbeiten, basierend auf dem markierten Text. UrsprĂŒnglich wollte ich meine Base64 in ein Element mit display:none; legen, aber in diesem Fall konnte ich es nicht in die Zwischenablage kopieren, da keine Markierung stattfindet. Daher habe ich anstelle von display:none; gemacht
position: absolute;
z-index: -1;
opacity: 0;
, was es mir ermöglichte, das Element unsichtbar zu machen und es faktisch auf der Seite zu belassen. VoilĂ , die Aufgabe war erledigt; beim Klicken auf meinen Button wurde eine Zeichenkette wie folgt in die Zwischenablage eingefĂŒgt:
echo 'base64string' | base64 --decode > config.zipdie ich einfach in die Konsole auf dem Server einfĂŒgte und sofort das Zip-Archiv mit allen Konfigurationen erhielt.
Und natĂŒrlich habe ich dem Autor einen Pull-Request geschickt, da das Projekt aktiv und lebendig ist; ich möchte sowohl die Updates des Autors sehen als auch meinen eigenen Button haben ) Wer interessiert ist, hier ist des Projekts und der , wo man sehen kann, was ich geĂ€ndert bzw. ergĂ€nzt habe.
Allen viel Erfolg bei der Entwicklung )
Quelle: habr.com
