Completed
Push — master ( 6ab97c...6a4e84 )
by Maxence
02:33
created

FederatedService::linkCircle()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 20
rs 9.2
cc 4
eloc 11
nc 4
nop 2
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\Circles\Service;
28
29
30
use Exception;
31
use OC\Http\Client\ClientService;
32
use OCA\Circles\Api\v1\Circles;
33
use OCA\Circles\Db\CirclesRequest;
34
use OCA\Circles\Db\FederatedLinksRequest;
35
use OCA\Circles\Exceptions\CircleDoesNotExistException;
36
use OCA\Circles\Exceptions\FederatedCircleLinkFormatException;
37
use OCA\Circles\Exceptions\FederatedCircleNotAllowedException;
38
use OCA\Circles\Exceptions\CircleTypeNotValidException;
39
use OCA\Circles\Exceptions\FederatedCircleStatusUpdateException;
40
use OCA\Circles\Exceptions\FederatedLinkUpdateException;
41
use OCA\Circles\Exceptions\FederatedRemoteCircleDoesNotExistException;
42
use OCA\Circles\Exceptions\FederatedRemoteDoesNotAllowException;
43
use OCA\Circles\Exceptions\FederatedRemoteIsDownException;
44
use OCA\Circles\Exceptions\PayloadDeliveryException;
45
use OCA\Circles\Exceptions\SharingFrameAlreadyExistException;
46
use OCA\Circles\Exceptions\FederatedLinkCreationException;
47
use OCA\Circles\Exceptions\MemberIsNotAdminException;
48
use OCA\Circles\Exceptions\SharingFrameDoesNotExistException;
49
use OCA\Circles\Model\Circle;
50
use OCA\Circles\Model\FederatedLink;
51
use OCA\Circles\Model\SharingFrame;
52
use OCP\Http\Client\IClientService;
53
use OCP\IL10N;
54
55
class FederatedService {
56
57
	const REMOTE_URL_LINK = '/index.php/apps/circles/v1/link';
58
	const REMOTE_URL_PAYLOAD = '/index.php/apps/circles/v1/payload';
59
60
	/** @var string */
61
	private $userId;
62
63
	/** @var IL10N */
64
	private $l10n;
65
66
	/** @var CirclesRequest */
67
	private $circlesRequest;
68
69
	/** @var ConfigService */
70
	private $configService;
71
72
	/** @var CirclesService */
73
	private $circlesService;
74
75
	/** @var BroadcastService */
76
	private $broadcastService;
77
78
	/** @var FederatedLinksRequest */
79
	private $federatedLinksRequest;
80
81
	/** @var EventsService */
82
	private $eventsService;
83
84
	/** @var string */
85
	private $serverHost;
86
87
	/** @var IClientService */
88
	private $clientService;
89
90
	/** @var MiscService */
91
	private $miscService;
92
93
94
	/**
95
	 * CirclesService constructor.
96
	 *
97
	 * @param $userId
98
	 * @param IL10N $l10n
99
	 * @param CirclesRequest $circlesRequest
100
	 * @param ConfigService $configService
101
	 * @param CirclesService $circlesService
102
	 * @param BroadcastService $broadcastService
103
	 * @param FederatedLinksRequest $federatedLinksRequest
104
	 * @param EventsService $eventsService
105
	 * @param IClientService $clientService
106
	 * @param MiscService $miscService
107
	 */
108
	public function __construct(
109
		$userId, IL10N $l10n, CirclesRequest $circlesRequest, ConfigService $configService,
110
		CirclesService $circlesService, BroadcastService $broadcastService,
111
		FederatedLinksRequest $federatedLinksRequest, EventsService $eventsService,
112
		IClientService $clientService, MiscService $miscService
113
	) {
114
		$this->userId = $userId;
115
		$this->l10n = $l10n;
116
		$this->circlesRequest = $circlesRequest;
117
		$this->configService = $configService;
118
		$this->circlesService = $circlesService;
119
		$this->broadcastService = $broadcastService;
120
		$this->federatedLinksRequest = $federatedLinksRequest;
121
		$this->eventsService = $eventsService;
122
		$this->serverHost = $this->configService->getLocalAddress();
123
124
		$this->clientService = $clientService;
125
		$this->miscService = $miscService;
126
	}
127
128
129
	/**
130
	 * linkCircle();
131
	 *
132
	 * link to a circle.
133
	 * Function will check if settings allow Federated links between circles, and the format of
134
	 * the link ($remote). If no exception, a request to the remote circle will be initiated
135
	 * using requestLinkWithCircle()
136
	 *
137
	 * $remote format: <circle_name>@<remote_host>
138
	 *
139
	 * @param string $circleUniqueId
140
	 * @param string $remote
141
	 *
142
	 * @throws Exception
143
	 * @throws FederatedCircleLinkFormatException
144
	 * @throws CircleTypeNotValidException
145
	 *
146
	 * @return FederatedLink
147
	 */
148
	public function linkCircle($circleUniqueId, $remote) {
149
150
		if (!$this->configService->isFederatedCirclesAllowed()) {
151
			throw new FederatedCircleNotAllowedException(
152
				$this->l10n->t("Federated circles are not allowed on this Nextcloud")
153
			);
154
		}
155
156
		if (strpos($remote, '@') === false) {
157
			throw new FederatedCircleLinkFormatException(
158
				$this->l10n->t("Federated link does not have a valid format")
159
			);
160
		}
161
162
		try {
163
			return $this->requestLinkWithCircle($circleUniqueId, $remote);
164
		} catch (Exception $e) {
165
			throw $e;
166
		}
167
	}
168
169
170
	/**
171
	 * linkStatus()
172
	 *
173
	 * Update the status of a link.
174
	 * Function will check if user can edit the status, will update it and send the update to
175
	 * remote
176
	 *
177
	 * @param int $linkId
178
	 * @param int $status
179
	 *
180
	 * @throws Exception
181
	 * @throws FederatedCircleLinkFormatException
182
	 * @throws CircleTypeNotValidException
183
	 * @throws MemberIsNotAdminException
184
	 *
185
	 * @return FederatedLink[]
186
	 */
187
	public function linkStatus($linkId, $status) {
188
189
		$status = (int)$status;
190
		$link = null;
191
		try {
192
193
			$link = $this->circlesRequest->getLinkFromId($linkId);
194
			$circle = $this->circlesRequest->getCircle($link->getCircleId(), $this->userId);
195
			$circle->hasToBeFederated();
196
			$circle->getHigherViewer()
197
				   ->hasToBeAdmin();
198
			$link->hasToBeValidStatusUpdate($status);
199
200
			if (!$this->eventOnLinkStatus($circle, $link, $status)) {
201
				return $this->circlesRequest->getLinksFromCircle($circle->getUniqueId());
202
			}
203
204
		} catch (Exception $e) {
205
			throw $e;
206
		}
207
208
		$link->setStatus($status);
209
		$link->setCircleId($circle->getUniqueId(true));
210
211
		try {
212
			$this->updateLinkRemote($link);
213
		} catch (Exception $e) {
214
			if ($status !== FederatedLink::STATUS_LINK_REMOVE) {
215
				throw $e;
216
			}
217
		}
218
219
		$this->federatedLinksRequest->update($link);
220
221
		return $this->circlesRequest->getLinksFromCircle($circle->getUniqueId());
222
	}
223
224
225
	/**
226
	 * eventOnLinkStatus();
227
	 *
228
	 * Called by linkStatus() to manage events when status is changing.
229
	 * If status does not need update, returns false;
230
	 *
231
	 * @param Circle $circle
232
	 * @param FederatedLink $link
233
	 * @param $status
234
	 *
235
	 * @return bool
236
	 */
237
	private function eventOnLinkStatus(Circle $circle, FederatedLink $link, $status) {
238
		if ($link->getStatus() === $status) {
239
			return false;
240
		}
241
242
		if ($status === FederatedLink::STATUS_LINK_REMOVE) {
243
			$this->eventsService->onLinkRemove($circle, $link);
244
		}
245
246
		if ($status === FederatedLink::STATUS_LINK_UP) {
247
			$this->eventsService->onLinkRequestAccepting($circle, $link);
248
			$this->eventsService->onLinkUp($circle, $link);
249
		}
250
251
		return true;
252
	}
253
254
255
	/**
256
	 * requestLinkWithCircle()
257
	 *
258
	 * Using CircleId, function will get more infos from the database.
259
	 * Will check if author is at least admin and initiate a FederatedLink, save it
260
	 * in the database and send a request to the remote circle using requestLink()
261
	 * If any issue, entry is removed from the database.
262
	 *
263
	 * @param string $circleUniqueId
264
	 * @param string $remote
265
	 *
266
	 * @return FederatedLink
267
	 * @throws Exception
268
	 */
269
	private function requestLinkWithCircle($circleUniqueId, $remote) {
270
271
		$link = null;
272
		try {
273
			list($remoteCircle, $remoteAddress) = explode('@', $remote, 2);
274
275
			$circle = $this->circlesService->detailsCircle($circleUniqueId);
276
			$circle->getHigherViewer()
277
				   ->hasToBeAdmin();
278
			$circle->hasToBeFederated();
279
			$circle->cantBePersonal();
280
281
			$link = new FederatedLink();
282
			$link->setCircleId($circleUniqueId)
283
				 ->setLocalAddress($this->serverHost)
284
				 ->setAddress($remoteAddress)
285
				 ->setRemoteCircleName($remoteCircle)
286
				 ->setStatus(FederatedLink::STATUS_LINK_SETUP)
287
				 ->generateToken();
288
289
			$this->federatedLinksRequest->create($link);
290
			$this->requestLink($circle, $link);
291
292
		} catch (Exception $e) {
293
			if ($link !== null) {
294
				$this->federatedLinksRequest->delete($link);
295
			}
296
			throw $e;
297
		}
298
299
		return $link;
300
	}
301
302
303
	/**
304
	 * @param string $remote
305
	 *
306
	 * @return string
307
	 */
308
	private function generateLinkRemoteURL($remote) {
309
		return $this->generateRemoteHost($remote) . self::REMOTE_URL_LINK;
310
	}
311
312
313
	/**
314
	 * @param string $remote
315
	 *
316
	 * @return string
317
	 */
318
	private function generatePayloadDeliveryURL($remote) {
319
		return $this->generateRemoteHost($remote) . self::REMOTE_URL_PAYLOAD;
320
	}
321
322
323
	/**
324
	 * @param string $remote
325
	 *
326
	 * @return string
327
	 */
328
	private function generateRemoteHost($remote) {
329
		if ((!$this->configService->isNonSSLLinksAllowed() || strpos($remote, 'http://') !== 0)
330
			&& strpos($remote, 'https://') !== 0
331
		) {
332
			$remote = 'https://' . $remote;
333
		}
334
335
		return rtrim($remote, '/');
336
	}
337
338
339
	/**
340
	 * requestLink()
341
	 *
342
	 *
343
	 * @param Circle $circle
344
	 * @param FederatedLink $link
345
	 *
346
	 * @return boolean
347
	 * @throws Exception
348
	 */
349
	private function requestLink(Circle $circle, FederatedLink &$link) {
350
		$args = [
351
			'apiVersion' => Circles::version(),
352
			'token'      => $link->getToken(true),
353
			'uniqueId'   => $circle->getUniqueId(true),
354
			'sourceName' => $circle->getName(),
355
			'linkTo'     => $link->getRemoteCircleName(),
356
			'address'    => $link->getLocalAddress()
357
		];
358
359
		$client = $this->clientService->newClient();
360
361
		try {
362
			$request = $client->put(
363
				$this->generateLinkRemoteURL($link->getAddress()), [
364
																	 'body'            => $args,
365
																	 'timeout'         => 10,
366
																	 'connect_timeout' => 10,
367
																 ]
368
			);
369
370
			$result = json_decode($request->getBody(), true);
371
			if ($result === null) {
372
				throw new FederatedRemoteIsDownException(
373
					$this->l10n->t(
374
						'The remote host is down or the Circles app is not installed on it'
375
					)
376
				);
377
			}
378
379
			$this->eventOnRequestLink(
380
				$circle, $link, $result['status'],
381
				((key_exists('reason', $result)) ? $result['reason'] : '')
382
			);
383
384
			$link->setUniqueId($result['uniqueId']);
385
			$this->federatedLinksRequest->update($link);
386
387
			return true;
388
		} catch (Exception $e) {
389
			throw $e;
390
		}
391
	}
392
393
394
	/**
395
	 * eventOnRequestLink();
396
	 *
397
	 * Called by requestLink() will update status and event
398
	 * Will also manage errors returned by the remote link
399
	 *
400
	 * @param Circle $circle
401
	 * @param FederatedLink $link
402
	 * @param $status
403
	 * @param $reason
404
	 *
405
	 * @throws Exception
406
	 */
407
	private function eventOnRequestLink(Circle $circle, FederatedLink $link, $status, $reason) {
408
409
		try {
410
			if ($status === FederatedLink::STATUS_LINK_UP) {
411
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
412
				$this->eventsService->onLinkUp($circle, $link);
413
			} else if ($status === FederatedLink::STATUS_LINK_REQUESTED) {
414
				$link->setStatus(FederatedLink::STATUS_REQUEST_SENT);
415
				$this->eventsService->onLinkRequestSent($circle, $link);
416
			} else {
417
				$this->parseRequestLinkError($reason);
418
			}
419
		} catch (Exception $e) {
420
			throw $e;
421
		}
422
	}
423
424
425
	/**
426
	 * parseRequestLinkError();
427
	 *
428
	 * Will parse the error reason returned by requestLink() and throw an Exception
429
	 *
430
	 * @param $reason
431
	 *
432
	 * @throws Exception
433
	 * @throws FederatedRemoteCircleDoesNotExistException
434
	 * @throws FederatedRemoteDoesNotAllowException
435
	 */
436
	private function parseRequestLinkError($reason) {
437
438
		if ($reason === 'federated_not_allowed') {
439
			throw new FederatedRemoteDoesNotAllowException(
440
				$this->l10n->t('Federated circles are not allowed on the remote Nextcloud')
441
			);
442
		}
443
444
		if ($reason === 'circle_links_disable') {
445
			throw new FederatedRemoteDoesNotAllowException(
446
				$this->l10n->t('The remote circle does not accept federated links')
447
			);
448
		}
449
450
		if ($reason === 'duplicate_unique_id') {
451
			throw new FederatedRemoteDoesNotAllowException(
452
				$this->l10n->t('It seems that you are trying to link a circle to itself')
453
			);
454
		}
455
456
		if ($reason === 'duplicate_link') {
457
			throw new FederatedRemoteDoesNotAllowException(
458
				$this->l10n->t('This link exists already')
459
			);
460
		}
461
462
		if ($reason === 'circle_does_not_exist') {
463
			throw new FederatedRemoteCircleDoesNotExistException(
464
				$this->l10n->t('The requested remote circle does not exist')
465
			);
466
		}
467
468
		throw new Exception($reason);
469
	}
470
471
472
	/**
473
	 * @param string $token
474
	 * @param string $uniqueId
475
	 * @param int $status
476
	 *
477
	 * @return FederatedLink
478
	 * @throws Exception
479
	 */
480
	public function updateLinkFromRemote($token, $uniqueId, $status) {
481
		try {
482
			$link = $this->circlesRequest->getLinkFromToken($token, $uniqueId);
483
			$circle = $this->circlesRequest->forceGetCircle($link->getCircleId());
484
			$circle->hasToBeFederated();
485
486
			$this->checkUpdateLinkFromRemote($status);
487
			$this->checkUpdateLinkFromRemoteLinkUp($circle, $link, $status);
488
			$this->checkUpdateLinkFromRemoteLinkRemove($circle, $link, $status);
489
490
			if ($link->getStatus() !== $status) {
491
				$this->federatedLinksRequest->update($link);
492
			}
493
494
			return $link;
495
		} catch (Exception $e) {
496
			throw $e;
497
		}
498
	}
499
500
	/**
501
	 * checkUpdateLinkFromRemote();
502
	 *
503
	 * will throw exception is the status sent by remote is not correct
504
	 *
505
	 * @param int $status
506
	 *
507
	 * @throws FederatedCircleStatusUpdateException
508
	 */
509
	private function checkUpdateLinkFromRemote($status) {
510
		$status = (int)$status;
511
		if ($status !== FederatedLink::STATUS_LINK_UP
512
			&& $status !== FederatedLink::STATUS_LINK_REMOVE
513
		) {
514
			throw new FederatedCircleStatusUpdateException(
515
				$this->l10n->t('Cannot proceed with this status update')
516
			);
517
		}
518
	}
519
520
521
	/**
522
	 * checkUpdateLinkFromRemoteLinkUp()
523
	 *
524
	 * in case of a request of status update from remote for a link up, we check the current
525
	 * status of the link locally.
526
	 *
527
	 * @param Circle $circle
528
	 * @param FederatedLink $link
529
	 * @param int $status
530
	 *
531
	 * @throws FederatedCircleStatusUpdateException
532
	 */
533
	private function checkUpdateLinkFromRemoteLinkUp(Circle $circle, FederatedLink $link, $status) {
534
		if ((int)$status !== FederatedLink::STATUS_LINK_UP) {
535
			return;
536
		}
537
538
		if ($link->getStatus() !== FederatedLink::STATUS_REQUEST_SENT) {
539
			throw new FederatedCircleStatusUpdateException(
540
				$this->l10n->t('Cannot proceed with this status update')
541
			);
542
		}
543
544
		$this->eventsService->onLinkRequestAccepted($circle, $link);
545
		$this->eventsService->onLinkUp($circle, $link);
546
		$link->setStatus($status);
547
	}
548
549
550
	/**
551
	 * checkUpdateLinkFromRemoteLinkRemove();
552
	 *
553
	 * in case of a request of status update from remote for a link down, we check the current
554
	 * status of the link locally
555
	 *
556
	 * @param Circle $circle
557
	 * @param FederatedLink $link
558
	 * @param int $status
559
	 *
560
	 * @throws FederatedCircleStatusUpdateException
561
	 */
562
	private function checkUpdateLinkFromRemoteLinkRemove(
563
		Circle $circle, FederatedLink $link, $status
564
	) {
565
		if ((int)$status !== FederatedLink::STATUS_LINK_REMOVE) {
566
			return;
567
		}
568
569 View Code Duplication
		if ($link->getStatus() === FederatedLink::STATUS_REQUEST_SENT) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
570
			$link->setStatus(FederatedLink::STATUS_REQUEST_DECLINED);
571
			$this->eventsService->onLinkRequestRejected($circle, $link);
572
573
			return;
574
		}
575
576 View Code Duplication
		if ($link->getStatus() === FederatedLink::STATUS_LINK_REQUESTED) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
577
			$link->setStatus(FederatedLink::STATUS_LINK_REMOVE);
578
			$this->eventsService->onLinkRequestCanceled($circle, $link);
579
580
			return;
581
		}
582
583 View Code Duplication
		if ($link->getStatus() > FederatedLink::STATUS_LINK_DOWN) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
584
			$link->setStatus(FederatedLink::STATUS_LINK_DOWN);
585
			$this->eventsService->onLinkDown($circle, $link);
586
587
			return;
588
		}
589
590
		throw new FederatedCircleStatusUpdateException(
591
			$this->l10n->t('Cannot proceed with this status update')
592
		);
593
	}
594
595
596
	/**
597
	 * updateLinkRemote()
598
	 *
599
	 * Send a request to the remote of the link to update its status.
600
	 *
601
	 * @param FederatedLink $link
602
	 *
603
	 * @return bool
604
	 * @throws Exception
605
	 */
606
	public function updateLinkRemote(FederatedLink &$link) {
607
		$args = [
608
			'apiVersion' => Circles::version(),
609
			'token'      => $link->getToken(true),
610
			'uniqueId'   => $link->getCircleId(true),
611
			'status'     => $link->getStatus()
612
		];
613
614
		$client = $this->clientService->newClient();
615
		try {
616
			$request = $client->post(
617
				$this->generateLinkRemoteURL($link->getAddress()), [
618
																	 'body'            => $args,
619
																	 'timeout'         => 10,
620
																	 'connect_timeout' => 10,
621
																 ]
622
			);
623
624
			$result = json_decode($request->getBody(), true);
625
			if ($result['status'] === -1) {
626
				throw new FederatedLinkUpdateException($result['reason']);
627
			}
628
629
			return true;
630
		} catch (Exception $e) {
631
			throw $e;
632
		}
633
	}
634
635
636
	/**
637
	 * Create a new link into database and assign the correct status.
638
	 *
639
	 * @param Circle $circle
640
	 * @param FederatedLink $link
641
	 *
642
	 * @throws Exception
643
	 */
644
	public function initiateLink(Circle $circle, FederatedLink &$link) {
645
646
		try {
647
			$this->checkLinkRequestValidity($circle, $link);
648
			$link->setCircleId($circle->getUniqueId());
649
650
			if ($circle->getSetting('allow_links_auto') === 'true') {
651
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
652
				$this->eventsService->onLinkUp($circle, $link);
653
			} else {
654
				$link->setStatus(FederatedLink::STATUS_LINK_REQUESTED);
655
				$this->eventsService->onLinkRequestReceived($circle, $link);
656
			}
657
658
			$this->federatedLinksRequest->create($link);
659
		} catch (Exception $e) {
660
			throw $e;
661
		}
662
	}
663
664
665
	/**
666
	 * @param Circle $circle
667
	 * @param FederatedLink $link
668
	 *
669
	 * @throws FederatedLinkCreationException
670
	 */
671
	private function checkLinkRequestValidity($circle, $link) {
672
		if ($circle->getUniqueId(true) === $link->getUniqueId(true)) {
673
			throw new FederatedLinkCreationException('duplicate_unique_id');
674
		}
675
676
		if ($this->getLink($circle->getUniqueId(), $link->getUniqueId(true)) !== null) {
677
			throw new FederatedLinkCreationException('duplicate_link');
678
		}
679
680
		if ($circle->getSetting('allow_links') !== 'true') {
681
			throw new FederatedLinkCreationException('circle_links_disable');
682
		}
683
	}
684
685
686
	/**
687
	 * @param string $token
688
	 * @param string $uniqueId
689
	 * @param SharingFrame $frame
690
	 *
691
	 * @return bool
692
	 * @throws Exception
693
	 */
694
	public function receiveFrame($token, $uniqueId, SharingFrame &$frame) {
695
		try {
696
			$link = $this->circlesRequest->getLinkFromToken((string)$token, (string)$uniqueId);
697
		} catch (Exception $e) {
698
			throw $e;
699
		}
700
701
		try {
702
			$this->circlesRequest->getFrame($link->getCircleId(), $frame->getUniqueId());
703
			throw new SharingFrameAlreadyExistException('shares_is_already_known');
704
		} catch (SharingFrameDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
705
		}
706
707
		try {
708
			$circle = $this->circlesRequest->forceGetCircle($link->getCircleId());
709
		} catch (CircleDoesNotExistException $e) {
710
			throw new CircleDoesNotExistException('unknown_circle');
711
		}
712
713
		$frame->setCircle($circle);
714
		$this->circlesRequest->saveFrame($frame);
715
716
		return true;
717
	}
718
719
	/**
720
	 * @param string $circleUniqueId
721
	 * @param string $uniqueId
722
	 *
723
	 * @return FederatedLink
0 ignored issues
show
Documentation introduced by
Should the return type not be FederatedLink|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
724
	 */
725
	public function getLink($circleUniqueId, $uniqueId) {
726
		return $this->federatedLinksRequest->getFromUniqueId($circleUniqueId, $uniqueId);
727
	}
728
729
730
	/**
731
	 * @param string $circleUniqueId
732
	 *
733
	 * @return FederatedLink[]
734
	 */
735
	public function getLinksFromCircle($circleUniqueId) {
736
		return $this->federatedLinksRequest->getLinked($circleUniqueId);
737
	}
738
739
740
	/**
741
	 * @param string $circleUniqueId
742
	 * @param string $frameUniqueId
743
	 *
744
	 * @return bool
745
	 * @throws Exception
746
	 */
747
	public function initiateShare($circleUniqueId, $frameUniqueId) {
748
		$args = [
749
			'circleId' => $circleUniqueId,
750
			'frameId'  => $frameUniqueId
751
		];
752
753
		$client = $this->clientService->newClient();
754
		try {
755
			$client->post(
756
				$this->generatePayloadDeliveryURL($this->serverHost), [
757
																		'body'            => $args,
758
																		'timeout'         => 10,
759
																		'connect_timeout' => 10,
760
																	]
761
			);
762
763
//			$result = json_decode($request->getBody(), true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
764
//			$this->miscService->log(
765
//				"initiateRemoteShare result: " . $uniqueId . '  ----  ' . var_export($result, true)
766
//			);
767
768
			return true;
769
		} catch (Exception $e) {
770
			throw $e;
771
		}
772
	}
773
774
775
	/**
776
	 * @param SharingFrame $frame
777
	 *
778
	 * @throws Exception
779
	 */
780
	public function sendRemoteShare(SharingFrame $frame) {
781
782
		try {
783
			$circle = $this->circlesRequest->forceGetCircle(
784
				$frame->getCircle()
785
					  ->getUniqueId()
786
			);
787
		} catch (CircleDoesNotExistException $e) {
788
			throw new CircleDoesNotExistException('unknown_circle');
789
		}
790
791
		$links = $this->getLinksFromCircle(
792
			$frame->getCircle()
793
				  ->getUniqueId()
794
		);
795
796
		foreach ($links AS $link) {
797
798
799
			$args = [
800
				'apiVersion' => Circles::version(),
801
				'token'      => $link->getToken(true),
802
				'uniqueId'   => $circle->getUniqueId(true),
803
				'item'       => json_encode($frame)
804
			];
805
806
			$client = $this->clientService->newClient();
807
			try {
808
				$request = $client->put(
809
					$this->generatePayloadDeliveryURL($link->getAddress()), [
810
																			  'body'            => $args,
811
																			  'timeout'         => 10,
812
																			  'connect_timeout' => 10,
813
																		  ]
814
				);
815
816
				$result = json_decode($request->getBody(), true);
817
				if ($result['status'] === -1) {
818
					throw new PayloadDeliveryException($result['reason']);
819
				}
820
821
			} catch (Exception $e) {
822
				$this->miscService->log(
823
					'Issue while sending sharing frame to ' . $link->getAddress() . ' - '
824
					. $e->getMessage()
825
				);
826
			}
827
		}
828
	}
829
830
831
	/**
832
	 * generateHeaders()
833
	 *
834
	 * Generate new headers for the current Payload, and save them in the SharingFrame.
835
	 *
836
	 * @param SharingFrame $frame
837
	 */
838
	public function updateFrameWithCloudId(SharingFrame $frame) {
839
		$frame->setCloudId($this->serverHost);
840
		$this->circlesRequest->updateFrame($frame);
841
	}
842
843
}