diff options
author | Maxence Lange <maxence@artificial-owl.com> | 2018-08-18 23:43:23 +0300 |
---|---|---|
committer | Maxence Lange <maxence@artificial-owl.com> | 2018-08-18 23:43:23 +0300 |
commit | b8c2bf10fc68d3b5e15985a04891c836a6c4e0bd (patch) | |
tree | 81e38c3b45ca8310c81d20a566ba557d1b77cab3 /lib | |
parent | 6de2f3692ff7fdff9938a75da72d3e1dc2869aff (diff) |
new UI for live
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Command/Live.php | 389 |
1 files changed, 381 insertions, 8 deletions
diff --git a/lib/Command/Live.php b/lib/Command/Live.php index 70a1037..266eec1 100644 --- a/lib/Command/Live.php +++ b/lib/Command/Live.php @@ -31,6 +31,8 @@ use OCA\FullTextSearch\Exceptions\InterruptException; use OCA\FullTextSearch\Exceptions\TickDoesNotExistException; use OCA\FullTextSearch\Model\ExtendedBase; use OCA\FullTextSearch\Model\Runner; +use OCA\FullTextSearch\Model\Index as ModelIndex; +use OCA\FullTextSearch\Service\CliService; use OCA\FullTextSearch\Service\ConfigService; use OCA\FullTextSearch\Service\IndexService; use OCA\FullTextSearch\Service\MiscService; @@ -38,6 +40,7 @@ use OCA\FullTextSearch\Service\PlatformService; use OCA\FullTextSearch\Service\ProviderService; use OCA\FullTextSearch\Service\RunningService; use OCP\IUserManager; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -46,6 +49,43 @@ class Live extends ExtendedBase { const CYCLE_DELAY = 10; + const PANEL_RUN = 'run'; + const PANEL_RUN_LINE_MEMORY = 'Memory: %_memory%'; + + const PANEL_INDEX = 'indexing'; + const PANEL_INDEX_LINE_HEADER = '┌─ Indexing %_paused% ────'; + const PANEL_INDEX_LINE_ACCOUNT = '│ Provider: <info>%providerName:-20s%</info> Account: <info>%userId%</info>'; + const PANEL_INDEX_LINE_ACTION = '│ Action: <info>%action%</info>'; + const PANEL_INDEX_LINE_DOCUMENT = '│ Document: <info>%documentId%</info>'; + const PANEL_INDEX_LINE_INFO = '│ Info: <info>%info%</info>'; + const PANEL_INDEX_LINE_TITLE = '│ Title: <info>%title%</info>'; + const PANEL_INDEX_LINE_CONTENT = '│ Content size: <info>%content%</info>'; + const PANEL_INDEX_LINE_RESULT = '│ Result: %resultColored%'; + const PANEL_INDEX_LINE_FOOTER = '└──'; + + const PANEL_STATUS = 'status'; + const PANEL_STATUS_LINE_HEADER = '┌─ Status ────'; + const PANEL_STATUS_LINE_DOCUMENTS = '│ Progress: %documentLeft:6s%/%documentTotal% %progressStatus%'; +// const PANEL_STATUS_LINE_DOCUMENTS_LEFT = '│ Document left:'; + const PANEL_STATUS_LINE_ERRORS = '│ Error: <comment>%errorCurrent:6s%</comment>/<comment>%errorTotal%</comment>'; + const PANEL_STATUS_LINE_ERROR_MESSAGE = '│ Message: <comment>%errorMessage%</comment>'; + const PANEL_STATUS_LINE_ERROR_EXCEPTION = '│ Exception: <comment>%errorException%</comment>'; + const PANEL_STATUS_LINE_ERROR_INDEX = '│ Index: <comment>%errorIndex%</comment>'; + + + const PANEL_STATUS_LINE_FOOTER = '└──'; + + const PANEL_LINE_EMPTY = '│ '; + + const PANEL_COMMANDS_ROOT = 'root'; + const PANEL_COMMANDS_ROOT_LINE = '## <char>q</char>:quit ## <char>p</char>:pause '; + const PANEL_COMMANDS_PAUSED = 'paused'; + const PANEL_COMMANDS_PAUSED_LINE = '## <char>q</char>:quit ## <char>u</char>:unpause ## <char>n</char>:next step'; + const PANEL_COMMANDS_DONE = 'done'; + const PANEL_COMMANDS_DONE_LINE = '## <char>q</char>:quit'; + const PANEL_COMMANDS_ERRORS = 'errors'; + const PANEL_COMMANDS_ERRORS_LINE = '## <char>f</char>:first error ## <char>h</char>/<char>j</char>:prec/next error ## <char>d</char>:delete error ## <char>l</char>:last error'; + /** @var IUserManager */ private $userManager; @@ -53,6 +93,12 @@ class Live extends ExtendedBase { /** @var ConfigService */ private $configService; + /** @var CliService */ + private $cliService; + + /** @var RunningService */ + private $runningService; + /** @var IndexService */ private $indexService; @@ -65,10 +111,16 @@ class Live extends ExtendedBase { /** @var MiscService */ private $miscService; - /** @var Runner */ private $runner; + + /** @var array */ + private $errors = []; + + /** @var bool */ + private $navigateLastError = true; + /** * Index constructor. * @@ -82,7 +134,7 @@ class Live extends ExtendedBase { */ public function __construct( IUserManager $userManager, RunningService $runningService, ConfigService $configService, - IndexService $indexService, PlatformService $platformService, + CliService $cliService, IndexService $indexService, PlatformService $platformService, ProviderService $providerService, MiscService $miscService ) { parent::__construct(); @@ -90,6 +142,8 @@ class Live extends ExtendedBase { $this->runner = new Runner($runningService, 'commandLive'); $this->configService = $configService; + $this->cliService = $cliService; + $this->runningService = $runningService; $this->indexService = $indexService; $this->platformService = $platformService; $this->providerService = $providerService; @@ -120,19 +174,43 @@ class Live extends ExtendedBase { throw new Exception('This feature is only available on Nextcloud 14 or newer'); } + /** do not get stuck while waiting interactive input */ + readline_callback_handler_install( + '', function() { + } + ); + stream_set_blocking(STDIN, false); + + $outputStyle = new OutputFormatterStyle('white', 'black', ['bold']); + $output->getFormatter() + ->setStyle('char', $outputStyle); + + $this->runner = new Runner($this->runningService, 'commandIndex', ['nextStep' => 'n']); + $this->runner->onKeyPress([$this, 'onKeyPressed']); + $this->runner->onNewAction([$this, 'onNewAction']); + $this->runner->onNewIndexError([$this, 'onNewIndexError']); + + $this->indexService->setRunner($this->runner); + $this->cliService->setRunner($this->runner); + + $this->generatePanels(); + + try { $this->runner->sourceIsCommandLine($this, $output); $this->runner->start(); - $this->runner->output('live.'); + + $this->cliService->runDisplay($output); + $this->generateIndexErrors(); + $this->displayError(); + + $this->liveCycle(); } catch (Exception $e) { $this->runner->exception($e->getMessage(), true); throw $e; } - $this->indexService->setRunner($this->runner); - - $this->liveCycle(); $this->runner->stop(); } @@ -165,9 +243,9 @@ class Live extends ExtendedBase { } } - $this->runner->updateAction('waiting'); + $this->runner->updateAction('waiting', true); - sleep(self::CYCLE_DELAY); + usleep(300000); } $this->runner->stop(); @@ -175,6 +253,301 @@ class Live extends ExtendedBase { } + /** + * @param $key + */ + public function onKeyPressed($key) { + $key = strtolower($key); + if ($key === 'q') { + try { + $this->runner->stop(); + } catch (TickDoesNotExistException $e) { + /** we do nohtin' */ + } + exit(); + } + + $current = $this->cliService->currentPanel('commands'); + if ($current === self::PANEL_COMMANDS_ROOT && $key === 'p') { + $this->cliService->switchPanel('commands', self::PANEL_COMMANDS_PAUSED); + $this->runner->pause(true); + } + if ($current === self::PANEL_COMMANDS_PAUSED && $key === 'u') { + $this->cliService->switchPanel('commands', self::PANEL_COMMANDS_ROOT); + $this->runner->pause(false); + } + + if ($key === 'f') { + $this->displayError(-99); + } + if ($key === 'h') { + $this->displayError(-1); + } + if ($key === 'j') { + $this->displayError(1); + } + if ($key === 'l') { + $this->displayError(99); + } + if ($key === 'd') { + $this->deleteError(); + } + } + + + /** + * @param array $error + */ + public function onNewIndexError($error) { + $this->errors[] = $error; + $this->displayError(); + } + + + /** + * + */ + private function generatePanels() { + + $this->cliService->createPanel( + self::PANEL_RUN, + [ + self::PANEL_RUN_LINE_MEMORY + ] + ); + $this->cliService->createPanel( + self::PANEL_INDEX, [ + self::PANEL_INDEX_LINE_HEADER, + self::PANEL_INDEX_LINE_ACCOUNT, + self::PANEL_INDEX_LINE_ACTION, + self::PANEL_INDEX_LINE_DOCUMENT, + self::PANEL_INDEX_LINE_INFO, + self::PANEL_INDEX_LINE_TITLE, + self::PANEL_INDEX_LINE_CONTENT, + self::PANEL_INDEX_LINE_RESULT, + self::PANEL_INDEX_LINE_FOOTER, + ] + ); + + $this->cliService->createPanel( + self::PANEL_STATUS, [ + self::PANEL_STATUS_LINE_HEADER, + self::PANEL_STATUS_LINE_DOCUMENTS, + self::PANEL_STATUS_LINE_ERRORS, + self::PANEL_STATUS_LINE_ERROR_MESSAGE, + self::PANEL_STATUS_LINE_ERROR_EXCEPTION, + self::PANEL_STATUS_LINE_ERROR_INDEX, + self::PANEL_STATUS_LINE_FOOTER, + ] + ); + + $this->cliService->createPanel( + self::PANEL_COMMANDS_ROOT, [ + self::PANEL_COMMANDS_ROOT_LINE + ] + ); + + $this->cliService->createPanel( + self::PANEL_COMMANDS_PAUSED, [ + self::PANEL_COMMANDS_PAUSED_LINE + ] + ); + + $this->cliService->createPanel( + self::PANEL_COMMANDS_ERRORS, [ + self::PANEL_COMMANDS_ERRORS_LINE + ] + ); + + $this->cliService->initDisplay(); + $this->cliService->displayPanel('run', self::PANEL_RUN); + $this->cliService->displayPanel('topPanel', self::PANEL_INDEX); + $this->cliService->displayPanel('bottomPanel', self::PANEL_STATUS); + + $this->cliService->displayPanel('errors', self::PANEL_COMMANDS_ERRORS); + + if ($this->runner->isPaused()) { + $this->cliService->displayPanel('commands', self::PANEL_COMMANDS_PAUSED); + } else { + $this->cliService->displayPanel('commands', self::PANEL_COMMANDS_ROOT); + } + + $this->runner->setInfoArray( + [ + 'userId' => '', + 'providerName' => '', + '_memory' => '', + 'documentId' => '', + 'action' => '', + 'info' => '', + 'title' => '', + '_paused' => '', + 'content' => '', + 'resultColored' => '', + 'documentLeft' => '', + 'documentTotal' => '', + 'progressStatus' => '', + 'errorCurrent' => '0', + 'errorTotal' => '0', + 'errorMessage' => '', + 'errorException' => '', + 'errorIndex' => '' + ] + ); + } + + + /** + * + */ + private function generateIndexErrors() { + $indexes = $this->indexService->getErrorIndexes(); + + foreach ($indexes as $index) { + foreach ($index->getErrors() as $error) { + $this->errors[] = [ + 'index' => $index, + 'message' => $error['message'], + 'exception' => $error['exception'], + 'severity' => $error['sev'] + ]; + } + + } + + + } + + + /** + * @param int $pos + */ + private function displayError($pos = 0) { + $total = sizeof($this->errors); + + if ($total === 0) { + $this->runner->setInfoArray( + [ + 'errorCurrent' => 0, + 'errorTotal' => 0, + ] + ); + + return; + } + + $current = key($this->errors) + 1; + $error = $this->getNavigationError($pos, ($current === 1), ($current === $total)); + $current = key($this->errors) + 1; + + if ($error === false) { + return; + } + + /** @var ModelIndex $index */ + $index = $error['index']; + $errorIndex = ''; + if ($index !== null) { + $errorIndex = $index->getProviderId() . ':' . $index->getDocumentId(); + } + + $this->runner->setInfoArray( + [ + 'errorCurrent' => $current, + 'errorTotal' => $total, + 'errorMessage' => MiscService::get('message', $error, ''), + 'errorException' => MiscService::get('exception', $error, ''), + 'errorIndex' => $errorIndex + ] + ); + } + + + /** + * @param int $pos + * @param bool $isFirst + * @param bool $isLast + * + * @return bool|array + */ + private function getNavigationError($pos, $isFirst, $isLast) { + + if ($pos === 0) { + if ($this->navigateLastError === true) { + return end($this->errors); + } else { + return current($this->errors); + } + } + + $this->navigateLastError = false; + if ($pos === -99) { + return reset($this->errors); + } + + if ($pos === -1 && !$isFirst) { + return prev($this->errors); + } + + if ($pos === 1 && !$isLast) { + return next($this->errors); + } + + if ($pos === 99) { + $this->navigateLastError = true; + + return end($this->errors); + } + + return false; + } + + + /** + * + */ + private function deleteError() { + $current = current($this->errors); + if ($current === false) { + return; + } + + $this->runner->setInfoArray( + [ + 'errorMessage' => '', + 'errorException' => '', + 'errorIndex' => '' + ] + ); + + $pos = key($this->errors); + + /** @var ModelIndex $index */ + $index = $current['index']; + $this->indexService->resetErrorFromIndex($index); + + $errors = []; + foreach ($this->errors as $error) { + /** @var ModelIndex $errorIndex */ + $errorIndex = $error['index']; + if ($index->getProviderId() === $errorIndex->getProviderId() + && $index->getDocumentId() === $errorIndex->getDocumentId()) { + continue; + } + + $errors[] = $error; + } + + $this->errors = $errors; + while (key($this->errors) < $pos) { + if (next($this->errors) === false) { + end($this->errors); + break; + } + } + + $this->displayError(); + } } |