mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-12-29 21:18:17 +03:00
API improvements
- added `Archive.closeStreams()` method to close all the unpacking streams - added `Downloader.closeStreams()` method to close all the downloading streams - added the same methods to the streams itself - fixed launch button events execution - added prefix creation during the game installation/updagin if it is not created - added some hack to the `Process.running()` method to show that the process is not running if it is a zombie
This commit is contained in:
parent
e8c721dc93
commit
68d766da58
8 changed files with 145 additions and 33 deletions
|
@ -27,7 +27,7 @@
|
||||||
"maximize": false,
|
"maximize": false,
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"resizable": false,
|
"resizable": false,
|
||||||
"exitProcessOnClose": true
|
"exitProcessOnClose": false
|
||||||
},
|
},
|
||||||
"browser": {},
|
"browser": {},
|
||||||
"cloud": {}
|
"cloud": {}
|
||||||
|
|
|
@ -1,11 +1,21 @@
|
||||||
import '../i18n';
|
import '../i18n';
|
||||||
import App from '../index.svelte';
|
import App from '../index.svelte';
|
||||||
|
import Archive from '../ts/core/Archive';
|
||||||
|
import Downloader from '../ts/core/Downloader';
|
||||||
|
|
||||||
declare const Neutralino;
|
declare const Neutralino;
|
||||||
|
|
||||||
Neutralino.init();
|
Neutralino.init();
|
||||||
|
|
||||||
Neutralino.events.on('ready', () => import('../defaultSettings'));
|
Neutralino.events.on('ready', () => import('../defaultSettings'));
|
||||||
|
|
||||||
|
Neutralino.events.on('windowClose', () => {
|
||||||
|
Downloader.closeStreams(true);
|
||||||
|
Archive.closeStreams(true);
|
||||||
|
|
||||||
|
Neutralino.app.exit();
|
||||||
|
});
|
||||||
|
|
||||||
const app = new App({
|
const app = new App({
|
||||||
target: document.getElementById('app')!
|
target: document.getElementById('app')!
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default class Launcher
|
||||||
this.progressBar = new ProgressBar(this);
|
this.progressBar = new ProgressBar(this);
|
||||||
|
|
||||||
// Progress bar test
|
// Progress bar test
|
||||||
this.progressBar.init({
|
/*this.progressBar.init({
|
||||||
label: 'Abobus',
|
label: 'Abobus',
|
||||||
showSpeed: true,
|
showSpeed: true,
|
||||||
showEta: true,
|
showEta: true,
|
||||||
|
@ -42,7 +42,7 @@ export default class Launcher
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
t(0);
|
t(0);*/
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,16 @@ declare const NL_CWD;
|
||||||
|
|
||||||
class Stream
|
class Stream
|
||||||
{
|
{
|
||||||
|
protected _id: number = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the archive unpacker process
|
||||||
|
*/
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interval in ms between progress event calls
|
* The interval in ms between progress event calls
|
||||||
*/
|
*/
|
||||||
|
@ -67,6 +77,8 @@ class Stream
|
||||||
|
|
||||||
Neutralino.os.execCommand(command, {
|
Neutralino.os.execCommand(command, {
|
||||||
background: true
|
background: true
|
||||||
|
}).then((result) => {
|
||||||
|
this._id = result.pid;
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateProgress = async () => {
|
const updateProgress = async () => {
|
||||||
|
@ -156,10 +168,20 @@ class Stream
|
||||||
if (this.throwedError)
|
if (this.throwedError)
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close unpacking stream
|
||||||
|
*/
|
||||||
|
public close(forced: boolean = false)
|
||||||
|
{
|
||||||
|
Neutralino.os.execCommand(`kill ${forced ? '-9' : '-15'} ${this._id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Archive
|
export default class Archive
|
||||||
{
|
{
|
||||||
|
protected static streams: Stream[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get type of archive
|
* Get type of archive
|
||||||
*
|
*
|
||||||
|
@ -259,7 +281,23 @@ export default class Archive
|
||||||
*/
|
*/
|
||||||
public static unpack(path: string, unpackDir: string|null = null): Promise<Stream>
|
public static unpack(path: string, unpackDir: string|null = null): Promise<Stream>
|
||||||
{
|
{
|
||||||
return new Promise((resolve) => resolve(new Stream(path, unpackDir)));
|
return new Promise((resolve) => {
|
||||||
|
const stream = new Stream(path, unpackDir);
|
||||||
|
|
||||||
|
this.streams.push(stream);
|
||||||
|
|
||||||
|
resolve(stream);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close every open archive unpacking stream
|
||||||
|
*/
|
||||||
|
public static closeStreams(forced: boolean = false)
|
||||||
|
{
|
||||||
|
this.streams.forEach((stream) => {
|
||||||
|
stream.close(forced);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,16 @@ declare const Neutralino;
|
||||||
|
|
||||||
class Stream
|
class Stream
|
||||||
{
|
{
|
||||||
|
protected _id: number = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the curl process
|
||||||
|
*/
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interval in ms between progress event calls
|
* The interval in ms between progress event calls
|
||||||
*/
|
*/
|
||||||
|
@ -31,12 +41,14 @@ class Stream
|
||||||
|
|
||||||
Neutralino.os.execCommand(`curl -s -L -N -o "${output}" "${uri}"`, {
|
Neutralino.os.execCommand(`curl -s -L -N -o "${output}" "${uri}"`, {
|
||||||
background: true
|
background: true
|
||||||
|
}).then((result) => {
|
||||||
|
this._id = result.pid;
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateProgress = () => {
|
const updateProgress = () => {
|
||||||
Neutralino.filesystem.getStats(output).then((stats) => {
|
Neutralino.filesystem.getStats(output).then((stats) => {
|
||||||
if (this.onProgress)
|
if (this.onProgress)
|
||||||
this.onProgress(stats.size, this.total, this.previous - stats.size);
|
this.onProgress(stats.size, this.total, stats.size - this.previous);
|
||||||
|
|
||||||
this.previous = stats.size;
|
this.previous = stats.size;
|
||||||
|
|
||||||
|
@ -94,10 +106,20 @@ class Stream
|
||||||
if (this.finished)
|
if (this.finished)
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close downloading stream
|
||||||
|
*/
|
||||||
|
public close(forced: boolean = false)
|
||||||
|
{
|
||||||
|
Neutralino.os.execCommand(`kill ${forced ? '-9' : '-15'} ${this._id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Downloader
|
export default class Downloader
|
||||||
{
|
{
|
||||||
|
protected static streams: Stream[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download file
|
* Download file
|
||||||
*
|
*
|
||||||
|
@ -110,11 +132,28 @@ export default class Downloader
|
||||||
{
|
{
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
fetch(uri).then((response) => {
|
fetch(uri).then((response) => {
|
||||||
resolve(new Stream(uri, output ?? this.fileFromUri(uri), response.length!));
|
const stream = new Stream(uri, output ?? this.fileFromUri(uri), response.length!);
|
||||||
|
|
||||||
|
this.streams.push(stream);
|
||||||
|
|
||||||
|
resolve(stream);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close every open downloading stream
|
||||||
|
*/
|
||||||
|
public static closeStreams(forced: boolean = false)
|
||||||
|
{
|
||||||
|
this.streams.forEach((stream) => {
|
||||||
|
stream.close(forced);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a file name from the URI
|
||||||
|
*/
|
||||||
public static fileFromUri(uri: string): string
|
public static fileFromUri(uri: string): string
|
||||||
{
|
{
|
||||||
const file = uri.split('/').pop()!.split('#')[0].split('?')[0];
|
const file = uri.split('/').pop()!.split('#')[0].split('?')[0];
|
||||||
|
|
|
@ -8,12 +8,12 @@ export default class State
|
||||||
|
|
||||||
public launchButton: HTMLElement;
|
public launchButton: HTMLElement;
|
||||||
|
|
||||||
protected _state: LauncherState = 'game-launch-available';
|
protected _state: LauncherState = 'game-installation-available';
|
||||||
|
|
||||||
protected events = {
|
protected events = {
|
||||||
'game-launch-available': import('./states/Launch'),
|
'game-launch-available': import('./states/Launch'),
|
||||||
|
|
||||||
'game-install-available': import('./states/Install'),
|
'game-installation-available': import('./states/Install'),
|
||||||
'game-update-available': import('./states/Install')
|
'game-update-available': import('./states/Install')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export default class State
|
||||||
|
|
||||||
this.launchButton.onclick = () => {
|
this.launchButton.onclick = () => {
|
||||||
if (this.events[this._state])
|
if (this.events[this._state])
|
||||||
this.events[this._state].then((event) => event.default());
|
this.events[this._state].then((event) => event.default(this.launcher));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,64 @@
|
||||||
import type Launcher from '../../Launcher';
|
import type Launcher from '../../Launcher';
|
||||||
|
|
||||||
import Game from '../../Game';
|
import Game from '../../Game';
|
||||||
|
import constants from '../../Constants';
|
||||||
|
import Runners from '../../core/Runners';
|
||||||
|
|
||||||
|
declare const Neutralino;
|
||||||
|
|
||||||
export default (launcher: Launcher): Promise<void> => {
|
export default (launcher: Launcher): Promise<void> => {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
Game.update(await Game.current).then((stream) => {
|
const prefixDir = await constants.paths.prefix.current;
|
||||||
launcher.progressBar?.init({
|
|
||||||
label: 'Downloading game...',
|
Neutralino.filesystem.getStats(prefixDir)
|
||||||
showSpeed: true,
|
.then(() => updateGame())
|
||||||
showEta: true,
|
.catch(() => {
|
||||||
showPercents: true,
|
Runners.createPrefix(prefixDir).then((result) => {
|
||||||
showTotals: true
|
if (result === true)
|
||||||
|
updateGame();
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
console.error('There\'s no wine version installed to use to create the prefix');
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
stream?.downloadStart(() => launcher.progressBar?.show());
|
const updateGame = async () => {
|
||||||
|
Game.update(await Game.current).then((stream) => {
|
||||||
stream?.downloadProgress((current: number, total: number, difference: number) => {
|
|
||||||
launcher.progressBar?.update(current, total, difference);
|
|
||||||
});
|
|
||||||
|
|
||||||
stream?.unpackStart(() => {
|
|
||||||
launcher.progressBar?.init({
|
launcher.progressBar?.init({
|
||||||
label: 'Unpacking game...',
|
label: 'Downloading game...',
|
||||||
showSpeed: true,
|
showSpeed: true,
|
||||||
showEta: true,
|
showEta: true,
|
||||||
showPercents: true,
|
showPercents: true,
|
||||||
showTotals: true
|
showTotals: true
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
stream?.unpackProgress((current: number, total: number, difference: number) => {
|
stream?.downloadStart(() => launcher.progressBar?.show());
|
||||||
launcher.progressBar?.update(current, total, difference);
|
|
||||||
});
|
|
||||||
|
|
||||||
stream?.unpackFinish(() => resolve());
|
stream?.downloadProgress((current: number, total: number, difference: number) => {
|
||||||
});
|
launcher.progressBar?.update(current, total, difference);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream?.unpackStart(() => {
|
||||||
|
launcher.progressBar?.init({
|
||||||
|
label: 'Unpacking game...',
|
||||||
|
showSpeed: true,
|
||||||
|
showEta: true,
|
||||||
|
showPercents: true,
|
||||||
|
showTotals: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
stream?.unpackProgress((current: number, total: number, difference: number) => {
|
||||||
|
launcher.progressBar?.update(current, total, difference);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream?.unpackFinish(() => resolve());
|
||||||
|
});
|
||||||
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -106,8 +106,8 @@ class Process
|
||||||
public running(): Promise<boolean>
|
public running(): Promise<boolean>
|
||||||
{
|
{
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
Neutralino.os.execCommand(`ps -p ${this.id}`).then((output) => {
|
Neutralino.os.execCommand(`ps -p ${this.id} -S`).then((output) => {
|
||||||
resolve(output.stdOut.includes(this.id));
|
resolve(output.stdOut.includes(this.id) && !output.stdOut.includes('Z '));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue