Files
speckle-server/packages/server/modules/automate/rest/logStream.ts
T
Chuck Driesler e312110933 Automate Public Beta (#3472)
* feat(automate): query active user functions

* fix(automate): show automations to non-stream-owners

* feat(automate): associate function with workspace

* fix(automate): split functions page between user and example functions

* fix(automate): ugh

* fix(functions): use correct query type in different places

* fix(automate): workspace functions page

* feat(automate): query specific categories of functions

* fix(automate): checkpoint

* fix(workspaces): successful queries w local env

* fix(automate): createFunctionWithoutVersion

* fix(automate): successful associate function with workspace

* fix(automate): query and return workspaces on functions

* fix(automate): show current function workspace

* fix(automate): query functions in automation create dialog

* fix(automate): audit non-owner automation access

* refactor(automate): logs api can get the projectId from the path

* fix(automate): multiregion gql resolvers

* fix(automate): multiregion event listeners

* fix(automate): drop automationCount

* fix(automate): multiregion run status

* fix(automate): correctness

* fix(automate): successful usage of multiregion results

* fix(automate): actually finish event listeners

* chore(automate): fix tests fix tests

* fix(automate): fix tests but make it multiregion flavor

* fix(automate): logs endpoint

* fix(automate): inject projectid correctly

* fix(automate): drop user-source functions

* fix(automate): owners edit, others can view

* fix(automate): simplify queries, auto workspace association

* chore(automate): appease

* chore(automate): fix function types

* fix(automate): get to workspace functions from empty state

* chore(automate): death to all slugs

* fix(automate): no create automation from function

* fix(automate): hide workspace change, tweak role access

---------

Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
2024-11-29 17:33:14 +01:00

93 lines
3.2 KiB
TypeScript

import { db } from '@/db/knex'
import { getAutomationRunLogs } from '@/modules/automate/clients/executionEngine'
import { ExecutionEngineFailedResponseError } from '@/modules/automate/errors/executionEngine'
import { getAutomationRunWithTokenFactory } from '@/modules/automate/repositories/automations'
import { corsMiddleware } from '@/modules/core/configs/cors'
import { getStreamFactory } from '@/modules/core/repositories/streams'
import { getProjectDbClient } from '@/modules/multiregion/dbSelector'
import {
validateRequiredStreamFactory,
validateResourceAccess,
validateScope,
validateServerRoleBuilderFactory,
validateStreamRoleBuilderFactory
} from '@/modules/shared/authz'
import { authMiddlewareCreator } from '@/modules/shared/middleware'
import { getRolesFactory } from '@/modules/shared/repositories/roles'
import { Roles, Scopes } from '@speckle/shared'
import { Application } from 'express'
export default (app: Application) => {
app.get(
'/api/v1/projects/:streamId/automations/:automationId/runs/:runId/logs',
corsMiddleware(),
authMiddlewareCreator([
validateServerRoleBuilderFactory({
getRoles: getRolesFactory({ db })
})({ requiredRole: Roles.Server.Guest }),
validateScope({ requiredScope: Scopes.Streams.Read }),
validateRequiredStreamFactory({
getStream: getStreamFactory({ db })
}),
validateStreamRoleBuilderFactory({ getRoles: getRolesFactory({ db }) })({
requiredRole: Roles.Stream.Reviewer
}),
validateResourceAccess
]),
async (req, res) => {
const projectDb = await getProjectDbClient({ projectId: req.params.streamId })
const automationId = req.params.automationId
const runId = req.params.runId
const getAutomationRunWithToken = getAutomationRunWithTokenFactory({
db: projectDb
})
const run = await getAutomationRunWithToken({
automationId,
automationRunId: runId
})
if (!run) {
throw new Error("Couldn't find automation or its run")
}
if (!run.executionEngineRunId) {
throw new Error('No associated run found on the execution engine')
}
const setPlaintextHeaders = () => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.setHeader('Cache-Control', 'no-cache')
}
try {
let firstLine = true
const logGenerator = getAutomationRunLogs({
automationId: run.executionEngineAutomationId,
automationRunId: run.executionEngineRunId,
automationToken: run.token
})
for await (const line of logGenerator) {
if (firstLine) {
// Only do this now, so that if log retrieval failed defaultErrorHandler correctly returns JSON response
setPlaintextHeaders()
firstLine = false
}
res.write(line)
}
} catch (e) {
if (e instanceof ExecutionEngineFailedResponseError) {
if (e.response.statusMessage === 'LOG_MISSING_OR_NOT_READY') {
setPlaintextHeaders()
res.write('')
res.end()
return
}
}
throw e
}
res.end()
}
)
}