Salutations, camarades. Magnifique sur mes serveurs de combat
Des amis m'ont demandé de créer une ferme de développement pour eux, et au lieu de leur glisser mes modèles spécifiques, je me suis souvenu d'un projet intéressant
Bien sûr, avant de fouiller dans les sources, j'ai regardé où Chrome récupérait l'archive zip générée avec les configurations, et là une adresse commençant par « blob : » m'attendait, oups. Il est déjà devenu clair que le service ne génère rien en cours de route, en fait, tout est fait par js. En effet, l'archive zip est générée par le client, le navigateur et le javascript lui-même. Ceux. la beauté c'est que le projet
Après avoir lancé le projet, j'ai commencé à réfléchir à mes options. La tâche était compliquée par le fait que je ne voulais pas déroger à la condition selon laquelle le projet devait rester un pur front-end, sans aucun back-end. Bien sûr, la solution la plus simple serait d'extraire nodejs et de le forcer à générer une archive avec des configurations à l'aide de liens directs.
En fait, il n’y avait pas beaucoup d’options. Plus précisément, un seul m'est venu à l'esprit. Nous devons configurer les configurations et obtenir un lien que nous pouvons copier sur la console du serveur pour obtenir une archive zip.
Plusieurs fichiers texte dans l'archive zip résultante pesaient un peu, littéralement quelques kilo-octets. La solution évidente était d'obtenir la chaîne base64 de l'archive zip générée et de la jeter dans le tampon, sur le serveur avec la commande dans la console
echo 'base64string' | base64 --decode > config.zip
nous pourrions créer ce même fichier zip.
Dans les ressources 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, en utilisant la bibliothèque
saveAs(content, 'nginxconfig.io-' + $scope.getDomains().join(',') + '.zip');
où content est l'objet blob résultant de l'archive zip.
Ok, tout ce que j'avais à faire était d'ajouter un autre bouton à côté et lorsque je cliquais dessus, je n'enregistrais pas l'archive zip résultante dans le navigateur, mais j'en récupérais le code base64. Après avoir bidouillé un peu, j'ai eu 2 méthodes, au lieu d'un seul 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',
});
};
Comme vous l'avez peut-être remarqué, j'ai déplacé la génération de l'archive zip elle-même vers la méthode privée generateZip, et ainsi de suite. Il s'agit d'AngularJS, et l'auteur lui-même s'en tient aux rappels et ne l'a pas mis en œuvre par le biais de promesses. downloadZip faisait toujours saveAs en sortie, tandis que downloadBase64 faisait quelque chose de légèrement différent. Nous créons un objet FileReader qui nous est parvenu en html5 et qui est déjà assez
position: absolute;
z-index: -1;
opacity: 0;
ce qui m'a permis à la fois de masquer l'élément et de le laisser sur la page. Voila, la tâche était terminée, lorsque j'ai cliqué sur mon bouton, une ligne comme celle-ci a été placée dans le buffer :
echo 'base64string' | base64 --decode > config.zip
que j'ai simplement collé dans la console du serveur et j'ai immédiatement reçu une archive zip avec toutes les configurations.
Et bien sûr, j'ai envoyé une pull request à l'auteur, parce que... le projet est actif et vivant, j'aimerais voir les mises à jour de l'auteur et avoir mon propre bouton) Pour ceux que ça intéresse, le voici
Bon développement à tous)
Source: habr.com