Skip to content

Commit

Permalink
fix: Error handling in instance mod loading
Browse files Browse the repository at this point in the history
  • Loading branch information
ci010 committed Oct 28, 2023
1 parent 9f1bbb8 commit c005197
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 8 deletions.
10 changes: 8 additions & 2 deletions xmcl-keystone-ui/src/composables/instanceMods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ export function useInstanceMods(instancePath: Ref<string>, instanceRuntime: Ref<
const enabledModCounts = computed(() => mods.value.filter(v => v.enabled).length)

watch([computed(() => state.value?.mods), java], () => {
if (!state.value?.mods) return
if (!state.value?.mods) {
mods.value = []
return
}
updateItems(state.value?.mods, instanceRuntime.value)
})
watch(instanceRuntime, () => {
if (!state.value?.mods) return
if (!state.value?.mods) {
mods.value = []
return
}
updateItems(state.value?.mods, instanceRuntime.value)
}, { deep: true })

Expand Down
2 changes: 2 additions & 0 deletions xmcl-keystone-ui/src/composables/syncableState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function useState<T extends object>(fetcher: (abortSignal: AbortSignal) =
// Avoid calling dispose multiple times
try {
isValidating.value = true
error.value = undefined
data = await fetcher(signal)
if (!data || signal.aborted) { return }
data.subscribeAll((mutation, payload) => {
Expand All @@ -28,6 +29,7 @@ export function useState<T extends object>(fetcher: (abortSignal: AbortSignal) =
} catch (e) {
if (signal.aborted) { return }
error.value = e
state.value = undefined
if (import.meta.env.DEV) console.error(e)
} finally {
isValidating.value = false
Expand Down
5 changes: 3 additions & 2 deletions xmcl-keystone-ui/src/views/HomeCardBase.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<v-card
class="flex h-full flex-col"
:color="cardColor"
:color="error ? 'red' : cardColor"
>
<v-card-title>
<v-icon left>
Expand All @@ -14,7 +14,7 @@
<v-skeleton-loader type="paragraph" />
</template>
<template v-else>
{{ text }}
{{ error ? (error.message || error) : text }}
<div
v-if="icons.length > 0"
class="mt-4"
Expand Down Expand Up @@ -61,6 +61,7 @@ defineProps<{
text: string
button: string
refreshing: boolean
error?: any
icons: Array<{ name: string; icon?: string; color?: string }>
}>()
const emit = defineEmits(['navigate'])
Expand Down
3 changes: 2 additions & 1 deletion xmcl-keystone-ui/src/views/HomeModCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:icons="icons"
:refreshing="isValidating"
:button="t('mod.manage')"
:error="error"
@navigate="push('/mods')"
/>
</template>
Expand All @@ -16,7 +17,7 @@ import HomeCardBase from './HomeCardBase.vue'
const props = defineProps<{ row: number; rowCount: number }>()
const { mods, enabledModCounts, isValidating } = injection(kInstanceModsContext)
const { mods, enabledModCounts, isValidating, error } = injection(kInstanceModsContext)
const icons = computed(() => mods.value.filter(i => i.enabled).map((m) => ({ name: m.name + ' (' + m.version + ')', icon: m.icon }))
.slice(0, props.row * props.rowCount))
const { push } = useRouter()
Expand Down
27 changes: 26 additions & 1 deletion xmcl-runtime/lib/resources/tryPersistResource.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ResourceDomain } from '@xmcl/runtime-api'
import { randomBytes } from 'crypto'
import filenamify from 'filenamify'
import { rename } from 'fs/promises'
import { rename, stat, unlink } from 'fs/promises'
import { dirname, extname, join } from 'path'
import { linkOrCopy } from '../util/fs'
import { getResourceEntry } from './getResourceEntry'
Expand Down Expand Up @@ -55,6 +55,31 @@ export async function tryPersistResource(resource: { fileName: string; domain: R
existedEntry = await context.db.selectFrom('snapshots').where('domainedPath', '=', `${resource.domain}/${fileName}`).selectAll().executeTakeFirst()
}

const fstat = await stat(filePath).catch(e => undefined)

if (fstat) {
// existed but not in database
// this is a broken resource
const localEntry = await getResourceEntry(filePath, context, true)
if (localEntry.sha1 === resource.hash) {
// The file is already imported...
// Recover db
await context.db.insertInto('snapshots').values({
domainedPath: entryName,
fileType: localEntry.fileType,
sha1: localEntry.sha1,
size: localEntry.size,
mtime: localEntry.mtime,
ctime: localEntry.ctime,
ino: localEntry.ino,
}).execute().catch(() => undefined)
return filePath
} else {
// Remove the file
await unlink(filePath)
}
}

if (dirname(resource.path) === dirname(filePath)) {
// Just rename if they are in same dir
await rename(resource.path, filePath)
Expand Down
7 changes: 5 additions & 2 deletions xmcl-runtime/lib/services/ResourceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,12 @@ export class ResourceService extends AbstractService implements IResourceService
this.log(`Persist new resource ${resource.path} -> ${storedPath}`)

return resource
}))
}).map(r => r.catch(e => {
this.error(e)
return undefined
})))

return result
return result.filter(r => r) as Resource[]
}

async exportResources({ resources, targetDirectory }: ExportResourceOptions) {
Expand Down

0 comments on commit c005197

Please sign in to comment.