aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/TaskProcessing/Db/Task.php16
-rw-r--r--lib/private/TaskProcessing/Manager.php79
2 files changed, 92 insertions, 3 deletions
diff --git a/lib/private/TaskProcessing/Db/Task.php b/lib/private/TaskProcessing/Db/Task.php
index 1ac40327899..9fc999faf1a 100644
--- a/lib/private/TaskProcessing/Db/Task.php
+++ b/lib/private/TaskProcessing/Db/Task.php
@@ -35,6 +35,10 @@ use OCP\TaskProcessing\Task as OCPTask;
* @method null|string getErrorMessage()
* @method setProgress(null|float $progress)
* @method null|float getProgress()
+ * @method setWebhookUri(string $webhookUri)
+ * @method string getWebhookUri()
+ * @method setWebhookMethod(string $webhookMethod)
+ * @method string getWebhookMethod()
*/
class Task extends Entity {
protected $lastUpdated;
@@ -48,16 +52,18 @@ class Task extends Entity {
protected $completionExpectedAt;
protected $errorMessage;
protected $progress;
+ protected $webhookUri;
+ protected $webhookMethod;
/**
* @var string[]
*/
- public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress'];
+ public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method'];
/**
* @var string[]
*/
- public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress'];
+ public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod'];
public function __construct() {
@@ -74,6 +80,8 @@ class Task extends Entity {
$this->addType('completionExpectedAt', 'datetime');
$this->addType('errorMessage', 'string');
$this->addType('progress', 'float');
+ $this->addType('webhookUri', 'string');
+ $this->addType('webhookMethod', 'string');
}
public function toRow(): array {
@@ -97,6 +105,8 @@ class Task extends Entity {
'customId' => $task->getCustomId(),
'completionExpectedAt' => $task->getCompletionExpectedAt(),
'progress' => $task->getProgress(),
+ 'webhookUri' => $task->getWebhookUri(),
+ 'webhookMethod' => $task->getWebhookMethod(),
]);
return $taskEntity;
}
@@ -114,6 +124,8 @@ class Task extends Entity {
$task->setCompletionExpectedAt($this->getCompletionExpectedAt());
$task->setErrorMessage($this->getErrorMessage());
$task->setProgress($this->getProgress());
+ $task->setWebhookUri($this->getWebhookUri());
+ $task->setWebhookMethod($this->getWebhookMethod());
return $task;
}
}
diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php
index d5a09ff2472..714a23ce5e2 100644
--- a/lib/private/TaskProcessing/Manager.php
+++ b/lib/private/TaskProcessing/Manager.php
@@ -9,9 +9,12 @@ declare(strict_types=1);
namespace OC\TaskProcessing;
+use GuzzleHttp\Exception\ClientException;
+use GuzzleHttp\Exception\ServerException;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\Files\SimpleFS\SimpleFile;
use OC\TaskProcessing\Db\TaskMapper;
+use OCP\App\IAppManager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\BackgroundJob\IJobList;
@@ -27,6 +30,7 @@ use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Http\Client\IClientService;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IServerContainer;
@@ -53,6 +57,8 @@ use OCP\TaskProcessing\TaskTypes\TextToText;
use OCP\TaskProcessing\TaskTypes\TextToTextHeadline;
use OCP\TaskProcessing\TaskTypes\TextToTextSummary;
use OCP\TaskProcessing\TaskTypes\TextToTextTopics;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
class Manager implements IManager {
@@ -83,6 +89,8 @@ class Manager implements IManager {
private \OCP\TextToImage\IManager $textToImageManager,
private \OCP\SpeechToText\ISpeechToTextManager $speechToTextManager,
private IUserMountCache $userMountCache,
+ private IClientService $clientService,
+ private IAppManager $appManager,
) {
$this->appData = $appDataFactory->get('core');
}
@@ -651,6 +659,7 @@ class Manager implements IManager {
$taskEntity = \OC\TaskProcessing\Db\Task::fromPublicTask($task);
try {
$this->taskMapper->update($taskEntity);
+ $this->runWebhook($task);
} catch (\OCP\DB\Exception $e) {
throw new \OCP\TaskProcessing\Exception\Exception('There was a problem finding the task', 0, $e);
}
@@ -739,6 +748,7 @@ class Manager implements IManager {
$taskEntity = \OC\TaskProcessing\Db\Task::fromPublicTask($task);
try {
$this->taskMapper->update($taskEntity);
+ $this->runWebhook($task);
} catch (\OCP\DB\Exception $e) {
throw new \OCP\TaskProcessing\Exception\Exception('There was a problem finding the task', 0, $e);
}
@@ -975,7 +985,7 @@ class Manager implements IManager {
/**
* @param mixed $fileId
- * @param string $userId
+ * @param string|null $userId
* @return void
* @throws UnauthorizedException
*/
@@ -989,4 +999,71 @@ class Manager implements IManager {
throw new UnauthorizedException('User ' . $userId . ' does not have access to file ' . $fileId);
}
}
+
+ /**
+ * Make a request to the task's webhookUri if necessary
+ *
+ * @param Task $task
+ */
+ private function runWebhook(Task $task): void {
+ $uri = $task->getWebhookUri();
+ $method = $task->getWebhookMethod();
+
+ if (!$uri || !$method) {
+ return;
+ }
+
+ if (in_array($method, ['HTTP:GET', 'HTTP:POST', 'HTTP:PUT', 'HTTP:DELETE'], true)) {
+ $client = $this->clientService->newClient();
+ $httpMethod = preg_replace('/^HTTP:/', '', $method);
+ $options = [
+ 'timeout' => 30,
+ 'body' => json_encode([
+ 'task' => $task->jsonSerialize(),
+ ]),
+ 'headers' => ['Content-Type' => 'application/json'],
+ ];
+ try {
+ $client->request($httpMethod, $uri, $options);
+ } catch (ClientException | ServerException $e) {
+ $this->logger->warning('Task processing HTTP webhook failed for task ' . $task->getId() . '. Request failed', ['exception' => $e]);
+ } catch (\Exception | \Throwable $e) {
+ $this->logger->warning('Task processing HTTP webhook failed for task ' . $task->getId() . '. Unknown error', ['exception' => $e]);
+ }
+ } elseif (str_starts_with($method, 'AppAPI:') && str_starts_with($uri, '/')) {
+ $parsedMethod = explode(':', $method, 4);
+ if (count($parsedMethod) < 3) {
+ $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Invalid method: ' . $method);
+ }
+ [, $exAppId, $httpMethod] = $parsedMethod;
+ if (!$this->appManager->isInstalled('app_api')) {
+ $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. AppAPI is disabled or not installed.');
+ return;
+ }
+ try {
+ $appApiFunctions = \OCP\Server::get(\OCA\AppAPI\PublicFunctions::class);
+ } catch (ContainerExceptionInterface|NotFoundExceptionInterface) {
+ $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Could not get AppAPI public functions.');
+ return;
+ }
+ $exApp = $appApiFunctions->getExApp($exAppId);
+ if ($exApp === null) {
+ $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. ExApp ' . $exAppId . ' is missing.');
+ return;
+ } elseif (!$exApp['enabled']) {
+ $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. ExApp ' . $exAppId . ' is disabled.');
+ return;
+ }
+ $requestParams = [
+ 'task' => $task->jsonSerialize(),
+ ];
+ $requestOptions = [
+ 'timeout' => 30,
+ ];
+ $response = $appApiFunctions->exAppRequest($exAppId, $uri, $task->getUserId(), $httpMethod, $requestParams, $requestOptions);
+ if (is_array($response) && isset($response['error'])) {
+ $this->logger->warning('Task processing AppAPI webhook failed for task ' . $task->getId() . '. Error during request to ExApp(' . $exAppId . '): ', $response['error']);
+ }
+ }
+ }
}