UNPKG

@xrengine/server-core

Version:

Shared components for XREngine server

188 lines (160 loc) 5.76 kB
import { Params } from '@feathersjs/feathers' import express from 'express' import multer from 'multer' import { SceneData } from '@xrengine/common/src/interfaces/SceneInterface' import { Application, ServerMode } from '../../../declarations' import { getStorageProvider } from '../../media/storageprovider/storageprovider' import { UploadParams } from '../../media/upload-asset/upload-asset.service' import { getActiveInstancesForScene } from '../../networking/instance/instance.service' import logger from '../../ServerLogger' import { getAllPortals, getEnvMapBake, getPortal } from './scene-helper' import { getSceneData, Scene } from './scene.class' import projectDocs from './scene.docs' import hooks from './scene.hooks' declare module '@xrengine/common/declarations' { interface ServiceTypes { scene: Scene 'scene/upload': { create: ReturnType<typeof uploadScene> } } interface ServiceTypes { portal: { get: ReturnType<typeof getPortal> find: ReturnType<typeof getAllPortals> } } interface ServiceTypes { 'scene-data': { get: ReturnType<typeof getScenesForProject> find: ReturnType<typeof getAllScenes> } } } export const uploadScene = (app: Application) => async (data: any, params: UploadParams) => { if (typeof data === 'string') data = JSON.parse(data) if (typeof data.sceneData === 'string') data.sceneData = JSON.parse(data.sceneData) const thumbnailBuffer = params.files.length > 0 ? params.files[0].buffer : undefined const { projectName, sceneName, sceneData, storageProviderName } = data const result = await app .service('scene') .update(projectName, { sceneName, sceneData, storageProviderName, thumbnailBuffer }) // Clear params otherwise all the files and auth details send back to client as response for (const prop of Object.getOwnPropertyNames(params)) delete params[prop] return result } export interface SceneParams extends Params { metadataOnly: boolean } type GetScenesArgsType = { projectName: string metadataOnly: boolean internal?: boolean storageProviderName?: string } export const getScenesForProject = (app: Application) => { return async function (args: GetScenesArgsType, params?: Params): Promise<{ data: SceneData[] }> { const storageProvider = getStorageProvider(args.storageProviderName) const { projectName, metadataOnly, internal } = args try { const project = await app.service('project').get(projectName, params) if (!project || !project.data) throw new Error(`No project named ${projectName} exists`) const newSceneJsonPath = `projects/${projectName}/` const fileResults = await storageProvider.listObjects(newSceneJsonPath, false) const files = fileResults.Contents.map((dirent) => dirent.Key) .filter((name) => name.endsWith('.scene.json')) .map((name) => name.slice(0, -'.scene.json'.length)) const sceneData: SceneData[] = await Promise.all( files.map(async (sceneName) => getSceneData(projectName, sceneName.replace(newSceneJsonPath, ''), metadataOnly, internal) ) ) return { data: sceneData } } catch (e) { logger.error(e) return { data: [] } } } } export const getAllScenes = (app: Application) => { return async function (params: SceneParams): Promise<{ data: SceneData[] }> { const projects = await app.service('project').find(params) const scenes = await Promise.all( projects.data.map( (project) => new Promise<SceneData[]>(async (resolve) => { const projectScenes = ( await getScenesForProject(app)( { projectName: project.name, metadataOnly: params.metadataOnly, internal: params.provider == null }, params ) ).data projectScenes.forEach((scene) => (scene.project = project.name)) resolve(projectScenes) }) ) ) return { data: scenes.flat() } } } const multipartMiddleware = multer({ limits: { fieldSize: Infinity, files: 1 } }) export default (app: Application) => { /** * Initialize our service with any options it requires and docs */ const event = new Scene(app) event.docs = projectDocs app.use('scene', event) app.use( 'scene/upload', multipartMiddleware.any(), (req: express.Request, res: express.Response, next: express.NextFunction) => { if (req?.feathers && req.method !== 'GET') { ;(req as any).feathers.files = (req as any).files.media ? (req as any).files.media : (req as any).files } next() }, { create: uploadScene(app) } ) app.use('scene-data', { get: getScenesForProject(app), find: getAllScenes(app) }) app.use('portal', { get: getPortal(app), find: getAllPortals(app) }) app.use('/cubemap/:entityId', getEnvMapBake(app)) /** * Get our initialized service so that we can register hooks */ const service = app.service('scene') service.hooks(hooks) if (app.serverMode === ServerMode.API) service.publish('updated', async (data, context) => { const instances = await getActiveInstancesForScene(app)({ query: { sceneId: data.sceneId } }) const users = ( await Promise.all( instances.map((instance) => app.service('user').Model.findAll({ where: { instanceId: instance.id } }) ) ) ).flat() const targetIds = users.map((user) => user.id) return Promise.all( targetIds.map((userId: string) => { return app.channel(`userIds/${userId}`).send({}) }) ) }) }