Generarea de configurații pentru nginx, istoricul unei cereri de extragere

Salutări, tovarăși. Frumos pe serverele mele de luptă Nginx funcționează din 2006 și de-a lungul anilor de administrare am acumulat o mulțime de configurații și șabloane. Am lăudat foarte mult nginx și cumva s-a dovedit că am început chiar și un hub nginx pe hub, arată-l pe m/
Prietenii mi-au cerut să înființez o fermă de dezvoltare pentru ei și, în loc să le trag șabloanele mele specifice, mi-am amintit un proiect interesant nginxconfig.io, care împrăștie configurațiile pe rafturi și pregătește totul pentru lets encrypt etc. M-am gândit, de ce nu? Totuși, am fost înfuriat de faptul că nginxconfig îmi oferă să descarc arhiva zip în browser, fără a-mi permite să o încarc direct pe server folosind wget/fetch/curl. Ce prostii, de ce am nevoie de el in browser, am nevoie de el pe server din consola. Supărat, m-am dus la github să văd curajul proiectului, ceea ce a dus la bifurcația acestuia și, ca urmare, la o cerere de tragere. Despre care nu aș scrie dacă nu ar fi interesant 😉

Generarea de configurații pentru nginx, istoricul unei cereri de extragere

Desigur, înainte de a căuta în surse, m-am uitat la locul în care Chrome trage arhiva zip generată cu configurații și acolo mă aștepta o adresă care începe cu „blob:”, hopa. A devenit deja clar că serviciul nu generează nimic pe parcurs, de fapt, totul este făcut de js. Într-adevăr, arhiva zip este generată de client, browser și javascript în sine. Acestea. frumusețea este că proiectul nginxconfig.io poate fi pur și simplu salvat ca o pagină html, încărcat pe unii narod.ru și va funcționa) Aceasta este o soluție foarte amuzantă și interesantă, cu toate acestea, este teribil de incomod pentru configurarea serverelor, de fapt, exact pentru ceea ce a fost creat acest proiect. Descărcați arhiva generată cu un browser și apoi transferați-o pe server folosind nc... în 2019? Mi-am propus sarcina de a găsi o modalitate de a descărca configurația rezultată direct pe server.
După ce am întrerupt proiectul, am început să mă gândesc care sunt opțiunile mele. Sarcina a fost complicată de faptul că nu am vrut să mă abat de la condiția ca proiectul să rămână un front-end pur, fără niciun back-end. Desigur, cea mai simplă soluție ar fi să trageți nodejs și să îl forțați să genereze o arhivă cu configurații folosind link-uri directe.
De fapt, nu erau multe opțiuni. Mai exact, doar unul mi-a venit în minte. Trebuie să setăm configurațiile și să obținem un link pe care îl putem copia în consola serverului pentru a obține o arhivă zip.
Câteva fișiere text din arhiva zip rezultată cântăreau destul de mult, literalmente câțiva kiloocteți. Soluția evidentă a fost să obțineți șirul base64 din arhiva zip generată și să-l aruncați în buffer, în timp ce erați pe server cu comanda în consolă

echo 'base64string' | base64 --decode > config.zip

am putea crea același fișier zip.

nginxconfig.io a fost scris în AngularJS, nici nu îmi pot imagina ce kilometri de cod ar fi fost necesari dacă autorul nu ar fi ales un cadru js reactiv. Dar îmi pot imagina perfect cât de mult mai simple și mai frumoase ar putea fi implementate toate acestea în VueJS, deși acesta este un subiect complet diferit.
În resursele proiectului vedem o metodă de generare a unei arhive 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',
	});
};

totul este destul de simplu, folosind biblioteca jszip Este creat un zip unde sunt plasate fișierele de configurare. După crearea arhivei zip, js o trimite în browser folosind biblioteca FileSaver.js:

saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');

unde conținutul este obiectul blob rezultat al arhivei zip.

Ok, tot ce trebuia să fac a fost să adaug un alt buton lângă el și când am dat clic pe el, nu salvam arhiva zip rezultată în browser, ci obțineam codul base64 de la ea. După ce m-am jucat puțin, am primit 2 metode, în loc de un singur 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,/, '');
			// в переменной base64 как раз нужный мне zip архив в виде base64 строки
		}
	});

	gtag('event', $scope.getDomains().join(','), {
		event_category: 'download_base64',
	});
};

După cum probabil ați observat, am mutat generarea arhivei zip în metoda privată generateZip și așa mai departe. Acesta este AngularJS, iar autorul însuși se limitează la apeluri și nu a implementat-o ​​prin promisiuni. downloadZip încă a salvat ca rezultat, în timp ce downloadBase64 a făcut ceva ușor diferit. Creăm un obiect FileReader care a venit la noi în html5 și este deja destul disponibil pentru utilizare. Care, la un moment dat, poate face un șir de bază64 dintr-un blob, sau mai degrabă, face un șir DataURL, dar acest lucru nu este atât de important pentru noi, deoarece DataURL conține exact ceea ce avem nevoie. Bingo, mă aștepta o mică problemă când am încercat să pun toate astea în buffer. Autorul a folosit biblioteca în proiect clipboardjs, care vă permite să lucrați cu clipboard-ul fără obiecte flash, pe baza textului selectat. Inițial, am decis să-mi pun base64 într-un element cu display:none;, dar în acest caz nu l-am putut pune în clipboard deoarece nu are loc nicio separare. Prin urmare, în loc de afișare:none; am facut

position: absolute;
z-index: -1;
opacity: 0;

ceea ce mi-a permis atât să ascund elementul din vedere, cât și să îl las pe pagină. Voila, sarcina a fost finalizată, când am dat clic pe butonul meu, o linie ca aceasta a fost plasată în buffer:

echo 'base64string' | base64 --decode > config.zip

pe care pur și simplu l-am lipit în consola de pe server și am primit imediat o arhivă zip cu toate configurațiile.
Și, bineînțeles, i-am trimis un pull request autorului, pentru că... proiectul este activ și plin de viață, aș dori să văd actualizări de la autor și să am propriul meu buton) Pentru cei interesați, iată-l furculița mea proiect și eu însumi trageți cererea, unde puteți vedea ce am corectat/adăugat.
Dezvoltare fericită tuturor)

Generarea de configurații pentru nginx, istoricul unei cereri de extragere

Sursa: www.habr.com

Adauga un comentariu