Completed
Push — master ( 1990ee...212490 )
by Maxence
04:38 queued 01:45
created

SharingFrameService   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 343
Duplicated Lines 11.08 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 27
c 6
b 0
f 0
lcom 1
cbo 15
dl 38
loc 343
rs 9.1666

13 Methods

Rating   Name   Duplication   Size   Complexity  
A createFrame() 17 17 2
A generateHeaders() 0 16 2
A initiateShare() 0 21 2
A generatePayloadDeliveryURL() 0 3 1
A forwardSharingFrame() 0 18 2
A deliverSharingFrameToLink() 0 23 3
A __construct() 21 21 1
A getFrameFromCircle() 0 3 1
A forceGetFrameFromCircle() 0 10 2
A getFrameFromUniqueId() 0 16 4
A receiveFrame() 0 21 4
A forwardSharingFrameToFederatedLinks() 0 13 2
A updateFrameWithCloudId() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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 OCA\Circles\Api\v1\Circles;
32
use OCA\Circles\AppInfo\Application;
33
use OCA\Circles\Db\CirclesRequest;
34
use OCA\Circles\Db\FederatedLinksRequest;
35
use OCA\Circles\Db\SharingFrameRequest;
36
use OCA\Circles\Exceptions\CircleDoesNotExistException;
37
use OCA\Circles\Exceptions\MemberDoesNotExistException;
38
use OCA\Circles\Exceptions\PayloadDeliveryException;
39
use OCA\Circles\Exceptions\SharingFrameAlreadyDeliveredException;
40
use OCA\Circles\Exceptions\SharingFrameAlreadyExistException;
41
use OCA\Circles\Exceptions\SharingFrameDoesNotExistException;
42
use OCA\Circles\Model\Circle;
43
use OCA\Circles\Model\FederatedLink;
44
use OCA\Circles\Model\SharingFrame;
45
use OCP\Http\Client\IClientService;
46
47
48
class SharingFrameService {
49
50
	/** @var string */
51
	private $userId;
52
53
	/** @var ConfigService */
54
	private $configService;
55
56
	/** @var SharingFrameRequest */
57
	private $sharingFrameRequest;
58
59
	/** @var CirclesRequest */
60
	private $circlesRequest;
61
62
	/** @var FederatedLinksRequest */
63
	private $federatedLinksRequest;
64
65
	/** @var BroadcastService */
66
	private $broadcastService;
67
68
	/** @var FederatedLinkService */
69
	private $federatedLinkService;
70
71
	/** @var IClientService */
72
	private $clientService;
73
74
	/** @var MiscService */
75
	private $miscService;
76
77
78
	/**
79
	 * SharingFrameService constructor.
80
	 *
81
	 * @param string $userId
82
	 * @param ConfigService $configService
83
	 * @param SharingFrameRequest $sharingFrameRequest
84
	 * @param CirclesRequest $circlesRequest
85
	 * @param FederatedLinksRequest $federatedLinksRequest
86
	 * @param BroadcastService $broadcastService
87
	 * @param FederatedLinkService $federatedLinkService
88
	 * @param IClientService $clientService
89
	 * @param MiscService $miscService
90
	 */
91 View Code Duplication
	public function __construct(
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...
92
		$userId,
93
		ConfigService $configService,
94
		SharingFrameRequest $sharingFrameRequest,
95
		CirclesRequest $circlesRequest,
96
		FederatedLinksRequest $federatedLinksRequest,
97
		BroadcastService $broadcastService,
98
		FederatedLinkService $federatedLinkService,
99
		IClientService $clientService,
100
		MiscService $miscService
101
	) {
102
		$this->userId = $userId;
103
		$this->configService = $configService;
104
		$this->sharingFrameRequest = $sharingFrameRequest;
105
		$this->circlesRequest = $circlesRequest;
106
		$this->federatedLinksRequest = $federatedLinksRequest;
107
		$this->broadcastService = $broadcastService;
108
		$this->federatedLinkService = $federatedLinkService;
109
		$this->clientService = $clientService;
110
		$this->miscService = $miscService;
111
	}
112
113
114
	/**
115
	 * createFrame()
116
	 *
117
	 * Save the Frame containing the Payload.
118
	 * The Payload will be shared locally, and spread it live if a Broadcaster is set.
119
	 * Function will also initiate the federated broadcast to linked circles.
120
	 *
121
	 * @param string $circleUniqueId
122
	 * @param SharingFrame $frame
123
	 * @param string|null $broadcast
124
	 *
125
	 * @throws Exception
126
	 * @throws MemberDoesNotExistException
127
	 */
128 View Code Duplication
	public function createFrame($circleUniqueId, SharingFrame $frame, $broadcast = null) {
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...
129
130
		try {
131
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
132
			$circle->getHigherViewer()
133
				   ->hasToBeMember();
134
135
			$frame->setCircle($circle);
136
137
			$this->generateHeaders($frame, $circle, $broadcast);
138
			$this->sharingFrameRequest->saveSharingFrame($frame);
139
140
			$this->initiateShare($circle->getUniqueId(), $frame->getUniqueId());
141
		} catch (Exception $e) {
142
			throw $e;
143
		}
144
	}
145
146
147
	/**
148
	 * Generate Headers and few more thing like UniqueId and Author.
149
	 * Check if the source is NOT Circles.
150
	 *
151
	 * @param SharingFrame $frame
152
	 * @param Circle $circle
153
	 * @param $broadcast
154
	 */
155
	private function generateHeaders(SharingFrame $frame, Circle $circle, $broadcast) {
156
157
		try {
158
			$frame->cannotBeFromCircles();
159
160
			$frame->setAuthor($this->userId);
161
			$frame->setHeader('author', $this->userId);
162
			$frame->setHeader('circleName', $circle->getName());
163
			$frame->setHeader('circleUniqueId', $circle->getUniqueId());
164
			$frame->setHeader('broadcast', (string)$broadcast);
165
			$frame->generateUniqueId();
166
167
		} catch (Exception $e) {
168
			throw new $e;
169
		}
170
	}
171
172
173
	/**
174
	 * return all SharingFrame from a circle regarding a userId.
175
	 *
176
	 * @param string $circleUniqueId
177
	 *
178
	 * @return SharingFrame[]
179
	 */
180
	public function getFrameFromCircle($circleUniqueId) {
181
		return $this->forceGetFrameFromCircle($circleUniqueId, $this->userId);
182
	}
183
184
185
	/**
186
	 * return all SharingFrame from a circle.
187
	 *
188
	 * Warning, result won't be filtered regarding current user session.
189
	 * Please use getFrameFromCircle();
190
	 *
191
	 * @param string $circleUniqueId
192
	 * @param $viewerId
193
	 *
194
	 * @return SharingFrame[]
195
	 */
196
	public function forceGetFrameFromCircle($circleUniqueId, $viewerId) {
197
198
		if ($viewerId !== '') {
199
			$circle = $this->circlesRequest->getCircle($circleUniqueId, $viewerId);
200
			$circle->getViewer()
201
				   ->hasToBeMember();
202
		}
203
204
		return $this->sharingFrameRequest->getSharingFramesFromCircle($circleUniqueId);
205
	}
206
207
208
	/**
209
	 * @param string $circleUniqueId
210
	 * @param string $frameUniqueId
211
	 *
212
	 * @return null|SharingFrame
213
	 * @throws SharingFrameAlreadyDeliveredException
214
	 * @throws SharingFrameDoesNotExistException
215
	 */
216
	public function getFrameFromUniqueId($circleUniqueId, $frameUniqueId) {
217
		if ($frameUniqueId === '') {
218
			throw new SharingFrameDoesNotExistException('unknown_share');
219
		}
220
221
		try {
222
			$frame = $this->sharingFrameRequest->getSharingFrame($circleUniqueId, $frameUniqueId);
223
			if ($frame->getCloudId() !== null) {
224
				throw new SharingFrameAlreadyDeliveredException('share_already_delivered');
225
			}
226
		} catch (SharingFrameDoesNotExistException $e) {
227
			throw new SharingFrameDoesNotExistException('unknown_share');
228
		}
229
230
		return $frame;
231
	}
232
233
234
	/**
235
	 * @param string $token
236
	 * @param string $uniqueId
237
	 * @param SharingFrame $frame
238
	 *
239
	 * @return bool
240
	 * @throws Exception
241
	 */
242
	public function receiveFrame($token, $uniqueId, SharingFrame &$frame) {
243
		try {
244
			$link = $this->federatedLinksRequest->getLinkFromToken((string)$token, (string)$uniqueId);
245
			$circle = $this->circlesRequest->forceGetCircle($link->getCircleId());
246
		} catch (CircleDoesNotExistException $e) {
247
			throw new CircleDoesNotExistException('unknown_circle');
248
		} catch (Exception $e) {
249
			throw $e;
250
		}
251
252
		try {
253
			$this->sharingFrameRequest->getSharingFrame($link->getCircleId(), $frame->getUniqueId());
254
			throw new SharingFrameAlreadyExistException('shares_is_already_known');
255
		} catch (SharingFrameDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
256
		}
257
258
		$frame->setCircle($circle);
259
		$this->sharingFrameRequest->saveSharingFrame($frame);
260
261
		return true;
262
	}
263
264
265
	/**
266
	 * @param string $circleUniqueId
267
	 * @param string $frameUniqueId
268
	 *
269
	 * @return bool
270
	 * @throws Exception
271
	 */
272
	public function initiateShare($circleUniqueId, $frameUniqueId) {
273
		$args = [
274
			'circleId' => $circleUniqueId,
275
			'frameId'  => $frameUniqueId
276
		];
277
278
		$client = $this->clientService->newClient();
279
		try {
280
			$client->post(
281
				$this->generatePayloadDeliveryURL($this->configService->getLocalAddress()), [
282
																							  'body'            => $args,
283
																							  'timeout'         => Application::CLIENT_TIMEOUT,
284
																							  'connect_timeout' => Application::CLIENT_TIMEOUT,
285
																						  ]
286
			);
287
288
			return true;
289
		} catch (Exception $e) {
290
			throw $e;
291
		}
292
	}
293
294
295
	/**
296
	 * @param string $remote
297
	 *
298
	 * @return string
299
	 */
300
	private function generatePayloadDeliveryURL($remote) {
301
		return $this->configService->generateRemoteHost($remote) . Application::REMOTE_URL_PAYLOAD;
302
	}
303
304
305
	/**
306
	 * @param SharingFrame $frame
307
	 *
308
	 * @throws Exception
309
	 */
310
	public function forwardSharingFrame(SharingFrame $frame) {
311
312
		try {
313
			$circle = $this->circlesRequest->forceGetCircle(
314
				$frame->getCircle()
315
					  ->getUniqueId()
316
			);
317
		} catch (CircleDoesNotExistException $e) {
318
			throw new CircleDoesNotExistException('unknown_circle');
319
		}
320
321
		$links = $this->federatedLinksRequest->getLinksFromCircle(
322
			$frame->getCircle()
323
				  ->getUniqueId(), FederatedLink::STATUS_LINK_UP
324
		);
325
326
		$this->forwardSharingFrameToFederatedLinks($circle, $frame, $links);
327
	}
328
329
330
	/**
331
	 * @param Circle $circle
332
	 * @param SharingFrame $frame
333
	 * @param FederatedLink[] $links
334
	 */
335
	private function forwardSharingFrameToFederatedLinks(Circle $circle, SharingFrame $frame, $links) {
336
337
		$args = [
338
			'apiVersion' => Circles::version(),
339
			'uniqueId'   => $circle->getUniqueId(true),
340
			'item'       => json_encode($frame)
341
		];
342
343
		foreach ($links AS $link) {
344
			$args['token'] = $link->getToken(true);
345
			$this->deliverSharingFrameToLink($link, $args);
346
		}
347
	}
348
349
350
	/**
351
	 * sendRemoteShareToLinks();
352
	 *
353
	 * @param FederatedLink $link
354
	 * @param array $args
355
	 */
356
	private function deliverSharingFrameToLink($link, $args) {
357
358
		$client = $this->clientService->newClient();
359
		try {
360
			$request = $client->put(
361
				$this->generatePayloadDeliveryURL($link->getAddress()), [
362
																		  'body'            => $args,
363
																		  'timeout'         => 10,
364
																		  'connect_timeout' => 10,
365
																	  ]
366
			);
367
368
			$result = json_decode($request->getBody(), true);
369
			if ($result['status'] === -1) {
370
				throw new PayloadDeliveryException($result['reason']);
371
			}
372
373
		} catch (Exception $e) {
374
			$this->miscService->log(
375
				'fail to send frame to ' . $link->getAddress() . ' - ' . $e->getMessage()
376
			);
377
		}
378
	}
379
380
381
	/**
382
	 * @param SharingFrame $frame
383
	 */
384
	public function updateFrameWithCloudId(SharingFrame $frame) {
385
		$frame->setCloudId($this->configService->getLocalAddress());
386
		$this->sharingFrameRequest->updateSharingFrame($frame);
387
	}
388
389
390
}