Split client into frontend website and server

This commit is contained in:
Pax1601 2024-02-08 22:04:23 +01:00
parent 55f3bd5adb
commit 5ca6c97cbe
792 changed files with 149898 additions and 13872 deletions

BIN
DCS Olympus Manager.lnk Normal file

Binary file not shown.

View File

@ -1,2 +0,0 @@
{
}

View File

@ -1,18 +0,0 @@
FROM node:20-alpine AS appbuild
WORKDIR /usr/src/app
COPY package.json ./
COPY package-lock.json ./
RUN npm install
COPY . .
RUN npm run build-release-linux
FROM node:20-alpine
WORKDIR /usr/src/app
COPY package.json ./
COPY package-lock.json ./
RUN npm install --omit=dev
COPY . .
COPY --from=appbuild /usr/src/app/public ./public
EXPOSE 3000
CMD npm start

View File

@ -1,124 +0,0 @@
const yargs = require('yargs');
var fs = require('fs');
/* Define configuration parameter */
yargs.alias('c', 'config').describe('c', 'olympus.json config location').string('rp');
args = yargs.argv;
console.log('\x1b[36m%s\x1b[0m', "*********************************************************************");
console.log('\x1b[36m%s\x1b[0m', "* _____ _____ _____ ____ _ *");
console.log('\x1b[36m%s\x1b[0m', "* | __ \\ / ____|/ ____| / __ \\| | *");
console.log('\x1b[36m%s\x1b[0m', "* | | | | | | (___ | | | | |_ _ _ __ ___ _ __ _ _ ___ *");
console.log('\x1b[36m%s\x1b[0m', "* | | | | | \\___ \\ | | | | | | | | '_ ` _ \\| '_ \\| | | / __| *");
console.log('\x1b[36m%s\x1b[0m', "* | |__| | |____ ____) | | |__| | | |_| | | | | | | |_) | |_| \\__ \\ *");
console.log('\x1b[36m%s\x1b[0m', "* |_____/ \\_____|_____/ \\____/|_|\\__, |_| |_| |_| .__/ \\__,_|___/ *");
console.log('\x1b[36m%s\x1b[0m', "* __/ | | | *");
console.log('\x1b[36m%s\x1b[0m', "* |___/ |_| *");
console.log('\x1b[36m%s\x1b[0m', "*********************************************************************");
console.log('\x1b[36m%s\x1b[0m', "");
console.log("Please wait while DCS Olympus DEMO Backend Server starts up...");
console.log(`Config location: ${args["config"]}`)
var fs = require('fs');
let rawdata = fs.readFileSync(args["config"]);
let config = JSON.parse(rawdata);
/**
* Module dependencies.
*/
var app = require('../demo')(args["config"]);
var debug = require('debug')('client:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var configPort = null;
if (config["server"] != undefined && config["server"]["port"] != undefined) {
configPort = config["server"]["port"];
}
var port = normalizePort(configPort || '3000');
app.set('port', port);
console.log("Express server listening on port: " + port)
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
console.log("DCS Olympus DEMO Backend Server {{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}} started correctly!")
console.log("Waiting for connections...")
process.title = `DCS Olympus DEMO Backend Server {{OLYMPUS_VERSION_NUMBER}} (${port})`;

View File

@ -1,102 +0,0 @@
const yargs = require('yargs');
var fs = require('fs');
/* Define configuration parameter */
yargs.alias('c', 'config').describe('c', 'olympus.json config location').string('rp');
args = yargs.argv;
console.log('\x1b[36m%s\x1b[0m', "*********************************************************************");
console.log('\x1b[36m%s\x1b[0m', "* _____ _____ _____ ____ _ *");
console.log('\x1b[36m%s\x1b[0m', "* | __ \\ / ____|/ ____| / __ \\| | *");
console.log('\x1b[36m%s\x1b[0m', "* | | | | | | (___ | | | | |_ _ _ __ ___ _ __ _ _ ___ *");
console.log('\x1b[36m%s\x1b[0m', "* | | | | | \\___ \\ | | | | | | | | '_ ` _ \\| '_ \\| | | / __| *");
console.log('\x1b[36m%s\x1b[0m', "* | |__| | |____ ____) | | |__| | | |_| | | | | | | |_) | |_| \\__ \\ *");
console.log('\x1b[36m%s\x1b[0m', "* |_____/ \\_____|_____/ \\____/|_|\\__, |_| |_| |_| .__/ \\__,_|___/ *");
console.log('\x1b[36m%s\x1b[0m', "* __/ | | | *");
console.log('\x1b[36m%s\x1b[0m', "* |___/ |_| *");
console.log('\x1b[36m%s\x1b[0m', "*********************************************************************");
console.log('\x1b[36m%s\x1b[0m', "");
console.log("Please wait while DCS Olympus Server starts up...");
console.log(`Config location: ${args["config"]}`)
/* Load the configuration file */
var clientPort = 0;
if (fs.existsSync(args["config"])) {
var json = JSON.parse(fs.readFileSync(args["config"], 'utf-8'));
clientPort = json["client"]["port"];
} else {
console.log("Failed to read config, aborting!");
return;
}
/* Load the dependencies. The app is loaded providing the configuration file location */
var app = require('../app')(args["config"]);
var debug = require('debug')('client:server');
var http = require('http');
/* Normalize port */
var port = normalizePort(clientPort);
app.set('port', port);
console.log("Express server listening on port: " + port)
/* Create HTTP server */
var server = http.createServer(app);
/* Listen on provided port, on all network interfaces. */
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/* Normalize a port into a number, string, or false. */
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
}
/* Event listener for HTTP server "error" event. */
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
/* Handle specific listen errors with friendly messages */
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/* Event listener for HTTP server "listening" event. */
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
/* Final user friendly printing */
console.log("DCS Olympus server {{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}} started correctly!")
console.log("Waiting for connections...")
process.title = `DCS Olympus server {{OLYMPUS_VERSION_NUMBER}} (${port})`;

View File

@ -1,194 +0,0 @@
const fs = require('fs')
const path = require('path')
const yargs = require('yargs');
const prompt = require('prompt-sync')({sigint: true});
const sha256 = require('sha256');
var jsonPath = path.join('..', 'olympus.json');
var regedit = require('regedit')
const shellFoldersKey = 'HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders'
const saveGamesKey = '{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}'
/* Set the acceptable values */
yargs.alias('a', 'address').describe('a', 'Backend address').string('a');
yargs.alias('b', 'backendPort').describe('b', 'Backend port').number('b');
yargs.alias('c', 'clientPort').describe('c', 'Client port').number('c');
yargs.alias('p', 'gameMasterPassword').describe('p', 'Game Master password').string('p');
yargs.alias('bp', 'blueCommanderPassword').describe('bp', 'Blue Commander password').string('bp');
yargs.alias('rp', 'redCommanderPassword').describe('rp', 'Red Commander password').string('rp');
yargs.alias('d', 'directory').describe('d', 'Directory where the DCS Olympus configurator is located').string('rp');
args = yargs.argv;
async function run() {
/* Check that we can read the json */
if (fs.existsSync(jsonPath)) {
var json = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
var address = args.address ?? json["server"]["address"];
var clientPort = args.clientPort ?? json["client"]["port"];
var backendPort = args.backendPort ?? json["server"]["port"];
var gameMasterPassword = args.gameMasterPassword? sha256(args.gameMasterPassword): json["authentication"]["gameMasterPassword"];
var blueCommanderPassword = args.blueCommanderPassword? sha256(args.blueCommanderPassword): json["authentication"]["blueCommanderPassword"];
var redCommanderPassword = args.redCommanderPassword? sha256(args.redCommanderPassword): json["authentication"]["redCommanderPassword"];
/* Run in interactive mode */
if (args.address === undefined && args.clientPort === undefined && args.backendPort === undefined &&
args.gameMasterPassword === undefined && args.blueCommanderPassword === undefined && args.redCommanderPassword === undefined) {
var newValue;
var result;
/* Get the new address */
newValue = prompt(`Insert an address or press Enter to keep current value ${address}. Use * for any address: `);
address = newValue !== ""? newValue: address;
/* Get the new client port */
while (true) {
newValue = prompt(`Insert a client port or press Enter to keep current value ${clientPort}. Integers between 1025 and 65535: `);
if (newValue === "")
break;
result = Number(newValue);
if (!isNaN(result) && Number.isInteger(result) && result > 1024 && result <= 65535)
break;
}
clientPort = newValue? result: clientPort;
/* Get the new backend port */
while (true) {
newValue = prompt(`Insert a backend port or press Enter to keep current value ${backendPort}. Integers between 1025 and 65535: `);
if (newValue === "")
break;
result = Number(newValue);
if (!isNaN(result) && Number.isInteger(result) && result > 1024 && result <= 65535 && result != clientPort)
break;
if (result === clientPort)
console.log("Client port and backend port must be different.");
}
backendPort = newValue? result: backendPort;
/* Get the new Game Master password */
while (true) {
newValue = prompt(`Insert a new Game Master password or press Enter to keep current value: `, {echo: "*"});
gameMasterPassword = newValue !== ""? sha256(newValue): gameMasterPassword;
// Check if Game Master password is unique
if (gameMasterPassword === blueCommanderPassword || gameMasterPassword === redCommanderPassword) {
console.log("Game Master password must be different from other passwords. Please try again.");
continue;
}
break;
}
/* Get the new Blue Commander password */
while (true) {
newValue = prompt(`Insert a new Blue Commander password or press Enter to keep current value: `, {echo: "*"});
blueCommanderPassword = newValue !== ""? sha256(newValue): blueCommanderPassword;
// Check if Blue Commander password is unique
if (blueCommanderPassword === gameMasterPassword || blueCommanderPassword === redCommanderPassword) {
console.log("Blue Commander password must be different from other passwords. Please try again.");
continue;
}
break;
}
/* Get the new Red Commander password */
while (true) {
newValue = prompt(`Insert a new Red Commander password or press Enter to keep current value: `, {echo: "*"});
redCommanderPassword = newValue !== ""? sha256(newValue): redCommanderPassword;
// Check if Red Commander password is unique
if (redCommanderPassword === gameMasterPassword || redCommanderPassword === blueCommanderPassword) {
console.log("Red Commander password must be different from other passwords. Please try again.");
continue;
}
break;
}
}
/* Apply the inputs */
json["server"]["address"] = address;
json["client"]["port"] = clientPort;
json["server"]["port"] = backendPort;
json["authentication"]["gameMasterPassword"] = gameMasterPassword;
json["authentication"]["blueCommanderPassword"] = blueCommanderPassword;
json["authentication"]["redCommanderPassword"] = redCommanderPassword;
/* Write the result to disk */
const serialized = JSON.stringify(json, null, 4);
fs.writeFileSync(jsonPath, serialized, 'utf8');
console.log("Olympus.json updated correctly, goodbye!");
}
else {
console.error("Error, could not read olympus.json file!")
}
/* Wait a bit before closing the window */
await new Promise(resolve => setTimeout(resolve, 3000));
}
console.log('\x1b[36m%s\x1b[0m', "*********************************************************************");
console.log('\x1b[36m%s\x1b[0m', "* _____ _____ _____ ____ _ *");
console.log('\x1b[36m%s\x1b[0m', "* | __ \\ / ____|/ ____| / __ \\| | *");
console.log('\x1b[36m%s\x1b[0m', "* | | | | | | (___ | | | | |_ _ _ __ ___ _ __ _ _ ___ *");
console.log('\x1b[36m%s\x1b[0m', "* | | | | | \\___ \\ | | | | | | | | '_ ` _ \\| '_ \\| | | / __| *");
console.log('\x1b[36m%s\x1b[0m', "* | |__| | |____ ____) | | |__| | | |_| | | | | | | |_) | |_| \\__ \\ *");
console.log('\x1b[36m%s\x1b[0m', "* |_____/ \\_____|_____/ \\____/|_|\\__, |_| |_| |_| .__/ \\__,_|___/ *");
console.log('\x1b[36m%s\x1b[0m', "* __/ | | | *");
console.log('\x1b[36m%s\x1b[0m', "* |___/ |_| *");
console.log('\x1b[36m%s\x1b[0m', "*********************************************************************");
console.log('\x1b[36m%s\x1b[0m', "");
console.log("DCS Olympus configurator {{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}");
console.log("");
/* Run the configurator */
if (args.directory) {
jsonPath = path.join(args.directory, "olympus.json");
}
else {
/* Automatically detect possible DCS installation folders */
regedit.list(shellFoldersKey, function(err, result) {
if (err) {
console.log(err);
}
else {
if (result[shellFoldersKey] !== undefined && result[shellFoldersKey]["exists"] && result[shellFoldersKey]['values'][saveGamesKey] !== undefined && result[shellFoldersKey]['values'][saveGamesKey]['value'] !== undefined)
{
const searchpath = result[shellFoldersKey]['values'][saveGamesKey]['value'];
const folders = fs.readdirSync(searchpath);
var options = [];
folders.forEach((folder) => {
if (fs.existsSync(path.join(searchpath, folder, "Logs", "dcs.log"))) {
options.push(folder);
}
})
console.log("The following DCS Saved Games folders have been automatically detected.")
options.forEach((folder, index) => {
console.log(`(${index + 1}) ${folder}`)
});
while (true) {
var newValue = prompt(`Please choose a folder onto which the configurator shall operate by typing the associated number: `)
result = Number(newValue);
if (!isNaN(result) && Number.isInteger(result) && result > 0 && result <= options.length) {
jsonPath = path.join(searchpath, options[result - 1], "Config", "olympus.json");
break;
}
else {
console.log(`Please type a number between 1 and ${options.length}`);
}
}
} else {
console.error("An error occured while trying to fetch the location of the DCS folder. Please type the folder location manually.")
jsonPath = path.join(prompt(`DCS Saved Games folder location: `), "olympus.json");
}
console.log(`Configurator will run on ${jsonPath}, if this is incorrect please restart the configurator`)
run();
}
})
}

View File

@ -1,4 +0,0 @@
cp ./node_modules/leaflet/dist/leaflet.css ./public/stylesheets/leaflet/leaflet.css
cp ./node_modules/leaflet-gesture-handling/dist/leaflet-gesture-handling.css ./public/stylesheets/leaflet/leaflet-gesture-handling.css
cp ./node_modules/leaflet.nauticscale/dist/leaflet.nauticscale.js ./public/javascripts/leaflet.nauticscale.js
cp ./node_modules/leaflet-path-drag/dist/L.Path.Drag.js ./public/javascripts/L.Path.Drag.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,661 +0,0 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

View File

@ -1,4 +0,0 @@
cd scripts
call copy.bat
cd ..
call browserify ./src/index.ts --debug -o ./public/javascripts/bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]

View File

@ -1,15 +0,0 @@
cd scripts
call copy.bat
cd ..
call browserify ./src/index.ts -o ./public/javascripts/bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]
echo D|xcopy /Y /S /E .\bin ..\build\client\bin
echo D|xcopy /Y /S /E .\public ..\build\client\public
echo D|xcopy /Y /S /E .\routes ..\build\client\routes
echo D|xcopy /Y /S /E .\views ..\build\client\views
echo F|xcopy /Y .\app.js ..\build\client\app.js
echo F|xcopy /Y .\client.js ..\build\client\client.js
echo F|xcopy /Y .\package.json ..\build\client\package.json
echo F|xcopy /Y /I .\*.vbs ..\build\client

View File

@ -1,6 +0,0 @@
cd ..
echo F|xcopy /Y .\node_modules\leaflet\dist\leaflet.css .\public\stylesheets\leaflet\leaflet.css
echo F|xcopy /Y .\node_modules\leaflet-gesture-handling\dist\leaflet-gesture-handling.css .\public\stylesheets\leaflet\leaflet-gesture-handling.css
echo F|xcopy /Y .\node_modules\leaflet.nauticscale\dist\leaflet.nauticscale.js .\public\javascripts\leaflet.nauticscale.js
echo F|xcopy /Y .\node_modules\leaflet-path-drag\dist\L.Path.Drag.js .\public\javascripts\L.Path.Drag.js
cd scripts

View File

@ -1,10 +0,0 @@
cd scripts
call ./copy.bat
cd ..
REM create a "fake" dcs Saved Games folder
mkdir "%temp%\DCS Olympus\dcs"
echo F|xcopy /Y "..\olympus.json" "%temp%\DCS Olympus\dcs\Config\olympus.json"
echo D|xcopy /Y /S /E "..\databases" "%temp%\DCS Olympus\dcs\Mods\Services\Olympus\databases"
concurrently --kill-others "node ./bin/demo --config \"%temp%\DCS Olympus\dcs\Config\olympus.json\"" "npm run watch" "nodemon --ignore ./public/databases/ ./bin/www -- --config \"%temp%\DCS Olympus\dcs\Config\olympus.json\""

View File

@ -1,7 +0,0 @@
@echo off
cd scripts
call ./copy.bat
cd ..
set /p "config=Enter DCS Saved Games folder location: "
concurrently --kill-others "npm run watch" "nodemon --ignore ./public/databases/ ./bin/www -- --config \"%config%\Config\Olympus.json\""

View File

@ -1 +0,0 @@
watchify ./src/index.ts --debug -o ./public/javascripts/bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]

View File

@ -1,82 +0,0 @@
import Ajv from "ajv";
import { AnySchemaObject } from "ajv/dist/core";
// For future extension
abstract class JSONSchemaValidator {
#ajv:Ajv;
#compiledValidator:any;
#schema!:AnySchemaObject;
constructor( schema:AnySchemaObject ) {
this.#schema = schema;
this.#ajv = new Ajv({
"allErrors": true
});
this.#compiledValidator = this.getAjv().compile(this.getSchema());
}
getAjv() {
return this.#ajv;
}
getCompiledValidator() {
return this.#compiledValidator;
}
getErrors() {
return this.getCompiledValidator().errors;
}
getSchema() {
return this.#schema;
}
validate(data:any) {
return (this.getCompiledValidator())(data);
}
}
export class AirbasesJSONSchemaValidator extends JSONSchemaValidator {
constructor() {
const schema = require("../schemas/airbases.schema.json");
super( schema );
[
require( "../../public/databases/airbases/caucasus.json" ),
require( "../../public/databases/airbases/falklands.json" ),
require( "../../public/databases/airbases/marianas.json" ),
require( "../../public/databases/airbases/nevada.json" ),
require( "../../public/databases/airbases/normandy.json" ),
require( "../../public/databases/airbases/persiangulf.json" ),
require( "../../public/databases/airbases/sinaimap.json" ),
require( "../../public/databases/airbases/syria.json" ),
require( "../../public/databases/airbases/thechannel.json" )
].forEach( data => {
const validate = this.getAjv().compile(this.getSchema());
const valid = validate(data);
if (!valid) console.error(validate.errors);
});
}
}
export class ImportFileJSONSchemaValidator extends JSONSchemaValidator {
constructor() {
const schema = require("../schemas/importdata.schema.json");
super( schema );
}
}

View File

@ -1,9 +0,0 @@
version: '3'
services:
client:
build: client
ports:
- 3000:3000
volumes:
- ./olympus.json:/usr/src/olympus.json

View File

@ -0,0 +1,5 @@
{
"recommendations": [
"rioj7.command-variable"
]
}

42
frontend/server/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Server (DCS)",
"skipFiles": [
"<node_internals>/**"
],
"args": ["--config", "${input:enterDir}/Config/olympus.json"],
"program": "./bin/www",
"preLaunchTask": "prepare-dcs"
},
{
"type": "node",
"request": "launch",
"name": "Launch Server (No DCS)",
"skipFiles": [
"<node_internals>/**"
],
"args": ["--config", "${input:enterDir}/Config/olympus.json"],
"program": "./bin/www",
"preLaunchTask": "demo-server"
}
],
"inputs": [
{
"id": "enterDir",
"type": "command",
"command": "extension.commandvariable.promptStringRemember",
"args": {
"key": "dir",
"description": "DCS Saved Games folder (leave default for mock dcs)",
"default": "../../mock-dcs"
}
}
]
}

28
frontend/server/.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,28 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "copy-website",
"type": "shell",
"command": "./scripts/copy.bat",
"isBackground": false
},
{
"label": "demo-server",
"type": "shell",
"command": "./scripts/demo-server.bat",
"args": ["${input:enterDir}/Config/olympus.json"],
"isBackground": true
}
],
"inputs": [
{
"id": "enterDir",
"type": "command",
"command": "extension.commandvariable.remember",
"args": { "key": "dir" }
}
]
}

View File

@ -0,0 +1,31 @@
{
"name": "DCSOlympus Server",
"main": "client.js",
"version": "{{OLYMPUS_VERSION_NUMBER}}",
"scripts": {
"build-release": "call ./scripts/build-release.bat",
"server": "node ./bin/www",
"client": "electron ."
},
"private": true,
"dependencies": {
"appjs": "^0.0.20",
"appjs-win32": "^0.0.19",
"body-parser": "^1.20.2",
"debug": "~2.6.9",
"ejs": "^3.1.8",
"electron": "^28.0.0",
"express": "^4.18.2",
"express-basic-auth": "^1.2.1",
"http-proxy-middleware": "^2.0.6",
"morgan": "~1.9.1",
"open": "^10.0.0",
"regedit": "^5.1.2",
"save": "^2.9.0",
"sha256": "^0.2.0",
"srtm-elevation": "^2.1.2",
"tcp-ping-port": "^1.0.1",
"uuid": "^9.0.1",
"yargs": "^17.7.2"
}
}

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 251 B

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 756 B

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 228 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 237 B

After

Width:  |  Height:  |  Size: 237 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 556 B

View File

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 509 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 613 B

View File

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

View File

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 287 B

View File

Before

Width:  |  Height:  |  Size: 353 B

After

Width:  |  Height:  |  Size: 353 B

View File

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 283 B

View File

Before

Width:  |  Height:  |  Size: 252 B

After

Width:  |  Height:  |  Size: 252 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

View File

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 231 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 221 B

View File

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 549 B

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 582 B

After

Width:  |  Height:  |  Size: 582 B

View File

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 249 B

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 643 B

After

Width:  |  Height:  |  Size: 643 B

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 346 B

View File

Before

Width:  |  Height:  |  Size: 910 B

After

Width:  |  Height:  |  Size: 910 B

View File

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 687 B

View File

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 484 B

View File

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

View File

Before

Width:  |  Height:  |  Size: 277 B

After

Width:  |  Height:  |  Size: 277 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 560 B

After

Width:  |  Height:  |  Size: 560 B

View File

Before

Width:  |  Height:  |  Size: 841 B

After

Width:  |  Height:  |  Size: 841 B

View File

Before

Width:  |  Height:  |  Size: 813 B

After

Width:  |  Height:  |  Size: 813 B

View File

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 286 B

View File

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

View File

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

View File

Before

Width:  |  Height:  |  Size: 619 B

After

Width:  |  Height:  |  Size: 619 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 687 B

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 225 B

View File

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 210 B

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 588 B

Some files were not shown because too many files have changed in this diff Show More