Skip to content

Commit

Permalink
fix: adapt to new core
Browse files Browse the repository at this point in the history
  • Loading branch information
ci010 committed Jan 5, 2022
1 parent 70cd627 commit 0afe97a
Show file tree
Hide file tree
Showing 40 changed files with 188 additions and 89 deletions.
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
},
{
"name": "Electron: Renderer (attach)",
"type": "chrome",
// "type": "chrome",
"type": "pwa-chrome",
"request": "attach",
"restart": true,
"port": 9300,
Expand Down
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,5 @@
"mojang",
"xmcl"
],
"volar.tsPlugin": true,
"cSpell.enabled": true
}
80 changes: 38 additions & 42 deletions src/main/electron/updater.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChecksumNotMatchError, DownloadTask } from '@xmcl/installer'
import { task, Task, TaskBase } from '@xmcl/task'
import { BaseTask, task, Task } from '@xmcl/task'
import { spawn } from 'child_process'
import { autoUpdater, Provider, UpdateInfo, UpdaterSignal, CancellationToken } from 'electron-updater'
import { close, stat, writeFile } from 'fs-extra'
import { autoUpdater, CancellationToken, Provider, UpdateInfo, UpdaterSignal } from 'electron-updater'
import { stat, writeFile } from 'fs-extra'
import got from 'got'
import { closeSync, existsSync, open, rename, unlink } from 'original-fs'
import { basename, dirname, join } from 'path'
Expand All @@ -15,76 +15,71 @@ import ElectronLauncherApp from './ElectronLauncherApp'
import { AZURE_CDN, AZURE_CDN_HOST, IS_DEV } from '/@main/constant'
import { UpdateInfo as _UpdateInfo } from '/@shared/entities/update'


/**
* Only download asar file update.
*
* If the this update is not a full update but an incremental update,
* you can call this to download asar update
*/
export class DownloadAsarUpdateTask extends DownloadTask {
private sha256 = ''

constructor(private updateInfo: UpdateInfo, private isInGFW: boolean, destination: string) {
super({ url: '', destination })
let sha256 = ''
super({
url: '', destination, validator: {
async validate(fd, file, url) {
const missed = await stat(file).then(s => s.size === 0, () => false)
if (missed) {
return
}
if (!sha256) {
sha256 = await got(`${url}.sha256`).text().catch(() => '')
}
if (!sha256) {
return
}
const expect = sha256
const actual = await checksum(file, 'sha256')
if (!expect !== actual) {
throw new ChecksumNotMatchError('sha256', expect, actual, file, url);
}
}
}
})
}

protected async process() {
const provider: Provider<UpdateInfo> = (await (autoUpdater as any).clientPromise)
const files = provider.resolveFiles(this.updateInfo)

const urls: string[] = []
const uObject = files[0].url
uObject.pathname = `${uObject.pathname.substring(0, uObject.pathname.lastIndexOf('/') + 1)}app.asar`
urls.push(uObject.toString())

if (this.isInGFW) {
uObject.host = AZURE_CDN_HOST
uObject.hostname = AZURE_CDN_HOST
uObject.pathname = 'releases/app.asar'
urls.unshift(uObject.toString())
}

this.url = uObject.toString()
this.originalUrl = this.url
this.download.urls.pop()
this.download.urls.push(...urls)

return super.process()
}

async shouldProcess() {
const missed = await stat(this.destination).then(s => s.size === 0, () => false)
if (missed) {
return true
}
if (!this.sha256) {
this.sha256 = await got(`${this.url}.sha256`).text().catch(() => '')
}
if (!this.sha256) {
return true
}
const expect = this.sha256
const actual = await checksum(this.destination, 'sha256')
return expect !== actual
}

async validate() {
if (this.sha256) {
const expect = this.sha256
const actual = await checksum(this.destination, 'sha256')
if (actual !== expect) {
throw new ChecksumNotMatchError('sha256', expect, actual, this.destination)
}
}
await close(this.fd).catch(() => { })
this.fd = -1
}
}

/**
* Download the full update. This size can be larger as it carry the whole electron thing...
*/
export class DownloadFullUpdateTask extends TaskBase<void> {
export class DownloadFullUpdateTask extends BaseTask<void> {
private updateSignal = new UpdaterSignal(autoUpdater)

private cancellationToken = new CancellationToken()

protected async run(): Promise<void> {
protected async runTask(): Promise<void> {
this.updateSignal.progress((info) => {
this._progress = info.transferred
this._total = info.total
Expand All @@ -93,19 +88,20 @@ export class DownloadFullUpdateTask extends TaskBase<void> {
await autoUpdater.downloadUpdate(this.cancellationToken)
}

protected performCancel(): Promise<void> {
protected cancelTask(): Promise<void> {
this.cancellationToken.cancel()
return new Promise((resolve) => {
autoUpdater.once('update-cancelled', resolve)
})
}

protected async performPause(): Promise<void> {
protected async pauseTask(): Promise<void> {
this.cancellationToken.cancel()
}

protected performResume(): void {
this.run()
protected resumeTask(): Promise<void> {
// this.runRunt()
return Promise.resolve();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/index.dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ app.on('web-contents-created', (event, contents) => {
// if (existsSync(extensionDir)) {
// contents.session.loadExtension(extensionDir)
// }
// contents.openDevTools({ mode: 'detach' });
contents.openDevTools({ mode: 'detach' });
console.log(event)
console.log(contents.getURL())
})
Expand Down
1 change: 0 additions & 1 deletion src/main/managers/NetworkManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export default class NetworkManager extends Manager {
return {
agents: this.agents,
headers: this.headers,
overwriteWhen: 'checksumNotMatchOrEmpty',
} as const
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/managers/TaskManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ export default class TaskManager extends Manager {
}

storeReady() {
this.emitter.on("fail", (uuid, task, error) => {
this.warn(`Task ${task.name}(${uuid}) failed!`)
this.warn(error)
})
}

// SETUP CODE
Expand Down
4 changes: 3 additions & 1 deletion src/main/services/ExternalAuthSkinService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import AbstractService, { ExportService, Inject, Singleton, Subscribe } from './
import LauncherApp from '../app/LauncherApp'
import { ExternalAuthSkinServiceKey, ExternalAuthSkinService as IExternalAuthSkinService } from '/@shared/services/ExternalAuthSkinService'
import UserService from './UserService'
import { compareRelease } from '/@shared/entities/version'

/**
* Majorly support the third party skin using authlib injector
*/
@ExportService(ExternalAuthSkinServiceKey)
export default class ExternalAuthSkinService extends AbstractService implements IExternalAuthSkinService {
constructor(
Expand Down
4 changes: 3 additions & 1 deletion src/main/services/InstanceGameSettingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FSWatcher, readFile, writeFile } from 'fs-extra'
import watch from 'node-watch'
import { join } from 'path'
import LauncherApp from '../app/LauncherApp'
import { isSystemError } from '../util/error'
import InstanceService from './InstanceService'
import { ExportService, Inject, Singleton, StatefulService, Subscribe } from './Service'
import { exists, missing } from '/@main/util/fs'
Expand Down Expand Up @@ -66,7 +67,7 @@ export default class InstanceGameSettingService extends StatefulService<GameSett
const result = await readFile(optionsPath, 'utf-8').then(parse)
this.state.instanceGameSettingsLoad(result)
} catch (e) {
if (!e.message.startsWith('ENOENT:')) {
if (isSystemError(e)) {
this.warn(`An error ocurrs during parse game options of ${path}.`)
this.warn(e)
}
Expand All @@ -86,6 +87,7 @@ export default class InstanceGameSettingService extends StatefulService<GameSett
async saveInstanceGameSetting() {
const instancePath = this.watchingInstance
const optionsTxtPath = join(instancePath, 'options.txt')

if (await exists(optionsTxtPath)) {
const buf = await readFile(optionsTxtPath)
const content = parse(buf.toString())
Expand Down
9 changes: 8 additions & 1 deletion src/main/services/InstanceModsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,18 @@ export default class InstanceModsService extends StatefulService<InstanceModsSta
const root = join(path, ResourceDomain.Mods)
for (const resource of mods) {
if (dirname(resource.path) !== root) {
this.warn(`Skip to uninstall unmanaged mod file on ${resource.path}!`)
const founded = this.state.mods.find(m => m.ino === resource.ino) ??
this.state.mods.find(m => m.hash === resource.hash)
if (founded) {
promises.push(unlink(founded.path))
} else {
this.warn(`Skip to uninstall unmanaged mod file on ${resource.path}!`)
}
} else {
promises.push(unlink(resource.path))
}
}
await Promise.all(promises)
this.log(`Finish to uninstall ${mods.length} from ${path}`)
}
}
22 changes: 22 additions & 0 deletions src/main/util/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { constants } from 'os'

export interface SystemError extends Error {
/**
* Please see `constants.errno` in `os` module
*/
errno: number
code: string
syscall?: string
path?: string
}

export interface SystemErrorWithSyscall extends SystemError {
syscall: string
}

export function isSystemError(e: any): e is SystemError {
if (typeof e.errno === 'number' && typeof e.code === 'string' && e instanceof Error) {
return true;
}
return false;
}
4 changes: 3 additions & 1 deletion src/main/util/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ export function linkWithTimeout(from: string, to: string, timeout = 1500) {
}

export function linkWithTimeoutOrCopy(from: string, to: string, timeout = 1500) {
return linkWithTimeout(from, to, timeout).catch(() => copy(from, to))
return linkWithTimeout(from, to, timeout).catch(() => {
copy(from, to)
})
}

export type FileType = FileExtension | 'unknown' | 'directory'
Expand Down
14 changes: 14 additions & 0 deletions src/renderer/component.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// declare module 'vue' {
// export interface GlobalComponents {
// }
// }

// declare module '@vue/runtime-dom' {
// export * from '@vue/runtime-dom/dist/runtime-dom'
// export { defineComponent, PropType } from '@vue/composition-api'
// }

declare module '@vue/composition-api' {
export * from '@vue/runtime-dom'
export * from '@vue/composition-api/dist/index'
}
1 change: 0 additions & 1 deletion src/renderer/hooks/useInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ export function useInstanceSaves() {
exportSave,
readAllInstancesSaves,
importSave: (options: ImportSaveOptions) => importSave(options).finally(refresh),
// path: computed(() => state.instance.path),
saves: computed(() => state.saves),
}
}
Expand Down
21 changes: 11 additions & 10 deletions src/renderer/hooks/useInstanceMod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { computed } from '@vue/composition-api'
import { FabricModMetadata } from '@xmcl/mod-parser'
import { useService } from '.'
import { useBusy } from './useSemaphore'
import { AnyResource, FabricResource, ForgeResource, isModResource, LiteloaderResource, ModResource } from '/@shared/entities/resource'
import { AnyResource, FabricResource, ForgeResource, isModResource, isPersistedResource, LiteloaderResource, ModResource } from '/@shared/entities/resource'
import { Resource } from '/@shared/entities/resource.schema'
import { InstanceModsServiceKey } from '/@shared/services/InstanceModsService'
import { InstanceResourcePacksServiceKey } from '../../shared/services/InstanceResourcePacksService'
import { ResourceServiceKey } from '/@shared/services/ResourceService'
import { isNonnull } from '/@shared/util/assert'

Expand Down Expand Up @@ -73,16 +72,17 @@ export function useInstanceModsService() {
export function useInstanceMods() {
const { state } = useInstanceModsService()
const { state: resourceState } = useService(ResourceServiceKey)
const { install: deploy, uninstall: undeploy } = useService(InstanceResourcePacksServiceKey)
const { install: deploy, uninstall: undeploy } = useService(InstanceModsServiceKey)
const loading = useBusy('mountModResources')

function getUrl(resource: Resource) {
return resource.uri.find(u => u.startsWith('http')) ?? ''
}
function getModItemFromModResource(resource: ForgeResource | FabricResource | LiteloaderResource | AnyResource): ModItem {
const icon = `dataroot://${resource.domain}/${resource.fileName}.png`
const isPersisted = isPersistedResource(resource)
const modItem: ModItem = {
path: 'filePath' in resource ? (resource as any).filePath : resource.path,
path: resource.path,
id: '',
name: resource.path,
version: '',
Expand All @@ -91,11 +91,11 @@ export function useInstanceMods() {
type: 'forge',
url: getUrl(resource),
hash: resource.hash,
tags: resource.tags,
tags: isPersisted ? resource.tags : [],
enabled: false,
subsequence: false,
hide: false,
curseforge: resource.curseforge,
curseforge: isPersisted ? resource.curseforge : undefined,
dependencies: {
minecraft: '',
},
Expand Down Expand Up @@ -138,6 +138,7 @@ export function useInstanceMods() {
if (isModResource(resource)) {
return getModItemFromModResource(resource)
}
const isPersisted = isPersistedResource(resource)
return {
path: resource.path,
id: resource.hash,
Expand All @@ -148,11 +149,11 @@ export function useInstanceMods() {
type: 'unknown',
url: getUrl(resource),
hash: resource.hash,
tags: resource.tags,
tags: isPersisted ? resource.tags : [],
enabled: false,
subsequence: false,
hide: false,
curseforge: resource.curseforge,
curseforge: isPersisted ? resource.curseforge : undefined,
dependencies: { minecraft: '[*]' },
}
}
Expand All @@ -170,8 +171,8 @@ export function useInstanceMods() {
const disabled = items.filter(m => !m.enabled).map((m) => map.get(m.hash)).filter(isNonnull)

await Promise.all([
deploy({ resources: enabled }),
undeploy(disabled),
deploy({ mods: enabled }),
undeploy({ mods: disabled }),
])
}

Expand Down
Loading

0 comments on commit 0afe97a

Please sign in to comment.