Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.

Commit 0f72f9c

Browse files
committed
Simplify Static Resources (#9061)
* simplify static resource parsing of scenes and uploads * add download button in file browser input * fix
1 parent 718eaa0 commit 0f72f9c

File tree

11 files changed

+70
-386
lines changed

11 files changed

+70
-386
lines changed

.env.local.default

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ LOCAL_STORAGE_PROVIDER_PORT=8642
9393
GOOGLE_ANALYTICS_TRACKING_ID=
9494
HUB_ENDPOINT=https://etherealengine.io
9595
INSTANCESERVER_UNREACHABLE_TIMEOUT_SECONDS=10
96-
CLONE_STATIC_RESOURCES=false
9796

9897

9998
MATCHMAKER_EMULATION_MODE=true

packages/editor/src/components/inputs/ArrayInputGroup.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
2323
Ethereal Engine. All Rights Reserved.
2424
*/
2525

26+
import Icon from '@etherealengine/ui/src/primitives/mui/Icon'
2627
import AddIcon from '@mui/icons-material/Add'
27-
import DeleteIcon from '@mui/icons-material/Delete'
2828
import IconButton from '@mui/material/IconButton'
2929
import React from 'react'
3030
import styles from './ArrayInputGroup.module.scss'
@@ -105,7 +105,7 @@ const ArrayInputGroup = ({
105105
padding: 0
106106
}}
107107
>
108-
<AddIcon sx={{ color: 'primary.contrastText' }} />
108+
<AddIcon sx={{ color: 'var(--textColor)' }} />
109109
</IconButton>
110110
</InputGroup>
111111
{values &&
@@ -125,7 +125,7 @@ const ArrayInputGroup = ({
125125
}}
126126
onClick={() => deleteInput(index + 1)}
127127
>
128-
<DeleteIcon sx={{ color: 'primary.contrastText' }} />
128+
<Icon type="Delete" style={{ color: 'var(--textColor)' }} />
129129
</IconButton>
130130
</InputGroup>
131131
))}

packages/editor/src/components/inputs/FileBrowserInput.tsx

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
2323
Ethereal Engine. All Rights Reserved.
2424
*/
2525

26+
import IconButton from '@mui/material/IconButton'
2627
import React from 'react'
2728
import { useDrop } from 'react-dnd'
2829

30+
import config from '@etherealengine/common/src/config'
31+
import Icon from '@etherealengine/ui/src/primitives/mui/Icon'
2932
import { ItemTypes } from '../../constants/AssetTypes'
3033
import useUpload from '../assets/useUpload'
3134
import { ControlledStringInput, StringInputProps } from './StringInput'
@@ -54,6 +57,32 @@ export function FileBrowserInput({
5457
}
5558
const onUpload = useUpload(uploadOptions)
5659

60+
// todo fix for invalid URLs
61+
const assetIsExternal = value && !value?.includes(config.client.fileServer)
62+
const uploadExternalAsset = () => {
63+
onUpload([
64+
{
65+
isFile: true,
66+
name: value?.split('/').pop(),
67+
file: async (onSuccess, onFail) => {
68+
try {
69+
const asset = await fetch(value!)
70+
const blob = await asset.blob()
71+
const file = new File([blob], value!.split('/').pop()!)
72+
onSuccess(file)
73+
} catch (error) {
74+
if (onFail) onFail(error)
75+
else throw error
76+
}
77+
}
78+
} as Partial<FileSystemFileEntry>
79+
] as any).then((assets) => {
80+
if (assets) {
81+
onChange?.(assets[0])
82+
}
83+
})
84+
}
85+
5786
const [{ canDrop, isOver }, dropRef] = useDrop({
5887
accept: [...acceptDropItems, ItemTypes.File],
5988
async drop(item: any, monitor) {
@@ -73,9 +102,7 @@ export function FileBrowserInput({
73102

74103
onUpload(entries).then((assets) => {
75104
if (assets) {
76-
for (let index = 0; index < assets.length; index++) {
77-
onChange?.(assets[index])
78-
}
105+
onChange?.(assets[0])
79106
}
80107
})
81108
}
@@ -96,6 +123,17 @@ export function FileBrowserInput({
96123
canDrop={isOver && canDrop}
97124
{...rest}
98125
/>
126+
{assetIsExternal && (
127+
<IconButton
128+
disableRipple
129+
style={{
130+
padding: 0
131+
}}
132+
onClick={uploadExternalAsset}
133+
>
134+
<Icon type="Download" style={{ color: 'var(--textColor)' }} />
135+
</IconButton>
136+
)}
99137
</>
100138
)
101139
}

packages/server-core/src/appconfig.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,6 @@ const server = {
145145
corsServerPort: process.env.CORS_SERVER_PORT!,
146146
storageProvider: process.env.STORAGE_PROVIDER!,
147147
storageProviderExternalEndpoint: process.env.STORAGE_PROVIDER_EXTERNAL_ENDPOINT!,
148-
cloneProjectStaticResources:
149-
typeof process.env.CLONE_STATIC_RESOURCES === 'undefined' ? true : process.env.CLONE_STATIC_RESOURCES === 'true',
150148
gaTrackingId: process.env.GOOGLE_ANALYTICS_TRACKING_ID!,
151149
hub: {
152150
endpoint: process.env.HUB_ENDPOINT!

packages/server-core/src/media/static-resource/static-resource-helper.test.ts

Lines changed: 1 addition & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,10 @@ Ethereal Engine. All Rights Reserved.
2525

2626
import appRootPath from 'app-root-path'
2727
import assert from 'assert'
28-
import fs from 'fs'
2928
import path from 'path'
3029

31-
import { destroyEngine } from '@etherealengine/engine/src/ecs/classes/Engine'
32-
33-
import { StaticResourceType, staticResourcePath } from '@etherealengine/engine/src/schemas/media/static-resource.schema'
34-
import { Paginated } from '@feathersjs/feathers'
35-
import { Application } from '../../../declarations'
3630
import { mockFetch, restoreFetch } from '../../../tests/util/mockFetch'
37-
import { createFeathersKoaApp } from '../../createApp'
38-
import { getCachedURL } from '../storageprovider/getCachedURL'
39-
import { getStorageProvider } from '../storageprovider/storageprovider'
40-
import { addAssetFromProject, downloadResourceAndMetadata } from './static-resource-helper'
31+
import { downloadResourceAndMetadata } from './static-resource-helper'
4132

4233
describe('static-resource-helper', () => {
4334
before(() => {
@@ -91,201 +82,3 @@ describe('static-resource-helper', () => {
9182
})
9283
})
9384
})
94-
95-
const testProject = 'test-project'
96-
97-
describe('audio-upload', () => {
98-
let app: Application
99-
100-
before(async () => {
101-
app = createFeathersKoaApp()
102-
await app.setup()
103-
const url = 'https://test.com/projects/default-project/assets/test.mp3'
104-
const url2 = getCachedURL('/projects/default-project/assets/test.mp3', getStorageProvider().cacheDomain)
105-
mockFetch({
106-
[url]: {
107-
contentType: 'audio/mpeg',
108-
response: fs.readFileSync(
109-
path.join(appRootPath.path, '/packages/projects/default-project/assets/SampleAudio.mp3')
110-
)
111-
},
112-
[url2]: {
113-
contentType: 'audio/mpeg',
114-
response: fs.readFileSync(
115-
path.join(appRootPath.path, '/packages/projects/default-project/assets/SampleAudio.mp3')
116-
)
117-
}
118-
})
119-
})
120-
121-
afterEach(async () => {
122-
const storageProvider = getStorageProvider()
123-
if (await storageProvider.doesExist('test.mp3', 'static-resources/test-project/'))
124-
await storageProvider.deleteResources(['static-resources/test-project/test.mp3'])
125-
126-
const existingResource = (await app.service(staticResourcePath).find({
127-
query: {
128-
mimeType: 'audio/mpeg'
129-
},
130-
paginate: false
131-
})) as StaticResourceType[]
132-
await Promise.all(existingResource.map((resource) => app.service(staticResourcePath).remove(resource.id)))
133-
})
134-
135-
after(() => {
136-
restoreFetch()
137-
return destroyEngine()
138-
})
139-
140-
describe('addAssetFromProject', () => {
141-
it('should download audio asset as a new static resource from external url when forced to download', async () => {
142-
const storageProvider = getStorageProvider()
143-
const url = 'https://test.com/projects/default-project/assets/test.mp3'
144-
145-
const staticResource = await addAssetFromProject(app, url, testProject, true)
146-
147-
assert(staticResource.id)
148-
assert.equal(staticResource.url, getCachedURL(staticResource.key!, storageProvider.cacheDomain))
149-
assert.equal(staticResource.key, 'static-resources/test-project/test.mp3')
150-
assert.equal(staticResource.mimeType, 'audio/mpeg')
151-
assert.equal(staticResource.project, testProject)
152-
153-
assert(await storageProvider.doesExist('test.mp3', 'static-resources/test-project/'))
154-
155-
const file = await storageProvider.getObject(staticResource.key!)
156-
assert.equal(file.ContentType, 'audio/mpeg')
157-
})
158-
159-
it('should link audio asset as a new static resource from external url when not forced to download', async () => {
160-
const storageProvider = getStorageProvider()
161-
const url = 'https://test.com/projects/default-project/assets/test.mp3'
162-
163-
const staticResource = await addAssetFromProject(app, url, testProject, false)
164-
165-
assert(staticResource.id)
166-
assert.equal(staticResource.url, 'https://test.com/projects/default-project/assets/test.mp3')
167-
assert.equal(staticResource.key, 'https://test.com/projects/default-project/assets/test.mp3')
168-
assert.equal(staticResource.mimeType, 'audio/mpeg')
169-
assert.equal(staticResource.project, testProject)
170-
171-
const fileExists = await storageProvider.doesExist('test.mp3', 'static-resources/test-project/')
172-
assert(!fileExists)
173-
})
174-
175-
it('should download audio asset as a new static resource from another project', async () => {
176-
const storageProvider = getStorageProvider()
177-
const url = getCachedURL('/projects/default-project/assets/test.mp3', storageProvider.cacheDomain)
178-
179-
const staticResource = await addAssetFromProject(app, url, testProject, true)
180-
181-
assert.equal(staticResource.key, 'static-resources/test-project/test.mp3')
182-
assert.equal(staticResource.url, getCachedURL(staticResource.key!, storageProvider.cacheDomain))
183-
assert.equal(staticResource.mimeType, 'audio/mpeg')
184-
assert.equal(staticResource.project, testProject)
185-
186-
assert(await storageProvider.doesExist('test.mp3', 'static-resources/test-project/'))
187-
188-
const file = await storageProvider.getObject(staticResource.key!)
189-
assert.equal(file.ContentType, 'audio/mpeg')
190-
})
191-
192-
it('should link audio asset as a new static resource from another project', async () => {
193-
const storageProvider = getStorageProvider()
194-
const url = getCachedURL('/projects/default-project/assets/test.mp3', storageProvider.cacheDomain)
195-
196-
const staticResource = await addAssetFromProject(app, url, testProject, false)
197-
198-
assert.equal(staticResource.key, url)
199-
assert.equal(staticResource.url, url)
200-
assert.equal(staticResource.mimeType, 'audio/mpeg')
201-
assert.equal(staticResource.project, testProject)
202-
203-
// should not exist under static resources
204-
const fileExists = await storageProvider.doesExist('test.mp3', 'static-resources/test-project/')
205-
assert(!fileExists)
206-
})
207-
208-
it('should link audio asset as a new static resource from url if from the same project', async () => {
209-
const storageProvider = getStorageProvider()
210-
const url = getCachedURL('/projects/default-project/assets/test.mp3', storageProvider.cacheDomain)
211-
212-
const staticResource = await addAssetFromProject(app, url, 'default-project', false)
213-
214-
assert.equal(staticResource.key, 'projects/default-project/assets/test.mp3')
215-
assert.equal(staticResource.url, url)
216-
assert.equal(staticResource.mimeType, 'audio/mpeg')
217-
assert.equal(staticResource.project, 'default-project')
218-
219-
// should not exist under static resources
220-
const fileExists = await storageProvider.doesExist('test.mp3', 'static-resources/test-project/')
221-
assert(!fileExists)
222-
})
223-
224-
it('should return existing static resource with the same hash and project', async () => {
225-
const storageProvider = getStorageProvider()
226-
const url = getCachedURL('/projects/default-project/assets/test.mp3', storageProvider.cacheDomain)
227-
228-
const response = await addAssetFromProject(app, url, 'default-project', false)
229-
const response2 = await addAssetFromProject(app, url, 'default-project', false)
230-
231-
const staticResources = (await app.service(staticResourcePath).find({
232-
query: {
233-
url
234-
}
235-
})) as Paginated<StaticResourceType>
236-
237-
assert.equal(staticResources.data.length, 1)
238-
assert.equal(response.id, response2.id)
239-
assert.equal(response.url, response2.url)
240-
assert.equal(response.key, response2.key)
241-
})
242-
243-
it('should return new static resource with the same hash exists in another project when forcing download', async () => {
244-
const storageProvider = getStorageProvider()
245-
const url = getCachedURL('/projects/default-project/assets/test.mp3', storageProvider.cacheDomain)
246-
247-
const response = await addAssetFromProject(app, url, 'default-project', true)
248-
const response2 = await addAssetFromProject(app, url, 'test-project', true)
249-
250-
const staticResources = (await app.service(staticResourcePath).find({
251-
query: {
252-
url: response.url
253-
}
254-
})) as Paginated<StaticResourceType>
255-
assert.equal(staticResources.data.length, 1)
256-
257-
const staticResources2 = (await app.service(staticResourcePath).find({
258-
query: {
259-
url: response2.url
260-
}
261-
})) as Paginated<StaticResourceType>
262-
assert.equal(staticResources2.data.length, 1)
263-
264-
assert.notEqual(response.id, response2.id)
265-
assert.notEqual(response.url, response2.url)
266-
assert.notEqual(response.key, response2.key)
267-
assert.equal(response.hash, response2.hash)
268-
})
269-
270-
it('should different static resource with the same url and hash if it exists in another project when not forcing download', async () => {
271-
const storageProvider = getStorageProvider()
272-
const url = getCachedURL('/projects/default-project/assets/test.mp3', storageProvider.cacheDomain)
273-
274-
const response = await addAssetFromProject(app, url, 'default-project', false)
275-
const response2 = await addAssetFromProject(app, url, 'test-project', false)
276-
277-
const staticResources = (await app.service(staticResourcePath).find({
278-
query: {
279-
url: response.url
280-
}
281-
})) as Paginated<StaticResourceType>
282-
assert.equal(staticResources.data.length, 2)
283-
284-
assert(response.id !== response2.id)
285-
assert.equal(response.url, response2.url)
286-
// key is different as it is a different project
287-
assert.notEqual(response.key, response2.key)
288-
assert.equal(response.hash, response2.hash)
289-
})
290-
})
291-
})

0 commit comments

Comments
 (0)