Skip to content

Commit

Permalink
v2.2.5 (#658)
Browse files Browse the repository at this point in the history
## Features:
- Infer file path for imported sound files correctly (bridge-core/editor-packages#29)
- Ability to refresh folder within the  (#659)

## Changes:
- Added "1.19.50" format version (ea61a76)
- Optimized directory copying (#650)

## Fixes:
- Fixed wrong file extension being appended upon exporting project on Android (#655)
- Fixed wrong icon color for ImageTab (#657)
- Removed rounded window corners on mobile (#652)
- Fixed project exports (#661)

Co-authored-by: Joelant05 <[email protected]>
  • Loading branch information
solvedDev and Joelant05 authored Oct 16, 2022
2 parents 8d2f79b + 2ab4b1c commit 61e9932
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bridge",
"version": "2.3.4",
"version": "2.3.5",
"private": true,
"scripts": {
"dev": "vite",
Expand Down
Binary file modified public/packages.zip
Binary file not shown.
38 changes: 38 additions & 0 deletions src/components/Common/GlobalMutex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Mutex } from './Mutex'

/**
* A global mutex manages multiple different, keyed mutexes.
*/
export class GlobalMutex {
protected mutexMap = new Map<string, Mutex>()

/**
* Lock the mutex with the given key. Creates the mutex if it does not exist.
*
* @param key Mutex to lock
*/
async lock(key: string) {
let mutex = this.mutexMap.get(key)
if (!mutex) {
mutex = new Mutex()
this.mutexMap.set(key, mutex)
}

await mutex.lock()
}

/**
* Unlock the mutex with the given key.
*
* @throws If the mutex does not exist.
* @param key
*/
unlock(key: string) {
const mutex = this.mutexMap.get(key)
if (!mutex) {
throw new Error('Trying to unlock a mutex that does not exist')
}

mutex.unlock()
}
}
10 changes: 10 additions & 0 deletions src/components/Common/Mutex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ export class Mutex {

constructor() {}

/**
* Lock the mutex. If it is already locked, the function will wait until it is unlocked.
*
* @returns When the mutex is unlocked
*/
lock() {
return new Promise<void>(async (resolve, reject) => {
if (this.isLocked) {
Expand All @@ -21,6 +26,11 @@ export class Mutex {
})
}

/**
* Unlock the mutex.
*
* @throws If the mutex is not locked.
*/
unlock() {
if (!this.isLocked) {
throw new Error('Trying to unlock a mutex that is not locked')
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editors/Image/ImageTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class ImageTab extends FileTab {
return 'mdi-file-image-outline'
}
get iconColor() {
return 'primary'
return 'resourcePack'
}

_save() {}
Expand Down
6 changes: 3 additions & 3 deletions src/components/FileSystem/FileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Signal } from '../Common/Event/Signal'
import json5 from 'json5'
import type { IGetHandleConfig, IMkdirConfig } from './Common'
import { iterateDir } from '/@/utils/iterateDir'
import { iterateDirParallel } from '/@/utils/iterateDir'
import { join, dirname, basename } from '/@/utils/path'
import { AnyDirectoryHandle, AnyFileHandle, AnyHandle } from './Types'
import { getStorageDirectory } from '/@/utils/getStorageDirectory'
Expand Down Expand Up @@ -269,7 +269,7 @@ export class FileSystem extends Signal<void> {
create: false,
})

await iterateDir(originHandle, async (fileHandle, filePath) => {
await iterateDirParallel(originHandle, async (fileHandle, filePath) => {
await this.copyFileHandle(
fileHandle,
await this.getFileHandle(join(destPath, filePath), true)
Expand All @@ -282,7 +282,7 @@ export class FileSystem extends Signal<void> {
) {
const destFs = new FileSystem(destHandle)

await iterateDir(originHandle, async (fileHandle, filePath) => {
await iterateDirParallel(originHandle, async (fileHandle, filePath) => {
await this.copyFileHandle(
fileHandle,
await destFs.getFileHandle(filePath, true)
Expand Down
74 changes: 59 additions & 15 deletions src/components/FileSystem/Virtual/DirectoryHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { VirtualHandle, BaseVirtualHandle } from './Handle'
import { VirtualFileHandle } from './FileHandle'
import { ISerializedDirectoryHandle } from './Comlink'
import { IDBWrapper } from './IDB'
import { GlobalMutex } from '/@/components/Common/GlobalMutex'

const globalMutex = new GlobalMutex()

/**
* A class that implements a virtual folder
Expand Down Expand Up @@ -67,8 +70,21 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {

this.updateIdb(clearDB)
}
/**
* Acquire exclusive access to this directory
*/
async lockAccess() {
await globalMutex.lock(this.idbKey)
}
/**
* Release exclusive access to this directory
*/
unlockAccess() {
globalMutex.unlock(this.idbKey)
}

async updateIdb(clearDB = false) {
await this.lockAccess()
if (clearDB) {
await this.idbWrapper.clear()
}
Expand All @@ -77,18 +93,14 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
await this.idbWrapper.set(this.idbKey, [])

this.setupDone.dispatch()
this.unlockAccess()
}

protected async addChild(child: VirtualHandle) {
if (await this.has(child.name)) {
return
}

if (this.children) this.children.set(child.name, child)
else
await this.idbWrapper.set(this.idbKey, [
...(await this.fromIdb()),
child.name,
...new Set([...(await this.fromIdb()), child.name]),
])
}
protected async fromIdb() {
Expand All @@ -99,11 +111,13 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
if (this.children) return [...this.children.values()]
else
return <VirtualHandle[]>(
await Promise.all(
(await this.fromIdb())
.map((name) => this.getChild(name))
.filter((child) => child !== undefined)
)
(
await Promise.all(
(
await this.fromIdb()
).map((name) => this.getChild(name))
)
).filter((child) => child !== undefined)
)
}
protected getChildPath(childName: string) {
Expand All @@ -125,13 +139,23 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
}
}

async deleteChild(childName: string) {
/**
* @deprecated THIS IS NOT A PUBLIC API
*
* @param childName
* @param lockMutex
*/
async deleteChild(childName: string, lockMutex = true) {
if (lockMutex) await this.lockAccess()

if (this.children) this.children.delete(childName)
else
await this.idbWrapper.set(
this.idbKey,
(await this.fromIdb()).filter((name) => name !== childName)
)

if (lockMutex) this.unlockAccess()
}

protected async hasChildren() {
Expand Down Expand Up @@ -183,9 +207,12 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
name: string,
{ create }: { create?: boolean } = {}
) {
await this.lockAccess()

let entry = await this.getChild(name)

if (entry && entry.kind === 'file') {
this.unlockAccess()
throw new Error(
`TypeMismatch: Expected directory with name "${name}", found file`
)
Expand All @@ -200,12 +227,15 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {

await this.addChild(entry)
} else {
this.unlockAccess()
throw new Error(
`No file with the name ${name} exists in this folder`
)
}
}

this.unlockAccess()

return <VirtualDirectoryHandle>entry
}
async getFileHandle(
Expand All @@ -215,9 +245,11 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
initialData,
}: { create?: boolean; initialData?: Uint8Array } = {}
) {
await this.lockAccess()
let entry = await this.getChild(name)

if (entry && entry.kind === 'directory') {
this.unlockAccess()
throw new Error(
`TypeMismatch: Expected file with name "${name}", found directory`
)
Expand All @@ -232,21 +264,27 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {

await this.addChild(entry)
} else {
this.unlockAccess()
throw new Error(
`No file with the name ${name} exists in this folder`
)
}
}

this.unlockAccess()

return <VirtualFileHandle>entry
}
async removeEntry(
name: string,
{ recursive }: { recursive?: boolean } = {}
) {
await this.lockAccess()

const entry = await this.getChild(name)

if (!entry) {
this.unlockAccess()
throw new Error(
`No entry with the name ${name} exists in this folder`
)
Expand All @@ -255,14 +293,16 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
!recursive &&
(await (<VirtualDirectoryHandle>entry).hasChildren())
) {
this.unlockAccess()
throw new Error(
`Cannot remove directory with children without "recursive" option being set to true`
)
}

await entry.removeSelf()
await entry.removeSelf(true, false)

await this.deleteChild(name)
await this.deleteChild(name, false)
this.unlockAccess()
}
async resolve(possibleDescendant: VirtualHandle) {
const path: string[] = [possibleDescendant.name]
Expand All @@ -276,7 +316,9 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {
if (current === null) return null
return path
}
async removeSelf(isFirst = true) {
async removeSelf(isFirst = true, lockMutex = true) {
if (lockMutex) await this.lockAccess()

const children = await this.getChildren()

for (const child of children) {
Expand All @@ -285,6 +327,8 @@ export class VirtualDirectoryHandle extends BaseVirtualHandle {

if (!this.children) await this.idbWrapper.del(this.idbKey)
if (this.parent && isFirst) this.parent.deleteChild(this.name)

if (lockMutex) this.unlockAccess()
}

[Symbol.asyncIterator]() {
Expand Down
1 change: 1 addition & 0 deletions src/components/FileSystem/Virtual/FileHandle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export class VirtualFileHandle extends BaseVirtualHandle {
const fileData = await this.loadFromIdb()
// console.log(this.path.join('/'), this.fileData, fileData)

// TODO: Support lastModified timestamp so lightning cache can make use of its optimizations
return new File([fileData], this.name)
}
async createWritable() {
Expand Down
22 changes: 20 additions & 2 deletions src/components/FileSystem/saveOrDownload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { InformationWindow } from '../Windows/Common/Information/InformationWind
import { FileSystem } from './FileSystem'
import { isUsingFileSystemPolyfill, isUsingOriginPrivateFs } from './Polyfill'
import { App } from '/@/App'
import { basename } from '/@/utils/path'
import { basename, extname } from '/@/utils/path'

export async function saveOrDownload(
filePath: string,
Expand Down Expand Up @@ -43,8 +43,26 @@ export async function saveOrDownload(
}
}

const knownExtensions = new Set([
'.mcpack',
'.mcaddon',
'.mcworld',
'.mctemplate',
'.brproject',

'.mcfunction',
'.lang',
'.material',
])

export function download(fileName: string, fileData: Uint8Array) {
const url = URL.createObjectURL(new Blob([fileData]))
const extension = extname(fileName)
let type: string | undefined = undefined

// Maintain the extension from the fileName, if the file that is being downloaded has a known extension
if (knownExtensions.has(extension)) type = 'application/file-export'

const url = URL.createObjectURL(new Blob([fileData], { type }))
const a = document.createElement('a')
a.download = fileName
a.href = url
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { DirectoryWrapper } from '/@/components/UIElements/DirectoryViewer/DirectoryView/DirectoryWrapper'

export const RefreshAction = (directoryWrapper: DirectoryWrapper) => ({
icon: 'mdi-refresh',
name: 'general.refresh',

onTrigger: () => {
directoryWrapper.refresh()
},
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EditAction } from './Actions/Edit'
import { CopyAction } from './Actions/Edit/Copy'
import { FindInFolderAction } from './Actions/FindInFolder'
import { ImportFileAction } from './Actions/ImportFile'
import { RefreshAction } from './Actions/Refresh'
import { RevealFilePathAction } from './Actions/RevealPath'
import { App } from '/@/App'
import { showContextMenu } from '/@/components/ContextMenu/showContextMenu'
Expand Down Expand Up @@ -98,6 +99,7 @@ export async function showFolderContextMenu(
]
: mutatingActions),
{ type: 'divider' },
RefreshAction(directoryWrapper),
DownloadAction(directoryWrapper),
RevealFilePathAction(directoryWrapper),
// {
Expand Down
Loading

0 comments on commit 61e9932

Please sign in to comment.