4
0
mirror of https://github.com/AltarikMC/Launcher synced 2024-11-22 06:19:50 +01:00

Merge pull request #334 from AltarikMC/electron28

Electron 28, moving to ESM, add eslint
This commit is contained in:
Quentin Legot 2023-12-06 13:26:35 +01:00 committed by GitHub
commit f5a8ec27f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1765 additions and 666 deletions

29
.eslintrc.cjs Normal file
View File

@ -0,0 +1,29 @@
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'standard'
],
overrides: [
{
env: {
node: true
},
files: [
'.eslintrc.{js,cjs}'
],
parserOptions: {
sourceType: 'script'
}
}
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: [],
rules: {
}
}

View File

@ -4,6 +4,7 @@
"version": "2.1.0", "version": "2.1.0",
"description": "Altarik Launcher", "description": "Altarik Launcher",
"main": "src/server/main.js", "main": "src/server/main.js",
"type": "module",
"homepage": "https://altarik.fr/", "homepage": "https://altarik.fr/",
"private": true, "private": true,
"repository": "AltarikMC/Launcher", "repository": "AltarikMC/Launcher",
@ -34,7 +35,12 @@
"@electron-forge/maker-zip": "^7.1.0", "@electron-forge/maker-zip": "^7.1.0",
"@electron-forge/plugin-auto-unpack-natives": "^7.1.0", "@electron-forge/plugin-auto-unpack-natives": "^7.1.0",
"@electron-forge/publisher-github": "^7.1.0", "@electron-forge/publisher-github": "^7.1.0",
"electron": "^27.1.0" "electron": "28.0.0",
"eslint": "^8.0.1",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
"eslint-plugin-promise": "^6.0.0"
}, },
"dependencies": { "dependencies": {
"decompress": "^4.2.1", "decompress": "^4.2.1",
@ -42,14 +48,14 @@
"electron-log": "^5.0.0", "electron-log": "^5.0.0",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"extract-zip": "^2.0.1", "extract-zip": "^2.0.1",
"hasha": "^5.2.2", "hasha": "^6.0.0",
"izitoast": "^1.4.0", "izitoast": "^1.4.0",
"minecraft-launcher-core": "^3.17.3", "minecraft-launcher-core": "^3.17.3",
"msmc": "^4.1.0", "msmc": "^4.1.0",
"node-fetch": "^2.7.0", "node-fetch": "^3.0.0",
"vue": "^3.3.8" "vue": "^3.3.8"
}, },
"config": { "config": {
"forge": "./config.forge.js" "forge": "./config.forge.cjs"
} }
} }

View File

@ -1,51 +1,47 @@
function handleSquirrelEvent(app) { export default function handleSquirrelEvent (app) {
if (process.argv.length === 1) { if (process.argv.length === 1) {
return false; return false
} }
const ChildProcess = require('child_process'); const ChildProcess = require('child_process')
const path = require('path'); const path = require('path')
const appFolder = path.resolve(process.execPath, '..'); const appFolder = path.resolve(process.execPath, '..')
const rootAtomFolder = path.resolve(appFolder, '..'); const rootAtomFolder = path.resolve(appFolder, '..')
const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe')); const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'))
const exeName = path.basename(process.execPath); const exeName = path.basename(process.execPath)
const spawn = function (command, args) { const spawn = function (command, args) {
let spawnedProcess; let spawnedProcess
try { try {
spawnedProcess = ChildProcess.spawn(command, args, {detached: true}); spawnedProcess = ChildProcess.spawn(command, args, { detached: true })
} catch (error) {} } catch (error) {}
return spawnedProcess; return spawnedProcess
}; }
const spawnUpdate = function (args) { const spawnUpdate = function (args) {
return spawn(updateDotExe, args); return spawn(updateDotExe, args)
}; }
const squirrelEvent = process.argv[1]; const squirrelEvent = process.argv[1]
switch (squirrelEvent) { switch (squirrelEvent) {
case '--squirrel-install': case '--squirrel-install':
case '--squirrel-updated': case '--squirrel-updated':
spawnUpdate(['--createShortcut', exeName]); spawnUpdate(['--createShortcut', exeName])
setTimeout(app.quit, 1000); setTimeout(app.quit, 1000)
return true; return true
case '--squirrel-uninstall': case '--squirrel-uninstall':
spawnUpdate(['--removeShortcut', exeName]); spawnUpdate(['--removeShortcut', exeName])
setTimeout(app.quit, 1000); setTimeout(app.quit, 1000)
return true; return true
case '--squirrel-obsolete': case '--squirrel-obsolete':
app.quit(); app.quit()
return true; return true
} }
} }
module.exports = {
handleSquirrelEvent
}

View File

@ -1,19 +1,24 @@
const { app, BrowserWindow, Menu, ipcMain, autoUpdater, dialog } = require('electron') import { app, BrowserWindow, Menu, ipcMain, autoUpdater, dialog } from 'electron'
const logger = require('electron-log') import isDev from 'electron-is-dev'
const { join } = require('path') import logger from 'electron-log'
const updater = require('./updater.js') import { join, dirname } from 'path'
let updaterInstance = new updater.Updater(app, autoUpdater, dialog, logger, showNotification) import Updater from './updater.js'
import electronStartup from 'electron-squirrel-startup'
import install from './install.js'
import Mc from './minecraft.js'
import { minimizeWindow, closeWindow } from './menubar.js'
import { fileURLToPath } from 'url'
const updaterInstance = new Updater(app, autoUpdater, dialog, logger, showNotification)
updaterInstance.configUpdater() updaterInstance.configUpdater()
if (require('electron-squirrel-startup')) { const minecraft = new Mc()
require("./install.js").handleSquirrelEvent(app)
app.quit()
return
}
const minecraft = require('./minecraft.js')
minecraft.showNotification = showNotification minecraft.showNotification = showNotification
const iconPath = join(__dirname, "icon.ico") const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const iconPath = join(__dirname, 'icon.ico')
let win = null let win = null
function createWindow () { function createWindow () {
@ -28,18 +33,43 @@ function createWindow () {
}, },
frame: false frame: false
}) })
//Menu.setApplicationMenu(null) if (!isDev) {
Menu.setApplicationMenu(null)
}
win.loadFile('src/client/checkingUpdate.html') win.loadFile('src/client/checkingUpdate.html')
win.on("close", () => { win.on('close', () => {
app.quit() app.quit()
}) })
} }
const { setWindow, minimizeWindow, closeWindow } = require("./menubar.js"); function showNotification (title, body = '', clazz = 'info') {
win.webContents.send('notification', { title, body, class: clazz })
}
ipcMain.on('disconnect', () => {
minecraft.auth = null
win.loadFile('src/client/login.html').then(() => showNotification('Déconnecté', 'Vous avez été déconnecté de votre compte', 'success'))
})
ipcMain.on('pageReady', (event) => {
event.sender.send('nick', { name: minecraft.auth.name })
minecraft.getModsInformations(event)
})
ipcMain.on('checking-update', () => {
updaterInstance.checkForUpdates(win, showNotification)
})
function main () {
if (electronStartup) {
install.handleSquirrelEvent(app)
app.quit()
return
}
app.whenReady().then(() => { app.whenReady().then(() => {
createWindow() createWindow()
setWindow(win)
}) })
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
@ -62,37 +92,21 @@ app.on('activate', () => {
} }
}) })
ipcMain.on("login", (event, args) => { ipcMain.on('login', (event, args) => {
minecraft.login(event, win, args.user, args.pass) minecraft.login(event, win, args.user, args.pass)
}) })
ipcMain.on("microsoft-login", (event) => { ipcMain.on('microsoft-login', (event) => {
minecraft.microsoftLogin(event, win) minecraft.microsoftLogin(event, win)
}) })
ipcMain.on("invalidateData", event => { ipcMain.on('invalidateData', event => {
minecraft.invalidateData(event) minecraft.invalidateData(event)
}) })
ipcMain.on("launch", (event, args) => { ipcMain.on('launch', (event, args) => {
minecraft.launch(event, args) minecraft.launch(event, args)
}) })
function showNotification(title, body="", clazz="info") {
win.webContents.send('notification', {title: title, body: body, class: clazz})
} }
ipcMain.on("disconnect", () => { main()
minecraft.auth = null
win.loadFile('src/client/login.html').then(() => showNotification("Déconnecté", "Vous avez été déconnecté de votre compte", "success"))
})
ipcMain.on("pageReady", (event) => {
event.sender.send("nick", { name: minecraft.auth.name })
minecraft.getModsInformations(event)
})
ipcMain.on("checking-update", () => {
updaterInstance.checkForUpdates(win, showNotification)
})

View File

@ -1,21 +1,9 @@
let win; export function minimizeWindow (browserWindow) {
function setWindow(browserWindow) {
win = browserWindow;
}
function minimizeWindow(browserWindow = win) {
if (browserWindow.minimizable) { if (browserWindow.minimizable) {
browserWindow.minimize() browserWindow.minimize()
} }
} }
function closeWindow(browserWindow = win) { export function closeWindow (browserWindow) {
browserWindow.close() browserWindow.close()
} }
module.exports = {
setWindow,
minimizeWindow,
closeWindow
}

View File

@ -1,27 +1,26 @@
const isDev = require("electron-is-dev") import isDev from 'electron-is-dev'
const { Authenticator, Client } = require("minecraft-launcher-core") import mlc from 'minecraft-launcher-core'
const fetch = require("node-fetch").default import fetch from 'node-fetch'
const hasha = require("hasha") import { hashFile } from 'hasha'
const fs = require("fs") import fs from 'fs'
const { join } = require("path") import { join } from 'path'
const constants = require("constants") import zip from 'extract-zip'
const zip = require("extract-zip") import logger from 'electron-log'
const logger = require("electron-log") import { Auth, lst } from 'msmc'
const { Auth, lst } = require("msmc") import decompress from 'decompress'
const decompress = require("decompress") import decompressTar from 'decompress-targz'
const decompressTar = require("decompress-targz")
const { Authenticator, Client } = mlc
class Minecraft { export default class Minecraft {
appdata = process.env.APPDATA || (process.platform === 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + '/.local/share')
appdata = process.env.APPDATA || (process.platform === "darwin" ? process.env.HOME + "/Library/Preferences" : process.env.HOME + "/.local/share") localappdata = process.env.LOCALAPPDATA || (process.platform === 'darwin' ? process.env.HOME + '/Library/Application Support/' : process.env.HOME + '/.config')
localappdata = process.env.LOCALAPPDATA || (process.platform === "darwin" ? process.env.HOME + "/Library/Application Support/" : process.env.HOME + "/.config") minecraftpath = join(this.appdata, '.altarik')
minecraftpath = join(this.appdata, ".altarik")
launcher = new Client() launcher = new Client()
auth = null auth = null
modsList = undefined modsList = undefined
showNotification = undefined showNotification = undefined
modsInformationsEndpoint = "https://launcher.altarik.fr" modsInformationsEndpoint = 'https://launcher.altarik.fr'
setShowNotification (showNotification) { setShowNotification (showNotification) {
this.showNotification = showNotification this.showNotification = showNotification
@ -33,17 +32,17 @@ class Minecraft {
*/ */
login (event, win, username, password) { login (event, win, username, password) {
this.auth = null this.auth = null
if(isDev || password.trim() !== "") { if (isDev || password.trim() !== '') {
this.auth = Authenticator.getAuth(username, password) this.auth = Authenticator.getAuth(username, password)
this.auth.then(v => { this.auth.then(v => {
win.loadFile("src/client/index.html") win.loadFile('src/client/index.html')
}).catch(() => { }).catch(() => {
event.sender.send("loginError") event.sender.send('loginError')
logger.error("[MJ login] User haven't purchase the game") logger.error("[MJ login] User haven't purchase the game")
this.showNotification("Erreur de connexion", "Vous ne possèdez pas de licence Minecraft sur ce compte", "error") this.showNotification('Erreur de connexion', 'Vous ne possèdez pas de licence Minecraft sur ce compte', 'error')
}) })
} else { } else {
this.showNotification("Erreur de connexion", "Veuillez renseignez un mot de passe", "warning") this.showNotification('Erreur de connexion', 'Veuillez renseignez un mot de passe', 'warning')
} }
} }
@ -51,28 +50,28 @@ class Minecraft {
* Used to login through a Microsoft account * Used to login through a Microsoft account
*/ */
microsoftLogin (event, win) { microsoftLogin (event, win) {
const authManager = new Auth("select_account") const authManager = new Auth('select_account')
authManager.launch("electron").then(async xboxManager => { authManager.launch('electron').then(async xboxManager => {
xboxManager.getMinecraft().then(async token => { xboxManager.getMinecraft().then(async token => {
if (!token.isDemo()) { if (!token.isDemo()) {
this.auth = token.mclc() this.auth = token.mclc()
logger.info("[MS login] User has been connected successfully to them account") logger.info('[MS login] User has been connected successfully to them account')
win.loadFile("src/client/index.html") win.loadFile('src/client/index.html')
} else { } else {
event.sender.send("loginError") event.sender.send('loginError')
logger.error("[MS login] User haven't purchase the game") logger.error("[MS login] User haven't purchase the game")
this.showNotification("Erreur de connexion", "Vous ne possèdez pas de licence Minecraft sur ce compte", "error") this.showNotification('Erreur de connexion', 'Vous ne possèdez pas de licence Minecraft sur ce compte', 'error')
} }
}).catch(err => { }).catch(err => {
event.sender.send("loginError") event.sender.send('loginError')
logger.error("[MS login] " + lst(err)) logger.error('[MS login] ' + lst(err))
this.showNotification("Erreur de connexion à Mojang", lst(err), "error") this.showNotification('Erreur de connexion à Mojang', lst(err), 'error')
}) })
}).catch(err => { }).catch(err => {
event.sender.send("loginError") event.sender.send('loginError')
if(err != "error.gui.closed") { if (err !== 'error.gui.closed') {
logger.error("[MS login] " + lst(err)) logger.error('[MS login] ' + lst(err))
this.showNotification("Une erreur de connexion à Xbox est survenue", lst(err), "error") this.showNotification('Une erreur de connexion à Xbox est survenue', lst(err), 'error')
} }
}) })
} }
@ -83,10 +82,10 @@ class Minecraft {
this.launcher.launch({ this.launcher.launch({
authorization: this.auth, authorization: this.auth,
root: this.minecraftpath, root: this.minecraftpath,
javaPath: javaPath, javaPath,
version: { version: {
number: chapter.minecraftVersion, number: chapter.minecraftVersion,
type: chapter.type | "release", type: chapter.type | 'release',
custom: chapter.customVersion custom: chapter.customVersion
}, },
memory: { memory: {
@ -98,40 +97,40 @@ class Minecraft {
this.close(event, -1) this.close(event, -1)
} }
}) })
this.launcher.on("debug", (e) => logger.info(`debug: ${e}`)); this.launcher.on('debug', (e) => logger.info(`debug: ${e}`))
this.launcher.on("data", (e) => logger.info(`data: ${e}`)); this.launcher.on('data', (e) => logger.info(`data: ${e}`))
this.launcher.on("progress", (e) => { this.launcher.on('progress', (e) => {
event.sender.send("progress", e) event.sender.send('progress', e)
logger.info(`progress ${e.type} :${e.task} / ${e.total}`) logger.info(`progress ${e.type} :${e.task} / ${e.total}`)
}) })
this.launcher.on("arguments", (e) => { this.launcher.on('arguments', (e) => {
event.sender.send("launch", e) event.sender.send('launch', e)
logger.info("launching the game") logger.info('launching the game')
logger.info(e) logger.info(e)
}) })
this.launcher.on("close", (e) => { this.launcher.on('close', (e) => {
this.close(event, e) this.close(event, e)
}) })
}).catch((err) => { }).catch((err) => {
this.showNotification("Impossible de lancer le jeu", "Erreur inconnue", "error") this.showNotification('Impossible de lancer le jeu', 'Erreur inconnue', 'error')
event.sender.send("close", 1) event.sender.send('close', 1)
logger.error("Unable to launch the game") logger.error('Unable to launch the game')
logger.error(err) logger.error(err)
}) })
}).catch(err => { }).catch(err => {
this.showNotification("Impossible de lancer le jeu", "Impossible d'installer Java pour votre configuration", "error") this.showNotification('Impossible de lancer le jeu', "Impossible d'installer Java pour votre configuration", 'error')
event.sender.send("close", 1) event.sender.send('close', 1)
logger.warn("Unable to install java") logger.warn('Unable to install java')
logger.warn(err) logger.warn(err)
}) })
} }
close (event, code) { close (event, code) {
event.sender.send("close", code) event.sender.send('close', code)
if (code !== 0) { if (code !== 0) {
logger.warn("Minecraft didn't close properly") logger.warn("Minecraft didn't close properly")
logger.warn(code) logger.warn(code)
this.showNotification("Une erreur est survenue", "Minecraft ne s'est pas fermé correctement", "error") this.showNotification('Une erreur est survenue', "Minecraft ne s'est pas fermé correctement", 'error')
} }
} }
@ -139,45 +138,43 @@ class Minecraft {
fetch(this.modsInformationsEndpoint).then(response => { fetch(this.modsInformationsEndpoint).then(response => {
if (response.ok) { if (response.ok) {
response.json().then(data => { response.json().then(data => {
let folder = join(this.localappdata, "altarik-launcher", "data") const folder = join(this.localappdata, 'altarik-launcher', 'data')
if(!fs.existsSync(folder)) if (!fs.existsSync(folder)) { fs.mkdirSync(folder, { recursive: true }) }
fs.mkdirSync(folder, {recursive: true}) const file = join(folder, 'launcher.json')
let file = join(folder, "launcher.json") if (fs.existsSync(file)) { fs.rmSync(file) }
if(fs.existsSync(file))
fs.rmSync(file)
fs.writeFileSync(file, JSON.stringify(data)) fs.writeFileSync(file, JSON.stringify(data))
event.sender.send("modsInformations", this.extractModsInformations(data)) event.sender.send('modsInformations', this.extractModsInformations(data))
}).catch(err => { }).catch(err => {
event.sender.send("modsInformations", this.extractModsFromFileSystem()) event.sender.send('modsInformations', this.extractModsFromFileSystem())
logger.warn(err) logger.warn(err)
logger.warn("An error occured while trying to connect to server") logger.warn('An error occured while trying to connect to server')
}) })
} else { } else {
logger.warn("Unable to connect to server") logger.warn('Unable to connect to server')
logger.warn(err) logger.warn(response.status)
event.sender.send("modsInformations", this.extractModsFromFileSystem()) event.sender.send('modsInformations', this.extractModsFromFileSystem())
} }
}).catch(err => { }).catch(err => {
logger.warn("Unable to connect to server") logger.warn('Unable to connect to server')
logger.warn(err) logger.warn(err)
event.sender.send("modsInformations", this.extractModsFromFileSystem()) event.sender.send('modsInformations', this.extractModsFromFileSystem())
}) })
} }
extractModsFromFileSystem () { extractModsFromFileSystem () {
let filepath = join(this.localappdata, "altarik-launcher/data/launcher.json") const filepath = join(this.localappdata, 'altarik-launcher/data/launcher.json')
if (fs.existsSync(filepath)) { if (fs.existsSync(filepath)) {
let content = fs.readFileSync(filepath) const content = fs.readFileSync(filepath)
if (content !== null) { if (content !== null) {
this.showNotification("Impossible de récupérer certaines informations en ligne", "utilisation des dernières données récupérées", "warning") this.showNotification('Impossible de récupérer certaines informations en ligne', 'utilisation des dernières données récupérées', 'warning')
return this.extractModsInformations(JSON.parse(content)) return this.extractModsInformations(JSON.parse(content))
} else { } else {
this.showNotification("Impossible de récupérer certaines informations en ligne", "Veuillez réessayez en cliquant sur le bouton", "warning") this.showNotification('Impossible de récupérer certaines informations en ligne', 'Veuillez réessayez en cliquant sur le bouton', 'warning')
logger.error("Unable to get chapters informations from server or filesystem") logger.error('Unable to get chapters informations from server or filesystem')
return null return null
} }
} else { } else {
return null; return null
} }
} }
@ -188,24 +185,21 @@ class Minecraft {
async extractMods (chapterId, event) { async extractMods (chapterId, event) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const modsFolder = join(this.minecraftpath, "mods") const modsFolder = join(this.minecraftpath, 'mods')
const shaderFolder = join(this.minecraftpath, "shaderpacks") const shaderFolder = join(this.minecraftpath, 'shaderpacks')
if(fs.existsSync(modsFolder)) if (fs.existsSync(modsFolder)) { fs.rmSync(modsFolder, { recursive: true }) }
fs.rmSync(modsFolder, { recursive: true }) if (fs.existsSync(shaderFolder)) { fs.rmSync(shaderFolder, { recursive: true }) }
if(fs.existsSync(shaderFolder))
fs.rmSync(shaderFolder, { recursive: true })
for (const i in this.modsList) { for (const i in this.modsList) {
if (Number(i) === chapterId) { if (Number(i) === chapterId) {
const chapter = this.modsList[i] const chapter = this.modsList[i]
for(let j in chapter.modspack.mods) { for (const j in chapter.modspack.mods) {
event.sender.send("progress", {type: "mods", task: 0, total: chapter.modspack.mods.length }) event.sender.send('progress', { type: 'mods', task: 0, total: chapter.modspack.mods.length })
let modpackFolder = join(this.minecraftpath, "modpack", chapter.title) const modpackFolder = join(this.minecraftpath, 'modpack', chapter.title)
if(!fs.existsSync(modpackFolder)) if (!fs.existsSync(modpackFolder)) { fs.mkdirSync(modpackFolder, { recursive: true }) }
fs.mkdirSync(modpackFolder, { recursive: true })
const path = join(modpackFolder, `modpack${j}.zip`) const path = join(modpackFolder, `modpack${j}.zip`)
try { try {
fs.accessSync(path, constants.W_OK) fs.accessSync(path, fs.W_OK)
let sha1 = await hasha.fromFile(path, {algorithm: "sha1"}) const sha1 = await hashFile(path, { algorithm: 'sha1' })
if (sha1 === chapter.modspack.sha1sum[j]) { if (sha1 === chapter.modspack.sha1sum[j]) {
await this.unzipMods(path).catch(err => { await this.unzipMods(path).catch(err => {
reject(err) reject(err)
@ -216,12 +210,12 @@ class Minecraft {
reject(err) reject(err)
}) })
} }
event.sender.send("progress", {type: "mods", task: Number(j)+1, total: chapter.modspack.mods.length }) event.sender.send('progress', { type: 'mods', task: Number(j) + 1, total: chapter.modspack.mods.length })
} catch (err) { } catch (err) {
try { try {
await this.downloadAndExtractMods(chapter.modspack.mods[j], path) await this.downloadAndExtractMods(chapter.modspack.mods[j], path)
} catch (e) { } catch (e) {
reject({ err, e }) reject(new Error({ err, e }))
return return
} }
} }
@ -230,24 +224,24 @@ class Minecraft {
return return
} }
} }
reject("didn't found the correct chapter" + chapter) reject(new Error("didn't found the correct chapter" + chapterId))
}) })
} }
downloadMods (link, path) { downloadMods (link, path) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fetch(link).then(response => { fetch(link).then(response => {
if (response.ok) { if (response.ok) {
if(fs.existsSync(path)) if (fs.existsSync(path)) { fs.rmSync(path) }
fs.rmSync(path)
const dest = fs.createWriteStream(path) const dest = fs.createWriteStream(path)
response.body.pipe(dest) response.body.pipe(dest)
response.body.on("end", () => { response.body.on('end', () => {
logger.log("download completed"); logger.log('download completed')
resolve("download completed") resolve('download completed')
})
dest.on('error', () => {
reject(new Error('An error appenned when using stream'))
}) })
dest.on("error", () => {
reject("An error appenned when using stream")
});
} else { } else {
reject(response.status) reject(response.status)
} }
@ -258,21 +252,19 @@ class Minecraft {
} }
async unzipMods (zipLocation, outLocation = this.minecraftpath) { async unzipMods (zipLocation, outLocation = this.minecraftpath) {
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
logger.info(`unzipping ${zipLocation} file to ${outLocation}`) logger.info(`unzipping ${zipLocation} file to ${outLocation}`)
zip(zipLocation, { dir: outLocation }).then(() => { zip(zipLocation, { dir: outLocation }).then(() => {
resolve() resolve()
}).catch(err => { }).catch(err => {
logger.error(`failed to unzip file`) logger.error('failed to unzip file')
reject(err) reject(err)
}) })
}) })
} }
async extractTar (tarLocation, outLocation = this.microsoftpath) { async extractTar (tarLocation, outLocation = this.microsoftpath) {
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
logger.info(`Extracting targz ${tarLocation} file to ${outLocation}`) logger.info(`Extracting targz ${tarLocation} file to ${outLocation}`)
decompress(tarLocation, outLocation, { decompress(tarLocation, outLocation, {
plugins: [ plugins: [
@ -281,14 +273,14 @@ class Minecraft {
}).then(() => { }).then(() => {
resolve() resolve()
}).catch((e) => { }).catch((e) => {
logger.error(`Failed to extract targz file`) logger.error('Failed to extract targz file')
reject(e) reject(e)
}) })
}) })
} }
async downloadAndExtractMods (link, path) { async downloadAndExtractMods (link, path) {
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
this.downloadMods(link, path).then(() => { this.downloadMods(link, path).then(() => {
this.unzipMods(path).then(() => { this.unzipMods(path).then(() => {
resolve() resolve()
@ -302,35 +294,39 @@ class Minecraft {
} }
async extractJava (chapterId, event) { async extractJava (chapterId, event) {
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
const runtime = join(this.minecraftpath, "runtime") const runtime = join(this.minecraftpath, 'runtime')
if(this.modsList[chapterId].java.platform[process.platform] !== undefined if (this.modsList[chapterId].java.platform[process.platform] !== undefined &&
&& this.modsList[chapterId].java.platform[process.platform][process.arch] !== undefined) { this.modsList[chapterId].java.platform[process.platform][process.arch] !== undefined) {
event.sender.send("progress", {type: "java", task: 0, total: 1 }) event.sender.send('progress', { type: 'java', task: 0, total: 1 })
const infos = this.modsList[chapterId].java.platform[process.platform][process.arch] const infos = this.modsList[chapterId].java.platform[process.platform][process.arch]
const jre = join(runtime, infos.name) const jre = join(runtime, infos.name)
const downloadFolder = join(runtime, "download") const downloadFolder = join(runtime, 'download')
const downloadFile = join(downloadFolder, `${infos.name}.zip`) const downloadFile = join(downloadFolder, `${infos.name}.zip`)
if(fs.existsSync(jre)) if (fs.existsSync(jre)) { fs.rmSync(jre, { recursive: true }) }
fs.rmSync(jre, { recursive: true }) if (!fs.existsSync(downloadFolder)) { fs.mkdirSync(downloadFolder, { recursive: true }) }
if(!fs.existsSync(downloadFolder))
fs.mkdirSync(downloadFolder, { recursive: true })
if (fs.existsSync(downloadFile)) { if (fs.existsSync(downloadFile)) {
let sha1 = await hasha.fromFile(downloadFile, {algorithm: "sha256"}) hashFile(downloadFile, { algorithm: 'sha256' }).then(sha1 => {
if (sha1 === infos.sha256sum) { if (sha1 === infos.sha256sum) {
await this.extractJavaArchive(downloadFile, runtime) this.extractJavaArchive(downloadFile, runtime).then(() => {
let filename = process.platform == "win32" ? "java.exe" : "java" const filename = process.platform === 'win32' ? 'java.exe' : 'java'
resolve(join(jre, "bin", filename)) resolve(join(jre, 'bin', filename))
}).catch(err => {
reject(err)
})
} else { } else {
logger.warn(`java sha256sum ${sha1} don't correspond to ${infos.sha256sum}`) logger.warn(`java sha256sum ${sha1} don't correspond to ${infos.sha256sum}`)
await this.downloadAndExtractJava(infos, downloadFolder, runtime).then(() => resolve(join(jre, "bin", process.platform === "win32" ? "java.exe" : "java"))).catch(err => reject(err)) this.downloadAndExtractJava(infos, downloadFolder, runtime).then(() => resolve(join(jre, 'bin', process.platform === 'win32' ? 'java.exe' : 'java'))).catch(err => reject(err))
} }
}).catch(err => {
reject(err)
})
} else { } else {
await this.downloadAndExtractJava(infos, downloadFolder, runtime).then(() => resolve(join(jre, "bin", process.platform === "win32" ? "java.exe" : "java"))).catch(err => reject(err)) this.downloadAndExtractJava(infos, downloadFolder, runtime).then(() => resolve(join(jre, 'bin', process.platform === 'win32' ? 'java.exe' : 'java'))).catch(err => reject(err))
} }
event.sender.send("progress", {type: "java", task: 1, total: 1 }) event.sender.send('progress', { type: 'java', task: 1, total: 1 })
} else { } else {
reject("There is not available version for this system") reject(new Error('There is not available version for this system'))
} }
}) })
} }
@ -339,13 +335,13 @@ class Minecraft {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logger.info(`Downloading ${infos.name}`) logger.info(`Downloading ${infos.name}`)
this.downloadMods(infos.link, join(downloadFolder, `${infos.name}.zip`)).then(() => { this.downloadMods(infos.link, join(downloadFolder, `${infos.name}.zip`)).then(() => {
logger.info(`download completed`) logger.info('download completed')
this.extractJavaArchive(join(downloadFolder, `${infos.name}.zip`), runtimeFolder).then(() => { this.extractJavaArchive(join(downloadFolder, `${infos.name}.zip`), runtimeFolder).then(() => {
logger.info(`File unzipped`) logger.info('File unzipped')
resolve() resolve()
}).catch(err => { }).catch(err => {
let join_s = join(downloadFolder, `${infos.name}.zip`) const joinS = join(downloadFolder, `${infos.name}.zip`)
logger.info(`Failed to unzip ${join_s}`) logger.info(`Failed to unzip ${joinS}`)
reject(err) reject(err)
}) })
}).catch(err => { }).catch(err => {
@ -356,7 +352,7 @@ class Minecraft {
} }
async extractJavaArchive (zipLocation, outLocation) { async extractJavaArchive (zipLocation, outLocation) {
if(process.platform === "win32") { if (process.platform === 'win32') {
await this.unzipMods(zipLocation, outLocation) await this.unzipMods(zipLocation, outLocation)
} else { } else {
await this.extractTar(zipLocation, outLocation) await this.extractTar(zipLocation, outLocation)
@ -364,22 +360,16 @@ class Minecraft {
} }
invalidateData (event) { invalidateData (event) {
logger.info("invalidate game data...") logger.info('invalidate game data...')
const assets = join(this.minecraftpath, "assets") const assets = join(this.minecraftpath, 'assets')
const librairies = join(this.minecraftpath,"libraries") const librairies = join(this.minecraftpath, 'libraries')
const natives = join(this.minecraftpath, "natives") const natives = join(this.minecraftpath, 'natives')
const versions = join(this.minecraftpath, "versions") const versions = join(this.minecraftpath, 'versions')
if(fs.existsSync(assets)) if (fs.existsSync(assets)) { fs.rmSync(assets, { recursive: true }) }
fs.rmSync(assets, { recursive: true }) if (fs.existsSync(librairies)) { fs.rmSync(librairies, { recursive: true }) }
if(fs.existsSync(librairies)) if (fs.existsSync(natives)) { fs.rmSync(natives, { recursive: true }) }
fs.rmSync(librairies, { recursive: true }) if (fs.existsSync(versions)) { fs.rmSync(versions, { recursive: true }) }
if(fs.existsSync(natives)) logger.info('Game data invalidated')
fs.rmSync(natives, { recursive: true }) event.sender.send('invalidated')
if(fs.existsSync(versions))
fs.rmSync(versions, { recursive: true })
logger.info("Game data invalidated")
event.sender.send("invalidated")
} }
} }
module.exports = new Minecraft

View File

@ -1,10 +1,10 @@
const isDev = require('electron-is-dev') import isDev from 'electron-is-dev'
const fetch = require('node-fetch').default import fetch from 'node-fetch'
const pkg = require('../../package.json') import pkg from '../../package.json' assert {type: 'json'}
const server = 'https://update.electronjs.org' const server = 'https://update.electronjs.org'
class Updater { export default class Updater {
constructor (app, autoUpdater, dialog, logger, ipcMain) { constructor (app, autoUpdater, dialog, logger, ipcMain) {
this.app = app this.app = app
this.autoUpdater = autoUpdater this.autoUpdater = autoUpdater
@ -14,9 +14,9 @@ class Updater {
} }
configUpdater () { configUpdater () {
this.logger.info(`electron version: ${process.versions['electron']}`) this.logger.info(`electron version: ${process.versions.electron}`)
this.logger.info(`chrome version: ${process.versions['chrome']}`) this.logger.info(`chrome version: ${process.versions.chrome}`)
this.logger.info(`Node version: ${process.versions['node']}`) this.logger.info(`Node version: ${process.versions.node}`)
this.logger.info(`platform: ${process.platform}`) this.logger.info(`platform: ${process.platform}`)
this.logger.info(`arch: ${process.arch}`) this.logger.info(`arch: ${process.arch}`)
if (isDev) { if (isDev) {
@ -27,38 +27,36 @@ class Updater {
// TODO : replace dialog by automatic restart // TODO : replace dialog by automatic restart
this.autoUpdater.on('update-downloaded', (_event, releaseNotes, releaseName) => { this.autoUpdater.on('update-downloaded', (_event, releaseNotes, releaseName) => {
this.logger.info(`update downloaded ${releaseName}`) this.logger.info(`update downloaded ${releaseName}`)
this.logger.info("Leaving application to install update...") this.logger.info('Leaving application to install update...')
this.autoUpdater.quitAndInstall() this.autoUpdater.quitAndInstall()
}) })
} }
checkForUpdates (win, showNotification) { checkForUpdates (win, showNotification) {
if (isDev) { if (isDev) {
win.loadFile('src/client/login.html') win.loadFile('src/client/login.html')
return; return
} }
this.logger.info("Checking for update...") this.logger.info('Checking for update...')
const feed = `${server}/${pkg.repository}/${process.platform}-${process.arch}/${this.app.getVersion()}` const feed = `${server}/${pkg.repository}/${process.platform}-${process.arch}/${this.app.getVersion()}`
if(process.platform != 'linux') { if (process.platform !== 'linux') {
this.autoUpdater.setFeedURL(feed) this.autoUpdater.setFeedURL(feed)
this.autoUpdater.on('error', message => { this.autoUpdater.on('error', message => {
this.displayError(win, showNotification, message) this.displayError(win, showNotification, message)
}) })
this.autoUpdater.on('update-available', () => { this.autoUpdater.on('update-available', () => {
this.logger.info("update available, downloading...") this.logger.info('update available, downloading...')
win.webContents.send("update-available") win.webContents.send('update-available')
}) })
this.autoUpdater.on("update-not-available", () => { this.autoUpdater.on('update-not-available', () => {
this.logger.info("update not available") this.logger.info('update not available')
win.loadFile('src/client/login.html') win.loadFile('src/client/login.html')
}) })
this.autoUpdater.checkForUpdates() this.autoUpdater.checkForUpdates()
} else { } else {
this.searchUpdateLinux(win, showNotification) this.searchUpdateLinux(win, showNotification)
} }
} }
searchUpdateLinux (win, showNotification) { searchUpdateLinux (win, showNotification) {
@ -67,21 +65,21 @@ class Updater {
if (response.status === 200) { if (response.status === 200) {
response.json().then(json => { response.json().then(json => {
if (json.tag_name !== pkg.version) { if (json.tag_name !== pkg.version) {
let asset = json.assets.filter(el => el.browser_download_url.includes(".zip")) const asset = json.assets.filter(el => el.browser_download_url.includes('.zip'))
if (asset.length === 1) { if (asset.length === 1) {
let downloadUrl = asset[0].browser_download_url const downloadUrl = asset[0].browser_download_url
win.webContents.send("please-download-update", { url: downloadUrl} ) win.webContents.send('please-download-update', { url: downloadUrl })
this.logger.info("update available, please download") this.logger.info('update available, please download')
} else { } else {
this.displayError(win, showNotification, "Can't find right asset in last update") this.displayError(win, showNotification, "Can't find right asset in last update")
} }
} else { } else {
this.logger.info("update not available") this.logger.info('update not available')
win.loadFile('src/client/login.html') win.loadFile('src/client/login.html')
} }
}).catch(err => this.displayError(win, showNotification, err)) }).catch(err => this.displayError(win, showNotification, err))
} else { } else {
this.displayError(win, showNotification, "Server unavailable") this.displayError(win, showNotification, 'Server unavailable')
} }
}).catch(err => this.displayError(win, showNotification, err)) }).catch(err => this.displayError(win, showNotification, err))
} }
@ -90,12 +88,7 @@ class Updater {
this.logger.error('There was a problem updating the application') this.logger.error('There was a problem updating the application')
this.logger.error(errorMessage) this.logger.error(errorMessage)
win.loadFile('src/client/login.html').then(() => { win.loadFile('src/client/login.html').then(() => {
showNotification("Une erreur est survenue lors de la vérification de la mise à jour", "Veuillez vérifier votre connexion internet et réessayer", "error") showNotification('Une erreur est survenue lors de la vérification de la mise à jour', 'Veuillez vérifier votre connexion internet et réessayer', 'error')
}) })
} }
}
module.exports = {
Updater
} }

1145
yarn.lock

File diff suppressed because it is too large Load Diff