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:
Observer KRypt0n_ 2021-12-27 00:27:39 +02:00
parent e8c721dc93
commit 68d766da58
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
8 changed files with 145 additions and 33 deletions

View file

@ -27,7 +27,7 @@
"maximize": false, "maximize": false,
"hidden": true, "hidden": true,
"resizable": false, "resizable": false,
"exitProcessOnClose": true "exitProcessOnClose": false
}, },
"browser": {}, "browser": {},
"cloud": {} "cloud": {}

View file

@ -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')!
}); });

View file

@ -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);*/
}); });
} }

View file

@ -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);
});
} }
} }

View file

@ -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];

View file

@ -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));
}; };
} }

View file

@ -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());
});
};
}); });
}; };

View file

@ -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 '));
}); });
}); });
} }