fix(proxy/api/ndJsonStream): send header for empty iterables
Introduced by ed987e161
This commit is contained in:
parent
4dc4b635f2
commit
84fdd3fe4b
@ -14,25 +14,30 @@ import { createLogger } from '@xen-orchestra/log'
|
|||||||
|
|
||||||
const { debug, warn } = createLogger('xo:proxy:api')
|
const { debug, warn } = createLogger('xo:proxy:api')
|
||||||
|
|
||||||
const ndJsonStream = asyncIteratorToStream(async function* (responseId, iterable) {
|
const ndJsonStream = asyncIteratorToStream(async function*(responseId, iterable) {
|
||||||
let headerSent = false
|
|
||||||
try {
|
try {
|
||||||
for await (const data of iterable) {
|
let cursor, iterator
|
||||||
if (!headerSent) {
|
try {
|
||||||
yield format.response(responseId, { $responseType: 'ndjson' }) + '\n'
|
const getIterator = iterable[Symbol.iterator] ?? iterable[Symbol.asyncIterator]
|
||||||
headerSent = true
|
iterator = getIterator.call(iterable)
|
||||||
}
|
|
||||||
|
cursor = await iterator.next()
|
||||||
|
yield format.response(responseId, { $responseType: 'ndjson' }) + '\n'
|
||||||
|
} catch (error) {
|
||||||
|
yield format.error(responseId, error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!cursor.done) {
|
||||||
try {
|
try {
|
||||||
yield JSON.stringify(data) + '\n'
|
yield JSON.stringify(cursor.value) + '\n'
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
warn('ndJsonStream, item error', { error })
|
warn('ndJsonStream, item error', { error })
|
||||||
}
|
}
|
||||||
|
cursor = await iterator.next()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
warn('ndJsonStream, fatal error', { error })
|
warn('ndJsonStream, fatal error', { error })
|
||||||
if (!headerSent) {
|
|
||||||
yield format.error(responseId, error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -47,7 +52,7 @@ export default class Api {
|
|||||||
ctx.req.setTimeout(0)
|
ctx.req.setTimeout(0)
|
||||||
|
|
||||||
const profile = await app.authentication.findProfile({
|
const profile = await app.authentication.findProfile({
|
||||||
authenticationToken: ctx.cookies.get('authenticationToken'),
|
authenticationToken: ctx.cookies.get('authenticationToken')
|
||||||
})
|
})
|
||||||
if (profile === undefined) {
|
if (profile === undefined) {
|
||||||
ctx.status = 401
|
ctx.status = 401
|
||||||
@ -118,7 +123,7 @@ export default class Api {
|
|||||||
this.addMethods({
|
this.addMethods({
|
||||||
system: {
|
system: {
|
||||||
getMethodsInfo: [
|
getMethodsInfo: [
|
||||||
function* () {
|
function*() {
|
||||||
const methods = this._methods
|
const methods = this._methods
|
||||||
for (const name in methods) {
|
for (const name in methods) {
|
||||||
const { description, params = {} } = methods[name]
|
const { description, params = {} } = methods[name]
|
||||||
@ -126,25 +131,25 @@ export default class Api {
|
|||||||
}
|
}
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
{
|
{
|
||||||
description: 'returns the signatures of all available API methods',
|
description: 'returns the signatures of all available API methods'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
getServerVersion: [
|
getServerVersion: [
|
||||||
() => appVersion,
|
() => appVersion,
|
||||||
{
|
{
|
||||||
description: 'returns the version of xo-server',
|
description: 'returns the version of xo-server'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
listMethods: [
|
listMethods: [
|
||||||
function* () {
|
function*() {
|
||||||
const methods = this._methods
|
const methods = this._methods
|
||||||
for (const name in methods) {
|
for (const name in methods) {
|
||||||
yield name
|
yield name
|
||||||
}
|
}
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
{
|
{
|
||||||
description: 'returns the name of all available API methods',
|
description: 'returns the name of all available API methods'
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
methodSignature: [
|
methodSignature: [
|
||||||
({ method: name }) => {
|
({ method: name }) => {
|
||||||
@ -159,14 +164,14 @@ export default class Api {
|
|||||||
{
|
{
|
||||||
description: 'returns the signature of an API method',
|
description: 'returns the signature of an API method',
|
||||||
params: {
|
params: {
|
||||||
method: { type: 'string' },
|
method: { type: 'string' }
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
range: [
|
range: [
|
||||||
function* ({ start = 0, stop, step }) {
|
function*({ start = 0, stop, step }) {
|
||||||
if (step === undefined) {
|
if (step === undefined) {
|
||||||
step = start > stop ? -1 : 1
|
step = start > stop ? -1 : 1
|
||||||
}
|
}
|
||||||
@ -184,11 +189,11 @@ export default class Api {
|
|||||||
params: {
|
params: {
|
||||||
start: { optional: true, type: 'number' },
|
start: { optional: true, type: 'number' },
|
||||||
step: { optional: true, type: 'number' },
|
step: { optional: true, type: 'number' },
|
||||||
stop: { type: 'number' },
|
stop: { type: 'number' }
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +220,7 @@ export default class Api {
|
|||||||
return required
|
return required
|
||||||
}),
|
}),
|
||||||
|
|
||||||
type: 'object',
|
type: 'object'
|
||||||
})
|
})
|
||||||
|
|
||||||
const m = params => {
|
const m = params => {
|
||||||
|
@ -27,3 +27,5 @@
|
|||||||
> - major: if the change breaks compatibility
|
> - major: if the change breaks compatibility
|
||||||
>
|
>
|
||||||
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
||||||
|
|
||||||
|
- @xen-orchestra/proxy patch
|
||||||
|
Loading…
Reference in New Issue
Block a user