Merge pull request #2998 from specklesystems/previews-ioc-3

chore(server): previews IoC 3 - sendObjectPreviewFactory
This commit is contained in:
Alessandro Magionami 2024-09-17 09:48:18 +02:00 коммит произвёл GitHub
Родитель a133738036 468ebac67e
Коммит f513053096
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 88 добавлений и 62 удалений

Просмотреть файл

@ -1,5 +1,6 @@
import { ObjectPreview } from '@/modules/previews/domain/types'
import { Nullable, Optional } from '@speckle/shared'
import express from 'express'
export type GetObjectPreviewInfo = (params: {
streamId: string
@ -17,7 +18,7 @@ export type GetPreviewImage = (params: {
export type GetObjectPreviewBufferOrFilepath = (params: {
streamId: string
objectId: string
angle: number
angle?: string
}) => Promise<
| {
type: 'file'
@ -25,5 +26,13 @@ export type GetObjectPreviewBufferOrFilepath = (params: {
error?: true
errorCode?: string
}
| { type: 'buffer'; buffer: Buffer }
| { type: 'buffer'; buffer: Buffer; error?: true; errorCode?: string }
>
export type SendObjectPreview = (
req: express.Request,
res: express.Response,
streamId: string,
objectId: string,
angle: string
) => Promise<void>

Просмотреть файл

@ -6,7 +6,7 @@ export type ObjectPreview = {
previewStatus: number
priority: number
lastUpdate: Date
preview: Nullable<string>
preview: Nullable<Record<string, string>>
}
export type Preview = {

Просмотреть файл

@ -21,7 +21,8 @@ const httpErrorImage = (httpErrorCode) =>
const cors = require('cors')
const { db } = require('@/db/knex')
const {
getObjectPreviewBufferOrFilepathFactory
getObjectPreviewBufferOrFilepathFactory,
sendObjectPreviewFactory
} = require('@/modules/previews/services/management')
const { getObject } = require('@/modules/core/services/objects')
const {
@ -39,59 +40,17 @@ exports.init = (app, isInitial) => {
moduleLogger.info('📸 Init object preview module')
}
const DEFAULT_ANGLE = '0'
const sendObjectPreview = async (req, res, streamId, objectId, angle) => {
const getObjectPreviewBufferOrFilepath = getObjectPreviewBufferOrFilepathFactory({
getObject,
getObjectPreviewInfo: getObjectPreviewInfoFactory({ db }),
createObjectPreview: createObjectPreviewFactory({ db }),
getPreviewImage: getPreviewImageFactory({ db })
})
let previewBufferOrFile = await getObjectPreviewBufferOrFilepath({
streamId,
objectId,
angle
})
if (req.query.postprocess === 'og') {
const stream = await getStream({ streamId: req.params.streamId })
const streamName = stream.name
if (previewBufferOrFile.type === 'file') {
previewBufferOrFile = {
type: 'buffer',
buffer: await makeOgImage(previewBufferOrFile.file, streamName)
}
} else {
previewBufferOrFile = {
type: 'buffer',
buffer: await makeOgImage(previewBufferOrFile.buffer, streamName)
}
}
}
if (previewBufferOrFile.error) {
res.set('X-Preview-Error', 'true')
}
if (previewBufferOrFile.errorCode) {
res.set('X-Preview-Error-Code', previewBufferOrFile.errorCode)
}
if (previewBufferOrFile.type === 'file') {
// we can't cache these cause they may switch to proper buffer previews in a sec
// at least if they're not in the error state which they will not get out of (and thus can be cached in that scenario)
if (previewBufferOrFile.error) {
res.set('Cache-Control', 'private, max-age=604800')
} else {
res.set('Cache-Control', 'no-cache, no-store')
}
res.sendFile(previewBufferOrFile.file)
} else {
res.contentType('image/png')
// If the preview is a buffer, it comes from the DB and can be cached on clients
res.set('Cache-Control', 'private, max-age=604800')
res.send(previewBufferOrFile.buffer)
}
}
const getObjectPreviewBufferOrFilepath = getObjectPreviewBufferOrFilepathFactory({
getObject,
getObjectPreviewInfo: getObjectPreviewInfoFactory({ db }),
createObjectPreview: createObjectPreviewFactory({ db }),
getPreviewImage: getPreviewImageFactory({ db })
})
const sendObjectPreview = sendObjectPreviewFactory({
getObject,
getObjectPreviewBufferOrFilepath,
makeOgImage
})
const checkStreamPermissions = async (req) => {
const stream = await getStream({
@ -151,7 +110,7 @@ exports.init = (app, isInitial) => {
res,
req.params.streamId,
lastCommit.referencedObject,
req.params.angle || DEFAULT_ANGLE
req.params.angle
)
})
@ -187,7 +146,7 @@ exports.init = (app, isInitial) => {
res,
req.params.streamId,
lastCommit.referencedObject,
req.params.angle || DEFAULT_ANGLE
req.params.angle
)
}
)
@ -211,7 +170,7 @@ exports.init = (app, isInitial) => {
res,
req.params.streamId,
commit.referencedObject,
req.params.angle || DEFAULT_ANGLE
req.params.angle
)
})
@ -227,7 +186,7 @@ exports.init = (app, isInitial) => {
res,
req.params.streamId,
req.params.objectId,
req.params.angle || DEFAULT_ANGLE
req.params.angle
)
})

Просмотреть файл

@ -1,14 +1,18 @@
import { logger } from '@/logging/logging'
import { getStream } from '@/modules/core/repositories/streams'
import { getObject } from '@/modules/core/services/objects'
import {
CreateObjectPreview,
GetObjectPreviewBufferOrFilepath,
GetObjectPreviewInfo,
GetPreviewImage
GetPreviewImage,
SendObjectPreview
} from '@/modules/previews/domain/operations'
import { makeOgImage } from '@/modules/previews/ogImage'
const noPreviewImage = require.resolve('#/assets/previews/images/no_preview.png')
const previewErrorImage = require.resolve('#/assets/previews/images/preview_error.png')
const defaultAngle = '0'
export const getObjectPreviewBufferOrFilepathFactory =
(deps: {
@ -18,6 +22,8 @@ export const getObjectPreviewBufferOrFilepathFactory =
getPreviewImage: GetPreviewImage
}): GetObjectPreviewBufferOrFilepath =>
async ({ streamId, objectId, angle }) => {
angle = angle || defaultAngle
if (process.env.DISABLE_PREVIEWS) {
return {
type: 'file',
@ -70,3 +76,55 @@ export const getObjectPreviewBufferOrFilepathFactory =
}
return { type: 'buffer', buffer: previewImg }
}
export const sendObjectPreviewFactory =
(deps: {
getObjectPreviewBufferOrFilepath: GetObjectPreviewBufferOrFilepath
getStream: typeof getStream
makeOgImage: typeof makeOgImage
}): SendObjectPreview =>
async (req, res, streamId, objectId, angle) => {
let previewBufferOrFile = await deps.getObjectPreviewBufferOrFilepath({
streamId,
objectId,
angle
})
if (req.query.postprocess === 'og') {
const stream = await deps.getStream({ streamId: req.params.streamId })
const streamName = stream!.name
if (previewBufferOrFile.type === 'file') {
previewBufferOrFile = {
type: 'buffer',
buffer: await deps.makeOgImage(previewBufferOrFile.file, streamName)
}
} else {
previewBufferOrFile = {
type: 'buffer',
buffer: await deps.makeOgImage(previewBufferOrFile.buffer, streamName)
}
}
}
if (previewBufferOrFile.error) {
res.set('X-Preview-Error', 'true')
}
if (previewBufferOrFile.errorCode) {
res.set('X-Preview-Error-Code', previewBufferOrFile.errorCode)
}
if (previewBufferOrFile.type === 'file') {
// we can't cache these cause they may switch to proper buffer previews in a sec
// at least if they're not in the error state which they will not get out of (and thus can be cached in that scenario)
if (previewBufferOrFile.error) {
res.set('Cache-Control', 'private, max-age=604800')
} else {
res.set('Cache-Control', 'no-cache, no-store')
}
res.sendFile(previewBufferOrFile.file)
} else {
res.contentType('image/png')
// If the preview is a buffer, it comes from the DB and can be cached on clients
res.set('Cache-Control', 'private, max-age=604800')
res.send(previewBufferOrFile.buffer)
}
}