universo-platform-3d
111 строк · 3.3 Кб
1import { BadRequestException, Inject, Injectable, Logger } from '@nestjs/common'
2import { pipeline, PassThrough } from 'stream'
3import { parser } from 'stream-json'
4import { pick } from 'stream-json/filters/Pick'
5import StreamValues, { streamValues } from 'stream-json/streamers/StreamValues'
6import FilterBase from 'stream-json/filters/FilterBase'
7import { Document, Extension, NodeIO } from '@gltf-transform/core'
8import { MirrorEquipableExtension } from './glb-extensions/mirror-equipable.extension'
9import { GLBAnalyzingHandler } from './abstractions/glb-analyzing-handler.type'
10import { FILE_ANALYZING_MIMETYPES } from './enums/file-analyzing-mimetypes.enum'
11import { ALL_EXTENSIONS } from '@gltf-transform/extensions'
12
13@Injectable()
14export class AssetAnalyzingService {
15constructor(
16private readonly logger: Logger,
17@Inject('NODE_IO') private readonly nodeIo: NodeIO
18) {}
19
20public async isAssetEquipable(
21assetFile: Express.Multer.File
22): Promise<boolean> {
23switch (assetFile.mimetype) {
24case FILE_ANALYZING_MIMETYPES.GLB:
25return await this.isGLBAssetEquippable(assetFile)
26case FILE_ANALYZING_MIMETYPES.GLTF:
27return await this.isGLTFAssetEquippable(assetFile)
28default:
29return false
30}
31}
32
33private async isGLBAssetEquippable(
34glbAssetFile: Express.Multer.File
35): Promise<boolean> {
36return await this.getGLBAnalyzingPipeline(
37glbAssetFile,
38(glbDocument: Document) =>
39glbDocument
40.getRoot()
41.listExtensionsUsed()
42.some(
43(asset) =>
44asset.extensionName === MirrorEquipableExtension.EXTENSION_NAME
45),
46[MirrorEquipableExtension, ...ALL_EXTENSIONS]
47)
48}
49
50private async isGLTFAssetEquippable(
51gltfAssetFile: Express.Multer.File
52): Promise<boolean> {
53try {
54return await new Promise((resolve, reject) => {
55this.getGLTFAnalyzingPipeline(gltfAssetFile, {
56filter: 'extensions'
57})
58.on('data', ({ value }) => {
59if (value.MIRROR_equipable) {
60resolve(true)
61}
62})
63.on('error', (err) => reject(err))
64.on('end', () => {
65resolve(false)
66})
67})
68} catch (err) {
69throw new BadRequestException('Invalid GLTF file')
70}
71}
72
73private getGLTFAnalyzingPipeline(
74gltfAssetFile: Express.Multer.File,
75filter: FilterBase.FilterOptions
76): StreamValues {
77const bufferStream = new PassThrough()
78bufferStream.end(gltfAssetFile.buffer)
79
80return pipeline(
81bufferStream,
82parser(),
83pick(filter),
84streamValues(),
85(err: Error) => {
86if (err) {
87this.logger.error('GLTF Processing Pipeline failed.', err.stack)
88} else {
89this.logger.log('GLTF Processing Pipeline completed.')
90}
91}
92)
93}
94
95private async getGLBAnalyzingPipeline(
96glbAssetFile: Express.Multer.File,
97processingHandler: GLBAnalyzingHandler,
98extensions: (typeof Extension)[] = []
99): Promise<boolean> {
100try {
101const glbDocument = await this.nodeIo
102.registerExtensions(extensions)
103.readBinary(glbAssetFile.buffer)
104
105return await processingHandler(glbDocument)
106} catch (err) {
107this.logger.error('GLB Processing Pipeline failed.', err.stack)
108throw new BadRequestException('Invalid GLB file')
109}
110}
111}
112