source: spip-zone/_plugins_/migrateur/dev-by-http/class/Client/Action/SyncDirectory.php @ 88705

Last change on this file since 88705 was 88705, checked in by marcimat@…, 5 years ago

Changement de tactique pour la synchronisation des répertoires : on demande au serveur la liste complète des fichiers, plutôt que de lui envoyer la sienne dans un POST ; Car s'il y a 40000 fichiers dans le IMG du site destination, le POST envoyé est trop gros !

File size: 5.2 KB
Line 
1<?php
2
3namespace SPIP\Migrateur\Client\Action;
4
5
6
7class SyncDirectory extends ActionBase {
8
9
10        private $directory = ''; // IMG
11        private $path = '';      // chemin/vers/IMG
12        private $test = false;
13
14
15        public function run($data = null) {
16
17                if (is_array($data)) {
18                        $data += array(
19                                'repertoire' => '',
20                                'test' => false
21                        );
22                        $this->directory = $data['repertoire'];
23                        $this->test = $data['test'];
24                } else {
25                        $this->directory = $data;
26                }
27
28                if (!$this->directory) {
29                        return "Aucun répertoire indiqué.";
30                }
31
32                $this->log_run("Sync Répertoire <em>$this->directory</em>" . ($this->test ? " [Test]" : ""));
33
34                // calcul du chemin complet
35                $path = rtrim($this->directory, '/') . DIRECTORY_SEPARATOR;
36                $this->path = $this->destination->dir . DIRECTORY_SEPARATOR . $path;
37                unset($path);
38
39
40                spip_timer('list');
41                $localFiles = $this->destination->getFileList($this->directory);
42                $t = spip_timer('list');
43                $n = count($localFiles);
44                if ($n > 1) {
45                        $this->log("$n fichiers locaux avant synchro. ($t)");
46                } else {
47                        $this->log("$n fichier local avant synchro. ($t)");
48                }
49
50                $data = array(
51                        'directory' => $this->directory,
52                );
53
54                spip_timer('list');
55                $this->log("Demande de la liste des fichiers");
56                $reponse = $this->client->ask('ListFiles', $data, 'json');
57                $t = spip_timer('list');
58
59                if (empty($reponse['message']['data']['files'])) {
60                        return $reponse;
61                }
62
63                $distantFiles = $reponse['message']['data']['files'];
64                $this->log("Réception de la liste de " . count($distantFiles) . " fichiers ($t)");
65                $this->log("Calcul des différences");
66
67
68                // calcul des différences !
69                spip_timer('diff');
70                $newFiles = $updatedFiles = $deletedFiles = array();
71                $totalSize = 0;
72
73                //compare local and remote file list to get updated files
74                foreach ($distantFiles as $filePath => $info) {
75                        if (empty($localFiles[$filePath])) {
76                                $newFiles[$filePath] = $info;
77                                $totalSize += $info[0];
78                        } elseif ($localFiles[$filePath] != $info) {
79                                $updatedFiles[$filePath] = $info;
80                                $totalSize += $info[0];
81                        }
82                        unset($localFiles[$filePath]);
83                }
84
85                // logiquement, ce qui reste, c'est les fichiers supprimés
86                $deletedFiles = $localFiles;
87
88                $t = spip_timer('diff');
89                $this->log("- " . count($newFiles) . " nouveaux fichiers");
90                $this->log("- " . count($updatedFiles) . " à mettre à jour");
91                $this->log("- " . count($deletedFiles) . " à supprimer");
92
93                include_spip('inc/filtres');
94                $this->log("Estimation des transferts : " . ($totalSize ? taille_en_octets($totalSize) : "Rien à faire ! "));
95
96
97                // en mode test, on ne fait pas de modifications.
98                if (!$this->test) {
99                        $this->delete($deletedFiles);
100                        $this->download($newFiles + $updatedFiles);
101                }
102
103                return $reponse;
104        }
105
106
107        /**
108         * Supprime tous les fichiers indiqués
109         *
110         * @paraam array $files Liste des fichiers
111        **/
112        private function delete($files) {
113                if (count($files)) {
114                        $this->log_run("Suppression de " . count($files) . " fichier(s)");
115                        foreach ($files as $filePath => $info) {
116                                unlink($this->path . DIRECTORY_SEPARATOR . $filePath);
117                        }
118                }
119        }
120
121        /**
122         * Télécharge tous les fichiers indiqués
123         *
124         * Comme on vérifie que le fichier reçu est correct, on demande
125         * à calculer les sha256 des fichiers à télécharger.
126         *
127         * On en demande pour 100Mo ou 100 fichiers car ces calculs peuvent
128         * être un peu long
129         *
130         * @paraam array $files Liste des fichiers
131        **/
132        private function download($files) {
133                if (count($files)) {
134                        $this->log_run("Téléchargement de " . count($files) . " fichier(s)");
135
136                        $nb = $size = 0;
137                        $slice = array();
138
139                        foreach ($files as $filePath => $info) {
140                                $nb++;
141                                $size += $info[0];
142                                $slice[$filePath] = $info;
143                                unset($files[$filePath]);
144
145                                if ($nb >= 100 OR $size >= 100*1000*1000) {
146                                        if (!$this->downloadSlice($slice)) {
147                                                return false;
148                                        }
149                                        $size = $nb = 0;
150                                        $slice = array();
151                                }
152                        }
153
154                        // le reste
155                        if (count($slice)) {
156                                return $this->downloadSlice($slice);
157                        }
158                }
159
160                return true;
161        }
162
163
164        /**
165         * Télécharge tous les fichiers indiqués
166         *
167         * Demande la liste des hash des fichiers indiqués,
168         * puis les télécharge un par un et vérifie les hash.
169         *
170         * @paraam array $files Liste des fichiers
171         * @return bool true si OK
172        **/
173        private function downloadSlice($files) {
174                if (!$files) {
175                        return false;
176                }
177                if (!$files = $this->getHash($files)) {
178                        return false;
179                }
180
181                foreach ($files as $filePath => $info) {
182                        $reponse = $this->client->action('GetFile', array(
183                                'fichier' => $this->directory . DIRECTORY_SEPARATOR. $filePath,
184                                'hash' => $info[2],
185                        ));
186
187                        if (!$reponse) {
188                                migrateur_log("Échec de récupération du fichier");
189                                return false;
190                        }
191
192                        // update modified time to match server
193                        touch($this->path . DIRECTORY_SEPARATOR. $filePath, $info[1]);
194                }
195
196                return true;
197        }
198
199
200
201        /**
202         * Récupère les hash de tous les fichiers indiqués
203         *
204         * @paraam array $files Liste des fichiers
205         * @return array|false
206         *    - Liste filePath => hash
207         *    - false si erreur.
208        **/
209        private function getHash($files) {
210                $this->log_run("Demande de hash pour " . count($files) . " fichiers");
211                $data = array(
212                        'directory' => $this->directory,
213                        'files' => $files
214                );
215                $reponse = $this->client->ask('HashFiles', $data, 'json');
216
217                if (!is_array($reponse)) {
218                        return false;
219                }
220
221                return $reponse['message']['data']['files'];
222        }
223
224}
Note: See TracBrowser for help on using the repository browser.