Completed
Push — master ( dba968...9e87bf )
by Maxence
02:27
created

Runner::onNewIndexResult()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * FullTextSearch - Full text search framework for Nextcloud
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 2018
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
28
namespace OCA\FullTextSearch\Model;
29
30
use OCA\FullTextSearch\Exceptions\InterruptException;
31
use OCA\FullTextSearch\Exceptions\RunnerAlreadyUpException;
32
use OCA\FullTextSearch\Exceptions\TickDoesNotExistException;
33
use OCA\FullTextSearch\Exceptions\TickIsNotAliveException;
34
use OCA\FullTextSearch\Service\MiscService;
35
use OCA\FullTextSearch\Service\RunningService;
36
use Symfony\Component\Console\Output\OutputInterface;
37
38
39
class Runner {
40
41
42
	const TICK_TTL = 300;
43
	const TICK_MINIMUM = 2;
44
	const MEMORY_INFO_UPDATE = 5;
45
46
	const RESULT_TYPE_SUCCESS = 1;
47
	const RESULT_TYPE_WARNING = 4;
48
	const RESULT_TYPE_FAIL = 9;
49
50
	/** @var RunningService */
51
	private $runningService;
52
53
	/** @var string */
54
	private $source;
55
56
	/** @var bool */
57
	private $strict = false;
58
59
	/** @var int */
60
	private $tickId;
61
62
	/** @var ExtendedBase */
63
	private $commandBase = null;
64
65
	/** @var OutputInterface */
66
	private $outputInterface = null;
67
68
	/** @var array */
69
	private $info = [];
70
71
	/** @var int */
72
	private $oldTick = 0;
73
74
	/** @var string */
75
	private $oldAction = '';
76
77
	/** @var int */
78
	private $ramTick = 0;
79
80
	/** @var array */
81
	private $methodOnKeyPress = [];
82
83
	/** @var array */
84
	private $methodOnInfoUpdate = [];
85
86
	/** @var array */
87
	private $methodOnIndexError = [];
88
89
	/** @var array */
90
	private $methodOnIndexResult = [];
91
92
	/** @var bool */
93
	private $paused = false;
94
95
	/** @var bool */
96
	private $pauseRunning = false;
97
98
	/** @var array */
99
	private $keys = ['nextStep' => 'n'];
100
101
102
	/**
103
	 * Runner constructor.
104
	 *
105
	 * @param RunningService $runningService
106
	 * @param string $source
107
	 * @param array $keys
108
	 */
109
	public function __construct(RunningService $runningService, $source, $keys = []) {
110
		$this->runningService = $runningService;
111
		$this->source = $source;
112
113
		if (sizeof($keys) > 0) {
114
			$this->keys = $keys;
115
		}
116
	}
117
118
119
	/**
120
	 * @param bool $strict
121
	 *
122
	 * @throws RunnerAlreadyUpException
123
	 */
124
	public function start($strict = false) {
125
		$this->strict = $strict;
126
		$this->tickId = $this->runningService->start($this->source);
127
	}
128
129
130
	/**
131
	 * @param string $action
132
	 * @param bool $force
133
	 *
134
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|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...
135
	 * @throws InterruptException
136
	 * @throws TickDoesNotExistException
137
	 */
138
	public function updateAction($action = '', $force = false) {
139
		$n = '';
140
		if (sizeof($this->methodOnKeyPress) > 0) {
141
			$n = fread(STDIN, 9999);
142
			if ($n !== '') {
143
				$n = substr($n, 0, 1);
144
				$this->keyPressed($n);
145
			}
146
		}
147
148
		if ($action === '') {
149
			return $n;
150
		}
151
152
		$tick = time();
153
		try {
154
			$this->hasBeenInterrupted();
155
		} catch (InterruptException $e) {
156
			$this->stop();
157
			throw $e;
158
		}
159
160
		if ($this->oldAction !== $action || $force) {
161
			while (true) {
162
				if (!$this->isPaused()) {
163
					break;
164
				}
165
166
				$this->pauseRunning(true);
167
				$pressed = strtolower($this->updateAction(''));
168
				if ($pressed === $this->keys['nextStep']) {
169
					break;
170
				}
171
				usleep(300000);
172
			}
173
174
			$this->pauseRunning(false);
175
		}
176
177
		if ($this->oldAction === $action && ($this->oldTick + self::TICK_MINIMUM > $tick)) {
178
			return '';
179
		}
180
181
		$this->setInfo('action', $action);
182
		try {
183
			$this->runningService->update($this->tickId, $action);
184
		} catch (TickIsNotAliveException $e) {
185
			$this->output('Force Quit');
186
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method updateAction() 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...
187
		}
188
189
		$this->updateTick($tick);
190
		$this->oldAction = $action;
191
		$this->oldTick = $tick;
192
193
		return '';
194
	}
195
196
197
	/**
198
	 * @param string $info
199
	 * @param string $value
200
	 * @param int $type
201
	 */
202
	public function setInfo($info, $value, $type = 0) {
203
		$this->info[$info] = $value;
204
		$this->setInfoColored($info, $type);
205
		$this->infoUpdated();
206
	}
207
208
	/**
209
	 * @param array $data
210
	 */
211
	public function setInfoArray($data) {
212
		$keys = array_keys($data);
213
		//$this->info['info'] = '';
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% 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...
214
		foreach ($keys as $k) {
215
			$this->info[$k] = $data[$k];
216
		}
217
218
		$this->infoUpdated();
219
	}
220
221
222
	/**
223
	 * @param string $info
224
	 * @param int $level
225
	 */
226
	public function setInfoColored($info, $level) {
227
228
		$value = $this->getInfo($info);
229
		if ($value === '') {
230
			return;
231
		}
232
233
		$color = '';
234
		switch ($level) {
235
			case self::RESULT_TYPE_SUCCESS:
236
				$color = 'info';
237
				break;
238
239
			case self::RESULT_TYPE_WARNING:
240
				$color = 'comment';
241
				break;
242
243
			case self::RESULT_TYPE_FAIL:
244
				$color = 'error';
245
				break;
246
		}
247
248
		if ($color !== '') {
249
			$this->info[$info . 'Colored'] = '<' . $color . '>' . $value . '</' . $color . '>';
250
		}
251
252
253
	}
254
255
	/**
256
	 * @return array
257
	 */
258
	public function getInfoAll() {
259
		return $this->info;
260
	}
261
262
263
	/**
264
	 * @param string $k
265
	 *
266
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer? Also, consider making the array more specific, something like array<String>, or String[].

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.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
267
	 */
268
	public function getInfo($k) {
269
		return MiscService::get($k, $this->info, '');
270
	}
271
272
273
	/**
274
	 * @param array $method
275
	 */
276
	public function onKeyPress($method) {
277
		$this->methodOnKeyPress[] = $method;
278
	}
279
280
	/**
281
	 * @param $key
282
	 */
283
	public function keyPressed($key) {
284
		foreach ($this->methodOnKeyPress as $method) {
285
			call_user_func($method, $key);
286
		}
287
	}
288
289
290
	/**
291
	 * @param array $method
292
	 */
293
	public function onInfoUpdate($method) {
294
		$this->methodOnInfoUpdate[] = $method;
295
	}
296
297
	/**
298
	 * @param $key
299
	 */
300
	public function infoUpdated() {
301
		foreach ($this->methodOnInfoUpdate as $method) {
302
			call_user_func($method, $this->info);
303
		}
304
	}
305
306
307
	/**
308
	 * @param array $method
309
	 */
310
	public function onNewIndexError($method) {
311
		$this->methodOnIndexError[] = $method;
312
	}
313
314
	/**
315
	 * @param Index $index
316
	 * @param string $message
317
	 * @param string $class
318
	 * @param int $sev
319
	 */
320
	public function newIndexError($index, $message, $class = '', $sev = 3) {
321
		$error = [
322
			'index'     => $index,
323
			'message'   => $message,
324
			'exception' => $class,
325
			'severity'  => $sev
326
		];
327
328
		foreach ($this->methodOnIndexError as $method) {
329
			call_user_func($method, $error);
330
		}
331
	}
332
333
334
	/**
335
	 * @param array $method
336
	 */
337
	public function onNewIndexResult($method) {
338
		$this->methodOnIndexResult[] = $method;
339
	}
340
341
342
	/**
343
	 * @param Index $index
344
	 * @param string $message
345
	 * @param string $status
346
	 * @param int $type
347
	 */
348
	public function newIndexResult($index, $message, $status, $type) {
349
		$result = [
350
			'index'   => $index,
351
			'message' => $message,
352
			'status'  => $status,
353
			'type'    => $type
354
		];
355
356
		foreach ($this->methodOnIndexResult as $method) {
357
			call_user_func($method, $result);
358
		}
359
	}
360
361
362
	/**
363
	 * @throws InterruptException
364
	 */
365
	private function hasBeenInterrupted() {
366
		if ($this->commandBase === null) {
367
			return;
368
		}
369
		$this->commandBase->hasBeenInterrupted();
370
	}
371
372
373
	/**
374
	 * @param $tick
375
	 */
376
	private function updateTick($tick) {
377
		if (($this->ramTick + self::MEMORY_INFO_UPDATE) > $tick) {
378
			return;
379
		}
380
381
		$this->setInfo('_memory', round((memory_get_usage() / 1024 / 1024)) . ' MB');
382
		$this->ramTick = $tick;
383
	}
384
385
386
	/**
387
	 * @deprecated - verifier l'interet !?
388
	 *
389
	 * @param $reason
390
	 * @param $stop
391
	 */
392
	public function exception($reason, $stop) {
393
		if (!$stop) {
394
			$this->output('Exception: ' . $reason);
395
			// TODO: feed an array of exceptions for log;
396
		}
397
		$this->runningService->exception($this->tickId, $reason, $stop);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\FullTextSearch\Servi...ingService::exception() has been deprecated with message: - verifier l'interet !

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
398
	}
399
400
401
	/**
402
	 * @throws TickDoesNotExistException
403
	 */
404
	public function stop() {
405
		$this->runningService->stop($this->tickId);
406
	}
407
408
409
	/**
410
	 * @param ExtendedBase $base
411
	 * @param OutputInterface $output
412
	 */
413
	public function sourceIsCommandLine(ExtendedBase $base, OutputInterface $output) {
414
		$this->outputInterface = $output;
415
		$this->commandBase = $base;
416
	}
417
418
419
	/**
420
	 * @param bool $pause
421
	 */
422
	public function pause($pause) {
423
		$this->paused = $pause;
424
		$this->infoUpdated();
425
	}
426
427
	/**
428
	 * @return bool
429
	 */
430
	public function isPaused() {
431
		return $this->paused;
432
	}
433
434
435
	/**
436
	 * @param bool $running
437
	 */
438
	public function pauseRunning($running) {
439
		$this->pauseRunning = $running;
440
		$this->infoUpdated();
441
	}
442
443
444
	public function isPauseRunning() {
445
		return $this->pauseRunning;
446
	}
447
448
449
	/**
450
	 * @return bool
451
	 */
452
	public function isStrict() {
453
		return $this->strict;
454
	}
455
456
	/**
457
	 * @param string $line
458
	 */
459
	public function output($line) {
460
		if ($this->outputInterface === null) {
461
			return;
462
		}
463
464
		$this->outputInterface->writeln($line);
465
	}
466
467
468
}