Completed
Push — master ( 2566be...2cb116 )
by Maxence
01:40 queued 10s
created

IndexService::deleteIndexes()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * FullTextSearch_Elasticsearch - Use Elasticsearch to index the content of your nextcloud
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later. See the COPYING file.
10
 *
11
 * @author Maxence Lange <[email protected]>
12
 * @copyright 2018
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\FullTextSearch_Elasticsearch\Service;
32
33
34
use daita\MySmallPhpTools\Traits\TArrayTools;
35
use Elasticsearch\Client;
36
use Elasticsearch\Common\Exceptions\BadRequest400Exception;
37
use Elasticsearch\Common\Exceptions\Missing404Exception;
38
use OCA\FullTextSearch_Elasticsearch\Exceptions\AccessIsEmptyException;
39
use OCA\FullTextSearch_Elasticsearch\Exceptions\ConfigurationException;
40
use OCP\FullTextSearch\Model\IIndex;
41
use OCP\FullTextSearch\Model\IIndexDocument;
42
43
44
/**
45
 * Class IndexService
46
 *
47
 * @package OCA\FullTextSearch_Elasticsearch\Service
48
 */
49
class IndexService {
50
51
52
	use TArrayTools;
53
54
55
	/** @var IndexMappingService */
56
	private $indexMappingService;
57
58
	/** @var MiscService */
59
	private $miscService;
60
61
62
	/**
63
	 * IndexService constructor.
64
	 *
65
	 * @param IndexMappingService $indexMappingService
66
	 * @param MiscService $miscService
67
	 */
68
	public function __construct(
69
		IndexMappingService $indexMappingService, MiscService $miscService
70
	) {
71
		$this->indexMappingService = $indexMappingService;
72
		$this->miscService = $miscService;
73
	}
74
75
76
	/**
77
	 * @param Client $client
78
	 *
79
	 * @return bool
80
	 * @throws ConfigurationException
81
	 */
82
	public function testIndex(Client $client): bool {
83
84
		$map = $this->indexMappingService->generateGlobalMap(false);
85
		$map['client'] = [
86
			'verbose' => true
87
		];
88
89
		return $client->indices()
90
					  ->exists($map);
91
	}
92
93
94
	/**
95
	 * @param Client $client
96
	 *
97
	 * @throws ConfigurationException
98
	 * @throws BadRequest400Exception
99
	 */
100
	public function initializeIndex(Client $client) {
101
		try {
102
			if ($client->indices()
103
					   ->exists($this->indexMappingService->generateGlobalMap(false))) {
104
				return;
105
			}
106
		} catch (BadRequest400Exception $e) {
107
			$this->parseBadRequest400($e);
108
		}
109
110
		try {
111
			$client->indices()
112
				   ->create($this->indexMappingService->generateGlobalMap());
113
			$client->ingest()
114
				   ->putPipeline($this->indexMappingService->generateGlobalIngest());
115
		} catch (BadRequest400Exception $e) {
116
			$this->resetIndexAll($client);
117
			$this->parseBadRequest400($e);
118
		}
119
	}
120
121
122
	/**
123
	 * @param Client $client
124
	 * @param string $providerId
125
	 *
126
	 * @throws ConfigurationException
127
	 */
128
	public function resetIndex(Client $client, string $providerId) {
129
		try {
130
			$client->deleteByQuery($this->indexMappingService->generateDeleteQuery($providerId));
131
		} catch (Missing404Exception $e) {
132
			/** we do nothin' */
133
		}
134
	}
135
136
137
	/**
138
	 * @param Client $client
139
	 *
140
	 * @throws ConfigurationException
141
	 */
142
	public function resetIndexAll(Client $client) {
143
		try {
144
			$client->ingest()
145
				   ->deletePipeline($this->indexMappingService->generateGlobalIngest(false));
146
		} catch (Missing404Exception $e) {
147
			/* 404Exception will means that the mapping for that provider does not exist */
148
		} catch (BadRequest400Exception $e) {
149
			throw new ConfigurationException(
150
				'Check your user/password and the index assigned to that cloud'
151
			);
152
		}
153
154
		try {
155
			$client->indices()
156
				   ->delete($this->indexMappingService->generateGlobalMap(false));
157
		} catch (Missing404Exception $e) {
158
			/* 404Exception will means that the mapping for that provider does not exist */
159
		}
160
	}
161
162
163
	/**
164
	 * @param Client $client
165
	 * @param IIndex[] $indexes
166
	 *
167
	 * @throws ConfigurationException
168
	 */
169
	public function deleteIndexes(Client $client, array $indexes) {
170
		foreach ($indexes as $index) {
171
			$this->indexMappingService->indexDocumentRemove(
172
				$client, $index->getProviderId(), $index->getDocumentId()
173
			);
174
		}
175
	}
176
177
178
	/**
179
	 * @param Client $client
180
	 * @param IIndexDocument $document
181
	 *
182
	 * @return array
183
	 * @throws ConfigurationException
184
	 * @throws AccessIsEmptyException
185
	 */
186
	public function indexDocument(Client $client, IIndexDocument $document): array {
187
		$result = [];
188
		$index = $document->getIndex();
189
		if ($index->isStatus(IIndex::INDEX_REMOVE)) {
190
			$this->indexMappingService->indexDocumentRemove(
191
				$client, $document->getProviderId(), $document->getId()
192
			);
193
		} else if ($index->isStatus(IIndex::INDEX_OK) && !$index->isStatus(IIndex::INDEX_CONTENT)
194
				   && !$index->isStatus(IIndex::INDEX_META)) {
195
			$result = $this->indexMappingService->indexDocumentUpdate($client, $document);
196
		} else {
197
			$result = $this->indexMappingService->indexDocumentNew($client, $document);
198
		}
199
200
		return $result;
201
	}
202
203
204
	/**
205
	 * @param IIndex $index
206
	 * @param array $result
207
	 *
208
	 * @return IIndex
209
	 */
210
	public function parseIndexResult(IIndex $index, array $result): IIndex {
211
212
		$index->setLastIndex();
213
214
		if (array_key_exists('exception', $result)) {
215
			$index->setStatus(IIndex::INDEX_FAILED);
216
			$index->addError(
217
				$this->get('message', $result, $result['exception']),
218
				'',
219
				IIndex::ERROR_SEV_3
220
			);
221
222
			return $index;
223
		}
224
225
		// TODO: parse result
226
		if ($index->getErrorCount() === 0) {
227
			$index->setStatus(IIndex::INDEX_DONE);
228
		}
229
230
		return $index;
231
	}
232
233
234
	/**
235
	 * @param BadRequest400Exception $e
236
	 *
237
	 * @throws ConfigurationException
238
	 * @throws BadRequest400Exception
239
	 */
240
	private function parseBadRequest400(BadRequest400Exception $e) {
241
242
		if ($e->getMessage() === '') {
243
			throw new ConfigurationException(
244
				'Check your user/password and the index assigned to that cloud'
245
			);
246
		}
247
248
249
		$error = json_decode($e->getMessage(), true)['error'];
250
251
		if ($error['type'] === 'parse_exception') {
252
			if ($error['reason'] === 'No processor type exists with name [attachment]') {
253
				throw new ConfigurationException(
254
					'please add ingest-attachment plugin to elasticsearch'
255
				);
256
			}
257
		}
258
259
		throw $e;
260
	}
261
262
}
263