Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 113
Diffusion
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 11
1056
0.00% covered (danger)
0.00%
0 / 113
 __construct
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 run
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 18
 getSiteDetail
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 copyFilesToCdnMirror
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 19
 createZone
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 createAlias
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 17
 getDomain
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getSubDomain
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 createDnsEntry
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 18
 getTrackerConfig
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 copyFilesToTrackers
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 25
1<?php
2
3
4namespace Qmp\Laravel\SiteGeneratorDiffusion\Services;
5
6use Illuminate\Support\Facades\{Log, Redis, Storage};
7use Illuminate\Http\File as HttpFile;
8use Qmp\Laravel\CDNApi\Cdn\InterfaceProvider;
9use Qmp\Laravel\MicroService\Client\Tools\Request as ClientRequest;
10use Qmp\Laravel\MicroService\Client\Client;
11use Qmp\Laravel\ToolsLaravel\FilesManager\FilesManager;
12use \Illuminate\Filesystem\FilesystemManager;
13
14class Diffusion
15{
16    private $cdn;
17
18    private $filesManager;
19
20    private $serviceSiteDetail = 'service_site_generator_detail';
21
22    private $serviceTracker = 'service_tracker';
23
24    private $serviceOvh = 'service_ovh';
25
26    private $siteDetail;
27
28    private $assetsFilesLocationDisk = 'site_generator';
29
30    private $originFilesLocationDisk = 'site_generator_sg_tpl';
31
32    private $cdnFilesLocationDisk = 'cdn_mirror_public';
33
34    private $trackersFilesLocationDisks = ['ssh_tracker1'];
35
36    private $pathCdnMirror = 'assets';
37
38    private $pathTracker = 'siteGenerator';
39
40    public function __construct()
41    {
42        $this->cdn = resolve(InterfaceProvider::class);
43
44        $this->filesManager = resolve(FilesManager::class);
45    }
46
47    public function run($siteId)
48    {
49        // Get site detail config
50        $this->siteDetail = $this->getSiteDetail($siteId);
51        $domainName = 'cdn.' . ($this->siteDetail->config->domain->text ?? '');
52
53        // Copy to project public cdn mirror url
54        $filesToPurge = $this->copyFilesToCdnMirror($siteId);
55        if (empty($filesToPurge)) {
56            Redis::publish('site-generator-creator', json_encode(['action' => 'upload-sites', 'siteId' => $siteId, 'message' => 'No files copies to CDN']));
57            return false;
58        } else {
59            // Upload assets to CDN
60            $zone = $this->cdn->getZoneByAliasName($domainName);
61            $urls = array_map(function($file) use ($domainName) {
62                return $domainName . '/' . $file;
63            }, $filesToPurge);
64
65            // Purge CDN files
66            if (!$this->cdn->purgeFilesByUrls($zone['id'], $urls)) {
67                Log::debug('Unable to purge files for ' . $siteId);
68            }
69
70            // upload html file to Tracker
71            $filesUploaded = $this->copyFilesToTrackers($siteId);
72
73            // Send pub/sub to finish diffusion of site
74            if (empty($filesUploaded)) {
75                Redis::publish('site-generator-creator', json_encode(['action' => 'upload-sites', 'siteId' => $siteId, 'message' => 'No files copies to Trackers']));
76                return false;
77            } else {
78                Redis::publish('site-generator-creator', json_encode(['action' => 'upload-sites', 'siteId' => $siteId, 'message' => 'files copied to CDN and Trackers']));
79                return true;
80            }
81        }
82    }
83
84    protected function getSiteDetail($siteId)
85    {
86        $request = ClientRequest::createObject($this->serviceSiteDetail, 'site');
87        $response = Client::systemSend('get', $request, $siteId);
88
89        return json_decode($response->body)->site_detail;
90    }
91
92    protected function copyFilesToCdnMirror($siteId)
93    {
94        $pathToSite = $this->pathCdnMirror . '/' . $this->siteDetail->config->url . '/' . $this->siteDetail->config->urlHash;
95        $this->filesManager->to(Storage::disk($this->cdnFilesLocationDisk));
96        
97        // Save file to good folder
98        $this->filesManager->from(Storage::disk($this->originFilesLocationDisk))
99            ->directory($siteId, $pathToSite, true);
100        
101        $this->filesManager->from(Storage::disk($this->assetsFilesLocationDisk));
102        
103        // Copy uploaded images to cdn
104        foreach ($this->siteDetail->template->images->affectation as $item) {
105            if ($item->value) {
106                $this->filesManager->file(
107                    $item->value, 
108                    $pathToSite . '/images/' . $item->value
109                );
110            }
111        }
112
113        // Copy uploaded regulation file to cdn
114        if (!empty($this->siteDetail->template->regulationFile->name)) {
115            $this->filesManager->file(
116                $this->siteDetail->template->regulationFile->name, 
117                $pathToSite . '/' . $this->siteDetail->template->regulationFile->name
118            );
119        }
120
121        // Copy uploaded terms file to cdn
122        if (!empty($this->siteDetail->template->termsFile->name)) {
123            $this->filesManager->file(
124                $this->siteDetail->template->termsFile->name, 
125                $pathToSite . '/' . $this->siteDetail->template->termsFile->name
126            );
127        }
128
129        return $this->filesManager->allDestinationFiles($pathToSite);
130    }
131
132    public function createZone($zoneName)
133    {
134        return $this->cdn->createZone([
135            'name' => $zoneName,
136            'originurl' => Storage::disk($this->cdnFilesLocationDisk)->url('')
137        ]);
138    }
139
140    public function createAlias($zoneId, $url)
141    {
142        // Create CDN Alias
143        $zone = $this->cdn->zone($zoneId);
144        $aliases = array_filter($zone['aliases'], function ($item) use ($zoneId, $url) {
145            return $item['zone_id'] === $zoneId || $item['name'] === $url;
146        });
147
148        if (!empty($aliases)) {
149            foreach ($aliases as $alias) {
150                $this->cdn->deleteAlias($alias['id']);
151            }
152        }
153
154        $aliasAction = $this->cdn->createAlias($zoneId, $url);
155
156        if ($aliasAction) {
157            // Create DNS for CDN
158            $domain = $this->getDomain($url);
159            $subdomain = $this->getSubDomain($url);
160            return $this->createDnsEntry($domain, [
161                'fieldType' => "CNAME",
162                'subDomain' => $subdomain,
163                'target' => $zone['zoneurl'],
164                'ttl' => 86400
165            ]);
166        }
167
168        return false;
169    }
170
171    protected function getDomain($url)
172    {
173        $explodedUrl = explode('.', $url);
174        return implode('.', array_slice($explodedUrl, -2, 2));
175    }
176
177    protected function getSubDomain($url)
178    {
179        $domain = $this->getDomain($url);
180        return sustr(str_replace($domain, '', $url), 0, -1);
181    }
182
183    protected function createDnsEntry(string $domainName, array $data)
184    {
185        $subDomainsRequest = ClientRequest::createObject($this->serviceOvh, 'records');
186        $subDomainsResponse = Client::systemSend('get', $subDomainsRequest);
187        $subDomains = json_decode($subDomainsResponse->body);
188
189        $subDomains = array_filter($subDomains, function ($item) use ($data) {
190            return $item['subDomain'] === $data['subDomain'] && $item['fieldType'] === $data['fieldType'];
191        });
192
193        if (!empty($subDomains)) {
194            $request = ClientRequest::createObject($this->serviceOvh, $domainName . '/records/' . $subDomains['id']);
195            $response = Client::systemSend('put', $request, $data);
196        } else {
197            $request = ClientRequest::createObject($this->serviceOvh, $domainName . '/records');
198            $response = Client::systemSend('post', $request, $data);
199        }
200
201        try {
202            $response = json_decode($response->body);
203            if (!$response->status || $response->status !== 'ok') {
204                throw new \Exception('cannot create DNS on OVH : ' . $domainName);
205            }
206
207            return true;
208        } catch (\Exception $e) {
209            Log::debug($e->getMessage());
210
211            return false;
212        }
213    }
214
215    protected function getTrackerConfig()
216    {
217        $request = ClientRequest::createObject($this->serviceTracker, 'config');
218        $response = Client::systemSend('get', $request);
219
220        return json_decode($response->body);
221    }
222
223    protected function copyFilesToTrackers($siteId)
224    {
225        $files = [];
226        
227        $config = $this->getTrackerConfig();
228        $fsMg = new FilesystemManager(app());
229        $this->filesManager->from(Storage::disk($this->originFilesLocationDisk));
230        foreach ($config as $trackerConfig) {
231            if ($trackerConfig->active && $trackerConfig->ssh && $trackerConfig->ssh->active) {
232                $pathToSite = $this->pathTracker . '/' . $this->siteDetail->config->url . '/' . $this->siteDetail->config->urlHash;
233            
234                $sshConfig = [
235                    'driver' => 'sftp',
236                    'host' => $trackerConfig->ip,
237                    'port' => $trackerConfig->ssh->port,
238                    'username' => $trackerConfig->ssh->user,
239                    'password' => $trackerConfig->ssh->password,
240                    'root' => $trackerConfig->ssh->root,
241                    'timeout' => 30,
242                ];
243                $tracker = $fsMg->createSftpDriver($sshConfig);
244                
245                // Save file to good folder
246                $this->filesManager->to($tracker)->put(
247                    $pathToSite, 
248                    new HttpFile(Storage::disk($this->originFilesLocationDisk)->path($siteId . '/index.html')), 
249                    'index.html', 
250                    true
251                );
252
253                $filesTracker = $this->filesManager->allDestinationFiles($pathToSite);
254                if (empty($filesTracker)) {
255                    Log::debug('No files copies to ' . $tracker->name . ' for id ' . $siteId);
256                } else {
257                    $files = array_merge([], $files, $filesTracker);
258                }
259            }
260        }
261        
262        return $files;
263    }
264}