UNPKG

@xrengine/server-core

Version:

Shared components for XREngine server

147 lines (127 loc) 5.05 kB
import fs from 'fs' import path from 'path' import { CommonKnownContentTypes } from '@xrengine/common/src/utils/CommonKnownContentTypes' import { Application } from '../../../declarations' import { addGenericAssetToS3AndStaticResources } from '../../media/upload-asset/upload-asset.service' import { getProjectPackageJson } from '../../projects/project/project-helper' import logger from '../../ServerLogger' import { UserParams } from '../user/user.class' export type AvatarCreateArguments = { modelResourceId?: string thumbnailResourceId?: string identifierName?: string name: string isPublic?: boolean project?: string } export type AvatarPatchArguments = { modelResourceId?: string thumbnailResourceId?: string identifierName?: string name?: string } export type AvatarUploadArguments = { avatar: Buffer thumbnail: Buffer avatarName: string isPublic: boolean avatarFileType?: string avatarId?: string project?: string } // todo: move this somewhere else const supportedAvatars = ['glb', 'gltf', 'vrm', 'fbx'] const PROJECT_NAME_REGEX = /projects\/([a-zA-Z0-9-_.]+)\/public\/avatars$/ export const installAvatarsFromProject = async (app: Application, avatarsFolder: string) => { const avatarsToInstall = fs .readdirSync(avatarsFolder, { withFileTypes: true }) .filter((dirent) => supportedAvatars.includes(dirent.name.split('.').pop()!)) .map((dirent) => { const avatarName = dirent.name.substring(0, dirent.name.lastIndexOf('.')) // remove extension const avatarFileType = dirent.name.substring(dirent.name.lastIndexOf('.') + 1, dirent.name.length) // just extension const pngPath = path.join(avatarsFolder, avatarName + '.png') const thumbnail = fs.existsSync(pngPath) ? fs.readFileSync(pngPath) : Buffer.from([]) return { avatar: fs.readFileSync(path.join(avatarsFolder, dirent.name)), thumbnail, avatarName, avatarFileType, isPublic: true } as AvatarUploadArguments }) const promises: Promise<any>[] = [] const projectNameExec = PROJECT_NAME_REGEX.exec(avatarsFolder) let projectJSON if (projectNameExec) projectJSON = getProjectPackageJson(projectNameExec[1]) let projectName if (projectJSON) projectName = projectJSON.name for (const avatar of avatarsToInstall) { promises.push( new Promise(async (resolve, reject) => { try { const existingAvatar = await app.service('avatar').Model.findOne({ where: { name: avatar.avatarName, isPublic: avatar.isPublic, project: projectName || null } }) let selectedAvatar if (!existingAvatar) { selectedAvatar = await app.service('avatar').create({ name: avatar.avatarName, isPublic: avatar.isPublic, project: projectName || null }) } else selectedAvatar = existingAvatar avatar.avatarName = selectedAvatar.identifierName avatar.project = projectName || null const [modelResource, thumbnailResource] = await uploadAvatarStaticResource(app, avatar) await app.service('avatar').patch(selectedAvatar.id, { modelResourceId: modelResource.id, thumbnailResourceId: thumbnailResource.id }) resolve(null) } catch (err) { logger.error(err) reject(err) } }) ) } await Promise.all(promises) } export const uploadAvatarStaticResource = async ( app: Application, data: AvatarUploadArguments, params?: UserParams ) => { const name = data.avatarName ? data.avatarName : 'Avatar-' + Math.round(Math.random() * 100000) const key = `avatars/${data.isPublic ? 'public' : params?.user!.id}/${name}` // const thumbnail = await generateAvatarThumbnail(data.avatar as Buffer) // if (!thumbnail) throw new Error('Thumbnail generation failed - check the model') const modelPromise = addGenericAssetToS3AndStaticResources(app, data.avatar, CommonKnownContentTypes.glb, { userId: params?.user!.id, key: `${key}.${data.avatarFileType ?? 'glb'}`, staticResourceType: 'avatar', project: data.project }) const thumbnailPromise = addGenericAssetToS3AndStaticResources(app, data.thumbnail, CommonKnownContentTypes.png, { userId: params?.user!.id, key: `${key}.${data.avatarFileType ?? 'glb'}.png`, staticResourceType: 'user-thumbnail', project: data.project }) const [modelResource, thumbnailResource] = await Promise.all([modelPromise, thumbnailPromise]) logger.info('Successfully uploaded avatar %o %o', modelResource, thumbnailResource) if (data.avatarId) { try { await app.service('avatar').patch(data.avatarId, { modelResourceId: modelResource.id, thumbnailResourceId: thumbnailResource.id }) } catch (err) {} } return [modelResource, thumbnailResource] } export const removeAvatarFromDatabase = async (app: Application, name: string) => {}