Saludos, camaradas. En mis servidores de batalla, el hermoso
nginx ha estado girando desde 2006 y durante los años de su administración he acumulado muchas configuraciones y plantillas. Alabé mucho a nginx y de alguna manera resultó que incluso el centro nginx en Habr también me inició, presumiendo \ m /
Amigos me pidieron que criara una granja de desarrollo para ellos, y en lugar de arrastrarlos con mis plantillas específicas, recordé un interesante proyecto
nginxconfig.io , que dispersa las configuraciones y prepara todo para encriptar, etc. Pensé, ¿por qué no? Sin embargo, me enfureció el hecho de que nginxconfig me ofrece descargar el archivo zip en el navegador, lo que no me permite fusionarlo directamente en el servidor usando wget / fetch / curl. Qué tipo de tonterías, por qué lo necesito en el navegador, lo necesito en el servidor desde la consola. Enojado, me subí a Github para ver las tripas del proyecto, lo que condujo a su tenedor y, como resultado, solicitarlo. Sobre el cual no escribiría si no fuera interesante;)

Por supuesto, antes de elegir la fuente, miré desde donde el cromo extrae el archivo zip generado con las configuraciones, y allí estaba esperando la dirección que comenzara con "blob:", oppa. Ya ha quedado claro que en el proceso el servicio no genera nada, de hecho, js hace todo esto. De hecho, el archivo zip es generado por el propio cliente, navegador, javascript. Es decir el encanto es que el proyecto
nginxconfig.io simplemente puede guardarse como una página html, cargarse en algún
narod.ru y funcionará) Esta es una solución muy divertida e interesante, sin embargo, es terriblemente inconveniente para configurar servidores, de hecho, para de para qué fue creado este proyecto. ¿Descargue el archivo generado por el navegador y luego transfiéralo al servidor usando nc ... en 2019? Me propuse la tarea de encontrar una manera de descargar la configuración resultante directamente al servidor.
Después de bifurcar el proyecto, comencé a pensar qué opciones tengo. La tarea fue complicada por el hecho de que no quería apartarme de la condición de que el proyecto debería seguir siendo un front-end limpio, sin ningún back-end. Por supuesto, la solución más simple sería extraer nodejs y hacer que genere un archivo con configuraciones a través de enlaces directos.
De hecho, no había muchas opciones. Más precisamente, solo uno vino a mi mente. Necesitamos configurar las configuraciones y obtener un enlace que podamos copiar a la consola del servidor para obtener un archivo zip.
Varios archivos de texto en el archivo zip resultante pesaban bastante, literalmente unos pocos kilobytes. La solución obvia era obtener la cadena base64 del archivo zip generado y tirarla al búfer, mientras estaba en el servidor con el comando en la consola
echo 'base64string' | base64 --decode > config.zip
podríamos crear este mismo archivo zip.
nginxconfig.io fue escrito en AngularJS, ni siquiera puedo imaginar qué kilómetros de código se requerirían si el autor no eligiera un framework js reactivo. Pero me imagino perfectamente cuánto más fácil y hermoso sería posible implementar todo esto en VueJS, aunque este ya es un tema completamente diferente.
En los recursos del proyecto vemos un método para generar un archivo 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', }); };
todo es bastante simple, usando la biblioteca
jszip , se crea un zip donde se colocan los archivos de configuración. Después de crear el archivo zip, js lo alimenta al navegador utilizando la biblioteca
FileSaver.js :
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
donde el contenido es el objeto de archivo zip blob resultante.
Ok, todo lo que tenía que hacer era agregar otro botón al lado y cuando hago clic en él, no guarde el archivo zip resultante en el navegador, sino que obtenga el código base64 de él. Después de un poco de chamanismo, obtuve 2 métodos, en lugar de una descarga Zip:
$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,/, '');
Como puede ver, puse la generación del archivo zip en el método generateZip privado, bueno, porque esto es AngularJS, y el propio autor se adhiere a las devoluciones de llamada, no lo implementó a través de promesas. downloadZip todavía hizo saveAs en la salida, mientras que downloadBase64 hizo un poco diferente. Creamos un objeto FileReader que nos llegó en html5 y ya está
disponible para su uso. Que, a su debido tiempo, sabe cómo hacer una cadena base64 a partir de blob, más precisamente hace una cadena DataURL, pero esto no es tan importante para nosotros, porque DataURL contiene exactamente lo que necesitamos. Bingo, una pequeña trampa me estaba esperando cuando intenté poner todo esto en un búfer. El autor utilizó la biblioteca
clipboardjs en el proyecto, que permite trabajar con el portapapeles sin objetos flash, en función del texto seleccionado. Inicialmente, decidí poner mi base64 en un elemento con pantalla: ninguno; pero en ese caso no pude ponerlo en el portapapeles, porque No se produce selección. Por lo tanto, en lugar de mostrar: ninguno; lo hice
position: absolute; z-index: -1; opacity: 0;
lo que me permitió ocultar el elemento de mis ojos y, de hecho, dejarlo en la página. Voila, la tarea se completó, cuando hice clic en mi botón, se colocó una línea del formulario en el búfer:
echo 'base64string' | base64 --decode > config.zip
que simplemente inserté en la consola en el servidor e inmediatamente recibí un archivo zip con todas las configuraciones.
Bueno, por supuesto, lancé la solicitud de extracción al autor, porque el proyecto está activo y activo, quiero ver las actualizaciones del autor y tengo mi propio botón) A quién le importa, aquí está
mi tenedor del proyecto y la
solicitud de extracción , donde puede ver lo que arreglé / actualicé.
Desarrollo lleno de vida :-)
