- add gui electron application
! sometimes the tray icon does not open it's context menu
This commit is contained in:
parent
16a2549942
commit
013ad881d3
@ -11,8 +11,10 @@ You can download complete binaries from the release tab.
|
|||||||
## Development build
|
## Development build
|
||||||
1. Download the repository
|
1. Download the repository
|
||||||
2. `npm install` to install dependecies
|
2. `npm install` to install dependecies
|
||||||
3. `node index.js` to launch
|
3. `npm start` to launch
|
||||||
|
|
||||||
|
### Startup Arguments
|
||||||
|
One can pass a `--headless` argument to start the server in headless mode. This will disable the GUI.
|
||||||
## Packaging
|
## Packaging
|
||||||
This is more a comment for the future version of me. There is one command for packaging using nexe.
|
This is more a comment for the future version of me. There is one command for packaging using nexe.
|
||||||
```bash
|
```bash
|
||||||
|
2
electronAssets/background.svg
Normal file
2
electronAssets/background.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 97 KiB |
222
electronAssets/index2.html
Normal file
222
electronAssets/index2.html
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>openCountdown</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<style>
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: rgba(35, 35, 35, 1);
|
||||||
|
color: white;
|
||||||
|
font-family: 'Helvetica';
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrap {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
width: 200px;
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#actions {
|
||||||
|
padding: 10px;
|
||||||
|
display: block;
|
||||||
|
box-shadow: inset 0px 5px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
background-color: #d40215;
|
||||||
|
background-image: url("background.svg");
|
||||||
|
background-position: 60% 60%;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dobutton {
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: 0px;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#launch {
|
||||||
|
background-color: rgba(255, 255, 255, 1);
|
||||||
|
margin-right: 5px;
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hide {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
color: white;
|
||||||
|
margin-right: 5px;
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#close {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
color: white;
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
background-color: white;
|
||||||
|
-webkit-rtl-ordering: logical;
|
||||||
|
cursor: text;
|
||||||
|
padding: 1px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: inset;
|
||||||
|
border-color: initial;
|
||||||
|
border-image: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status,
|
||||||
|
#model {
|
||||||
|
user-select: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 100;
|
||||||
|
margin: 0;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#model {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 40px;
|
||||||
|
padding-top: 20px;
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#url {
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
-webkit-app-region: no-drag !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#meh {
|
||||||
|
background-color: #b00013;
|
||||||
|
background-image: url("background.svg");
|
||||||
|
background-position: 90% 90%;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea:focus,
|
||||||
|
input:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifs,
|
||||||
|
input[type='button'] {
|
||||||
|
-webkit-app-region: no-drag !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
-webkit-app-region: no-drag !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifp {
|
||||||
|
width: 50px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
background-color: #d40215;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #fff;
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
border: 1px solid white;
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifpb {
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #b00013;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid white;
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
border-left-width: 0px;
|
||||||
|
margin-top: -1px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifpb:hover {
|
||||||
|
background-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ift {
|
||||||
|
color: white;
|
||||||
|
-webkit-appearance: checkbox;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifs {
|
||||||
|
background-color: #d40215;
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid white;
|
||||||
|
font-size: 12px !important;
|
||||||
|
margin-bottom: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#guitext {
|
||||||
|
font-size: 12px;
|
||||||
|
color: white;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bottombuttons {
|
||||||
|
padding-bottom: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="wrap">
|
||||||
|
<div id="topwrap">
|
||||||
|
<img id="logo" src="../static/logo/logoProposal.svg" alt="openCountdown" />
|
||||||
|
<div id="model">model_text (version_etc)</div>
|
||||||
|
</div>
|
||||||
|
<div id="meh">
|
||||||
|
<h1 id="status">Status</h1>
|
||||||
|
<div id="url">URL</div>
|
||||||
|
</div>
|
||||||
|
<div id="actions">
|
||||||
|
<p><input type="text" maxlength="5" id="ifp" value="8000" /><input type="button" id="ifpb" value="Change" /></p>
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" id="ift" />
|
||||||
|
<label for="ift" style="font-size: 12px">Start minimized</label>
|
||||||
|
</p>
|
||||||
|
<div id="bottombuttons">
|
||||||
|
<input type="button" class="dobutton" value="Launch GUI" id="launch" />
|
||||||
|
<input type="button" class="dobutton" value="Hide" id="hide" />
|
||||||
|
<input type="button" class="dobutton" value="Quit" id="close" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="window.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
33
electronAssets/window.js
Normal file
33
electronAssets/window.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
document.getElementById('launch').addEventListener('click', function () {
|
||||||
|
api.send('skeleton-launch-gui')
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('hide').addEventListener('click', function () {
|
||||||
|
api.send('skeleton-minimize')
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('close').addEventListener('click', function () {
|
||||||
|
api.send('skeleton-close')
|
||||||
|
})
|
||||||
|
|
||||||
|
api.receive('info', function (info) {
|
||||||
|
document.getElementById('status').innerHTML = info.appStatus
|
||||||
|
document.getElementById('url').innerHTML = info.appURL
|
||||||
|
document.getElementById('model').innerHTML = `${info.appName}`
|
||||||
|
document.getElementById('ift').checked = info.startMinimised
|
||||||
|
document.getElementById('ifp').value = configObject.port
|
||||||
|
document.title = info.appName
|
||||||
|
})
|
||||||
|
api.send('info')
|
||||||
|
|
||||||
|
document.getElementById('ifpb').addEventListener('click', function () {
|
||||||
|
var e = document.getElementById('ifp')
|
||||||
|
api.send('skeleton-bind-port', e.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('ift').addEventListener('click', function () {
|
||||||
|
var e = document.getElementById('ift')
|
||||||
|
api.send('skeleton-start-minimised', e.checked)
|
||||||
|
})
|
||||||
|
|
||||||
|
api.send('skeleton-ready')
|
12
electronAssets/windowPreload.js
Normal file
12
electronAssets/windowPreload.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const { contextBridge, ipcRenderer } = require('electron')
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('api', {
|
||||||
|
send: (channel, data) => {
|
||||||
|
// whitelist channels
|
||||||
|
ipcRenderer.send(channel, data)
|
||||||
|
},
|
||||||
|
receive: (channel, func) => {
|
||||||
|
// Deliberately strip event as it includes `sender`
|
||||||
|
ipcRenderer.on(channel, (event, ...args) => func(...args))
|
||||||
|
},
|
||||||
|
})
|
7
index.js
7
index.js
@ -73,11 +73,12 @@ currentState = {
|
|||||||
srvTime: 0,
|
srvTime: 0,
|
||||||
enableColoredText: true,
|
enableColoredText: true,
|
||||||
debug: false,
|
debug: false,
|
||||||
sessionToken: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
sessionToken: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15),
|
||||||
};
|
};
|
||||||
|
|
||||||
let configObject = {
|
let configObject = {
|
||||||
language: "en_uk"
|
language: "en_uk",
|
||||||
|
port: 3000
|
||||||
}
|
}
|
||||||
if(!fs.existsSync("config.json")) {
|
if(!fs.existsSync("config.json")) {
|
||||||
fs.writeFileSync("config.json", "{}");
|
fs.writeFileSync("config.json", "{}");
|
||||||
@ -463,7 +464,7 @@ app.use(function (req, res, next) {
|
|||||||
|
|
||||||
loggy.log("Starting server", "info", "Server");
|
loggy.log("Starting server", "info", "Server");
|
||||||
|
|
||||||
const port = 3006;
|
const port = configObject.port;
|
||||||
|
|
||||||
process.on('SIGINT', function () {
|
process.on('SIGINT', function () {
|
||||||
loggy.log("Caught interrupt signal and shutting down gracefully", "info", "Shutdown");
|
loggy.log("Caught interrupt signal and shutting down gracefully", "info", "Shutdown");
|
||||||
|
@ -1 +1 @@
|
|||||||
[{"timestamp":"2022-08-18 16:11:01.607","level":"info","module":"Logging","message":"2022-08-18 16:11:01.607 [info] [Logging] Logging initialized"},{"timestamp":"2022-08-18 16:11:01.608","level":"info","module":"Server","message":"2022-08-18 16:11:01.608 [info] [Server] Preparing server"},{"timestamp":"2022-08-18 16:11:01.609","level":"info","module":"Server","message":"2022-08-18 16:11:01.609 [info] [Server] Preparing static routes"},{"timestamp":"2022-08-18 16:11:01.610","level":"info","module":"Server","message":"2022-08-18 16:11:01.610 [info] [Server] Preparing middlewares"},{"timestamp":"2022-08-18 16:11:01.611","level":"info","module":"Config","message":"2022-08-18 16:11:01.611 [info] [Config] Loading config"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Language","message":"2022-08-18 16:11:01.612 [info] [Language] Searching for languages"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Language","message":"2022-08-18 16:11:01.612 [info] [Language] Found 3 languages"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Language","message":"2022-08-18 16:11:01.612 [info] [Language] Reading language file"},{"timestamp":"2022-08-18 16:11:01.612","level":"info","module":"Websocket","message":"2022-08-18 16:11:01.612 [info] [Websocket] Preparing websocket"},{"timestamp":"2022-08-18 16:11:01.613","level":"info","module":"Server","message":"2022-08-18 16:11:01.613 [info] [Server] Preparing routes"},{"timestamp":"2022-08-18 16:11:01.614","level":"info","module":"Server","message":"2022-08-18 16:11:01.614 [info] [Server] Starting server"},{"timestamp":"2022-08-18 16:13:27.222","level":"error","module":"Security","message":"2022-08-18 16:13:27.222 [error] [Security] Attempt to access restricted asset file mdbootstrap/js/mdb.min.js"},{"timestamp":"2022-08-18 16:13:27.674","level":"error","module":"Security","message":"2022-08-18 16:13:27.674 [error] [Security] Attempt to access restricted asset file mdbootstrap/js/mdb.min.js"},{"timestamp":"2022-08-18 16:13:46.931","level":"info","module":"Shutdown","message":"2022-08-18 16:13:46.931 [info] [Shutdown] Caught interrupt signal and shutting down gracefully"}]
|
[{"timestamp":"2022-08-18 16:19:06.649","level":"info","module":"Logging","message":"2022-08-18 16:19:06.649 [info] [Logging] Logging initialized"},{"timestamp":"2022-08-18 16:19:06.651","level":"info","module":"Server","message":"2022-08-18 16:19:06.651 [info] [Server] Preparing server"},{"timestamp":"2022-08-18 16:19:06.652","level":"info","module":"Server","message":"2022-08-18 16:19:06.652 [info] [Server] Preparing static routes"},{"timestamp":"2022-08-18 16:19:06.654","level":"info","module":"Server","message":"2022-08-18 16:19:06.654 [info] [Server] Preparing middlewares"},{"timestamp":"2022-08-18 16:19:06.655","level":"info","module":"Config","message":"2022-08-18 16:19:06.655 [info] [Config] Loading config"},{"timestamp":"2022-08-18 16:19:06.658","level":"info","module":"Language","message":"2022-08-18 16:19:06.658 [info] [Language] Searching for languages"},{"timestamp":"2022-08-18 16:19:06.659","level":"info","module":"Language","message":"2022-08-18 16:19:06.659 [info] [Language] Found 3 languages"},{"timestamp":"2022-08-18 16:19:06.659","level":"info","module":"Language","message":"2022-08-18 16:19:06.659 [info] [Language] Reading language file"},{"timestamp":"2022-08-18 16:19:06.675","level":"info","module":"Websocket","message":"2022-08-18 16:19:06.675 [info] [Websocket] Preparing websocket"},{"timestamp":"2022-08-18 16:19:06.675","level":"info","module":"Server","message":"2022-08-18 16:19:06.675 [info] [Server] Preparing routes"},{"timestamp":"2022-08-18 16:19:06.678","level":"info","module":"Server","message":"2022-08-18 16:19:06.678 [info] [Server] Starting server"},{"timestamp":"2022-08-18 16:22:57.338","level":"info","module":"Shutdown","message":"2022-08-18 16:22:57.338 [info] [Shutdown] Caught interrupt signal and shutting down gracefully"}]
|
191
newStartHandler.js
Normal file
191
newStartHandler.js
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
const { app, BrowserWindow, ipcMain, Tray, Menu, nativeImage, MenuItem, dialog } = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
const fs = require('fs')
|
||||||
|
const _ = require("underscore")
|
||||||
|
const open = require('open');
|
||||||
|
const childProcess = require('child_process');
|
||||||
|
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync("package.json"))
|
||||||
|
|
||||||
|
// a minimal config
|
||||||
|
let configObject = {
|
||||||
|
language: "en_uk",
|
||||||
|
startMinimised: false,
|
||||||
|
port: 3000
|
||||||
|
}
|
||||||
|
if (!fs.existsSync("config.json")) {
|
||||||
|
fs.writeFileSync("config.json", "{}");
|
||||||
|
}
|
||||||
|
const tempJsonText = JSON.parse(fs.readFileSync("config.json", "utf8"));
|
||||||
|
configObject = _.extend(configObject, tempJsonText);
|
||||||
|
fs.writeFileSync("config.json", JSON.stringify(configObject));
|
||||||
|
|
||||||
|
const processArgs = process.argv;
|
||||||
|
// Check if --headless is passed as an argument
|
||||||
|
if (processArgs.includes("--headless")) {
|
||||||
|
startServer()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Start electron
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
startServer()
|
||||||
|
createTray()
|
||||||
|
createWindow()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('info', function () {
|
||||||
|
if (win) {
|
||||||
|
win.webContents.send('info', { "appStatus": "Testing", "appURL": "http://127.0.0.1:" + configObject.port, "appName": "openCountdown " + packageJson.version, "startMinimised": configObject.startMinimised, "port": configObject.port })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('skeleton-close', function (req, cb) {
|
||||||
|
trayQuit()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('skeleton-minimize', function (req, cb) {
|
||||||
|
win.hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('skeleton-launch-gui', function () {
|
||||||
|
launchUI()
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('skeleton-start-minimised', function (e, msg) {
|
||||||
|
configObject.startMinimised = msg
|
||||||
|
fs.writeFileSync("config.json", JSON.stringify(configObject));
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.on('skeleton-bind-port', function (e, msg) {
|
||||||
|
configObject.port = msg
|
||||||
|
console.log("Update port")
|
||||||
|
fs.writeFileSync("config.json", JSON.stringify(configObject));
|
||||||
|
dialog.showMessageBoxSync({
|
||||||
|
message: "Port changed. Restart openCountdown to apply change.",
|
||||||
|
buttons: ["OK"]})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var win, tray = null;
|
||||||
|
|
||||||
|
|
||||||
|
const createWindow = () => {
|
||||||
|
win = new BrowserWindow({
|
||||||
|
width: 370,
|
||||||
|
height: 500,
|
||||||
|
transparent: true,
|
||||||
|
frame: false,
|
||||||
|
resizable: false,
|
||||||
|
icon: path.join(__dirname, 'static/logo/faviconLogo.svg'),
|
||||||
|
webPreferences: {
|
||||||
|
pageVisibility: true,
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: true,
|
||||||
|
preload: path.join(__dirname, 'electronAssets/windowPreload.js'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
win.loadFile('electronAssets/index2.html')
|
||||||
|
if (configObject.startMinimised) {
|
||||||
|
win.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTray() {
|
||||||
|
tray = new Tray('static/logo/faviconLogo.png')
|
||||||
|
tray.setIgnoreDoubleClickEvents(true)
|
||||||
|
|
||||||
|
const menu = new Menu()
|
||||||
|
menu.append(
|
||||||
|
new MenuItem({
|
||||||
|
label: 'Show window',
|
||||||
|
click: showScreen,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
menu.append(
|
||||||
|
new MenuItem({
|
||||||
|
label: 'Launch GUI',
|
||||||
|
click: launchUI,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
menu.append(
|
||||||
|
new MenuItem({
|
||||||
|
label: 'Quit',
|
||||||
|
accelerator: 'Command+Q',
|
||||||
|
click: trayQuit,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
tray.setToolTip('openCountdown ' + packageJson.version)
|
||||||
|
tray.setContextMenu(menu)
|
||||||
|
|
||||||
|
tray.on('click', function (e) {
|
||||||
|
if (win.isVisible()) {
|
||||||
|
win.hide()
|
||||||
|
} else {
|
||||||
|
win.show()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showScreen(){
|
||||||
|
win.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
function launchUI(){
|
||||||
|
open("http://127.0.0.1:" + configObject.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
function trayQuit(){
|
||||||
|
let options = {
|
||||||
|
buttons: ["Yes","No"],
|
||||||
|
message: "Do you really want to quit openCountdown?"
|
||||||
|
}
|
||||||
|
let response = dialog.showMessageBoxSync(options)
|
||||||
|
if(response == 0){
|
||||||
|
srvProc.kill("SIGINT")
|
||||||
|
setTimeout(app.quit, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// taken from https://stackoverflow.com/a/22649812/11317151
|
||||||
|
function runScript(scriptPath, callback, valueCb) {
|
||||||
|
|
||||||
|
// keep track of whether callback has been invoked to prevent multiple invocations
|
||||||
|
var invoked = false;
|
||||||
|
|
||||||
|
var process = childProcess.fork(scriptPath);
|
||||||
|
|
||||||
|
valueCb(process)
|
||||||
|
// listen for errors as they may prevent the exit event from firing
|
||||||
|
process.on('error', function (err) {
|
||||||
|
if (invoked) return;
|
||||||
|
invoked = true;
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
// execute the callback once the process has finished running
|
||||||
|
process.on('exit', function (code) {
|
||||||
|
if (invoked) return;
|
||||||
|
invoked = true;
|
||||||
|
// var err = code === 0 ? null : new Error('exit code ' + code);
|
||||||
|
callback(code);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
srvProc = null;
|
||||||
|
|
||||||
|
function setServer(process){
|
||||||
|
srvProc = process
|
||||||
|
}
|
||||||
|
|
||||||
|
function startServer(){
|
||||||
|
runScript(path.join(__dirname, 'index.js'), function (err) {
|
||||||
|
if (err) throw err;
|
||||||
|
}, setServer)
|
||||||
|
}
|
1643
package-lock.json
generated
1643
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "opencountdown",
|
"name": "opencountdown",
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"description": "An opensource countdown",
|
"description": "An opensource countdown",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "nexe index.js --build"
|
"build": "nexe index.js --build",
|
||||||
|
"start": "electron newStartHandler.js"
|
||||||
},
|
},
|
||||||
"author": "TheGreydiamond",
|
"author": "TheGreydiamond",
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
@ -23,7 +24,11 @@
|
|||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"less": "^3.13",
|
"less": "^3.13",
|
||||||
"mdbootstrap": "^4.20.0",
|
"mdbootstrap": "^4.20.0",
|
||||||
|
"open": "^8.4.0",
|
||||||
"underscore": "^1.13.3",
|
"underscore": "^1.13.3",
|
||||||
"ws": "^8.5.0"
|
"ws": "^8.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"electron": "^20.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
static/logo/faviconLogo.png
Normal file
BIN
static/logo/faviconLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Loading…
Reference in New Issue
Block a user