Implement IMAP email-to-ticket gateway
This commit is contained in:
1 parent
b7e5884457
commit
6f25869345
33 files changed
+5619
-5
No files matched your search
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Box\Mod\Mailgateway;
|
||||
|
||||
use FOSSBilling\InformationException;
|
||||
|
||||
class DependencyInstaller
|
||||
{
|
||||
public function status(): array
|
||||
{
|
||||
return ['installed' => $this->installed(), 'available' => function_exists('proc_open')
|
||||
&& $this->php() !== null && $this->composer() !== null && is_writable(__DIR__),
|
||||
'request_timeout_ms' => (RuntimeConfig::get('composer_timeout_seconds') + 30) * 1000];
|
||||
}
|
||||
|
||||
public function install(bool $force = false): array
|
||||
{
|
||||
if (!$force && $this->installed()) {
|
||||
return ['installed' => true];
|
||||
}
|
||||
$php = $this->php();
|
||||
$composer = $this->composer();
|
||||
if (!function_exists('proc_open') || $php === null || $composer === null || !is_writable(__DIR__)) {
|
||||
throw new InformationException('Web installation is unavailable. Run composer install from the Mailgateway directory using SSH.');
|
||||
}
|
||||
if (!is_file(__DIR__ . '/composer.lock')) {
|
||||
throw new InformationException('The module composer.lock is missing. Restore it before installing dependencies.');
|
||||
}
|
||||
$command = [$php, $composer, 'install', '--no-dev', '--prefer-dist', '--no-interaction',
|
||||
'--no-progress', '--no-scripts', '--no-plugins', '--optimize-autoloader'];
|
||||
$result = $this->run($command);
|
||||
if ($result['timeout']) {
|
||||
throw new InformationException('Dependency installation exceeded its configured timeout. Run composer install from the Mailgateway directory using SSH.');
|
||||
}
|
||||
if ($result['exit'] !== 0 || !$this->installed()) {
|
||||
throw new InformationException('Composer installation failed. Run composer install from the Mailgateway directory using SSH to see the detailed error.');
|
||||
}
|
||||
return ['installed' => true];
|
||||
}
|
||||
|
||||
private function installed(): bool
|
||||
{
|
||||
return is_file(__DIR__ . '/vendor/autoload.php')
|
||||
&& is_file(__DIR__ . '/vendor/webklex/php-imap/src/ClientManager.php');
|
||||
}
|
||||
|
||||
private function php(): ?string
|
||||
{
|
||||
foreach (RuntimeConfig::get('php_cli_paths') as $path) {
|
||||
if (is_file($path) && is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function composer(): ?string
|
||||
{
|
||||
foreach (RuntimeConfig::get('composer_paths') as $path) {
|
||||
if (is_file($path) && is_readable($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function run(array $command): array
|
||||
{
|
||||
// PHP may terminate a web request before Composer completes otherwise.
|
||||
@set_time_limit(RuntimeConfig::get('composer_timeout_seconds') + 15);
|
||||
$process = proc_open($command, [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes, __DIR__);
|
||||
if (!is_resource($process)) {
|
||||
throw new InformationException('Composer could not be started. Run composer install using SSH.');
|
||||
}
|
||||
fclose($pipes[0]);
|
||||
stream_set_blocking($pipes[1], false);
|
||||
stream_set_blocking($pipes[2], false);
|
||||
$deadline = microtime(true) + RuntimeConfig::get('composer_timeout_seconds');
|
||||
$exit = -1;
|
||||
$timeout = false;
|
||||
try {
|
||||
while (true) {
|
||||
// Drain both pipes to avoid deadlock. Never expose Composer output:
|
||||
// repository authentication and environment details can appear there.
|
||||
stream_get_contents($pipes[1]);
|
||||
stream_get_contents($pipes[2]);
|
||||
$status = proc_get_status($process);
|
||||
if (!$status['running']) {
|
||||
$exit = $status['exitcode'];
|
||||
break;
|
||||
}
|
||||
if (microtime(true) >= $deadline) {
|
||||
$timeout = true;
|
||||
proc_terminate($process, 9);
|
||||
break;
|
||||
}
|
||||
usleep(100000);
|
||||
}
|
||||
} finally {
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
$closed = proc_close($process);
|
||||
if ($exit === -1) {
|
||||
$exit = $closed;
|
||||
}
|
||||
}
|
||||
return ['exit' => $exit, 'timeout' => $timeout];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user