Qortal UI - Main Code Repository A User Interface for the Qortal Blockchain Project. Truly decentralized web hosting, application hosting, communications, data storage, and full infrastructure for the future global decentralized digital world.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1487 lines
37 KiB

const {
app,
BrowserWindow,
ipcMain,
Menu,
Notification,
Tray,
dialog,
nativeTheme,
crashReporter
} = require('electron')
const { autoUpdater } = require('electron-updater')
const server = require('./server.js')
const log = require('electron-log')
const path = require('path')
const i18n = require('./lib/i18n.js')
const fs = require('fs')
const os = require("os")
const electronDl = require('electron-dl')
const Store = require('electron-store')
const extract = require('extract-zip')
const execFile = require('child_process').execFile
const exec = require('child_process').exec
const spawn = require('child_process').spawn
const XMLHttpRequest = require('xhr2')
const homePath = app.getPath('home')
const downloadPath = app.getPath('downloads')
const logPath = app.getPath('logs')
const debugFileUnix = logPath + '/qortal-ui.log'
const debugFileWin = logPath + '\\qortal-ui.log'
const myMemory = os.totalmem()
const store = new Store()
crashReporter.start({
productName: 'Qortal-UI',
uploadToServer: false
})
3 years ago
if (myMemory > 16000000000) {
3 months ago
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=8192', '--max-semi-space-size=2')
log.info("Memory Size Is 16GB Using JS Memory Heap Size 8GB")
} else if (myMemory > 12000000000) {
3 months ago
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=6144', '--max-semi-space-size=2')
log.info("Memory Size Is 12GB Using JS Memory Heap Size 6GB")
} else if (myMemory > 7000000000) {
3 months ago
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=4096', '--max-semi-space-size=2')
log.info("Memory Size Is 8GB Using JS Memory Heap Size 4GB")
} else {
3 months ago
app.commandLine.appendSwitch('js-flags', '--max-executable-size=192', '--max-old-space-size=2048', '--max-semi-space-size=2')
log.info("Memory Size Is 4GB Using JS Memory Heap Size 2GB")
}
setInterval(function () {
let mu = process.memoryUsage()
log.info('heapTotal:', mu.heapTotal, 'heapUsed:', mu.heapUsed)
if (mu.heapUsed > 1024 * 1024 * 1024) {
log.info('Taking out the garbage')
global.gc()
}
}, 1000 * 120)
if (process.arch === 'arm') {
app.disableHardwareAcceleration()
app.commandLine.appendSwitch('enable-experimental-web-platform-features')
app.commandLine.appendSwitch('disable-software-rasterizer')
app.commandLine.appendSwitch('in-process-gpu')
log.info('We are on 32bit. Hardware Acceleration is disabled !')
} else {
app.commandLine.appendSwitch('enable-experimental-web-platform-features')
app.commandLine.appendSwitch('disable-renderer-backgrounding')
app.commandLine.appendSwitch('disable-http-cache')
app.commandLine.appendSwitch('disable-software-rasterizer')
app.commandLine.appendSwitch('in-process-gpu')
log.info('We are on 64bit. Hardware Acceleration is enabled !')
}
if (process.platform === 'win32') {
app.commandLine.appendSwitch('log-file', debugFileWin)
app.commandLine.appendSwitch('enable-logging')
} else {
app.commandLine.appendSwitch('log-file', debugFileUnix)
app.commandLine.appendSwitch('enable-logging')
}
app.enableSandbox()
electronDl()
3 years ago
process.env['APP_PATH'] = app.getAppPath()
3 years ago
autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = false
autoUpdater.logger = log
autoUpdater.logger.transports.file.level = 'info'
if (!store.has('askingCore')) {
store.set('askingCore', false)
}
log.info('App starting...')
log.info('App Platform is', process.platform)
log.info('Platform arch is', process.arch)
log.info("Memory Size", os.totalmem())
const winjar = String.raw`C:\Program Files\Qortal\qortal.jar`
const winurl = "https://github.com/Qortal/qortal/releases/latest/download/qortal.exe"
const winexe = downloadPath + "\\qortal.exe"
const startWinCore = "C:\\Program Files\\Qortal\\qortal.exe"
const zipdir = homePath
const zipfile = homePath + "/qortal.zip"
const zipurl = "https://github.com/Qortal/qortal/releases/latest/download/qortal.zip"
const qortaldir = homePath + "/qortal/"
const qortaljar = homePath + "/qortal/qortal.jar"
const qortalsettings = homePath + "/qortal/settings.json"
const javadir = homePath + "/jdk-17.0.2/"
const linjavax64url = "https://download.qortal.online/openjdk-17.0.2_linux-x64_bin.zip"
const linjavax64urlbackup = "https://cloud.qortal.org/s/aSxDWTskG8kBR5T/download/openjdk-17.0.2_linux-x64_bin.zip"
const linjavax64file = homePath + "/openjdk-17.0.2_linux-x64_bin.zip"
const linjavax64bindir = homePath + "/jdk-17.0.2/bin"
const linjavax64binfile = homePath + "/jdk-17.0.2/bin/java"
const linjavaarmurl = "https://download.qortal.online/openjdk-17.0.2_linux-arm_bin.zip"
const linjavaarmurlbackup = "https://cloud.qortal.org/s/DAMFBEri469R3dj/download/openjdk-17.0.2_linux-arm_bin.zip"
const linjavaarmfile = homePath + "/openjdk-17.0.2_linux-arm_bin.zip"
const linjavaarmbindir = homePath + "/jdk-17.0.2/bin"
const linjavaarmbinfile = homePath + "/jdk-17.0.2/bin/java"
const linjavaarm64url = "https://download.qortal.online/openjdk-17.0.2_linux-arm64_bin.zip"
const linjavaarm64urlbackup = "https://cloud.qortal.org/s/t7Kk9ZpEAroFmg2/download/openjdk-17.0.2_linux-arm64_bin.zip"
const linjavaarm64file = homePath + "/openjdk-17.0.2_linux-arm64_bin.zip"
const linjavaarm64bindir = homePath + "/jdk-17.0.2/bin"
const linjavaarm64binfile = homePath + "/jdk-17.0.2/bin/java"
const macjavax64url = "https://download.qortal.online/openjdk-17.0.2_macos-x64_bin.zip"
const macjavax64urlbackup = "https://cloud.qortal.org/s/7t9d6xPfk8tsDxB/download/openjdk-17.0.2_macos-x64_bin.zip"
const macjavax64file = homePath + "/openjdk-17.0.2_macos-x64_bin.zip"
const macjavax64bindir = homePath + "/jdk-17.0.2/Contents/Home/bin"
const macjavax64binfile = homePath + "/jdk-17.0.2/Contents/Home/bin/java"
const macjavaaarch64url = "https://download.qortal.online/openjdk-17.0.2_macos-aarch64_bin.zip"
const macjavaaarch64urlbackup = "https://cloud.qortal.org/s/GRE3CGqMospwtZP/download/openjdk-17.0.2_macos-aarch64_bin.zip"
const macjavaaarch64file = homePath + "/openjdk-17.0.2_macos-aarch64_bin.zip"
const macjavaaarch64bindir = homePath + "/jdk-17.0.2/Contents/Home/bin"
const macjavaaarch64binfile = homePath + "/jdk-17.0.2/Contents/Home/bin/java"
let win = BrowserWindow.getFocusedWindow()
const isRunning = (query, cb) => {
let platform = process.platform
let cmd = ''
switch (platform) {
case 'win32': cmd = `tasklist`; break
case 'darwin': cmd = `ps -ax | grep [q]ortal.jar`; break
case 'linux': cmd = `ps ax | grep [q]ortal.jar`; break
default: break
}
exec(cmd, (err, stdout, stderr) => {
cb(stdout.toLowerCase().indexOf(query.toLowerCase()) > -1)
})
}
function doesFileExist(urlToJavaFile) {
const xhr = new XMLHttpRequest()
xhr.open('HEAD', urlToJavaFile, true)
xhr.send()
6 months ago
return xhr.status != "404";
}
async function checkWin() {
if (fs.existsSync(winjar)) {
isRunning('qortal.exe', (status) => {
if (status == true) {
log.info("Core is running, perfect !")
} else {
if (!store.get('askingCore')) {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_13"), i18n.__("electron_translate_14")],
title: i18n.__("electron_translate_15"),
message: i18n.__("electron_translate_16"),
detail: i18n.__("electron_translate_17"),
checkboxLabel: i18n.__("electron_translate_28"),
checkboxChecked: false
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
spawn(startWinCore, { detached: true })
store.set('askingCore', returnValue.checkboxChecked)
} else {
store.set('askingCore', returnValue.checkboxChecked)
6 months ago
}
})
}
}
})
} else {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_18"), i18n.__("electron_translate_19")],
title: i18n.__("electron_translate_20"),
message: i18n.__("electron_translate_21"),
detail: i18n.__("electron_translate_22")
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
downloadWindows()
} else {
6 months ago
}
})
}
}
async function checkOsPlatform() {
if (process.platform === 'win32') {
await startElectronWin()
} else if (process.platform === 'linux' || process.platform === 'darwin') {
startElectronUnix()
} else {
6 months ago
}
}
async function startElectronWin() {
if (fs.existsSync(winjar)) {
isRunning('qortal.exe', (status) => {
if (status == true) {
log.info("Core is running, perfect !")
} else {
spawn(startWinCore, { detached: true })
}
})
} else {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_18"), i18n.__("electron_translate_19")],
title: i18n.__("electron_translate_20"),
message: i18n.__("electron_translate_21"),
detail: i18n.__("electron_translate_22")
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
downloadWindows()
} else {
6 months ago
}
})
}
}
function startElectronUnix() {
if (fs.existsSync(qortaljar)) {
isRunning('qortal.jar', (status) => {
if (status == true) {
log.info("Core is running, perfect !")
} else {
startQortal()
}
})
} else {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_18"), i18n.__("electron_translate_19")],
title: i18n.__("electron_translate_20"),
message: i18n.__("electron_translate_21"),
detail: i18n.__("electron_translate_22")
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
downloadQortal()
} else {
6 months ago
}
})
}
}
async function downloadWindows() {
let winLoader = new BrowserWindow({
width: 500,
height: 500,
transparent: true,
frame: false,
alwaysOnTop: true,
show: false
})
await winLoader.loadFile(path.join(__dirname + '/splash/download.html'))
winLoader.show()
await electronDl.download(myWindow, winurl, {
directory: downloadPath,
onProgress: function () { log.info("Starting Download Qortal Core Installer") }
})
winLoader.destroy()
const coreInstall = execFile(winexe, (e, stdout, stderr) => {
if (e) {
log.info(e)
removeQortalExe()
} else {
log.info('Qortal Core Installation Done', stdout, stderr)
removeQortalExe()
}
})
coreInstall.stdin.end()
}
async function removeQortalExe() {
try {
await fs.rmSync(winexe, {
force: true
})
} catch (err) {
log.info('renove error', err)
}
await checkWin()
}
async function checkPort() {
await fetch('http://localhost:12391/admin/info').catch(err => {
return {
ok: false,
status: -1,
statusText: 'Qortal Connect Failure'
}
}).then(checkResponseStatus)
}
async function checkResponseStatus(res) {
if (res.ok) {
} else if (process.platform === 'win32') {
await checkWin()
} else {
await javaversion()
}
}
async function javaversion() {
let stderrChunks = [];
let checkJava = await spawn('java', ['-version'], { shell: true })
if (process.platform === 'linux') {
if (process.arch === 'x64') {
if (fs.existsSync(linjavax64bindir)) {
checkJava = await spawn(linjavax64binfile, ['-version'], { cwd: homePath, shell: true, maxBuffer: Infinity })
}
} else if (process.arch === 'arm64') {
if (fs.existsSync(linjavaarm64bindir)) {
checkJava = await spawn(linjavaarm64binfile, ['-version'], { cwd: homePath, shell: true, maxBuffer: Infinity })
}
} else if (process.arch === 'arm') {
if (fs.existsSync(linjavaarmbindir)) {
checkJava = await spawn(linjavaarmbinfile, ['-version'], { cwd: homePath, shell: true, maxBuffer: Infinity })
}
}
} else if (process.platform === 'darwin') {
if (process.arch === 'x64') {
if (fs.existsSync(macjavax64bindir)) {
checkJava = await spawn(macjavax64binfile, ['-version'], { cwd: homePath, shell: true, maxBuffer: Infinity })
}
} else {
if (fs.existsSync(macjavaaarch64bindir)) {
checkJava = await spawn(macjavaaarch64file, ['-version'], { cwd: homePath, shell: true, maxBuffer: Infinity })
}
}
}
checkJava.stderr.on('data', (data) => {
stderrChunks = stderrChunks.concat(data)
})
checkJava.stderr.on('end', () => {
6 months ago
let datres = Buffer.concat(stderrChunks).toString().split('\n')[0]
const javaVersion = new RegExp('(java|openjdk) version').test(datres) ? datres.split(' ')[2].replace(/"/g, '') : false
log.info("Java Version", javaVersion)
if (javaVersion != false) {
checkQortal()
} else {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_23"), i18n.__("electron_translate_24")],
title: i18n.__("electron_translate_25"),
message: i18n.__("electron_translate_26"),
detail: i18n.__("electron_translate_27")
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
installJava()
} else {
6 months ago
}
})
}
})
}
async function installJava() {
let splashLoader = new BrowserWindow({
width: 500,
height: 500,
transparent: true,
frame: false,
alwaysOnTop: true,
show: false
})
await splashLoader.loadFile(path.join(__dirname + '/splash/download.html'))
if (process.platform === 'linux') {
if (process.arch === 'x64') {
if (doesFileExist(linjavax64url) == true) {
try {
splashLoader.show()
await electronDl.download(myWindow, linjavax64url, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaX64Linux()
} else {
try {
splashLoader.show()
await electronDl.download(myWindow, linjavax64urlbackup, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaX64Linux()
}
} else if (process.arch === 'arm64') {
if (doesFileExist(linjavaarm64url) == true) {
try {
splashLoader.show()
await electronDl.download(myWindow, linjavaarm64url, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaArm64Linux()
} else {
try {
splashLoader.show()
await electronDl.download(myWindow, linjavaarm64urlbackup, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaArm64Linux()
}
} else if (process.arch === 'arm') {
if (doesFileExist(linjavaarmurl) == true) {
try {
splashLoader.show()
await electronDl.download(myWindow, linjavaarmurl, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaArmLinux()
} else {
try {
splashLoader.show()
await electronDl.download(myWindow, linjavaarmurlbackup, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaArmLinux()
}
}
} else if (process.platform === 'darwin') {
if (process.arch === 'x64') {
if (doesFileExist(macjavax64url) == true) {
try {
splashLoader.show()
await electronDl.download(myWindow, macjavax64url, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaX64Mac()
} else {
try {
splashLoader.show()
await electronDl.download(myWindow, macjavax64urlbackup, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaX64Mac()
}
} else {
if (doesFileExist(macjavaaarch64url) == true) {
try {
splashLoader.show()
await electronDl.download(myWindow, macjavaaarch64url, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaAarch64Mac()
} else {
try {
splashLoader.show()
await electronDl.download(myWindow, macjavaaarch64urlbackup, {
directory: homePath,
onProgress: function () { log.info("Starting Download JAVA") }
})
} catch (err) {
splashLoader.destroy()
log.info('Download JAVA error', err)
}
splashLoader.destroy()
await unzipJavaAarch64Mac()
}
}
}
}
async function unzipJavaX64Linux() {
try {
await extract(linjavax64file, { dir: homePath })
log.info('Unzip Java complete')
} catch (err) {
log.info('Unzip Java error', err)
}
await chmodJava()
}
async function unzipJavaArm64Linux() {
try {
await extract(linjavaarm64file, { dir: homePath })
log.info('Unzip Java complete')
} catch (err) {
log.info('Unzip Java error', err)
}
await chmodJava()
}
async function unzipJavaArmLinux() {
try {
await extract(linjavaarmfile, { dir: homePath })
log.info('Unzip Java complete')
} catch (err) {
log.info('Unzip Java error', err)
}
await chmodJava()
}
async function unzipJavaX64Mac() {
try {
await extract(macjavax64file, { dir: homePath })
log.info('Unzip Java complete')
} catch (err) {
log.info('Unzip Java error', err)
}
await chmodJava()
}
async function unzipJavaAarch64Mac() {
try {
await extract(macjavaaarch64file, { dir: homePath })
log.info('Unzip Java complete')
} catch (err) {
log.info('Unzip Java error', err)
}
await chmodJava()
}
async function chmodJava() {
try {
await spawn(
'chmod', ['-R', '+x', javadir],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('chmod error', err)
}
await removeJavaZip()
}
async function removeJavaZip() {
if (process.platform === 'linux') {
if (process.arch === 'x64') {
try {
await spawn(
'rm', ['-rf', linjavax64file],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('rm error', err)
}
checkQortal()
} else if (process.arch === 'arm64') {
try {
await spawn(
'rm', ['-rf', linjavaarm64file],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('rm error', err)
}
checkQortal()
} else if (process.arch === 'arm') {
try {
await spawn(
'rm', ['-rf', linjavaarmfile],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('rm error', err)
}
checkQortal()
}
} else if (process.platform === 'darwin') {
if (process.arch === 'x64') {
try {
await spawn(
'rm', ['-rf', macjavax64file],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('rm error', err)
}
checkQortal()
} else {
try {
await spawn(
'rm', ['-rf', macjavaaarch64file],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('rm error', err)
}
checkQortal()
}
}
}
function checkQortal() {
if (fs.existsSync(qortaljar)) {
isRunning('qortal.jar', (status) => {
if (status == true) {
log.info("Core is running, perfect !")
} else {
1 year ago
if (!store.get('askingCore')) {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_13"), i18n.__("electron_translate_14")],
title: i18n.__("electron_translate_15"),
message: i18n.__("electron_translate_16"),
detail: i18n.__("electron_translate_17"),
checkboxLabel: i18n.__("electron_translate_28"),
checkboxChecked: false
}
1 year ago
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
startQortal()
store.set('askingCore', returnValue.checkboxChecked)
} else {
store.set('askingCore', returnValue.checkboxChecked)
6 months ago
1 year ago
}
})
}
}
})
} else {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_18"), i18n.__("electron_translate_19")],
title: i18n.__("electron_translate_20"),
message: i18n.__("electron_translate_21"),
detail: i18n.__("electron_translate_22")
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
downloadQortal()
} else {
6 months ago
}
})
}
}
async function downloadQortal() {
let qortalLoader = new BrowserWindow({
width: 500,
height: 500,
transparent: true,
frame: false,
alwaysOnTop: true,
show: false
})
await qortalLoader.loadFile(path.join(__dirname + '/splash/download.html'))
try {
qortalLoader.show()
await electronDl.download(myWindow, zipurl, {
directory: zipdir,
onProgress: function () { log.info("Starting Download Qortal") }
})
} catch (err) {
qortalLoader.destroy()
log.info('Download Qortal error', err)
}
qortalLoader.destroy()
await unzipQortal()
}
async function unzipQortal() {
try {
await extract(zipfile, { dir: zipdir })
log.info('Unzip Qortal complete')
} catch (err) {
log.info('Unzip Qortal error', err)
}
await chmodQortal()
}
async function chmodQortal() {
try {
await spawn(
'chmod', ['-R', '+x', qortaldir],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('chmod error', err)
}
await removeQortalZip()
}
async function removeQortalZip() {
try {
await spawn(
'rm', ['-rf', zipfile],
{ cwd: homePath, shell: true }
)
} catch (err) {
log.info('rm error', err)
}
await checkAndStart()
}
async function checkAndStart() {
try {
1 year ago
if (!store.get('askingCore')) {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_13"), i18n.__("electron_translate_14")],
title: i18n.__("electron_translate_15"),
message: i18n.__("electron_translate_16"),
detail: i18n.__("electron_translate_17"),
checkboxLabel: i18n.__("electron_translate_28"),
checkboxChecked: false
}
1 year ago
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
startQortal()
store.set('askingCore', returnValue.checkboxChecked)
} else {
store.set('askingCore', returnValue.checkboxChecked)
6 months ago
1 year ago
}
})
}
} catch (err) {
log.info('Sed error', err)
}
}
async function startQortal() {
if (process.platform === 'linux') {
switch (process.arch) {
case 'x64':
if (fs.existsSync(linjavax64bindir)) {
try {
await spawn(
'nohup', ['nice', '-n', '20', linjavax64binfile, '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
} else {
try {
await spawn(
'nohup', ['nice', '-n', '20', 'java', '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
}
break;
case 'arm64':
if (fs.existsSync(linjavaarm64bindir)) {
try {
await spawn(
'nohup', ['nice', '-n', '20', linjavaarm64binfile, '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
} else {
try {
await spawn(
'nohup', ['nice', '-n', '20', 'java', '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
}
break;
case 'arm':
if (fs.existsSync(linjavaarmbindir)) {
try {
await spawn(
'nohup', ['nice', '-n', '20', linjavaarmbinfile, '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
} else {
try {
await spawn(
'nohup', ['nice', '-n', '20', 'java', '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
}
break;
}
} else if (process.platform === 'darwin') {
if (process.arch === 'x64') {
if (fs.existsSync(macjavax64bindir)) {
try {
await spawn(
'nohup', ['nice', '-n', '20', macjavax64binfile, '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
} else {
try {
await spawn(
'nohup', ['nice', '-n', '20', 'java', '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
}
} else {
if (fs.existsSync(macjavaaarch64bindir)) {
try {
await spawn(
'nohup', ['nice', '-n', '20', macjavaaarch64binfile, '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
} else {
try {
await spawn(
'nohup', ['nice', '-n', '20', 'java', '-Djava.net.preferIPv4Stack=false', '-Xss256m', '-XX:+UseSerialGC', '-jar', qortaljar, qortalsettings, '1>run.log', '2>&1', '&'], {
cwd: qortaldir,
shell: true,
detached: true
}
)
} catch (err) {
log.info('Start qortal error', err)
}
}
}
}
}
3 years ago
3 years ago
const editMenu = Menu.buildFromTemplate([
{
label: "Qortal",
submenu: [
{ label: "Quit", click() { app.quit() } }
]
3 years ago
},
{
1 year ago
label: i18n.__("electron_translate_34"),
submenu: [{
label: i18n.__("electron_translate_31"),
click() {
const dialogOpts = {
type: 'info',
noLink: true,
buttons: [i18n.__("electron_translate_29"), i18n.__("electron_translate_30")],
title: i18n.__("electron_translate_31"),
message: i18n.__("electron_translate_32"),
detail: i18n.__("electron_translate_33"),
checkboxLabel: i18n.__("electron_translate_28"),
checkboxChecked: store.get('askingCore')
}
1 year ago
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
store.set('askingCore', returnValue.checkboxChecked)
} else {
store.set('askingCore', returnValue.checkboxChecked)
6 months ago
1 year ago
}
})
}
}]
},
{
label: "Edit",
submenu: [
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
{ type: "separator" },
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
]
},
{
label: "Check for update", click() { autoUpdater.checkForUpdatesAndNotify() }
3 years ago
}
])
3 years ago
Menu.setApplicationMenu(editMenu)
3 years ago
let myWindow = null
3 years ago
function createWindow() {
// Get saved window config, or default to empty object
let windowConfig = store.get('winBounds', {})
3 years ago
myWindow = new BrowserWindow({
backgroundColor: '#eee',
// Use saved size, or default values if config is empty
width: windowConfig.width || 1280,
height: windowConfig.height || 720,
3 years ago
minWidth: 700,
minHeight: 640,
icon: path.join(__dirname + '/img/icons/png/256x256.png'),
title: "Qortal UI",
3 years ago
autoHideMenuBar: true,
webPreferences: {
partition: 'persist:webviewsession',
nodeIntegration: true,
contextIsolation: true,
enableRemoteModule: false,
allowRunningInsecureContent: false,
experimentalFeatures: true,
preload: path.join(__dirname, '/lib/preload.js')
3 years ago
},
show: false
})
// Maximize window if saved config was maximized
if (store.get('isMaximized', false)) {
myWindow.maximize()
// Apply saved window position if config is not empty
} else if (windowConfig.x !== undefined && windowConfig.y !== undefined) {
myWindow.setPosition(windowConfig.x, windowConfig.y)
// Electron centers windows by default if position is not set
}
// Wait until window is ready before showing
myWindow.once('ready-to-show', myWindow.show)
1 year ago
myWindow.loadURL('http://localhost:12388/app')
// Save current window config when closing
myWindow.on('close', () => {
// Save current maximized state
const isMaximized = myWindow.isMaximized()
store.set('isMaximized', isMaximized)
// Save current size and position if not maximized
if (!isMaximized) {
store.set('winBounds', myWindow.getBounds())
}
})
3 years ago
myWindow.on('closed', function () {
myWindow = null
})
ipcMain.handle('dark-mode:toggle', () => {
if (nativeTheme.shouldUseDarkColors) {
nativeTheme.themeSource = 'light'
} else {
nativeTheme.themeSource = 'dark'
}
return nativeTheme.shouldUseDarkColors
})
ipcMain.handle('dark-mode:system', () => {
nativeTheme.themeSource = 'system'
})
3 years ago
}
let newWindow = null
function createNewWindow() {
newWindow = new BrowserWindow({
backgroundColor: '#eee',
width: 1280,
height: 720,
minWidth: 700,
minHeight: 640,
icon: path.join(__dirname + '/img/icons/png/256x256.png'),
title: "Qortal UI New Instance",
autoHideMenuBar: true,
webPreferences: {
partition: 'persist:webviewsession',
nodeIntegration: true,
contextIsolation: true,
enableRemoteModule: false,
allowRunningInsecureContent: false,
experimentalFeatures: false,
preload: path.join(__dirname, '/lib/preload.js')
},
show: false
})
newWindow.show()
1 year ago
newWindow.loadURL('http://localhost:12388/app')
newWindow.on('closed', function () {
newWindow = null
})
}
3 years ago
const createTray = () => {
let myTray = new Tray(path.join(__dirname + '/img/icons/png/tray/tray.png'))
const contextMenu = Menu.buildFromTemplate([
{
label: `Qortal UI v${app.getVersion()}`,
enabled: false
},
{
type: 'separator'
},
{
label: i18n.__("electron_translate_31"),
click: function () {
const dialogOpts = {
type: 'info',
noLink: true,
buttons: [i18n.__("electron_translate_29"), i18n.__("electron_translate_30")],
title: i18n.__("electron_translate_31"),
message: i18n.__("electron_translate_32"),
detail: i18n.__("electron_translate_33"),
checkboxLabel: i18n.__("electron_translate_28"),
checkboxChecked: store.get('askingCore')
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
store.set('askingCore', returnValue.checkboxChecked)
} else {
store.set('askingCore', returnValue.checkboxChecked)
6 months ago
}
})
},
},
{
type: 'separator'
},
{
label: i18n.__("electron_translate_1"),
click: function () {
myWindow.maximize()
myWindow.show()
}
},
{
label: i18n.__("electron_translate_2"),
click: function () {
myTray.destroy()
app.quit()
}
}
])
3 years ago
myTray.setTitle("QORTAL UI")
myTray.setToolTip(`Qortal UI v${app.getVersion()}`)
3 years ago
myTray.setContextMenu(contextMenu)
myTray.on("double-click", () => myWindow.maximize(), myWindow.show())
}
async function checkAll() {
if (process.platform === 'win32') {
app.setAppUserModelId("org.qortal.QortalUI")
await checkPort()
} else if (process.platform === 'darwin') {
await checkPort()
} else if (process.platform === 'linux') {
await checkPort()
} else {
const dl = new Notification({
title: "System Detector",
body: "No Supported Sytem Detected"
})
dl.show()
}
3 years ago
}
const isLock = app.requestSingleInstanceLock()
3 years ago
if (!isLock) {
app.quit()
3 years ago
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (myWindow) {
if (myWindow.isMinimized())
myWindow.maximize()
myWindow.show()
}
})
app.whenReady().then(async () => {
createWindow()
createTray()
if (!store.get('askingCore')) {
await checkAll()
}
await autoUpdater.checkForUpdatesAndNotify()
setInterval(() => {
autoUpdater.checkForUpdatesAndNotify()
}, 1000 * 60 * 720)
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
createTray()
}
})
3 years ago
})
3 years ago
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
3 years ago
}
})
3 years ago
ipcMain.on('app_version', (event) => {
log.info(app.getVersion())
myWindow.webContents.send('app_version', { version: app.getVersion() })
})
ipcMain.on('set-start-core', (event) => {
const dialogOpts = {
type: 'info',
noLink: true,
buttons: [i18n.__("electron_translate_29"), i18n.__("electron_translate_30")],
title: i18n.__("electron_translate_31"),
message: i18n.__("electron_translate_32"),
detail: i18n.__("electron_translate_33"),
checkboxLabel: i18n.__("electron_translate_28"),
checkboxChecked: store.get('askingCore')
}
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
store.set('askingCore', returnValue.checkboxChecked)
} else {
store.set('askingCore', returnValue.checkboxChecked)
6 months ago
}
})
})
ipcMain.on('clear-all-cache', (event) => {
const theWindows = BrowserWindow.getAllWindows()[0]
const ses = theWindows.webContents.session
console.clear()
ses.clearCache()
})
ipcMain.on('check-for-update', (event) => {
const check = new Notification({
title: i18n.__("electron_translate_43"),
body: i18n.__("electron_translate_44")
})
check.show()
autoUpdater.checkForUpdatesAndNotify()
})
ipcMain.on('start-core-electron', (event) => {
checkOsPlatform()
})
ipcMain.on('show-my-menu', (event) => {
let homePageOptions = Menu.buildFromTemplate([
{
label: i18n.__("electron_translate_35"),
role: 'copy'
},
{
label: i18n.__("electron_translate_36"),
role: 'paste'
},
{
type: "separator"
},
{
label: i18n.__("electron_translate_37"),
submenu: [
{
label: i18n.__("electron_translate_38"),
role: 'zoomIn'
},
{
label: i18n.__("electron_translate_39"),
role: 'zoomOut'
},
{
label: i18n.__("electron_translate_40"),
role: 'resetZoom'
},
{
type: 'separator'
},
{
label: i18n.__("electron_translate_41"),
role: 'togglefullscreen'
}
]
},
{
type: "separator"
},
{
label: i18n.__("electron_translate_42"),
click: function () {
createNewWindow()
},
}
])
homePageOptions.popup(myWindow)
})
autoUpdater.on('update-available', (event) => {
const downloadOpts = {
type: 'info',
buttons: ['YES', 'NO'],
title: i18n.__("electron_translate_3"),
detail: i18n.__("electron_translate_4")
}
dialog.showMessageBox(downloadOpts).then((returnValue) => {
if (returnValue.response === 0) {
autoUpdater.downloadUpdate()
const dl = new Notification({
title: i18n.__("electron_translate_11"),
body: i18n.__("electron_translate_12")
})
dl.show()
} else {
}
3 years ago
})
})
1 year ago
autoUpdater.on('update-not-available', (event) => {
log.info("NO UPDATE")
1 year ago
})
autoUpdater.on('download-progress', (progressObj) => {
myWindow.webContents.send('downloadProgress', progressObj)
3 years ago
})
3 years ago
autoUpdater.on('update-downloaded', (event) => {
const dialogOpts = {
type: 'info',
buttons: [i18n.__("electron_translate_5"), i18n.__("electron_translate_6")],
title: i18n.__("electron_translate_7"),
message: i18n.__("electron_translate_8"),
detail: i18n.__("electron_translate_9")
3 years ago
}
3 years ago
dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0) {
autoUpdater.quitAndInstall()
} else {
}
})
})
3 years ago
autoUpdater.on('error', (err) => {
const n = new Notification({
title: i18n.__("electron_translate_10"),
3 years ago
body: err
})
n.show()
3 years ago
})
ipcMain.on('focus-app', (event) => {
if (myWindow.isMinimized()) {
myWindow.restore()
}
myWindow.maximize()
myWindow.focus()
})
process.on('uncaughtException', function (err) {
log.info("*** WHOOPS TIME ***" + err)
})
}