Completed
Push — master ( c4f011...0a2d75 )
by Maxence
03:16
created

FederatedService::getLink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
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\CircleTypeNotValid;
39
use OCA\Circles\Exceptions\FederatedCircleStatusUpdateException;
40
use OCA\Circles\Exceptions\FederatedRemoteCircleDoesNotExistException;
41
use OCA\Circles\Exceptions\FederatedRemoteDoesNotAllowException;
42
use OCA\Circles\Exceptions\FrameAlreadyExistException;
43
use OCA\Circles\Exceptions\LinkCreationException;
44
use OCA\Circles\Exceptions\MemberIsNotAdminException;
45
use OCA\Circles\Model\Circle;
46
use OCA\Circles\Model\FederatedLink;
47
use OCA\Circles\Model\SharingFrame;
48
use OCP\IL10N;
49
50
class FederatedService {
51
52
53
	/** @var string */
54
	private $userId;
55
56
	/** @var IL10N */
57
	private $l10n;
58
59
	/** @var CirclesRequest */
60
	private $circlesRequest;
61
62
	/** @var ConfigService */
63
	private $configService;
64
65
	/** @var CirclesService */
66
	private $circlesService;
67
68
	/** @var BroadcastService */
69
	private $broadcastService;
70
71
	/** @var FederatedLinksRequest */
72
	private $federatedLinksRequest;
73
74
	/** @var string */
75
	private $serverHost;
76
77
	/** @var ClientService */
78
	private $clientService;
79
80
	/** @var MiscService */
81
	private $miscService;
82
83
	/** @var bool */
84
	private $localTest = false;
85
86
	/**
87
	 * CirclesService constructor.
88
	 *
89
	 * @param $userId
90
	 * @param IL10N $l10n
91
	 * @param CirclesRequest $circlesRequest
92
	 * @param ConfigService $configService
93
	 * @param CirclesService $circlesService
94
	 * @param BroadcastService $broadcastService
95
	 * @param FederatedLinksRequest $federatedLinksRequest
96
	 * @param string $serverHost
97
	 * @param ClientService $clientService
98
	 * @param MiscService $miscService
99
	 */
100
	public function __construct(
101
		$userId,
102
		IL10N $l10n,
103
		CirclesRequest $circlesRequest,
104
		ConfigService $configService,
105
		CirclesService $circlesService,
106
		BroadcastService $broadcastService,
107
		FederatedLinksRequest $federatedLinksRequest,
108
		$serverHost,
109
		ClientService $clientService,
110
		MiscService $miscService
111
	) {
112
		$this->userId = $userId;
113
		$this->l10n = $l10n;
114
		$this->circlesRequest = $circlesRequest;
115
		$this->configService = $configService;
116
		$this->circlesService = $circlesService;
117
		$this->broadcastService = $broadcastService;
118
		$this->federatedLinksRequest = $federatedLinksRequest;
119
		$this->serverHost = (string)$serverHost;
120
		$this->clientService = $clientService;
121
		$this->miscService = $miscService;
122
	}
123
124
125
	/**
126
	 * linkCircle()
127
	 *
128
	 * link to a circle.
129
	 * Function will check if settings allow Federated links between circles, and the format of
130
	 * the link ($remote). If no exception, a request to the remote circle will be initiated
131
	 * using requestLinkWithCircle()
132
	 *
133
	 * $remote format: <circle_name>@<remote_host>
134
	 *
135
	 * @param int $circleId
136
	 * @param string $remote
137
	 *
138
	 * @throws Exception
139
	 * @throws FederatedCircleLinkFormatException
140
	 * @throws CircleTypeNotValid
141
	 * @throws MemberIsNotAdminException
142
	 *
143
	 * @return FederatedLink
144
	 */
145
	public function linkCircle($circleId, $remote) {
146
147
		if (!$this->configService->isFederatedAllowed()) {
148
			throw new FederatedCircleNotAllowedException(
149
				$this->l10n->t("Federated circles are not allowed on this Nextcloud")
150
			);
151
		}
152
153
		if (strpos($remote, '@') === false) {
154
			throw new FederatedCircleLinkFormatException(
155
				$this->l10n->t("Federated link does not have a valid format")
156
			);
157
		}
158
159
		try {
160
			return $this->requestLinkWithCircle($circleId, $remote);
161
		} catch (Exception $e) {
162
			throw $e;
163
		}
164
	}
165
166
167
	/**
168
	 * linkStatus()
169
	 *
170
	 * Update the status of a link.
171
	 * Function will check if user can edit the status, will update it and send the update to
172
	 * remote
173
	 *
174
	 * @param int $linkId
175
	 * @param int $status
176
	 *
177
	 * @throws Exception
178
	 * @throws FederatedCircleLinkFormatException
179
	 * @throws CircleTypeNotValid
180
	 * @throws MemberIsNotAdminException
181
	 *
182
	 * @return FederatedLink[]
183
	 */
184
	public function linkStatus($linkId, $status) {
185
186
		$status = (int)$status;
187
		$link = null;
188
		try {
189
190
			$link = $this->circlesRequest->getLinkFromId($linkId);
191
			$circle = $this->circlesRequest->getCircleFromId($link->getCircleId(), $this->userId);
192
			$circle->hasToBeFederated();
193
194
			$link->hasToBeValidStatusUpdate($status);
195
			$link->setStatus($status);
196
197
			$this->federatedLinksRequest->update($link);
0 ignored issues
show
Bug introduced by
It seems like $link defined by $this->circlesRequest->getLinkFromId($linkId) on line 190 can be null; however, OCA\Circles\Db\FederatedLinksRequest::update() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
198
199
		} catch (Exception $e) {
200
			throw $e;
201
		}
202
203
		try {
204
			$link->setUniqueId($circle->getUniqueId());
205
			$this->updateLinkRemote($link);
0 ignored issues
show
Bug introduced by
It seems like $link defined by $this->circlesRequest->getLinkFromId($linkId) on line 190 can be null; however, OCA\Circles\Service\Fede...ice::updateLinkRemote() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
206
		} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
207
		}
208
209
		return $this->circlesRequest->getLinksFromCircle($circle->getId());
210
	}
211
212
213
	/**
214
	 * requestLinkWithCircle()
215
	 *
216
	 * Using CircleId, function will get more infos from the database.
217
	 * Will check if author is at least admin and initiate a FederatedLink, save it
218
	 * in the database and send a request to the remote circle using requestLink()
219
	 * If any issue, entry is removed from the database.
220
	 *
221
	 * @param integer $circleId
222
	 * @param string $remote
223
	 *
224
	 * @return FederatedLink
225
	 * @throws Exception
226
	 */
227
	private function requestLinkWithCircle($circleId, $remote) {
228
229
		$link = null;
230
		try {
231
			list($remoteCircle, $remoteAddress) = explode('@', $remote, 2);
232
233
			$circle = $this->circlesService->detailsCircle($circleId);
234
			$circle->getUser()
235
				   ->hasToBeAdmin();
236
			$circle->hasToBeFederated();
237
			$circle->cantBePersonal();
238
239
			$link = new FederatedLink();
240
			$link->setCircleId($circleId)
241
				 ->setLocalAddress($this->serverHost)
242
				 ->setAddress($remoteAddress)
243
				 ->setRemoteCircleName($remoteCircle)
244
				 ->setStatus(FederatedLink::STATUS_LINK_SETUP)
245
				 ->generateToken();
246
247
			$this->federatedLinksRequest->create($link);
248
			$this->requestLink($circle, $link);
249
250
		} catch (Exception $e) {
251
			if ($link !== null) {
252
				$this->federatedLinksRequest->delete($link);
253
			}
254
			throw $e;
255
		}
256
257
		return $link;
258
	}
259
260
261
	/**
262
	 * @param string $remote
263
	 *
264
	 * @return string
265
	 */
266 View Code Duplication
	private function generateLinkRemoteURL($remote) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
267
		if ($this->localTest === false && strpos($remote, 'https') !== 0) {
268
			$remote = 'https://' . $remote;
269
		}
270
271
		return rtrim($remote, '/') . '/index.php/apps/circles/v1/link';
272
	}
273
274
275
	/**
276
	 * @param string $remote
277
	 *
278
	 * @return string
279
	 */
280 View Code Duplication
	private function generatePayloadDeliveryURL($remote) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
281
		if ($this->localTest === false && strpos($remote, 'https') !== 0) {
282
			$remote = 'https://' . $remote;
283
		}
284
285
		return rtrim($remote, '/') . '/index.php/apps/circles/v1/payload';
286
	}
287
288
289
	public function allowNonSSLLink() {
290
		$this->localTest = true;
291
	}
292
293
294
	/**
295
	 * requestLink()
296
	 *
297
	 *
298
	 * @param Circle $circle
299
	 * @param FederatedLink $link
300
	 *
301
	 * @return boolean
302
	 * @throws Exception
303
	 */
304
	private function requestLink(Circle $circle, FederatedLink & $link) {
305
		$args = [
306
			'apiVersion' => Circles::API_VERSION,
307
			'token'      => $link->getToken(),
308
			'uniqueId'   => $circle->getUniqueId(),
309
			'sourceName' => $circle->getName(),
310
			'linkTo'     => $link->getRemoteCircleName(),
311
			'address'    => $link->getLocalAddress()
312
		];
313
314
		$client = $this->clientService->newClient();
315
316
		try {
317
			$request = $client->put(
318
				$this->generateLinkRemoteURL($link->getAddress()), [
319
																	 'body'            => $args,
320
																	 'timeout'         => 10,
321
																	 'connect_timeout' => 10,
322
																 ]
323
			);
324
325
			$result = json_decode($request->getBody(), true);
326
327
			if ($result['status'] === FederatedLink::STATUS_LINK_UP) {
328
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
329
			} else if ($result['status'] === FederatedLink::STATUS_LINK_REQUESTED) {
330
				$link->setStatus(FederatedLink::STATUS_REQUEST_SENT);
331
			} else {
332
				$this->parsingRequestLinkResult($result);
333
			}
334
335
			$link->setUniqueId($result['uniqueId']);
336
			$this->federatedLinksRequest->uniqueness($link);
337
			$this->federatedLinksRequest->update($link);
338
339
			return true;
340
		} catch (Exception $e) {
341
			throw $e;
342
		}
343
	}
344
345
346
	/**
347
	 * @param $token
348
	 * @param $uniqueId
349
	 * @param $status
350
	 *
351
	 * @return FederatedLink
352
	 * @throws Exception
353
	 */
354
	public function updateLinkFromRemote($token, $uniqueId, $status) {
355
		try {
356
			$link = $this->circlesRequest->getLinkFromToken($token, $uniqueId);
357
			$circle = $this->circlesRequest->getCircleFromId($link->getCircleId());
358
			$circle->hasToBeFederated();
359
360
361
			$this->checkUpdateLinkFromRemote($link, $status);
0 ignored issues
show
Bug introduced by
It seems like $link defined by $this->circlesRequest->g...oken($token, $uniqueId) on line 356 can be null; however, OCA\Circles\Service\Fede...kUpdateLinkFromRemote() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
362
			$this->checkUpdateLinkFromRemoteLinkUp($link, $status);
363
			$this->checkUpdateLinkFromRemoteLinkRemove($link, $status);
364
365
			if ($link->getStatus() !== $status) {
366
				$this->federatedLinksRequest->update($link);
367
			}
368
369
			return $link;
370
		} catch (Exception $e) {
371
			throw $e;
372
		}
373
	}
374
375
	/**
376
	 * @param FederatedLink $link
377
	 * @param $status
378
	 *
379
	 * @throws FederatedCircleStatusUpdateException
380
	 */
381
	private function checkUpdateLinkFromRemote(FederatedLink &$link, $status) {
0 ignored issues
show
Unused Code introduced by
The parameter $link is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
382
		$status = (int)$status;
383
		if ($status === FederatedLink::STATUS_LINK_UP
384
			|| $status === FederatedLink::STATUS_LINK_REMOVE
385
		) {
386
			return;
387
		}
388
389
		throw new FederatedCircleStatusUpdateException(
390
			$this->l10n->t('Cannot proceed with this status update')
391
		);
392
	}
393
394
395
	/**
396
	 * @param FederatedLink $link
397
	 * @param $status
398
	 *
399
	 * @throws FederatedCircleStatusUpdateException
400
	 */
401
	private function checkUpdateLinkFromRemoteLinkUp(FederatedLink &$link, $status) {
402
		if ((int)$status !== FederatedLink::STATUS_LINK_UP) {
403
			return;
404
		}
405
406
		if ($link->getStatus() !== FederatedLink::STATUS_REQUEST_SENT) {
407
			throw new FederatedCircleStatusUpdateException(
408
				$this->l10n->t('Cannot proceed with this status update')
409
			);
410
		}
411
412
		$link->setStatus($status);
413
	}
414
415
416
	/**
417
	 * @param FederatedLink $link
418
	 * @param $status
419
	 *
420
	 * @throws FederatedCircleStatusUpdateException
421
	 */
422
	private function checkUpdateLinkFromRemoteLinkRemove(FederatedLink &$link, $status) {
423
		if ((int)$status !== FederatedLink::STATUS_LINK_REMOVE) {
424
			return;
425
		}
426
427
		if ($link->getStatus() === FederatedLink::STATUS_REQUEST_SENT) {
428
			$link->setStatus(FederatedLink::STATUS_REQUEST_DECLINED);
429
430
			return;
431
		} else if ($link->getStatus() === FederatedLink::STATUS_LINK_REQUESTED) {
432
			$link->setStatus(FederatedLink::STATUS_LINK_REMOVE);
433
434
			return;
435
		} else if ($link->getStatus() > FederatedLink::STATUS_LINK_DOWN) {
436
437
			$link->setStatus(FederatedLink::STATUS_LINK_DOWN);
438
439
			return;
440
		}
441
		throw new FederatedCircleStatusUpdateException(
442
			$this->l10n->t('Cannot proceed with this status update')
443
		);
444
	}
445
446
447
	/**
448
	 * updateLinkRemote()
449
	 *
450
	 * Send a request to the remote of the link to update its status.
451
	 *
452
	 * @param FederatedLink $link
453
	 *
454
	 * @return boolean
455
	 * @throws Exception
456
	 */
457
	public function updateLinkRemote(FederatedLink & $link) {
458
		$args = [
459
			'apiVersion' => Circles::API_VERSION,
460
			'token'      => $link->getToken(),
461
			'uniqueId'   => $link->getUniqueId(),
462
			'status'     => $link->getStatus()
463
		];
464
465
		$client = $this->clientService->newClient();
466
467
		try {
468
			$client->post(
469
				$this->generateLinkRemoteURL($link->getAddress()), [
470
																	 'body'            => $args,
471
																	 'timeout'         => 10,
472
																	 'connect_timeout' => 10,
473
																 ]
474
			);
475
476
			return true;
477
		} catch (Exception $e) {
478
			throw $e;
479
		}
480
	}
481
482
483
	private function parsingRequestLinkResult($result) {
484
485
		if ($result['reason'] === 'federated_not_allowed') {
486
			throw new FederatedRemoteDoesNotAllowException(
487
				$this->l10n->t('Federated circles are not allowed on the remote Nextcloud')
488
			);
489
		}
490
491
		if ($result['reason'] === 'circle_links_disable') {
492
			throw new FederatedRemoteDoesNotAllowException(
493
				$this->l10n->t('The remote circle does not accept Federated Links')
494
			);
495
		}
496
497
		if ($result['reason'] === 'duplicate_unique_id') {
498
			throw new FederatedRemoteDoesNotAllowException(
499
				$this->l10n->t('It seems that you are trying to link a circle to itself')
500
			);
501
		}
502
503
		if ($result['reason'] === 'duplicate_link') {
504
			throw new FederatedRemoteDoesNotAllowException(
505
				$this->l10n->t('This link exists already')
506
			);
507
		}
508
509
		if ($result['reason'] === 'circle_does_not_exist') {
510
			throw new FederatedRemoteCircleDoesNotExistException(
511
				$this->l10n->t('The requested remote circle does not exist')
512
			);
513
		}
514
515
		throw new Exception($result['reason']);
516
	}
517
518
519
	/**
520
	 * Create a new link into database and assign the correct status.
521
	 *
522
	 * @param Circle $circle
523
	 * @param FederatedLink $link
524
	 *
525
	 * @throws Exception
526
	 */
527
	public function initiateLink(Circle $circle, FederatedLink & $link) {
528
529
		try {
530
			$this->checkLinkRequestValidity($circle, $link);
531
			$link->setCircleId($circle->getId());
532
533
			if ($circle->getSetting('allow_links_auto') === 'true') {
534
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
535
			} else {
536
				$link->setStatus(FederatedLink::STATUS_LINK_REQUESTED);
537
			}
538
539
			$this->federatedLinksRequest->create($link);
540
		} catch (Exception $e) {
541
			throw $e;
542
		}
543
	}
544
545
546
	/**
547
	 * @param Circle $circle
548
	 * @param FederatedLink $link
549
	 *
550
	 * @throws LinkCreationException
551
	 */
552
	private function checkLinkRequestValidity($circle, $link) {
553
		if ($circle->getUniqueId() === $link->getUniqueId()) {
554
			throw new LinkCreationException('duplicate_unique_id');
555
		}
556
557
		if ($this->getLink($circle->getId(), $link->getUniqueId()) !== null) {
558
			throw new LinkCreationException('duplicate_link');
559
		}
560
561
		if ($circle->getSetting('allow_links') !== 'true') {
562
			throw new LinkCreationException('circle_links_disable');
563
		}
564
	}
565
566
567
	/**
568
	 * @param string $token
569
	 * @param string $uniqueId
570
	 * @param SharingFrame $frame
571
	 *
572
	 * @return bool
573
	 * @throws Exception
574
	 */
575
	public function receiveFrame($token, $uniqueId, SharingFrame & $frame) {
576
		try {
577
578
			$link = $this->circlesRequest->getLinkFromToken((string)$token, (string)$uniqueId);
579
		} catch (Exception $e) {
580
			throw $e;
581
		}
582
583
		if ($this->circlesRequest->getFrame($link->getCircleId(), $frame->getUniqueId())) {
584
			$this->miscService->log("Frame already exist");
585
			throw new FrameAlreadyExistException('shares_is_already_known');
586
		}
587
588
		try {
589
			$circle = $this->circlesRequest->getCircleFromId($link->getCircleId());
590
		} catch (CircleDoesNotExistException $e) {
591
			throw new CircleDoesNotExistException('unknown_circle');
592
		}
593
594
		$frame->setCircleId($link->getCircleId());
595
		$frame->setCircleName($circle->getName());
596
597
		$this->circlesRequest->saveFrame($frame);
598
		$this->broadcastService->broadcastFrame($frame->getHeader('broadcast'), $frame);
599
600
		return true;
601
	}
602
603
	/**
604
	 * @param integer $circleId
605
	 * @param string $uniqueId
606
	 *
607
	 * @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...
608
	 */
609
	public function getLink($circleId, $uniqueId) {
610
		return $this->federatedLinksRequest->getFromUniqueId($circleId, $uniqueId);
611
	}
612
613
614
	/**
615
	 * @param integer $circleId
616
	 *
617
	 * @return FederatedLink[]
618
	 */
619
	public function getLinks($circleId) {
620
		return $this->federatedLinksRequest->getLinked($circleId);
621
	}
622
623
624
	/**
625
	 * @param int $circleId
626
	 * @param string $uniqueId
627
	 *
628
	 * @return bool
629
	 * @throws Exception
630
	 */
631
	public function initiateRemoteShare($circleId, $uniqueId) {
632
		$args = [
633
			'apiVersion' => Circles::API_VERSION,
634
			'circleId'   => (int)$circleId,
635
			'uniqueId'   => (string)$uniqueId
636
		];
637
638
		$client = $this->clientService->newClient();
639
		try {
640
			$request = $client->post(
641
				$this->generatePayloadDeliveryURL($this->serverHost), [
642
																		'body'            => $args,
643
																		'timeout'         => 10,
644
																		'connect_timeout' => 10,
645
																	]
646
			);
647
648
			$result = json_decode($request->getBody(), true);
649
			$this->miscService->log(
650
				"initiateRemoteShare result: " . $uniqueId . '  ----  ' . var_export($result, true)
651
			);
652
653
			return true;
654
		} catch (Exception $e) {
655
			throw $e;
656
		}
657
	}
658
659
660
	/**
661
	 * @param SharingFrame $frame
662
	 *
663
	 * @throws Exception
664
	 */
665
	public function sendRemoteShare(SharingFrame $frame) {
666
667
		$circle = $this->circlesRequest->getCircleFromId($frame->getCircleId());
668
		if ($circle === null) {
669
			throw new Exception('unknown_circle');
670
		}
671
672
		$links = $this->getLinks($frame->getCircleId());
673
		foreach ($links AS $link) {
674
675
			$args = [
676
				'apiVersion' => Circles::API_VERSION,
677
				'token'      => $link->getToken(),
678
				'uniqueId'   => $circle->getUniqueId(),
679
				'item'       => json_encode($frame)
680
			];
681
682
			$client = $this->clientService->newClient();
683
			try {
684
				$client->put(
685
					$this->generatePayloadDeliveryURL($link->getAddress()), [
686
																			  'body'            => $args,
687
																			  'timeout'         => 10,
688
																			  'connect_timeout' => 10,
689
																		  ]
690
				);
691
			} catch (Exception $e) {
692
				throw $e;
693
			}
694
		}
695
	}
696
697
698
	/**
699
	 * generateHeaders()
700
	 *
701
	 * Generate new headers for the current Payload, and save them in the SharingFrame.
702
	 *
703
	 * @param SharingFrame $frame
704
	 */
705
	public function updateFrameWithCloudId(SharingFrame $frame) {
706
		$frame->setCloudId($this->serverHost);
707
		$this->circlesRequest->updateFrame($frame);
708
	}
709
710
}