Krijimi i konfigurimeve për nginx, historia e një pull request

Përshëndetje, shokë. Në serverat e mi të luftës funksionon mjaft mirë nginx që nga viti 2006 dhe gjatë viteve të administrimit kam grumbulluar shumë konfiguracione dhe shabllone. Kam lavdëruar shumë nginx, dhe ndodhi që madje unë kam themeluar edhe një hub nginx në habrë, shfaqje m/
Mikpritësit e mi më kërkuan të ngrija një fermë zhvillimi dhe, në vend që t'u çoja atyre shabllonet e mia specifike, më erdhi në mendje një projekt interesant nginxconfig.io, i cili organizon konfigurimet dhe përgatit gjithçka për lets encrypt, etj. Mendova, pse jo? Megjithatë, më bezdiste fakti se nginxconfig më ofronte të shkarkoja një arkiv zip në shfletues, duke mos më lejuar ta shkarkoja drejtpërdrejt në server me wget/fetch/curl. Çfarë marrëzie, pse e kam në shfletues, më nevojitet në server nga konsola. Duke u zemëruar, hyra në github për të parë brendësinë e projektit, çka solli në forkimin e tij dhe, si pasojë, në një pull request. Për të cilin nuk do të kisha shkruajtur, nëse nuk do të ishte interesante 😉

Krijimi i konfigurimeve për nginx, historia e një pull request

Sigurisht, para se të gërmoja në kod, shikova nga ku chrome merrte arkivin zip të gjeneruar me konfigurimet, dhe aty e gjeta një adresë që fillonte me "blob:", oho. Ishte e qartë që shërbimi nuk gjeneron asgjë, për faktin që gjithçka e bën javascripti. Në të vërtetë, arkivi zip gjenerohet nga klienti, shfletuesi, javascript. Pra, bukuria e saj është se projekti nginxconfig.io mund të ruhet thjesht si një faqe html, të ngarkohet në ndonjë narod.ru dhe do të funksionojë :) Ky është një zgjidhje shumë qesharake e interesante, megjithatë, është jashtëzakonisht e papërshtatshme për konfigurimin e serverëve, pikërisht për atë arsye për të cilën është krijuar ky projekt. Të shkarkosh arkivin e gjeneruar përmes shfletuesit dhe pastaj ta kalosh atë në server me nc... në vitin 2019? Vura përpara vetes një objektiv për të gjetur një mënyrë për të shkarkuar konfigurimin e marrë direkt në server.
Duke bërë fork të projektit, fillova të mendoj çfarë opsionesh kisha. Problemi u komplikua nga fakti se nuk doja të largohem nga kushti që projekti duhet të mbetet një front-end i pastruar, pa ndonjë back-end. Sigurisht, zgjidhja më e thjeshtë do të ishte të tërhiqja nodejs dhe ta detyroja atë të gjeneronte arkivin me konfigurimet përmes lidhjeve direkte.
Opsionet, në të vërtetë, nuk ishin shumë. Më saktë, në mendje më erdhi vetëm një. Ne duhet të konfigurojmë konfigurimet dhe të marrim një lidhje, e cila mund ta kopjojmë në konsolën e serverit, për të marrë arkivin zip.
Disa shumë skedarë tekstualë në arkivin zip të përftuar kishin peshë të vogël, vetëm disa kilobajtë. Zgjidhja e dukshme ishte të merrnim një varg base64 nga arkivi zip i gjeneruar dhe ta vendosnim atë në memorje, ndërsa në server me komandën në konsolë

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

ne mund të krijonim këtë arkiv zip.

nginxconfig.io ishte shkruar në AngularJS, madje nuk e imagjinoj se sa kilometra kodi do të ishin kërkuar nëse autori nuk do të kishte zgjedhur një kornizë reaktive js. Por e imagjinoj shkurt, sa më e lehtë dhe më elegante do të ishte realizimi i gjithçkaje me VueJS, megjithatë, kjo është një temë krejtësisht tjetër.
Në burimet e projektit shohim metodën e gjenerimit të arkivit 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',
	});
};

gjitha janë mjaft të thjeshta, me ndihmën e bibliotekës jszip krijohet zip, ku vendosen skedarët e konfigurimeve. Pas krijimit të arkivit zip, js e ushqen atë shfletuesit me ndihmën e bibliotekës FileSaver.js:

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

ku përmbajtja, është objekti blob i marrë nga arkivi zip.

Ok, gjithçka që duhej të bëja, ishte të shtoja një buton tjetër ngjitur dhe kur të shtypja atë, të mos ruaja arkivin zip të marrë në shfletues, por të merrja kodin base64 prej tij. Pasi bëra disa manipulime, arrita në 2 metoda, në vend të njërit 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\/, '');
			// në variablin base64 është pikërisht arkivi zip që më nevojitet në formën e vargut base64
		}
	});

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

Si keni mundur të vini re, gjenerimin e arkivës zip e kam futur në një metodë private generateZip, dhe meqë është AngularJS, po ashtu autori përqendrohet te callback-et, nuk e realizova atë me premtimet. downloadZip vazhdon të bëjë saveAs, ndërsa downloadBase64 bëntë diçka tjetër. Ne krijojmë një objekt FileReader, i cili na ka ardhur në html5 dhe është plotësisht i disponueshëm për përdorim. Ai, në kohën e tij, di të bëjë një varg base64 nga blob, më saktësisht ai krijon një varg DataURL, por kjo nuk është kaq e rëndësishme për ne, pasi DataURL përmban pikërisht atë që na nevojitet. Bingo, një e vogël pengesë më priste gjatë përpjekjes për ta vendosur këtë në bufer. Autori përdori në projektin e tij bibliotekën clipboardjs, e cila lejon të punosh me buferin e skëmbimit pa objekte flash, mbi tekstin e theksuar. Fillimisht, unë vendosa të vendosja base64-në time në një element me display:none;, por në atë rast nuk arrija ta vendosja në buferin e skëmbimit, pasi nuk ndodhte thekësim. Prandaj, në vend të display:none; e bëra

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

çka më lejoj të fsheh elementin nga syri dhe në fakt ta lë atë në faqe. Voilà, detyra është përmbushur, kur klikoja butonin tim, një varg dukej si:

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

e cila unë thjesht e kopjoja në konsolën në server dhe menjëherë merrja një arkiv zip me të gjitha konfigurimet.
Po ashtu, sigurisht, dërgova një pull request autorit, pasi projekti është aktiv dhe i gjallë, më pëlqen të shoh përditësime nga autori dhe të kem butonin tim ) Për ata që janë të interesuar, ja fork-u im i projektit dhe vetë pull request, ku mund të shihni çfarë kam korrigjuar/shtuar.
Të gjithë zhvillim të këndshëm )

Krijimi i konfigurimeve për nginx, historia e një pull request

Burimi: habr.com

Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS 🔥 Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS | ProHoster