Zdravím, súdruhovia. Na mojich serveroch mám skvelú hru. Funguje to od roku 2006 a za tie roky, čo som to spravoval, som nazhromaždil množstvo konfigurácií a šablón. Veľa som nginx chválil a nejako sa dokonca stalo, že som si na Habr spustil nginx hub, len tak pre parádu.
Priatelia ma požiadali, aby som pre nich založil vývojovú farmu, a namiesto toho, aby som im pretiahol svoje konkrétne šablóny, som si spomenul na zaujímavý projekt. , ktorý distribuuje konfigurácie po policiach a pripravuje všetko pre Let's Encrypt atď. Tak som si pomyslel, prečo nie? Otravovalo ma však, že nginxconfig ma vyzval na stiahnutie zip archívu v prehliadači bez toho, aby mi umožnil priamo ho nahrať na server cez wget/fetch/curl. Aký nezmysel! Načo ho potrebujem v prehliadači? Potrebujem ho na serveri z konzoly. Rozzúrený som išiel na GitHub pozrieť sa na vnútornosti projektu, čo viedlo k forku a v dôsledku toho k pull requestu. O čom by som nepísal, keby to nebolo zaujímavé 😉
Samozrejme, predtým, ako som sa ponoril do zdrojového kódu, som sa pozrel, kde Chrome sťahoval vygenerovaný zip archív s konfiguráciami, a tam na mňa čakala adresa začínajúca na „blob:“ – ups! Už teraz bolo jasné, že služba nič negenerovala; v skutočnosti to všetko robil JavaScript. V skutočnosti zip archív vygeneroval klient, prehliadač a samotný JavaScript. Krása projektu teda spočíva v tom, že Dá sa jednoducho uložiť ako HTML stránka a nahrať na nejakú webovú stránku. A bude to fungovať.) Toto je veľmi zábavné a zaujímavé riešenie, ale je neuveriteľne nepohodlné na nastavovanie serverov, čo je presne to, na čo bol tento projekt vytvorený. Stiahnutie vygenerovaného archívu pomocou prehliadača a jeho následný prenos na server pomocou nc... v roku 2019? Dal som si za úlohu nájsť spôsob, ako výslednú konfiguráciu priamo nahrať na server.
Po forkovaní projektu som začal zvažovať možnosti. Úlohu komplikovala skutočnosť, že som sa nechcel odchýliť od požiadavky, aby projekt zostal čisto front-endový, bez akéhokoľvek back-endu. Samozrejme, najjednoduchším riešením by bolo stiahnuť nodejs a nechať ich vygenerovať konfiguračný archív prostredníctvom priamych odkazov.
Vlastne nebolo veľa možností. Presnejšie povedané, napadla mi len jedna. Potrebujeme nakonfigurovať konfigurácie a získať odkaz, ktorý môžeme skopírovať do konzoly servera na vytvorenie zip archívu.
Niekoľko textových súborov vo výslednom zip archíve bolo veľmi malých, len niekoľko kilobajtov. Zjavným riešením bolo extrahovať reťazec base64 z vygenerovaného zip archívu a pomocou konzolového príkazu ho uložiť do vyrovnávacej pamäte na serveri.
echo 'base64string' | base64 --decode > config.zipMohli by sme vytvoriť tento veľmi podobný zip súbor.
Bolo to napísané v AngularJS a ani si neviem predstaviť, koľko kilometrov kódu by bolo potrebných, keby si autor nezvolil reaktívny JS framework. Viem si však jasne predstaviť, o koľko jednoduchšie a krajšie by to všetko mohlo byť implementované vo VueJS, aj keď to je úplne iná téma.
V zdrojoch projektu vidíme metódu na generovanie zip archívu:
$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',
});
};
Je to všetko celkom jednoduché, s pomocou knižnice Vytvorí sa zip súbor obsahujúci konfiguračné súbory. Po vytvorení zip archívu ho JS pomocou knižnice odošle do prehliadača. :
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
kde obsah je výsledný objekt blob zip archívu.
Dobre, stačilo pridať ďalšie tlačidlo do blízkosti a keď som naň klikol, namiesto uloženia výsledného zip archívu do prehliadača som z neho získal base64 kód. Po troche experimentovania som namiesto stiahnutiaZip získal dve metódy:
$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',
});
};
Ako ste si možno všimli, generovanie samotného zip archívu som presunul do súkromnej metódy generateZip. Keďže ide o AngularJS a samotný autor je vývojár s podporou callback, neimplementoval som to pomocou promisov. downloadZip stále používal na výstupe saveAs, zatiaľ čo downloadBase64 robil niečo trochu iné. Vytvárame objekt FileReader, čo je novinka v HTML5 a je celkom užitočná. na použitie. Ktorý vo svojej dobe dokázal previesť blob na reťazec base64, presnejšie povedané, previedol reťazec DataURL, ale to pre nás nie je až také dôležité, keďže DataURL obsahuje presne to, čo potrebujeme. Bingo, pri pokuse o vloženie tohto všetkého do buffera ma čakal malý zádrhel. Autor v projekte použil knižnicu. , čo umožňuje pracovať so schránkou bez flash objektov na základe vybratého textu. Spočiatku som sa rozhodol umiestniť svoj base64 do elementu s display:none;, ale v tomto prípade som ho nemohol umiestniť do schránky, pretože k žiadnemu výberu nedochádza. Preto som namiesto display:none; urobil
position: absolute;
z-index: -1;
opacity: 0;
To mi umožnilo skryť prvok a zároveň ho ponechať na stránke. Voilà, úloha bola dokončená. Keď som klikol na tlačidlo, do vyrovnávacej pamäte sa umiestnil reťazec podobný tomuto:
echo 'base64string' | base64 --decode > config.zipktorý som jednoducho vložil do konzoly na serveri a okamžite som dostal zip archív so všetkými konfiguráciami.
Samozrejme, autorovi som poslal pull request, keďže projekt je aktívny a živý, chcem vidieť aktualizácie od autora a mať vlastné tlačidlo) Pre každého, kto má záujem, tu je projekt a ja , kde si môžete pozrieť, čo som opravil/pridal.
Prajem všetkým šťastný vývoj!
Zdroj: hab.com
