Files
speckle-server/packages/server/modules/gendo/rest/index.ts
T

95 lines
3.3 KiB
TypeScript

import { corsMiddlewareFactory } from '@/modules/core/configs/cors'
import { updateRenderRequestFactory } from '@/modules/gendo/services'
import type express from 'express'
import {
getRenderByGenerationIdFactory,
updateRenderRecordFactory
} from '@/modules/gendo/repositories'
import { uploadFileStreamFactory } from '@/modules/blobstorage/services/management'
import {
updateBlobFactory,
upsertBlobFactory
} from '@/modules/blobstorage/repositories'
import { publish } from '@/modules/shared/utils/subscriptions'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import { createHmac, timingSafeEqual } from 'node:crypto'
import { getGendoAIKey } from '@/modules/shared/helpers/envHelper'
import { getProjectObjectStorage } from '@/modules/multiregion/utils/blobStorageSelector'
import { storeFileStreamFactory } from '@/modules/blobstorage/repositories/blobs'
import { withOperationLogging } from '@/observability/domain/businessLogging'
export default function (app: express.Express) {
// const responseToken = getGendoAIResponseKey()
// Gendo api calls hit these endpoints w/ the results
app.options('/api/thirdparty/gendo/:projectId', corsMiddlewareFactory())
app.post(
'/api/thirdparty/gendo/:projectId',
corsMiddlewareFactory(),
async (req, res) => {
const sig = Buffer.from(req.get('x-signature-sha256') || '', 'utf8')
// //Calculate HMAC
const hmac = createHmac('sha256', getGendoAIKey())
const digest = Buffer.from(hmac.update(req.body).digest('base64'), 'utf-8')
// //Compare HMACs
if (
sig.length !== digest.length ||
!timingSafeEqual(new Uint8Array(digest), new Uint8Array(sig))
) {
return res
.status(401)
.send('Speckle says your webhook signature is not valid 😠')
}
const payload = JSON.parse(req.body)
const responseImage = payload.imageBase64
const status = payload.status
const gendoGenerationId = payload.generationId
const projectId = req.params.projectId
const logger = req.log.child({
projectId,
gendoGenerationId,
gendoResponseStatus: status
})
const [projectDb, projectStorage] = await Promise.all([
getProjectDbClient({ projectId }),
getProjectObjectStorage({ projectId })
])
const storeFileStream = storeFileStreamFactory({
storage: projectStorage.private
})
const updateRenderRequest = updateRenderRequestFactory({
getRenderByGenerationId: getRenderByGenerationIdFactory({ db: projectDb }),
uploadFileStream: uploadFileStreamFactory({
storeFileStream,
upsertBlob: upsertBlobFactory({ db: projectDb }),
updateBlob: updateBlobFactory({ db: projectDb })
}),
updateRenderRecord: updateRenderRecordFactory({ db: projectDb }),
publish
})
await withOperationLogging(
async () =>
await updateRenderRequest({
gendoGenerationId,
responseImage,
status
}),
{
logger,
operationName: 'updateGendoRenderRequest',
operationDescription:
'Handle response from GendoAI and update a render request'
}
)
res.status(200).send('Speckle says thank you 💖')
}
)
}