Skip to content

Commit 9dc93ad

Browse files
committed
feat(task-streaming): add preferStreaming boolean attribute to taskprocessing tasks. pass it to ISynchronousProgressiveProvider::process
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
1 parent b271bfd commit 9dc93ad

13 files changed

Lines changed: 802 additions & 10 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OC\Core\Migrations;
10+
11+
use Closure;
12+
use OCP\DB\ISchemaWrapper;
13+
use OCP\DB\Types;
14+
use OCP\Migration\Attributes\AddColumn;
15+
use OCP\Migration\Attributes\ColumnType;
16+
use OCP\Migration\IOutput;
17+
use OCP\Migration\SimpleMigrationStep;
18+
19+
/**
20+
*
21+
*/
22+
#[AddColumn(table: 'taskprocessing_tasks', name: 'prefer_streaming', type: ColumnType::SMALLINT)]
23+
class Version35000Date20260527162338 extends SimpleMigrationStep {
24+
25+
/**
26+
* @param IOutput $output
27+
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
28+
* @param array $options
29+
* @return null|ISchemaWrapper
30+
*/
31+
#[\Override]
32+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
33+
/** @var ISchemaWrapper $schema */
34+
$schema = $schemaClosure();
35+
36+
if ($schema->hasTable('taskprocessing_tasks')) {
37+
$table = $schema->getTable('taskprocessing_tasks');
38+
if (!$table->hasColumn('prefer_streaming')) {
39+
$table->addColumn('prefer_streaming', Types::SMALLINT, [
40+
'notnull' => true,
41+
'default' => 1,
42+
'unsigned' => true,
43+
]);
44+
return $schema;
45+
}
46+
}
47+
48+
return null;
49+
}
50+
}

core/ResponseDefinitions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
* allowCleanup: bool,
214214
* includeWatermark: bool,
215215
* userFacingErrorMessage: ?string,
216+
* preferStreaming: bool,
216217
* }
217218
*
218219
* @psalm-type CoreProfileAction = array{

core/openapi-ex_app.json

Lines changed: 237 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@
204204
"endedAt",
205205
"allowCleanup",
206206
"includeWatermark",
207-
"userFacingErrorMessage"
207+
"userFacingErrorMessage",
208+
"preferStreaming"
208209
],
209210
"properties": {
210211
"id": {
@@ -285,6 +286,9 @@
285286
"userFacingErrorMessage": {
286287
"type": "string",
287288
"nullable": true
289+
},
290+
"preferStreaming": {
291+
"type": "boolean"
288292
}
289293
}
290294
},
@@ -2207,6 +2211,238 @@
22072211
}
22082212
}
22092213
},
2214+
"/ocs/v2.php/taskprocessing/tasks_provider/{taskId}/stream-result": {
2215+
"post": {
2216+
"operationId": "task_processing_api-set-intermediate-result",
2217+
"summary": "Sets the task intermediate result while it is running",
2218+
"description": "This endpoint requires admin access",
2219+
"tags": [
2220+
"task_processing_api"
2221+
],
2222+
"security": [
2223+
{
2224+
"bearer_auth": []
2225+
},
2226+
{
2227+
"basic_auth": []
2228+
}
2229+
],
2230+
"requestBody": {
2231+
"required": false,
2232+
"content": {
2233+
"application/json": {
2234+
"schema": {
2235+
"type": "object",
2236+
"properties": {
2237+
"output": {
2238+
"type": "object",
2239+
"nullable": true,
2240+
"description": "The intermediate task output, files are represented by their IDs",
2241+
"additionalProperties": {
2242+
"type": "object"
2243+
}
2244+
}
2245+
}
2246+
}
2247+
}
2248+
}
2249+
},
2250+
"parameters": [
2251+
{
2252+
"name": "taskId",
2253+
"in": "path",
2254+
"description": "The id of the task",
2255+
"required": true,
2256+
"schema": {
2257+
"type": "integer",
2258+
"format": "int64"
2259+
}
2260+
},
2261+
{
2262+
"name": "OCS-APIRequest",
2263+
"in": "header",
2264+
"description": "Required to be true for the API request to pass",
2265+
"required": true,
2266+
"schema": {
2267+
"type": "boolean",
2268+
"default": true
2269+
}
2270+
}
2271+
],
2272+
"responses": {
2273+
"200": {
2274+
"description": "Result updated successfully",
2275+
"content": {
2276+
"application/json": {
2277+
"schema": {
2278+
"type": "object",
2279+
"required": [
2280+
"ocs"
2281+
],
2282+
"properties": {
2283+
"ocs": {
2284+
"type": "object",
2285+
"required": [
2286+
"meta",
2287+
"data"
2288+
],
2289+
"properties": {
2290+
"meta": {
2291+
"$ref": "#/components/schemas/OCSMeta"
2292+
},
2293+
"data": {
2294+
"type": "object",
2295+
"required": [
2296+
"task"
2297+
],
2298+
"properties": {
2299+
"task": {
2300+
"$ref": "#/components/schemas/TaskProcessingTask"
2301+
}
2302+
}
2303+
}
2304+
}
2305+
}
2306+
}
2307+
}
2308+
}
2309+
}
2310+
},
2311+
"500": {
2312+
"description": "",
2313+
"content": {
2314+
"application/json": {
2315+
"schema": {
2316+
"type": "object",
2317+
"required": [
2318+
"ocs"
2319+
],
2320+
"properties": {
2321+
"ocs": {
2322+
"type": "object",
2323+
"required": [
2324+
"meta",
2325+
"data"
2326+
],
2327+
"properties": {
2328+
"meta": {
2329+
"$ref": "#/components/schemas/OCSMeta"
2330+
},
2331+
"data": {
2332+
"type": "object",
2333+
"required": [
2334+
"message"
2335+
],
2336+
"properties": {
2337+
"message": {
2338+
"type": "string"
2339+
}
2340+
}
2341+
}
2342+
}
2343+
}
2344+
}
2345+
}
2346+
}
2347+
}
2348+
},
2349+
"404": {
2350+
"description": "Task not found",
2351+
"content": {
2352+
"application/json": {
2353+
"schema": {
2354+
"type": "object",
2355+
"required": [
2356+
"ocs"
2357+
],
2358+
"properties": {
2359+
"ocs": {
2360+
"type": "object",
2361+
"required": [
2362+
"meta",
2363+
"data"
2364+
],
2365+
"properties": {
2366+
"meta": {
2367+
"$ref": "#/components/schemas/OCSMeta"
2368+
},
2369+
"data": {
2370+
"type": "object",
2371+
"required": [
2372+
"message"
2373+
],
2374+
"properties": {
2375+
"message": {
2376+
"type": "string"
2377+
}
2378+
}
2379+
}
2380+
}
2381+
}
2382+
}
2383+
}
2384+
}
2385+
}
2386+
},
2387+
"401": {
2388+
"description": "Current user is not logged in",
2389+
"content": {
2390+
"application/json": {
2391+
"schema": {
2392+
"type": "object",
2393+
"required": [
2394+
"ocs"
2395+
],
2396+
"properties": {
2397+
"ocs": {
2398+
"type": "object",
2399+
"required": [
2400+
"meta",
2401+
"data"
2402+
],
2403+
"properties": {
2404+
"meta": {
2405+
"$ref": "#/components/schemas/OCSMeta"
2406+
},
2407+
"data": {}
2408+
}
2409+
}
2410+
}
2411+
}
2412+
}
2413+
}
2414+
},
2415+
"403": {
2416+
"description": "Logged in account must be an admin",
2417+
"content": {
2418+
"application/json": {
2419+
"schema": {
2420+
"type": "object",
2421+
"required": [
2422+
"ocs"
2423+
],
2424+
"properties": {
2425+
"ocs": {
2426+
"type": "object",
2427+
"required": [
2428+
"meta",
2429+
"data"
2430+
],
2431+
"properties": {
2432+
"meta": {
2433+
"$ref": "#/components/schemas/OCSMeta"
2434+
},
2435+
"data": {}
2436+
}
2437+
}
2438+
}
2439+
}
2440+
}
2441+
}
2442+
}
2443+
}
2444+
}
2445+
},
22102446
"/ocs/v2.php/taskprocessing/tasks_consumer/tasks/{taskId}/cancel": {
22112447
"post": {
22122448
"operationId": "task_processing_api-cancel-task-ex-app-endpoint",

0 commit comments

Comments
 (0)