Bonjour, camarades. Sur mes serveurs de production, un magnifique fonctionne depuis 2006 et au fil des ans, j'ai accumulĂ© de nombreuses configurations et modĂšles. J'ai beaucoup louĂ© nginx et il se trouve mĂȘme que j'ai créé le hub nginx sur Habr, un peu de frime m/
Des amis m'ont demandĂ© de mettre en place une ferme de dĂ©veloppement et au lieu de leur apporter mes modĂšles spĂ©cifiques, je me suis souvenu d'un projet intĂ©ressant , qui organise les configurations et prĂ©pare tout pour lets encrypt, etc. J'ai pensĂ©, pourquoi pas ? Cependant, j'Ă©tais irritĂ© par le fait que nginxconfig me propose de tĂ©lĂ©charger une archive zip dans le navigateur, me permettant pas de le transfĂ©rer directement sur le serveur par wget/fetch/curl. Quelle absurditĂ©, pourquoi en aurais-je besoin dans le navigateur ? Je en veux sur le serveur depuis la console. EnnuyĂ©, je suis allĂ© sur github pour voir les entrailles du projet, ce qui a conduit Ă son fork et, par consĂ©quent, Ă une demande de tirage. Dont je n'aurais pas parlĂ© s'il n'Ă©tait pas intĂ©ressant đ
Bien sĂ»r, avant de fouiller dans le code source, j'ai vĂ©rifiĂ© d'oĂč Chrome tĂ©lĂ©charge l'archive zip gĂ©nĂ©rĂ©e avec les configurations, et lĂ , j'ai trouvĂ© une adresse commençant par « blob: », Ă©tonnant. On a dĂ©jĂ compris que le service ne gĂ©nĂšre rien, en fait, tout cela est fait par js. En effet, c'est le client, le navigateur, javascript qui gĂ©nĂšre l'archive zip. En d'autres termes, la beautĂ© du projet peut simplement ĂȘtre sauvegardĂ©e comme une page html, tĂ©lĂ©chargĂ©e sur un site comme et elle fonctionnera ) C'est une solution trĂšs amusante et intĂ©ressante, cependant, elle est extrĂȘmement peu pratique pour configurer des serveurs, en fait, prĂ©cisĂ©ment pour cela que ce projet a Ă©tĂ© créé. TĂ©lĂ©charger l'archive gĂ©nĂ©rĂ©e via le navigateur, puis la transfĂ©rer sur le serveur avec nc... en 2019 ? Je me suis fixĂ© comme objectif de trouver un moyen de tĂ©lĂ©charger la configuration obtenue directement sur le serveur.
Ayant effectué un fork du projet, j'ai commencé à réfléchir aux options dont je disposais. La tùche était compliquée par le fait que je ne voulais pas m'éloigner de la condition que le projet doive rester un front-end pur, sans aucun back-end. Bien sûr, la solution la plus simple aurait été de tirer nodejs et de le forcer à générer l'archive de configurations à partir de liens directs.
Il n'y avait en fait pas beaucoup d'options. En fait, une seule m'est venue Ă l'esprit. Nous devons configurer les configurations et obtenir un lien que nous pourrions copier dans la console du serveur pour obtenir l'archive zip.
Quelques fichiers texte dans l'archive zip reçue pesaient trÚs peu, à peine quelques kilooctets. Une solution évidente était d'obtenir la chaßne base64 de l'archive zip générée et de la mettre dans le tampon, tandis que sur le serveur, la commande dans la console
echo 'base64string' | base64 --decode > config.zipnous pourrions créer ce fichier zip.
Ă©tait Ă©crit en AngularJS, je ne peux mĂȘme pas imaginer combien de kilomĂštres de code seraient nĂ©cessaires si l'auteur n'avait pas choisi un framework JS rĂ©actif. En revanche, je peux parfaitement imaginer Ă quel point tout cela aurait Ă©tĂ© plus simple et plus beau Ă rĂ©aliser sur VueJS, bien que ce soit lĂ un tout autre sujet.
Dans les sources du projet, nous voyons une méthode pour générer une archive 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',
});
};
tout est assez simple, avec l'aide de la bibliothĂšque un zip est créé, oĂč les fichiers de configuration sont placĂ©s. AprĂšs la crĂ©ation de l'archive zip, js l'envoie au navigateur grĂące Ă la bibliothĂšque :
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
oĂč content est l'objet blob obtenu de l'archive zip.
D'accord, tout ce que je devais faire était d'ajouter un autre bouton à cÎté et, en cliquant dessus, de ne pas enregistrer l'archive zip obtenue dans le navigateur, mais d'en obtenir le code base64. AprÚs avoir un peu bricolé, j'ai obtenu 2 méthodes, au lieu d'une, 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,/, '');
// dans la variable base64 se trouve exactement l'archive zip dont j'ai besoin sous forme de chaĂźne base64
}
});
gtag('event', $scope.getDomains().join(','), {
event_category: 'download_base64',
});
};
Comme vous avez pu le remarquer, la gĂ©nĂ©ration du fichier zip lui-mĂȘme a Ă©tĂ© dĂ©lĂ©guĂ©e Ă une mĂ©thode privĂ©e generateZip, et comme il s'agit d'AngularJS, et que l'auteur utilise des callbacks, je n'ai pas choisi de l'implĂ©menter via des promesses. La mĂ©thode downloadZip continue d'utiliser saveAs, tandis que downloadBase64 fait quelque chose d'un peu diffĂ©rent. Nous crĂ©ons un objet FileReader, arrivĂ© avec HTML5 et dĂ©jĂ tout Ă fait prĂȘt Ă ĂȘtre utilisĂ©. Celui-ci sait, Ă l'Ă©poque, transformer un blob en chaĂźne base64, en rĂ©alitĂ©, il gĂ©nĂšre une chaĂźne DataURL, mais cela n'a pas d'importance pour nous, car la DataURL contient exactement ce dont nous avons besoin. Bingo, j'ai rencontrĂ© une petite complexitĂ© en essayant de placer tout cela dans le presse-papiers. L'auteur a utilisĂ© dans le projet la bibliothĂšque , qui permet de travailler avec le presse-papiers sans objets Flash, en se basant sur le texte sĂ©lectionnĂ©. Au dĂ©part, j'avais dĂ©cidĂ© de mettre ma base64 dans un Ă©lĂ©ment avec display:none;, mais dans ce cas, je ne parvenais pas Ă y placer quoi que ce soit dans le presse-papiers, car il n'y avait pas de sĂ©lection. Ainsi, au lieu de display:none;, j'ai fait
position: absolute;
z-index: -1;
opacity: 0;
ce qui m'a permis de cacher l'élément des yeux tout en le laissant sur la page. Voilà , mission accomplie, lorsque j'appuyais sur mon bouton, la chaßne était placée dans le presse-papiers :
echo 'base64string' | base64 --decode > config.zipque je copiais simplement dans la console sur le serveur et je recevais immédiatement un fichier zip avec toutes les configurations.
Et bien sĂ»r, j'ai soumis une pull request Ă l'auteur, car le projet est actif et vivant, j'ai envie de voir les mises Ă jour de l'auteur et d'avoir mon petit bouton) Pour ceux qui sont intĂ©ressĂ©s, voici du projet et la , oĂč vous pouvez voir ce que j'ai corrigĂ©/ajoutĂ©.
à tous, bon développement )
Source : habr.com
