@xrengine/server-core
Version:
Shared components for XREngine server
72 lines (65 loc) • 3.09 kB
text/typescript
import appRootPath from 'app-root-path'
import { spawn } from 'child_process'
import fs from 'fs'
import path from 'path'
import { getStorageProvider } from '../../media/storageprovider/storageprovider'
import { getFileKeysRecursive } from '../../media/storageprovider/storageProviderUtils'
import logger from '../../ServerLogger'
import { deleteFolderRecursive, writeFileSyncRecursive } from '../../util/fsHelperFunctions'
/**
* Downloads a specific project to the local file system from the storage provider cache
* Then runs `npm install --legacy-peer-deps` inside the project to install it's dependencies
* @param projectName
* @param storageProviderName
* @returns {Promise<boolean>}
*/
export const download = async (projectName: string, storageProviderName?: string) => {
const storageProvider = getStorageProvider(storageProviderName)
try {
logger.info(`[ProjectLoader]: Installing project "${projectName}"...`)
let files = await getFileKeysRecursive(`projects/${projectName}/`)
const assetsRegex = new RegExp(`^projects/${projectName}/assets`)
files = files.filter((file) => !assetsRegex.test(file))
logger.info('[ProjectLoader]: Found files:' + files)
const localProjectDirectory = path.join(appRootPath.path, 'packages/projects/projects', projectName)
if (fs.existsSync(localProjectDirectory)) {
logger.info('[Project temp debug]: fs exists, deleting')
deleteFolderRecursive(localProjectDirectory)
}
await Promise.all(
files.map(async (filePath) => {
logger.info(`[ProjectLoader]: - downloading "${filePath}"`)
const fileResult = await storageProvider.getObject(filePath)
if (fileResult.Body.length === 0) logger.info(`[ProjectLoader]: WARNING file "${filePath}" is empty`)
writeFileSyncRecursive(path.join(appRootPath.path, 'packages/projects', filePath), fileResult.Body)
})
)
logger.info(`[ProjectLoader]: Successfully downloaded and mounted project "${projectName}".`)
if (projectName !== 'default-project') {
const npmInstallPromise = new Promise<void>((resolve) => {
const npmInstallProcess = spawn('npm', ['install', '--legacy-peer-deps'], { cwd: localProjectDirectory })
npmInstallProcess.once('exit', () => {
logger.info('Finished npm installing %s', projectName)
resolve()
})
npmInstallProcess.once('error', resolve)
npmInstallProcess.once('disconnect', resolve)
npmInstallProcess.stdout.on('data', (data) => logger.info(data.toString()))
}).then((result) => logger.info(result))
await Promise.race([
npmInstallPromise,
new Promise<void>((resolve) => {
setTimeout(() => {
logger.warn(`WARNING: npm installing ${projectName} took too long!`)
resolve()
}, 5 * 60 * 1000) // timeout after 5 minutes
})
])
}
} catch (e) {
const errorMsg = `[ProjectLoader]: Failed to download project ${projectName} with error: ${e.message}`
logger.error(e, errorMsg)
throw e
}
return true
}