From 5eeb6709da04c5466f497b24615ef61432d228f8 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Thu, 11 Jul 2024 10:50:15 +0200 Subject: [PATCH] feat(TaskProcessing): Allow defining custom task types Signed-off-by: provokateurin --- lib/AppInfo/Application.php | 1 + lib/Controller/TaskProcessingController.php | 5 +- .../TaskProcessing/TaskProcessingProvider.php | 8 +++ .../Version2800Date20240711080316.php | 38 +++++++++++ .../ProvidersAI/TaskProcessingService.php | 67 ++++++++++++++++++- 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 lib/Migration/Version2800Date20240711080316.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f16aff31..9f4f7ea5 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -99,6 +99,7 @@ public function register(IRegistrationContext $context): void { /** @var TaskProcessingService $taskProcessingService */ $taskProcessingService = $container->get(TaskProcessingService::class); $taskProcessingService->registerExAppTaskProcessingProviders($context, $container->getServer()); + $taskProcessingService->registerExAppTaskProcessingCustomTaskTypes($context); } catch (NotFoundExceptionInterface|ContainerExceptionInterface) { } $context->registerEventListener(NodeCreatedEvent::class, FileEventsListener::class); diff --git a/lib/Controller/TaskProcessingController.php b/lib/Controller/TaskProcessingController.php index c20b46ba..9ac7cd18 100644 --- a/lib/Controller/TaskProcessingController.php +++ b/lib/Controller/TaskProcessingController.php @@ -35,14 +35,15 @@ public function __construct( public function registerProvider( string $name, string $displayName, - string $taskType + string $taskType, + ?array $customTaskType, ): DataResponse { if (!$this->isSupported()) { return new DataResponse([], Http::STATUS_NOT_IMPLEMENTED); } $provider = $this->taskProcessingService->registerTaskProcessingProvider( - $this->request->getHeader('EX-APP-ID'), $name, $displayName, $taskType, + $this->request->getHeader('EX-APP-ID'), $name, $displayName, $taskType, $customTaskType, ); if ($provider === null) { diff --git a/lib/Db/TaskProcessing/TaskProcessingProvider.php b/lib/Db/TaskProcessing/TaskProcessingProvider.php index c67cbb58..110e3f0b 100644 --- a/lib/Db/TaskProcessing/TaskProcessingProvider.php +++ b/lib/Db/TaskProcessing/TaskProcessingProvider.php @@ -20,6 +20,8 @@ * @method string getDisplayName() * @method void setTaskType(string $taskType) * @method string getTaskType() + * @method void setCustomTaskType(string|null $customTaskType) + * @method string|null getCustomTaskType() */ class TaskProcessingProvider extends Entity implements JsonSerializable { protected ?string $appId = null; @@ -27,12 +29,14 @@ class TaskProcessingProvider extends Entity implements JsonSerializable { protected ?string $displayName = null; protected ?string $actionHandler = null; protected ?string $taskType = null; + protected ?string $customTaskType = null; public function __construct(array $params = []) { $this->addType('app_id', 'string'); $this->addType('name', 'string'); $this->addType('display_name', 'string'); $this->addType('task_type', 'string'); + $this->addType('custom_task_type', 'string'); if (isset($params['app_id'])) { $this->setAppId($params['app_id']); @@ -46,6 +50,9 @@ public function __construct(array $params = []) { if (isset($params['task_type'])) { $this->setTaskType($params['task_type']); } + if (isset($params['custom_task_type'])) { + $this->setCustomTaskType($params['custom_task_type']); + } } public function jsonSerialize(): array { @@ -54,6 +61,7 @@ public function jsonSerialize(): array { 'name' => $this->name, 'display_name' => $this->displayName, 'task_type' => $this->taskType, + 'custom_task_type' => $this->customTaskType, ]; } } diff --git a/lib/Migration/Version2800Date20240711080316.php b/lib/Migration/Version2800Date20240711080316.php new file mode 100644 index 00000000..4cfdd705 --- /dev/null +++ b/lib/Migration/Version2800Date20240711080316.php @@ -0,0 +1,38 @@ +getTable('ex_task_processing'); + if (!$table->hasColumn('custom_task_type')) { + $table->addColumn('custom_task_type', Types::TEXT, [ + 'notnull' => false, + ]); + } + + return $schema; + } +} diff --git a/lib/Service/ProvidersAI/TaskProcessingService.php b/lib/Service/ProvidersAI/TaskProcessingService.php index 3a209166..6feea744 100644 --- a/lib/Service/ProvidersAI/TaskProcessingService.php +++ b/lib/Service/ProvidersAI/TaskProcessingService.php @@ -14,7 +14,10 @@ use OCP\ICache; use OCP\ICacheFactory; use OCP\IServerContainer; +use OCP\TaskProcessing\EShapeType; use OCP\TaskProcessing\IProvider; +use OCP\TaskProcessing\ITaskType; +use OCP\TaskProcessing\ShapeDescriptor; use Psr\Log\LoggerInterface; class TaskProcessingService { @@ -71,7 +74,8 @@ public function registerTaskProcessingProvider( string $appId, string $name, string $displayName, - string $taskType + string $taskType, + ?array $customTaskType, ): ?TaskProcessingProvider { try { $taskProcessingProvider = $this->mapper->findByAppidName($appId, $name); @@ -84,6 +88,7 @@ public function registerTaskProcessingProvider( 'name' => $name, 'display_name' => $displayName, 'task_type' => $taskType, + 'custom_task_type' => json_encode($customTaskType, JSON_THROW_ON_ERROR), ]); if ($taskProcessingProvider !== null) { @@ -186,4 +191,64 @@ public function unregisterExAppTaskProcessingProviders(string $appId): int { $this->resetCacheEnabled(); return $result; } + + /** + * @param IRegistrationContext $context + * + * @return void + */ + public function registerExAppTaskProcessingCustomTaskTypes(IRegistrationContext $context): void { + $exAppsProviders = $this->getRegisteredTaskProcessingProviders(); + foreach ($exAppsProviders as $exAppProvider) { + if ($exAppProvider->getCustomTaskType() === null) { + continue; + } + + $className = '\\OCA\\AppAPI\\' . $exAppProvider->getAppId() . '\\' . $exAppProvider->getName() . '\\TaskType'; + $taskType = $this->getAnonymousTaskType(json_decode($exAppProvider->getCustomTaskType(), true, 512, JSON_THROW_ON_ERROR)); + $context->registerService($className, function () use ($taskType) { + return $taskType; + }); + $context->registerTaskProcessingTaskType($className); + } + } + + private function getAnonymousTaskType( + array $customTaskType, + ): ITaskType { + return new class($customTaskType) implements ITaskType { + public function __construct( + private readonly array $customTaskType, + ) { + } + + public function getId(): string { + return $this->customTaskType['id']; + } + + public function getName(): string { + return $this->customTaskType['name']; + } + + public function getDescription(): string { + return $this->customTaskType['description']; + } + + public function getInputShape(): array { + return array_map(static fn (array $shape) => new ShapeDescriptor( + $shape['name'], + $shape['description'], + EShapeType::from($shape['type']), + ), $this->customTaskType['input_shape']); + } + + public function getOutputShape(): array { + return array_map(static fn (array $shape) => new ShapeDescriptor( + $shape['name'], + $shape['description'], + EShapeType::from($shape['type']), + ), $this->customTaskType['output_shape']); + } + }; + } }