Completed
Push — federated-circles ( 92a91f...545292 )
by Maxence
02:39
created

FederatedController::receiveFederatedDelivery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 0
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\Controller;
28
29
use OC\AppFramework\Http;
30
use OCA\Circles\Model\FederatedLink;
31
use OCA\Circles\Service\FederatedService;
32
use OCA\Circles\Service\CirclesService;
33
use OCA\Circles\Service\ConfigService;
34
use OCA\Circles\Service\MembersService;
35
use OCA\Circles\Service\MiscService;
36
use OCA\Circles\Service\SharesService;
37
use OCP\AppFramework\Http\DataResponse;
38
use OCP\IL10N;
39
40
class FederatedController extends BaseController {
41
42
	/** @var string */
43
	protected $userId;
44
45
	/** @var IL10N */
46
	protected $l10n;
47
48
	/** @var ConfigService */
49
	protected $configService;
50
51
	/** @var CirclesService */
52
	protected $circlesService;
53
54
	/** @var MembersService */
55
	protected $membersService;
56
57
	/** @var SharesService */
58
	protected $sharesService;
59
60
	/** @var FederatedService */
61
	protected $federatedService;
62
63
	/** @var MiscService */
64
	protected $miscService;
65
66
67
	/**
68
	 * requestedLink()
69
	 *
70
	 * Called when a remote circle want to create a link.
71
	 * The function check if it is possible first; then create a link- object
72
	 * and sent it to be saved in the database.
73
	 *
74
	 * @PublicPage
75
	 * @NoCSRFRequired
76
	 *
77
	 * @param string $token
78
	 * @param string $uniqueId
79
	 * @param string $sourceName
80
	 * @param string $linkTo
81
	 * @param string $address
82
	 *
83
	 * @return DataResponse
84
	 */
85
	public function requestedLink($token, $uniqueId, $sourceName, $linkTo, $address) {
86
87
		if ($uniqueId === '' || !$this->configService->isFederatedAllowed()) {
88
			return $this->federatedFail('federated_not_allowed');
89
		}
90
91
		$circle = $this->circlesService->infoCircleByName($linkTo);
92
		if ($circle === null) {
93
			return $this->federatedFail('circle_does_not_exist');
94
		}
95
96
		if ($circle->getUniqueId() === $uniqueId) {
97
			return $this->federatedFail('duplicate_unique_id');
98
		}
99
100
		if ($this->federatedService->getLink($circle->getId(), $uniqueId) !== null) {
101
			return $this->federatedFail('duplicate_link');
102
		}
103
104
		$link = new FederatedLink();
105
		$link->setToken($token)
106
			 ->setUniqueId($uniqueId)
107
			 ->setRemoteCircleName($sourceName)
108
			 ->setAddress($address);
109
110
		if ($this->federatedService->initiateLink($circle, $link)) {
111
			return $this->federatedSuccess(
112
				['status' => $link->getStatus(), 'uniqueId' => $circle->getUniqueId()], $link
113
			);
114
		} else {
115
			return $this->federatedFail('link_failed');
116
		}
117
	}
118
119
120
	/**
121
	 * initFederatedDelivery()
122
	 *
123
	 * Note: this function will close the request mid-run from the client but will still
124
	 * running its process.
125
	 * Called by locally, the function will get the payload by its uniqueId from the database, and
126
	 * will deliver it to each remotes linked to the circle the payload belongs to.
127
	 * A status response is sent to free the client process before starting to broadcast the item
128
	 * to other federated links.
129
	 *
130
	 * @PublicPage
131
	 * @NoCSRFRequired
132
	 */
133
	public function initFederatedDelivery($uniqueId) {
134
135
		$this->miscService->log("initFederatedDelivery start " . $uniqueId);
136
137
		// We don't want to keep the connection with the client up and running
138
		// as he might have others things to do
139
		$this->asyncAndLeaveClientOutOfThis('done');
140
141
		sleep(15);
142
		$this->miscService->log("initFederatedDelivery end");
143
		exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method initFederatedDelivery() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
144
	}
145
146
147
	/**
148
	 * shareFederatedItem()
149
	 *
150
	 * Note: this function will close the request mid-run from the client but will still
151
	 * running its process.
152
	 * Called by a remote circle to broadcast a Share item, the function will save the item
153
	 * in the database and broadcast it locally. A status response is sent to the remote to free
154
	 * the remote process before starting to broadcast the item to other federated links.
155
	 *
156
	 * @PublicPage
157
	 * @NoCSRFRequired
158
	 */
159
	public function receiveFederatedDelivery() {
160
161
		$this->miscService->log("receiveFederatedDelivery start");
162
163
		// We don't want to keep the connection with the client up and running
164
		// as he might have others things to do
165
		$this->asyncAndLeaveClientOutOfThis('done');
166
167
		sleep(15);
168
		$this->miscService->log("receiveFederatedDelivery end");
169
		exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method receiveFederatedDelivery() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
170
	}
171
172
	/**
173
	 * Hacky way to async the rest of the process without keeping client on hold.
174
	 *
175
	 * @param string $result
176
	 */
177
	private function asyncAndLeaveClientOutOfThis($result = '') {
178
		if (ob_get_contents() !== false) {
179
			ob_end_clean();
180
		}
181
182
		header("Connection: close");
183
		ignore_user_abort();
184
		ob_start();
185
		echo($result);
186
		$size = ob_get_length();
187
		header("Content-Length: $size");
188
		ob_end_flush();
189
		flush();
190
	}
191
192
	/**
193
	 * send a positive response to a request with an array of data, and confirm
194
	 * the identity of the link with a token
195
	 *
196
	 * @param array $data
197
	 * @param FederatedLink $link
198
	 *
199
	 * @return DataResponse
200
	 */
201
	private function federatedSuccess($data, $link) {
202
		return new DataResponse(
203
			array_merge($data, ['token' => $link->getToken()]), Http::STATUS_OK
204
		);
205
206
	}
207
208
	/**
209
	 * send a negative response to a request, with a reason of the failure.
210
	 *
211
	 * @param string $reason
212
	 *
213
	 * @return DataResponse
214
	 */
215
	private function federatedFail($reason) {
216
		return new DataResponse(
217
			[
218
				'status' => FederatedLink::STATUS_ERROR,
219
				'reason' => $reason
220
			],
221
			Http::STATUS_OK
222
		);
223
	}
224
}