Completed
Push — master ( 41fdc1...6665fc )
by Maxence
02:50
created

FederatedService::receiveFrame()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 24
rs 8.6845
c 1
b 1
f 0
cc 4
eloc 16
nc 5
nop 3
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\IL10N;
53
54
class FederatedService {
55
56
	const REMOTE_URL_LINK = '/index.php/apps/circles/v1/link';
57
	const REMOTE_URL_PAYLOAD = '/index.php/apps/circles/v1/payload';
58
59
	/** @var string */
60
	private $userId;
61
62
	/** @var IL10N */
63
	private $l10n;
64
65
	/** @var CirclesRequest */
66
	private $circlesRequest;
67
68
	/** @var ConfigService */
69
	private $configService;
70
71
	/** @var CirclesService */
72
	private $circlesService;
73
74
	/** @var BroadcastService */
75
	private $broadcastService;
76
77
	/** @var FederatedLinksRequest */
78
	private $federatedLinksRequest;
79
80
	/** @var EventsService */
81
	private $eventsService;
82
83
	/** @var string */
84
	private $serverHost;
85
86
	/** @var ClientService */
87
	private $clientService;
88
89
	/** @var MiscService */
90
	private $miscService;
91
92
93
	/**
94
	 * CirclesService constructor.
95
	 *
96
	 * @param $userId
97
	 * @param IL10N $l10n
98
	 * @param CirclesRequest $circlesRequest
99
	 * @param ConfigService $configService
100
	 * @param CirclesService $circlesService
101
	 * @param BroadcastService $broadcastService
102
	 * @param FederatedLinksRequest $federatedLinksRequest
103
	 * @param EventsService $eventsService
104
	 * @param ClientService $clientService
105
	 * @param MiscService $miscService
106
	 */
107
	public function __construct(
108
		$userId,
109
		IL10N $l10n,
110
		CirclesRequest $circlesRequest,
111
		ConfigService $configService,
112
		CirclesService $circlesService,
113
		BroadcastService $broadcastService,
114
		FederatedLinksRequest $federatedLinksRequest,
115
		EventsService $eventsService,
116
		ClientService $clientService,
117
		MiscService $miscService
118
	) {
119
		$this->userId = $userId;
120
		$this->l10n = $l10n;
121
		$this->circlesRequest = $circlesRequest;
122
		$this->configService = $configService;
123
		$this->circlesService = $circlesService;
124
		$this->broadcastService = $broadcastService;
125
		$this->federatedLinksRequest = $federatedLinksRequest;
126
		$this->eventsService = $eventsService;
127
		$this->serverHost = $this->configService->getLocalAddress();
128
129
130
		$this->clientService = $clientService;
131
		$this->miscService = $miscService;
132
	}
133
134
135
	/**
136
	 * linkCircle();
137
	 *
138
	 * link to a circle.
139
	 * Function will check if settings allow Federated links between circles, and the format of
140
	 * the link ($remote). If no exception, a request to the remote circle will be initiated
141
	 * using requestLinkWithCircle()
142
	 *
143
	 * $remote format: <circle_name>@<remote_host>
144
	 *
145
	 * @param string $circleUniqueId
146
	 * @param string $remote
147
	 *
148
	 * @throws Exception
149
	 * @throws FederatedCircleLinkFormatException
150
	 * @throws CircleTypeNotValidException
151
	 *
152
	 * @return FederatedLink
153
	 */
154
	public function linkCircle($circleUniqueId, $remote) {
155
156
		if (!$this->configService->isFederatedCirclesAllowed()) {
157
			throw new FederatedCircleNotAllowedException(
158
				$this->l10n->t("Federated circles are not allowed on this Nextcloud")
159
			);
160
		}
161
162
		if (strpos($remote, '@') === false) {
163
			throw new FederatedCircleLinkFormatException(
164
				$this->l10n->t("Federated link does not have a valid format")
165
			);
166
		}
167
168
		try {
169
			return $this->requestLinkWithCircle($circleUniqueId, $remote);
170
		} catch (Exception $e) {
171
			throw $e;
172
		}
173
	}
174
175
176
	/**
177
	 * linkStatus()
178
	 *
179
	 * Update the status of a link.
180
	 * Function will check if user can edit the status, will update it and send the update to
181
	 * remote
182
	 *
183
	 * @param int $linkId
184
	 * @param int $status
185
	 *
186
	 * @throws Exception
187
	 * @throws FederatedCircleLinkFormatException
188
	 * @throws CircleTypeNotValidException
189
	 * @throws MemberIsNotAdminException
190
	 *
191
	 * @return FederatedLink[]
192
	 */
193
	public function linkStatus($linkId, $status) {
194
195
		$status = (int)$status;
196
		$link = null;
197
		try {
198
199
			$link = $this->circlesRequest->getLinkFromId($linkId);
200
			$circle = $this->circlesRequest->getCircle($link->getCircleId(), $this->userId);
201
			$circle->hasToBeFederated();
202
			$circle->getHigherViewer()
203
				   ->hasToBeAdmin();
204
			$link->hasToBeValidStatusUpdate($status);
205
206
			if (!$this->eventOnLinkStatus($circle, $link, $status)) {
207
				return $this->circlesRequest->getLinksFromCircle($circle->getUniqueId());
208
			}
209
210
		} catch (Exception $e) {
211
			throw $e;
212
		}
213
214
		$link->setStatus($status);
215
		$link->setCircleId($circle->getUniqueId(true));
216
217
		try {
218
			$this->updateLinkRemote($link);
219
		} catch (Exception $e) {
220
			if ($status !== FederatedLink::STATUS_LINK_REMOVE) {
221
				throw $e;
222
			}
223
		}
224
225
		$this->federatedLinksRequest->update($link);
226
227
		return $this->circlesRequest->getLinksFromCircle($circle->getUniqueId());
228
	}
229
230
231
	/**
232
	 * eventOnLinkStatus();
233
	 *
234
	 * Called by linkStatus() to manage events when status is changing.
235
	 * If status does not need update, returns false;
236
	 *
237
	 * @param Circle $circle
238
	 * @param FederatedLink $link
239
	 * @param $status
240
	 *
241
	 * @return bool
242
	 */
243
	private function eventOnLinkStatus(Circle $circle, FederatedLink $link, $status) {
244
		if ($link->getStatus() === $status) {
245
			return false;
246
		}
247
248
		if ($status === FederatedLink::STATUS_LINK_REMOVE) {
249
			$this->eventsService->onLinkRemove($circle, $link);
250
		}
251
252
		if ($status === FederatedLink::STATUS_LINK_UP) {
253
			$this->eventsService->onLinkRequestAccepting($circle, $link);
254
			$this->eventsService->onLinkUp($circle, $link);
255
		}
256
257
		return true;
258
	}
259
260
261
	/**
262
	 * requestLinkWithCircle()
263
	 *
264
	 * Using CircleId, function will get more infos from the database.
265
	 * Will check if author is at least admin and initiate a FederatedLink, save it
266
	 * in the database and send a request to the remote circle using requestLink()
267
	 * If any issue, entry is removed from the database.
268
	 *
269
	 * @param string $circleUniqueId
270
	 * @param string $remote
271
	 *
272
	 * @return FederatedLink
273
	 * @throws Exception
274
	 */
275
	private function requestLinkWithCircle($circleUniqueId, $remote) {
276
277
		$link = null;
278
		try {
279
			list($remoteCircle, $remoteAddress) = explode('@', $remote, 2);
280
281
			$circle = $this->circlesService->detailsCircle($circleUniqueId);
282
			$circle->getHigherViewer()
283
				   ->hasToBeAdmin();
284
			$circle->hasToBeFederated();
285
			$circle->cantBePersonal();
286
287
			$link = new FederatedLink();
288
			$link->setCircleId($circleUniqueId)
289
				 ->setLocalAddress($this->serverHost)
290
				 ->setAddress($remoteAddress)
291
				 ->setRemoteCircleName($remoteCircle)
292
				 ->setStatus(FederatedLink::STATUS_LINK_SETUP)
293
				 ->generateToken();
294
295
			$this->federatedLinksRequest->create($link);
296
			$this->requestLink($circle, $link);
297
298
		} catch (Exception $e) {
299
			if ($link !== null) {
300
				$this->federatedLinksRequest->delete($link);
301
			}
302
			throw $e;
303
		}
304
305
		return $link;
306
	}
307
308
309
	/**
310
	 * @param string $remote
311
	 *
312
	 * @return string
313
	 */
314
	private function generateLinkRemoteURL($remote) {
315
		return $this->generateRemoteHost($remote) . self::REMOTE_URL_LINK;
316
	}
317
318
319
	/**
320
	 * @param string $remote
321
	 *
322
	 * @return string
323
	 */
324
	private function generatePayloadDeliveryURL($remote) {
325
		return $this->generateRemoteHost($remote) . self::REMOTE_URL_PAYLOAD;
326
	}
327
328
329
	/**
330
	 * @param string $remote
331
	 *
332
	 * @return string
333
	 */
334
	private function generateRemoteHost($remote) {
335
		if ((!$this->configService->isNonSSLLinksAllowed() || strpos($remote, 'http://') !== 0)
336
			&& strpos($remote, 'https://') !== 0
337
		) {
338
			$remote = 'https://' . $remote;
339
		}
340
341
		return rtrim($remote, '/');
342
	}
343
344
345
	/**
346
	 * requestLink()
347
	 *
348
	 *
349
	 * @param Circle $circle
350
	 * @param FederatedLink $link
351
	 *
352
	 * @return boolean
353
	 * @throws Exception
354
	 */
355
	private function requestLink(Circle $circle, FederatedLink &$link) {
356
		$args = [
357
			'apiVersion' => Circles::version(),
358
			'token'      => $link->getToken(true),
359
			'uniqueId'   => $circle->getUniqueId(true),
360
			'sourceName' => $circle->getName(),
361
			'linkTo'     => $link->getRemoteCircleName(),
362
			'address'    => $link->getLocalAddress()
363
		];
364
365
		$client = $this->clientService->newClient();
366
367
		try {
368
			$request = $client->put(
369
				$this->generateLinkRemoteURL($link->getAddress()), [
370
																	 'body'            => $args,
371
																	 'timeout'         => 10,
372
																	 'connect_timeout' => 10,
373
																 ]
374
			);
375
376
			$result = json_decode($request->getBody(), true);
377
			if ($result === null) {
378
				throw new FederatedRemoteIsDownException(
379
					$this->l10n->t(
380
						'The remote host is down or the Circles app is not installed on it'
381
					)
382
				);
383
			}
384
385
			$this->eventOnRequestLink(
386
				$circle, $link, $result['status'],
387
				((key_exists('reason', $result)) ? $result['reason'] : '')
388
			);
389
390
			$link->setUniqueId($result['uniqueId']);
391
			$this->federatedLinksRequest->update($link);
392
393
			return true;
394
		} catch (Exception $e) {
395
			throw $e;
396
		}
397
	}
398
399
400
	/**
401
	 * eventOnRequestLink();
402
	 *
403
	 * Called by requestLink() will update status and event
404
	 * Will also manage errors returned by the remote link
405
	 *
406
	 * @param Circle $circle
407
	 * @param FederatedLink $link
408
	 * @param $status
409
	 * @param $reason
410
	 *
411
	 * @throws Exception
412
	 */
413
	private function eventOnRequestLink(Circle $circle, FederatedLink $link, $status, $reason) {
414
415
		try {
416
			if ($status === FederatedLink::STATUS_LINK_UP) {
417
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
418
				$this->eventsService->onLinkUp($circle, $link);
419
			} else if ($status === FederatedLink::STATUS_LINK_REQUESTED) {
420
				$link->setStatus(FederatedLink::STATUS_REQUEST_SENT);
421
				$this->eventsService->onLinkRequestSent($circle, $link);
422
			} else {
423
				$this->parseRequestLinkError($reason);
424
			}
425
		} catch (Exception $e) {
426
			throw $e;
427
		}
428
	}
429
430
431
	/**
432
	 * parseRequestLinkError();
433
	 *
434
	 * Will parse the error reason returned by requestLink() and throw an Exception
435
	 *
436
	 * @param $reason
437
	 *
438
	 * @throws Exception
439
	 * @throws FederatedRemoteCircleDoesNotExistException
440
	 * @throws FederatedRemoteDoesNotAllowException
441
	 */
442
	private function parseRequestLinkError($reason) {
443
444
		if ($reason === 'federated_not_allowed') {
445
			throw new FederatedRemoteDoesNotAllowException(
446
				$this->l10n->t('Federated circles are not allowed on the remote Nextcloud')
447
			);
448
		}
449
450
		if ($reason === 'circle_links_disable') {
451
			throw new FederatedRemoteDoesNotAllowException(
452
				$this->l10n->t('The remote circle does not accept federated links')
453
			);
454
		}
455
456
		if ($reason === 'duplicate_unique_id') {
457
			throw new FederatedRemoteDoesNotAllowException(
458
				$this->l10n->t('It seems that you are trying to link a circle to itself')
459
			);
460
		}
461
462
		if ($reason === 'duplicate_link') {
463
			throw new FederatedRemoteDoesNotAllowException(
464
				$this->l10n->t('This link exists already')
465
			);
466
		}
467
468
		if ($reason === 'circle_does_not_exist') {
469
			throw new FederatedRemoteCircleDoesNotExistException(
470
				$this->l10n->t('The requested remote circle does not exist')
471
			);
472
		}
473
474
		throw new Exception($reason);
475
	}
476
477
478
	/**
479
	 * @param string $token
480
	 * @param string $uniqueId
481
	 * @param int $status
482
	 *
483
	 * @return FederatedLink
484
	 * @throws Exception
485
	 */
486
	public function updateLinkFromRemote($token, $uniqueId, $status) {
487
		try {
488
			$link = $this->circlesRequest->getLinkFromToken($token, $uniqueId);
489
			$circle = $this->circlesRequest->forceGetCircle($link->getCircleId());
490
			$circle->hasToBeFederated();
491
492
			$this->checkUpdateLinkFromRemote($status);
493
			$this->checkUpdateLinkFromRemoteLinkUp($circle, $link, $status);
494
			$this->checkUpdateLinkFromRemoteLinkRemove($circle, $link, $status);
495
496
			if ($link->getStatus() !== $status) {
497
				$this->federatedLinksRequest->update($link);
498
			}
499
500
			return $link;
501
		} catch (Exception $e) {
502
			throw $e;
503
		}
504
	}
505
506
	/**
507
	 * checkUpdateLinkFromRemote();
508
	 *
509
	 * will throw exception is the status sent by remote is not correct
510
	 *
511
	 * @param int $status
512
	 *
513
	 * @throws FederatedCircleStatusUpdateException
514
	 */
515
	private function checkUpdateLinkFromRemote($status) {
516
		$status = (int)$status;
517
		if ($status !== FederatedLink::STATUS_LINK_UP
518
			&& $status !== FederatedLink::STATUS_LINK_REMOVE
519
		) {
520
			throw new FederatedCircleStatusUpdateException(
521
				$this->l10n->t('Cannot proceed with this status update')
522
			);
523
		}
524
	}
525
526
527
	/**
528
	 * checkUpdateLinkFromRemoteLinkUp()
529
	 *
530
	 * in case of a request of status update from remote for a link up, we check the current
531
	 * status of the link locally.
532
	 *
533
	 * @param Circle $circle
534
	 * @param FederatedLink $link
535
	 * @param int $status
536
	 *
537
	 * @throws FederatedCircleStatusUpdateException
538
	 */
539
	private function checkUpdateLinkFromRemoteLinkUp(Circle $circle, FederatedLink $link, $status) {
540
		if ((int)$status !== FederatedLink::STATUS_LINK_UP) {
541
			return;
542
		}
543
544
		if ($link->getStatus() !== FederatedLink::STATUS_REQUEST_SENT) {
545
			throw new FederatedCircleStatusUpdateException(
546
				$this->l10n->t('Cannot proceed with this status update')
547
			);
548
		}
549
550
		$this->eventsService->onLinkRequestAccepted($circle, $link);
551
		$this->eventsService->onLinkUp($circle, $link);
552
		$link->setStatus($status);
553
	}
554
555
556
	/**
557
	 * checkUpdateLinkFromRemoteLinkRemove();
558
	 *
559
	 * in case of a request of status update from remote for a link down, we check the current
560
	 * status of the link locally
561
	 *
562
	 * @param Circle $circle
563
	 * @param FederatedLink $link
564
	 * @param int $status
565
	 *
566
	 * @throws FederatedCircleStatusUpdateException
567
	 */
568
	private function checkUpdateLinkFromRemoteLinkRemove(
569
		Circle $circle, FederatedLink $link, $status
570
	) {
571
		if ((int)$status !== FederatedLink::STATUS_LINK_REMOVE) {
572
			return;
573
		}
574
575 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...
576
			$link->setStatus(FederatedLink::STATUS_REQUEST_DECLINED);
577
			$this->eventsService->onLinkRequestRejected($circle, $link);
578
579
			return;
580
		}
581
582 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...
583
			$link->setStatus(FederatedLink::STATUS_LINK_REMOVE);
584
			$this->eventsService->onLinkRequestCanceled($circle, $link);
585
586
			return;
587
		}
588
589 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...
590
			$link->setStatus(FederatedLink::STATUS_LINK_DOWN);
591
			$this->eventsService->onLinkDown($circle, $link);
592
593
			return;
594
		}
595
596
		throw new FederatedCircleStatusUpdateException(
597
			$this->l10n->t('Cannot proceed with this status update')
598
		);
599
	}
600
601
602
	/**
603
	 * updateLinkRemote()
604
	 *
605
	 * Send a request to the remote of the link to update its status.
606
	 *
607
	 * @param FederatedLink $link
608
	 *
609
	 * @return bool
610
	 * @throws Exception
611
	 */
612
	public function updateLinkRemote(FederatedLink &$link) {
613
		$args = [
614
			'apiVersion' => Circles::version(),
615
			'token'      => $link->getToken(true),
616
			'uniqueId'   => $link->getCircleId(true),
617
			'status'     => $link->getStatus()
618
		];
619
620
		$client = $this->clientService->newClient();
621
		try {
622
			$request = $client->post(
623
				$this->generateLinkRemoteURL($link->getAddress()), [
624
																	 'body'            => $args,
625
																	 'timeout'         => 10,
626
																	 'connect_timeout' => 10,
627
																 ]
628
			);
629
630
			$result = json_decode($request->getBody(), true);
631
			if ($result['status'] === -1) {
632
				throw new FederatedLinkUpdateException($result['reason']);
633
			}
634
635
			return true;
636
		} catch (Exception $e) {
637
			throw $e;
638
		}
639
	}
640
641
642
	/**
643
	 * Create a new link into database and assign the correct status.
644
	 *
645
	 * @param Circle $circle
646
	 * @param FederatedLink $link
647
	 *
648
	 * @throws Exception
649
	 */
650
	public function initiateLink(Circle $circle, FederatedLink &$link) {
651
652
		try {
653
			$this->checkLinkRequestValidity($circle, $link);
654
			$link->setCircleId($circle->getUniqueId());
655
656
			if ($circle->getSetting('allow_links_auto') === 'true') {
657
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
658
				$this->eventsService->onLinkUp($circle, $link);
659
			} else {
660
				$link->setStatus(FederatedLink::STATUS_LINK_REQUESTED);
661
				$this->eventsService->onLinkRequestReceived($circle, $link);
662
			}
663
664
			$this->federatedLinksRequest->create($link);
665
		} catch (Exception $e) {
666
			throw $e;
667
		}
668
	}
669
670
671
	/**
672
	 * @param Circle $circle
673
	 * @param FederatedLink $link
674
	 *
675
	 * @throws FederatedLinkCreationException
676
	 */
677
	private function checkLinkRequestValidity($circle, $link) {
678
		if ($circle->getUniqueId(true) === $link->getUniqueId(true)) {
679
			throw new FederatedLinkCreationException('duplicate_unique_id');
680
		}
681
682
		if ($this->getLink($circle->getUniqueId(), $link->getUniqueId(true)) !== null) {
683
			throw new FederatedLinkCreationException('duplicate_link');
684
		}
685
686
		if ($circle->getSetting('allow_links') !== 'true') {
687
			throw new FederatedLinkCreationException('circle_links_disable');
688
		}
689
	}
690
691
692
	/**
693
	 * @param string $token
694
	 * @param string $uniqueId
695
	 * @param SharingFrame $frame
696
	 *
697
	 * @return bool
698
	 * @throws Exception
699
	 */
700
	public function receiveFrame($token, $uniqueId, SharingFrame &$frame) {
701
		try {
702
			$link = $this->circlesRequest->getLinkFromToken((string)$token, (string)$uniqueId);
703
		} catch (Exception $e) {
704
			throw $e;
705
		}
706
707
		try {
708
			$this->circlesRequest->getFrame($link->getCircleId(), $frame->getUniqueId());
709
			throw new SharingFrameAlreadyExistException('shares_is_already_known');
710
		} catch (SharingFrameDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
711
		}
712
713
		try {
714
			$circle = $this->circlesRequest->forceGetCircle($link->getCircleId());
715
		} catch (CircleDoesNotExistException $e) {
716
			throw new CircleDoesNotExistException('unknown_circle');
717
		}
718
719
		$frame->setCircle($circle);
720
		$this->circlesRequest->saveFrame($frame);
721
722
		return true;
723
	}
724
725
	/**
726
	 * @param string $circleUniqueId
727
	 * @param string $uniqueId
728
	 *
729
	 * @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...
730
	 */
731
	public function getLink($circleUniqueId, $uniqueId) {
732
		return $this->federatedLinksRequest->getFromUniqueId($circleUniqueId, $uniqueId);
733
	}
734
735
736
	/**
737
	 * @param string $circleUniqueId
738
	 *
739
	 * @return FederatedLink[]
740
	 */
741
	public function getLinksFromCircle($circleUniqueId) {
742
		return $this->federatedLinksRequest->getLinked($circleUniqueId);
743
	}
744
745
746
	/**
747
	 * @param string $circleUniqueId
748
	 * @param string $frameUniqueId
749
	 *
750
	 * @return bool
751
	 * @throws Exception
752
	 */
753
	public function initiateShare($circleUniqueId, $frameUniqueId) {
754
		$args = [
755
			'circleId'   => $circleUniqueId,
756
			'frameId'    => $frameUniqueId
757
		];
758
759
		$client = $this->clientService->newClient();
760
		try {
761
			$client->post(
762
				$this->generatePayloadDeliveryURL($this->serverHost), [
763
																		'body'            => $args,
764
																		'timeout'         => 10,
765
																		'connect_timeout' => 10,
766
																	]
767
			);
768
769
//			$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...
770
//			$this->miscService->log(
771
//				"initiateRemoteShare result: " . $uniqueId . '  ----  ' . var_export($result, true)
772
//			);
773
774
			return true;
775
		} catch (Exception $e) {
776
			throw $e;
777
		}
778
	}
779
780
781
	/**
782
	 * @param SharingFrame $frame
783
	 *
784
	 * @throws Exception
785
	 */
786
	public function sendRemoteShare(SharingFrame $frame) {
787
788
		try {
789
			$circle = $this->circlesRequest->forceGetCircle(
790
				$frame->getCircle()
791
					  ->getUniqueId()
792
			);
793
		} catch (CircleDoesNotExistException $e) {
794
			throw new CircleDoesNotExistException('unknown_circle');
795
		}
796
797
		$links = $this->getLinksFromCircle(
798
			$frame->getCircle()
799
				  ->getUniqueId()
800
		);
801
802
		foreach ($links AS $link) {
803
804
805
			$args = [
806
				'apiVersion' => Circles::version(),
807
				'token'      => $link->getToken(true),
808
				'uniqueId'   => $circle->getUniqueId(true),
809
				'item'       => json_encode($frame)
810
			];
811
812
			$client = $this->clientService->newClient();
813
			try {
814
				$request = $client->put(
815
					$this->generatePayloadDeliveryURL($link->getAddress()), [
816
																			  'body'            => $args,
817
																			  'timeout'         => 10,
818
																			  'connect_timeout' => 10,
819
																		  ]
820
				);
821
822
				$result = json_decode($request->getBody(), true);
823
				if ($result['status'] === -1) {
824
					throw new PayloadDeliveryException($result['reason']);
825
				}
826
827
			} catch (Exception $e) {
828
				$this->miscService->log(
829
					'Issue while sending sharing frame to ' . $link->getAddress() . ' - '
830
					. $e->getMessage()
831
				);
832
			}
833
		}
834
	}
835
836
837
	/**
838
	 * generateHeaders()
839
	 *
840
	 * Generate new headers for the current Payload, and save them in the SharingFrame.
841
	 *
842
	 * @param SharingFrame $frame
843
	 */
844
	public function updateFrameWithCloudId(SharingFrame $frame) {
845
		$frame->setCloudId($this->serverHost);
846
		$this->circlesRequest->updateFrame($frame);
847
	}
848
849
}