Skip to content

Commit

Permalink
fix: Curseforge modpack installation resolved some duplicated files
Browse files Browse the repository at this point in the history
  • Loading branch information
ci010 committed May 7, 2023
1 parent 652211b commit 97fc26e
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 26 deletions.
2 changes: 1 addition & 1 deletion xmcl
2 changes: 1 addition & 1 deletion xmcl-keystone-ui/src/views/HomeCardBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
v-if="a.icon"
:src="a.icon"
>
<span v-else> {{ a.name[0].toUpperCase() }} </span>
<span v-else> {{ a.name[0]?.toUpperCase() }} </span>
</v-avatar>
</div>
</template>
Expand Down
1 change: 0 additions & 1 deletion xmcl-keystone-ui/src/windows/app/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
</div>
<AppContextMenu />
<AppNotifier />
<AppTaskDialog />
<ImageDialog />
<SharedTooltip />
</v-app>
Expand Down
1 change: 1 addition & 0 deletions xmcl-runtime/lib/engineBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Represent a long lived connection between the main process (server) and renderer process (client)
*/
export interface Client {
isDestroyed(): boolean
/**
* Send the message to the client in a specific channel
*/
Expand Down
6 changes: 5 additions & 1 deletion xmcl-runtime/lib/managers/NetworkManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ export default class NetworkManager extends Manager {
this.downloadAgent = resolveAgent({
rangePolicy: new DefaultRangePolicy(4 * 1024 * 1024, 4),
dispatcher: downloadDispatcher,
// checkpointHandler: createInMemoryCheckpointHandler(),
checkpointHandler: {
lookup: async (url) => { return undefined },
put: async (url, checkpoint) => { },
delete: async (url) => { },
},
})

this.apiClientFactories = apiClientFactories
Expand Down
8 changes: 7 additions & 1 deletion xmcl-runtime/lib/managers/TaskManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@ export default class TaskManager extends Manager {
this.pushers.get(event.sender)!()
}
const pusher = createTaskPusher(this.logger, this.emitter, 500, 30, (payload) => {
event.sender.send('task-update', payload)
if (event.sender.isDestroyed()) {
pusher()
this.pushers.delete(event.sender)
} else {
event.sender.send('task-update', payload)
}
})
this.pushers.set(event.sender, pusher)
return Object.entries(this.record).map(([uuid, task]) => mapTaskToTaskPayload(uuid, task))
})
app.controller.handle('task-unsubscribe', (event) => {
const pusher = this.pushers.get(event.sender)
if (pusher) { pusher() }
this.pushers.delete(event.sender)
})
app.controller.handle('task-operation', (event, { type, id }) => {
if (!this.record[id]) {
Expand Down
33 changes: 17 additions & 16 deletions xmcl-runtime/lib/services/InstanceInstallService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export class ResolveInstanceFileTask extends AbortableTask<void> {
for (const r of result) {
const p = curseforgeProjects.find(p => p.curseforge.fileId === r.id)!
if (!p.downloads) { p.downloads = [] }
p.downloads.push(...(r.downloadUrl ? [r.downloadUrl] : guessCurseforgeFileUrl(r.id, r.fileName)))
const url = r.downloadUrl ? [r.downloadUrl] : guessCurseforgeFileUrl(r.id, r.fileName)
p.downloads = [...new Set<string>([...url, ...p.downloads])]
}
}

Expand All @@ -77,7 +78,9 @@ export class ResolveInstanceFileTask extends AbortableTask<void> {
for (const r of result) {
const p = modrinthProjects.find(p => p.modrinth.versionId === r.id)!
if (!p.downloads) { p.downloads = [] }
p.downloads.push(r.files[0].url)
if (p.downloads.indexOf(r.files[0].url) === -1) {
p.downloads.push(r.files[0].url)
}
}
}

Expand Down Expand Up @@ -279,7 +282,7 @@ export class InstanceInstallService extends AbstractService implements IInstance
await linkWithTimeoutOrCopy(res.path, dest)
})

const createDownloadTask = async (file: InstanceFile, destination: string, sha1?: string) => {
const createDownloadTask = async (file: InstanceFile, destination: string, pending?: string, sha1?: string) => {
if (!file.downloads) {
throw new Error(`Cannot resolve file! ${file.path}`)
}
Expand Down Expand Up @@ -314,6 +317,8 @@ export class InstanceInstallService extends AbstractService implements IInstance
...this.networkManager.getDownloadBaseOptions(),
url: file.downloads.filter(u => u.startsWith('http')),
destination,
pendingFile: pending,
skipRevalidate: true,
validator: sha1
? {
hash: sha1,
Expand Down Expand Up @@ -390,22 +395,18 @@ export class InstanceInstallService extends AbstractService implements IInstance
}

const shouldPending = file.path.startsWith(ResourceDomain.Mods) || file.path.startsWith(ResourceDomain.ResourcePacks) || file.path.startsWith(ResourceDomain.ShaderPacks)
const destination = shouldPending ? `${filePath}.pending` : filePath
const destination = filePath
const pending = shouldPending ? `${filePath}.pending` : undefined

const downloadTask = await createDownloadTask(file, destination, pending, sha1)

const downloadTask = await createDownloadTask(file, destination, sha1)
if (file.operation === 'backup-add') {
// backup legacy file
await rename(destination, destination + '.backup').catch(() => undefined)
}

return downloadTask.setName('file').map(async () => {
if (shouldPending) {
await this.resourceService.updateResources([{ hash: file.hashes.sha1, metadata }])
const renamedPath = destination.substring(0, destination.length - '.pending'.length)
if (file.operation === 'backup-add') {
// backup legacy file
await rename(renamedPath, renamedPath + '.backup').catch(() => undefined)
}
await rename(destination, renamedPath).catch(e => {
this.warn(`Skip to rename ${destination} -> ${renamedPath} as the file already existed`)
})
}
await this.resourceService.updateResources([{ hash: file.hashes.sha1, metadata }])
return undefined
})
}
Expand Down
24 changes: 19 additions & 5 deletions xmcl-runtime/lib/services/ModpackService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CurseforgeV1Client, HashAlgo } from '@xmcl/curseforge'
import { File, HashAlgo } from '@xmcl/curseforge'
import { UnzipTask } from '@xmcl/installer'
import { CurseforgeModpackManifest, EditInstanceOptions, ExportModpackOptions, getCurseforgeModpackFromInstance, getInstanceConfigFromCurseforgeModpack, getInstanceConfigFromMcbbsModpack, getInstanceConfigFromModrinthModpack, getMcbbsModpackFromInstance, getModrinthModpackFromInstance, getResolvedVersion, ImportModpackOptions, InstanceFile, isAllowInModrinthModpack, LockKey, McbbsModpackManifest, ModpackException, ModpackFileInfoCurseforge, ModpackService as IModpackService, ModpackServiceKey, ModrinthModpackManifest, ResourceDomain, ResourceMetadata } from '@xmcl/runtime-api'
import { CurseforgeModpackManifest, EditInstanceOptions, ExportModpackOptions, ModpackService as IModpackService, ImportModpackOptions, InstanceFile, LockKey, McbbsModpackManifest, ModpackException, ModpackFileInfoCurseforge, ModpackServiceKey, ModrinthModpackManifest, ResourceDomain, ResourceMetadata, getCurseforgeModpackFromInstance, getInstanceConfigFromCurseforgeModpack, getInstanceConfigFromMcbbsModpack, getInstanceConfigFromModrinthModpack, getMcbbsModpackFromInstance, getModrinthModpackFromInstance, getResolvedVersion, isAllowInModrinthModpack } from '@xmcl/runtime-api'
import { task } from '@xmcl/task'
import { open, openEntryReadStream, readAllEntries, readEntry } from '@xmcl/unzip'
import { createHash } from 'crypto'
Expand All @@ -10,7 +10,7 @@ import { pipeline } from 'stream/promises'
import { Entry, ZipFile } from 'yauzl'
import LauncherApp from '../app/LauncherApp'
import { LauncherAppKey } from '../app/utils'
import { kResourceWorker, ResourceWorker } from '../entities/resourceWorker'
import { ResourceWorker, kResourceWorker } from '../entities/resourceWorker'
import { guessCurseforgeFileUrl } from '../util/curseforge'
import { checksumFromStream, isFile } from '../util/fs'
import { requireObject } from '../util/object'
Expand Down Expand Up @@ -114,8 +114,21 @@ export class ModpackService extends AbstractService implements IModpackService {
const files = await curseforgeService.client.getFiles(curseforgeFiles.map(f => f.fileID))
const infos: InstanceFile[] = []

for (let i = 0; i < files.length; i++) {
const file = files[i]
const dict: Record<string, File> = {}
for (const file of files) {
if (dict[file.id]) {
this.warn(`Duplicated curseforge file return from curseforge API: ${file.id}`)
}
dict[file.id] = file
}

for (let i = 0; i < manifest.files.length; i++) {
const manifestFile = manifest.files[i]
const file = dict[manifestFile.fileID]
if (!file) {
this.warn(`Skip file ${manifestFile.fileID} because it is not found in curseforge API`)
continue
}
const domain = file.fileName.endsWith('.jar') ? ResourceDomain.Mods : file.modules.some(f => f.name === 'META-INF') ? ResourceDomain.Mods : ResourceDomain.ResourcePacks
const sha1 = file.hashes.find(v => v.algo === HashAlgo.Sha1)?.value
infos.push({
Expand Down Expand Up @@ -336,6 +349,7 @@ export class ModpackService extends AbstractService implements IModpackService {
const instance = handler.resolveInstanceOptions(manifest)

const instanceFiles = await handler.resolveInstanceFiles(manifest)

const files = (await Promise.all(entries
.filter((e) => !!handler.resolveUnpackPath(manifest, e) && !e.fileName.endsWith('/'))
.map(async (e) => {
Expand Down

0 comments on commit 97fc26e

Please sign in to comment.