mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Merge pull request #255 from Pax1601/38-user-authentication-missing
38 user authentication missing
This commit is contained in:
commit
d146a47e71
@ -3,6 +3,7 @@ var path = require('path');
|
||||
var cookieParser = require('cookie-parser');
|
||||
var logger = require('morgan');
|
||||
var fs = require('fs');
|
||||
var basicAuth = require('express-basic-auth')
|
||||
|
||||
var atcRouter = require('./routes/api/atc');
|
||||
var indexRouter = require('./routes/index');
|
||||
@ -26,7 +27,8 @@ app.set('view engine', 'ejs');
|
||||
|
||||
let rawdata = fs.readFileSync('../olympus.json');
|
||||
let config = JSON.parse(rawdata);
|
||||
app.get('/config', (req, res) => res.send(config));
|
||||
if (config["server"] != undefined)
|
||||
app.get('/config', (req, res) => res.send(config["server"]));
|
||||
|
||||
module.exports = app;
|
||||
|
||||
@ -38,3 +40,8 @@ app.get('/demo/bullseyes', (req, res) => demoDataGenerator.bullseyes(req, res));
|
||||
app.get('/demo/airbases', (req, res) => demoDataGenerator.airbases(req, res));
|
||||
app.get('/demo/mission', (req, res) => demoDataGenerator.mission(req, res));
|
||||
|
||||
app.use('/demo', basicAuth({
|
||||
users: { 'admin': 'socks' }
|
||||
}))
|
||||
|
||||
|
||||
|
||||
19
client/package-lock.json
generated
19
client/package-lock.json
generated
@ -31,6 +31,7 @@
|
||||
"browserify": "^17.0.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"esmify": "^2.1.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"nodemon": "^2.0.20",
|
||||
"sortablejs": "^1.15.0",
|
||||
"tsify": "^5.0.4",
|
||||
@ -3283,6 +3284,15 @@
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express-basic-auth": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz",
|
||||
"integrity": "sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"basic-auth": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/cookie": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
|
||||
@ -8148,6 +8158,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"express-basic-auth": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz",
|
||||
"integrity": "sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"basic-auth": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"fast-safe-stringify": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
"browserify": "^17.0.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"esmify": "^2.1.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"nodemon": "^2.0.20",
|
||||
"sortablejs": "^1.15.0",
|
||||
"tsify": "^5.0.4",
|
||||
|
||||
@ -16,12 +16,13 @@
|
||||
|
||||
#olympus-toolbar-summary {
|
||||
background-image: url("/images/icon-round.png");
|
||||
background-position: 25px 20px;
|
||||
background-position: 20px 22px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 36px 36px;
|
||||
background-size: 45px 45px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-indent: 44px;
|
||||
text-indent: 60px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
dl.ol-data-grid {
|
||||
|
||||
@ -251,13 +251,14 @@ form>div {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
padding: 5px;
|
||||
border-radius: var(--border-radius-sm);
|
||||
}
|
||||
|
||||
.ol-select>.ol-select-options>div a:hover,
|
||||
.ol-select>.ol-select-options>div button:hover {
|
||||
background-color: #FFF3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ol-panel-list {
|
||||
@ -725,21 +726,21 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
|
||||
#splash-screen {
|
||||
background-image: url("/images/splash/splash_pic_ship.png");
|
||||
background-position: 100% 50%;
|
||||
background-size: 320px;
|
||||
background-size: 60%;
|
||||
border-radius: var(--border-radius-lg);
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
width: 700px;
|
||||
width: 1200px;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
#splash-content {
|
||||
background-color: var(--background-steel);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
padding: 30px;
|
||||
position: relative;
|
||||
row-gap: 10px;
|
||||
width: 55%;
|
||||
width: 50%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@ -747,7 +748,7 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
|
||||
background-color: var(--background-steel);
|
||||
content: "";
|
||||
display: block;
|
||||
height: 250px;
|
||||
height: 800px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
@ -775,20 +776,84 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
|
||||
line-height: 25px;
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#splash-content .app-version {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#splash-content #legal-stuff h4 {
|
||||
#splash-content #legal-stuff h5 {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#splash-content #legal-stuff p {
|
||||
font-size: 10px;
|
||||
color:#FFF7;
|
||||
width: 120%;
|
||||
}
|
||||
|
||||
#splash-content.ol-dialog-content {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.feature-splashScreen #splash-screen {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#gray-out {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
z-index: 9999;
|
||||
background-color: #000A;
|
||||
}
|
||||
|
||||
#authentication-form {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
column-gap: 10px;
|
||||
margin: 10px 0px;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#authentication-form>div {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
row-gap: 4px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#authentication-form>div>input {
|
||||
height: 35px;
|
||||
border-radius: var(--border-radius-sm);
|
||||
border: 0px solid transparent;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#splash-content a {
|
||||
color: #FFFB;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#connection-status {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#connection-status[data-status="connecting"]::before {
|
||||
content: "Connecting...";
|
||||
animation: blinker 1s linear infinite;
|
||||
}
|
||||
|
||||
#connection-status[data-status="failed"]::before {
|
||||
content: "Incorrect username/password!";
|
||||
color: var(--primary-red);
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@ -90,7 +90,7 @@ export class FeatureSwitches {
|
||||
}),
|
||||
|
||||
new FeatureSwitch({
|
||||
"defaultEnabled": false,
|
||||
"defaultEnabled": true,
|
||||
"label": "Show splash screen",
|
||||
"masterSwitch": true,
|
||||
"name": "splashScreen"
|
||||
@ -116,36 +116,24 @@ export class FeatureSwitches {
|
||||
|
||||
|
||||
#testSwitches() {
|
||||
|
||||
for ( const featureSwitch of this.#featureSwitches ) {
|
||||
|
||||
if ( featureSwitch.isEnabled() ) {
|
||||
|
||||
if ( typeof featureSwitch.onEnabled === "function" ) {
|
||||
featureSwitch.onEnabled();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
document.querySelectorAll( "[data-feature-switch='" + featureSwitch.name + "']" ).forEach( el => {
|
||||
|
||||
if ( featureSwitch.removeArtifactsIfDisabled === false ) {
|
||||
el.remove();
|
||||
} else {
|
||||
el.classList.add( "hide" );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
document.body.classList.toggle( "feature-" + featureSwitch.name, featureSwitch.isEnabled() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
savePreferences() {
|
||||
|
||||
let preferences:any = {};
|
||||
|
||||
@ -9,7 +9,7 @@ import { AIC } from "./aic/aic";
|
||||
import { ATC } from "./atc/atc";
|
||||
import { FeatureSwitches } from "./featureswitches";
|
||||
import { LogPanel } from "./panels/logpanel";
|
||||
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
|
||||
import { getAirbases, getBullseye, getConfig, getFreezed, getMission, getUnits, setAddress, setCredentials, setFreezed, startUpdate, toggleDemoEnabled } from "./server/server";
|
||||
import { UnitDataTable } from "./units/unitdatatable";
|
||||
import { keyEventWasInInput } from "./other/utils";
|
||||
import { Popup } from "./popups/popup";
|
||||
@ -31,11 +31,8 @@ var logPanel: LogPanel;
|
||||
|
||||
var infoPopup: Popup;
|
||||
|
||||
var connected: boolean = false;
|
||||
var paused: boolean = false;
|
||||
var activeCoalition: string = "blue";
|
||||
|
||||
var sessionHash: string | null = null;
|
||||
var unitDataTable: UnitDataTable;
|
||||
|
||||
var featureSwitches;
|
||||
@ -49,15 +46,18 @@ function setup() {
|
||||
missionHandler = new MissionHandler();
|
||||
|
||||
/* Panels */
|
||||
unitInfoPanel = new UnitInfoPanel("unit-info-panel");
|
||||
unitControlPanel = new UnitControlPanel("unit-control-panel");
|
||||
connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel");
|
||||
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
|
||||
unitInfoPanel = new UnitInfoPanel("unit-info-panel");
|
||||
unitControlPanel = new UnitControlPanel("unit-control-panel");
|
||||
connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel");
|
||||
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
|
||||
//logPanel = new LogPanel("log-panel");
|
||||
|
||||
/* Popups */
|
||||
infoPopup = new Popup("info-popup");
|
||||
|
||||
/* Controls */
|
||||
new Dropdown("app-icon", () => { });
|
||||
|
||||
/* Unit data table */
|
||||
unitDataTable = new UnitDataTable("unit-data-table");
|
||||
|
||||
@ -65,7 +65,6 @@ function setup() {
|
||||
let aicFeatureSwitch = featureSwitches.getSwitch("aic");
|
||||
if (aicFeatureSwitch?.isEnabled()) {
|
||||
aic = new AIC();
|
||||
// TODO: add back buttons
|
||||
}
|
||||
|
||||
/* ATC */
|
||||
@ -75,82 +74,23 @@ function setup() {
|
||||
atc.startUpdates();
|
||||
}
|
||||
|
||||
new Dropdown( "app-icon", () => {} );
|
||||
|
||||
/* Setup event handlers */
|
||||
setupEvents();
|
||||
|
||||
getConfig(readConfig)
|
||||
/* Load the config file */
|
||||
getConfig(readConfig);
|
||||
}
|
||||
|
||||
function readConfig(config: any)
|
||||
{
|
||||
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined)
|
||||
{
|
||||
const address = config["server"]["address"];
|
||||
const port = config["server"]["port"];
|
||||
function readConfig(config: any) {
|
||||
if (config && config["address"] != undefined && config["port"] != undefined) {
|
||||
const address = config["address"];
|
||||
const port = config["port"];
|
||||
if (typeof address === 'string' && typeof port == 'number')
|
||||
setAddress(address == "*"? window.location.hostname: address, <number>port);
|
||||
|
||||
/* On the first connection, force request of full data */
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {getMissionData()?.update(data)});
|
||||
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
|
||||
|
||||
/* Start periodically requesting updates */
|
||||
startPeriodicUpdate();
|
||||
setAddress(address == "*" ? window.location.hostname : address, <number>port);
|
||||
}
|
||||
else {
|
||||
throw new Error('Could not read configuration file!');
|
||||
}
|
||||
}
|
||||
|
||||
function startPeriodicUpdate() {
|
||||
requestUpdate();
|
||||
requestRefresh();
|
||||
}
|
||||
|
||||
function requestUpdate() {
|
||||
/* Main update rate = 250ms is minimum time, equal to server update time. */
|
||||
getUnits((data: UnitsData) => {
|
||||
if (!getPaused()){
|
||||
getUnitsManager()?.update(data);
|
||||
checkSessionHash(data.sessionHash);
|
||||
}
|
||||
}, false);
|
||||
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
|
||||
|
||||
getConnectionStatusPanel()?.update(getConnected());
|
||||
}
|
||||
|
||||
function requestRefresh() {
|
||||
/* Main refresh rate = 5000ms. */
|
||||
getUnits((data: UnitsData) => {
|
||||
if (!getPaused()){
|
||||
getUnitsManager()?.update(data);
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {
|
||||
getMissionData()?.update(data)
|
||||
});
|
||||
|
||||
// Update the list of existing units
|
||||
getUnitDataTable()?.update();
|
||||
|
||||
checkSessionHash(data.sessionHash);
|
||||
}
|
||||
}, true);
|
||||
window.setTimeout(() => requestRefresh(), 5000);
|
||||
}
|
||||
|
||||
function checkSessionHash(newSessionHash: string) {
|
||||
if (sessionHash != null) {
|
||||
if (newSessionHash != sessionHash)
|
||||
location.reload();
|
||||
}
|
||||
else
|
||||
sessionHash = newSessionHash;
|
||||
}
|
||||
|
||||
function setupEvents() {
|
||||
@ -164,7 +104,7 @@ function setupEvents() {
|
||||
}
|
||||
|
||||
const triggerElement = target.closest("[data-on-click]");
|
||||
|
||||
|
||||
if (triggerElement instanceof HTMLElement) {
|
||||
const eventName: string = triggerElement.dataset.onClick || "";
|
||||
let params = JSON.parse(triggerElement.dataset.onClickParams || "{}");
|
||||
@ -181,7 +121,7 @@ function setupEvents() {
|
||||
|
||||
/* Keyup events */
|
||||
document.addEventListener("keyup", ev => {
|
||||
if ( keyEventWasInInput( ev ) ) {
|
||||
if (keyEventWasInInput(ev)) {
|
||||
return;
|
||||
}
|
||||
switch (ev.code) {
|
||||
@ -195,13 +135,13 @@ function setupEvents() {
|
||||
unitDataTable.toggle();
|
||||
break
|
||||
case "Space":
|
||||
setPaused(!getPaused());
|
||||
setFreezed(!getFreezed());
|
||||
break;
|
||||
case "KeyW":
|
||||
case "KeyA":
|
||||
case "KeyS":
|
||||
case "KeyD":
|
||||
case "ArrowLeft":
|
||||
case "ArrowLeft":
|
||||
case "ArrowRight":
|
||||
case "ArrowUp":
|
||||
case "ArrowDown":
|
||||
@ -212,7 +152,7 @@ function setupEvents() {
|
||||
|
||||
/* Keydown events */
|
||||
document.addEventListener("keydown", ev => {
|
||||
if ( keyEventWasInInput( ev ) ) {
|
||||
if (keyEventWasInInput(ev)) {
|
||||
return;
|
||||
}
|
||||
switch (ev.code) {
|
||||
@ -220,7 +160,7 @@ function setupEvents() {
|
||||
case "KeyA":
|
||||
case "KeyS":
|
||||
case "KeyD":
|
||||
case "ArrowLeft":
|
||||
case "ArrowLeft":
|
||||
case "ArrowRight":
|
||||
case "ArrowUp":
|
||||
case "ArrowDown":
|
||||
@ -229,15 +169,31 @@ function setupEvents() {
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener( "closeDialog", (ev: CustomEventInit) => {
|
||||
ev.detail._element.closest( ".ol-dialog" ).classList.add( "hide" );
|
||||
document.addEventListener("closeDialog", (ev: CustomEventInit) => {
|
||||
ev.detail._element.closest(".ol-dialog").classList.add("hide");
|
||||
});
|
||||
|
||||
document.addEventListener( "toggleElements", (ev: CustomEventInit) => {
|
||||
document.querySelectorAll( ev.detail.selector ).forEach( el => {
|
||||
el.classList.toggle( "hide" );
|
||||
document.addEventListener("toggleElements", (ev: CustomEventInit) => {
|
||||
document.querySelectorAll(ev.detail.selector).forEach(el => {
|
||||
el.classList.toggle("hide");
|
||||
})
|
||||
});
|
||||
|
||||
document.addEventListener("tryConnection", () => {
|
||||
const form = document.querySelector("#splash-content")?.querySelector("#authentication-form");
|
||||
const username = (<HTMLInputElement> (form?.querySelector("#username"))).value;
|
||||
const password = (<HTMLInputElement> (form?.querySelector("#password"))).value;
|
||||
setCredentials(username, btoa("admin" + ":" + password));
|
||||
|
||||
/* Start periodically requesting updates */
|
||||
startUpdate();
|
||||
|
||||
setConnectionStatus("connecting");
|
||||
})
|
||||
|
||||
document.addEventListener("reloadPage", () => {
|
||||
location.reload();
|
||||
})
|
||||
}
|
||||
|
||||
export function getMap() {
|
||||
@ -285,23 +241,10 @@ export function getActiveCoalition() {
|
||||
return activeCoalition;
|
||||
}
|
||||
|
||||
export function setConnected(newConnected: boolean) {
|
||||
if (connected != newConnected)
|
||||
newConnected? getInfoPopup().setText("Connected to DCS Olympus server"): getInfoPopup().setText("Disconnected from DCS Olympus server");
|
||||
connected = newConnected;
|
||||
}
|
||||
|
||||
export function getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
export function setPaused(newPaused: boolean) {
|
||||
paused = newPaused;
|
||||
paused? getInfoPopup().setText("Paused"): getInfoPopup().setText("Unpaused");
|
||||
}
|
||||
|
||||
export function getPaused() {
|
||||
return paused;
|
||||
export function setConnectionStatus(status: string) {
|
||||
const el = document.querySelector("#connection-status") as HTMLElement;
|
||||
if (el)
|
||||
el.dataset["status"] = status;
|
||||
}
|
||||
|
||||
export function getInfoPopup() {
|
||||
|
||||
@ -316,7 +316,7 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
this.setView(bounds.getCenter(), 8);
|
||||
this.setMaxBounds(bounds);
|
||||
//this.setMaxBounds(bounds);
|
||||
|
||||
if (this.#miniMap)
|
||||
this.#miniMap.remove();
|
||||
|
||||
@ -219,7 +219,7 @@ export class UnitControlPanel extends Panel {
|
||||
|
||||
// Default values for "normal" units
|
||||
this.#radioCallsignDropdown.setOptions(["Enfield", "Springfield", "Uzi", "Colt", "Dodge", "Ford", "Chevy", "Pontiac"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
|
||||
|
||||
// Input values
|
||||
var tankerCheckbox = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")
|
||||
@ -241,7 +241,7 @@ export class UnitControlPanel extends Panel {
|
||||
this.#radioDecimalsDropdown.setValue("." + radioDecimals);
|
||||
|
||||
// Make sure its in the valid range
|
||||
if (!this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign))
|
||||
if (!this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1))
|
||||
this.#radioCallsignDropdown.selectValue(0);
|
||||
|
||||
// Set options for tankers
|
||||
@ -249,7 +249,7 @@ export class UnitControlPanel extends Panel {
|
||||
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker")){
|
||||
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.remove("hide");
|
||||
this.#radioCallsignDropdown.setOptions(["Texaco", "Arco", "Shell"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
|
||||
}
|
||||
else {
|
||||
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.add("hide");
|
||||
@ -259,7 +259,7 @@ export class UnitControlPanel extends Panel {
|
||||
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("AWACS")){
|
||||
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.remove("hide");
|
||||
this.#radioCallsignDropdown.setOptions(["Overlord", "Magic", "Wizard", "Focus", "Darkstar"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
|
||||
} else {
|
||||
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.add("hide");
|
||||
}
|
||||
@ -276,7 +276,7 @@ export class UnitControlPanel extends Panel {
|
||||
const TACANCallsign = <string> this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input")?.value
|
||||
const radioMHz = Number(this.#advancedSettingsDialog.querySelector("#radio-mhz")?.querySelector("input")?.value);
|
||||
const radioDecimals = this.#radioDecimalsDropdown.getValue();
|
||||
const radioCallsign = this.#radioCallsignDropdown.getIndex();
|
||||
const radioCallsign = this.#radioCallsignDropdown.getIndex() + 1;
|
||||
const radioCallsignNumber = Number(this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input")?.value);
|
||||
|
||||
var radioFrequency = (radioMHz * 1000 + Number(radioDecimals.substring(1))) * 1000;
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import * as L from 'leaflet'
|
||||
import { setConnected } from '..';
|
||||
import { getConnectionStatusPanel, getInfoPopup, getMissionData, getUnitDataTable, getUnitsManager, setConnectionStatus } from '..';
|
||||
import { SpawnOptions } from '../controls/mapcontextmenu';
|
||||
|
||||
var connected: boolean = false;
|
||||
var freezed: boolean = false;
|
||||
|
||||
var REST_ADDRESS = "http://localhost:30000/olympus";
|
||||
var DEMO_ADDRESS = window.location.href + "demo";
|
||||
const UNITS_URI = "units";
|
||||
@ -10,29 +13,50 @@ const AIRBASES_URI = "airbases";
|
||||
const BULLSEYE_URI = "bullseyes";
|
||||
const MISSION_URI = "mission";
|
||||
|
||||
var username = "";
|
||||
var credentials = "";
|
||||
|
||||
var sessionHash: string | null = null;
|
||||
var lastUpdateTime = 0;
|
||||
var demoEnabled = false;
|
||||
|
||||
export function toggleDemoEnabled()
|
||||
{
|
||||
export function toggleDemoEnabled() {
|
||||
demoEnabled = !demoEnabled;
|
||||
}
|
||||
|
||||
export function GET(callback: CallableFunction, uri: string, options?: string){
|
||||
export function setCredentials(newUsername: string, newCredentials: string) {
|
||||
username = newUsername;
|
||||
credentials = newCredentials;
|
||||
}
|
||||
|
||||
export function GET(callback: CallableFunction, uri: string, options?: string) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}${options? options: ''}`, true);
|
||||
if (credentials)
|
||||
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
if (uri !== UNITS_URI || parseInt(data.time) > lastUpdateTime)
|
||||
{
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
if (isNaN(lastUpdateTime))
|
||||
lastUpdateTime = 0;
|
||||
setConnected(true);
|
||||
if (xmlHttp.status == 200) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
if (uri !== UNITS_URI || parseInt(data.time) > lastUpdateTime)
|
||||
{
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
if (isNaN(lastUpdateTime))
|
||||
lastUpdateTime = 0;
|
||||
setConnected(true);
|
||||
}
|
||||
} else if (xmlHttp.status == 401) {
|
||||
console.error("Incorrect username/password");
|
||||
setConnectionStatus("failed");
|
||||
} else {
|
||||
setConnected(false);
|
||||
}
|
||||
};
|
||||
xmlHttp.onerror = function () {
|
||||
xmlHttp.onreadystatechange = function (res) {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
setConnected(false);
|
||||
};
|
||||
xmlHttp.onerror = function (res) {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
setConnected(false);
|
||||
};
|
||||
@ -40,13 +64,15 @@ export function GET(callback: CallableFunction, uri: string, options?: string){
|
||||
}
|
||||
|
||||
export function POST(request: object, callback: CallableFunction){
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", demoEnabled? DEMO_ADDRESS: REST_ADDRESS);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("PUT", demoEnabled? DEMO_ADDRESS: REST_ADDRESS);
|
||||
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||
if (credentials)
|
||||
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
|
||||
xmlHttp.onreadystatechange = () => {
|
||||
callback();
|
||||
};
|
||||
xhr.send(JSON.stringify(request));
|
||||
xmlHttp.send(JSON.stringify(request));
|
||||
}
|
||||
|
||||
export function getConfig(callback: CallableFunction) {
|
||||
@ -208,4 +234,81 @@ export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolea
|
||||
|
||||
var data = { "setAdvancedOptions": command };
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function startUpdate() {
|
||||
/* On the first connection, force request of full data */
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => { getMissionData()?.update(data) });
|
||||
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
|
||||
|
||||
requestUpdate();
|
||||
requestRefresh();
|
||||
}
|
||||
|
||||
export function requestUpdate() {
|
||||
/* Main update rate = 250ms is minimum time, equal to server update time. */
|
||||
getUnits((data: UnitsData) => {
|
||||
if (!getFreezed()) {
|
||||
getUnitsManager()?.update(data);
|
||||
checkSessionHash(data.sessionHash);
|
||||
}
|
||||
}, false);
|
||||
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
|
||||
|
||||
getConnectionStatusPanel()?.update(getConnected());
|
||||
}
|
||||
|
||||
export function requestRefresh() {
|
||||
/* Main refresh rate = 5000ms. */
|
||||
getUnits((data: UnitsData) => {
|
||||
if (!getFreezed()) {
|
||||
getUnitsManager()?.update(data);
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {
|
||||
getMissionData()?.update(data)
|
||||
});
|
||||
|
||||
// Update the list of existing units
|
||||
getUnitDataTable()?.update();
|
||||
|
||||
checkSessionHash(data.sessionHash);
|
||||
}
|
||||
}, true);
|
||||
window.setTimeout(() => requestRefresh(), 5000);
|
||||
}
|
||||
|
||||
export function checkSessionHash(newSessionHash: string) {
|
||||
if (sessionHash != null) {
|
||||
if (newSessionHash != sessionHash)
|
||||
location.reload();
|
||||
}
|
||||
else
|
||||
sessionHash = newSessionHash;
|
||||
}
|
||||
|
||||
export function setConnected(newConnected: boolean) {
|
||||
if (connected != newConnected)
|
||||
newConnected ? getInfoPopup().setText("Connected to DCS Olympus server") : getInfoPopup().setText("Disconnected from DCS Olympus server");
|
||||
connected = newConnected;
|
||||
|
||||
if (connected) {
|
||||
document.querySelector("#splash-screen")?.classList.add("hide");
|
||||
document.querySelector("#gray-out")?.classList.add("hide");
|
||||
}
|
||||
}
|
||||
|
||||
export function getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
export function setFreezed(newFreezed: boolean) {
|
||||
freezed = newFreezed;
|
||||
freezed ? getInfoPopup().setText("Freezed") : getInfoPopup().setText("Unfreezed");
|
||||
}
|
||||
|
||||
export function getFreezed() {
|
||||
return freezed;
|
||||
}
|
||||
@ -1,20 +1,25 @@
|
||||
<div id="splash-screen" class="ol-dialog" data-on-click="closeDialog" oncontextmenu="return false;">
|
||||
|
||||
<div id="splash-screen" class="ol-dialog" oncontextmenu="return false;">
|
||||
<div id="splash-content" class="ol-dialog-content">
|
||||
|
||||
<div id="app-summary">
|
||||
<h2>DCS Olympus</h2>
|
||||
<h4>Dynamic Unit Command</h4>
|
||||
<div class="app-version">Version <span class="app-version-number">v0.2.0</span></div>
|
||||
</div>
|
||||
|
||||
<div id="legal-stuff">
|
||||
<h4>Disclaimer</h4>
|
||||
<p>We ain't no friends with no Eagle Dynamics.</p>
|
||||
<div id="authentication-form">
|
||||
<div><h5>Username</h5> <input type="text" id="username" name="username" required autocomplete="username" placeholder="Enter username..."></div>
|
||||
<div><h5>Password</h5> <input type="password" id="password" name="password" minlength="8" required autocomplete="current-password" placeholder="Enter password..."></div>
|
||||
<button id="connection-button" class="ol-button-apply" data-on-click="tryConnection">Connect</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<h5 id="connection-status"><br></h5>
|
||||
|
||||
<div id="legal-stuff">
|
||||
<h5>DISCLAIMER</h5>
|
||||
<p> DCS Olympus (the "MATERIAL" or "Software") is provided completely free to users subject to the terms of the <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0 Licence</a> except where such terms conflict with this disclaimer, in which case, the terms of this disclaimer shall prevail.
|
||||
The authors and/or copyright holders of the Software have not received any financial benefit in connection with the Software. In any event, the Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non-infringement. In no event shall the authors and/or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software. Any party making use of the Software in any manner agrees to be bound by the terms set out in this disclaimer. THIS MATERIAL IS NOT MADE OR SUPPORTED BY EAGLE DYNAMICS SA.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="advanced-settings-dialog" class="ol-panel ol-dialog olympus-dialog-close hide" oncontextmenu="return false;">
|
||||
|
||||
@ -34,6 +34,8 @@
|
||||
<%- include('dialogs.ejs') %>
|
||||
<%- include('unitdatatable.ejs') %>
|
||||
<%- include('popups.ejs') %>
|
||||
|
||||
<div id="gray-out"></div>
|
||||
|
||||
<% /* %>
|
||||
<%- include('log.ejs') %>
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
</div>
|
||||
<div class="ol-select-options">
|
||||
<div id="olympus-toolbar-summary">
|
||||
<h3>Olympus</h3>
|
||||
<div class="accent-green app-version-number">v0.2.0</div>
|
||||
<h3>DCS Olympus</h3>
|
||||
<div class="accent-green app-version-number">version v0.2.0</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://www.discord.com" target="_blank">Discord</a>
|
||||
@ -15,6 +15,9 @@
|
||||
<div>
|
||||
<a href="https://github.com/Pax1601/DCSOlympus" target="_blank">Github</a>
|
||||
</div>
|
||||
<div data-on-click="reloadPage">
|
||||
<a href="" target="_blank" data-on-click="reloadPage">Restart Olyumpus</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -2,5 +2,8 @@
|
||||
"server": {
|
||||
"address": "localhost",
|
||||
"port": 30000
|
||||
},
|
||||
"authentication": {
|
||||
"password": "password"
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\base64\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
||||
@ -27,5 +27,7 @@ private:
|
||||
void task();
|
||||
|
||||
atomic<bool> runListener;
|
||||
|
||||
wstring password = L"";
|
||||
};
|
||||
|
||||
|
||||
@ -96,14 +96,13 @@ public:
|
||||
void pushActivePathBack(Coords newActivePathBack);
|
||||
void popActivePathFront();
|
||||
void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));}
|
||||
void setIsTanker(bool newIsTanker) { isTanker = newIsTanker; addMeasure(L"isTanker", json::value(newIsTanker));}
|
||||
void setIsAWACS(bool newIsAWACS) { isAWACS = newIsAWACS; addMeasure(L"isAWACS", json::value(newIsAWACS));}
|
||||
void setTACANOn(bool newTACANOn);
|
||||
void setIsTanker(bool newIsTanker);
|
||||
void setIsAWACS(bool newIsAWACS);
|
||||
void setTACANChannel(int newTACANChannel);
|
||||
void setTACANXY(wstring newTACANXY);
|
||||
void setTACANCallsign(wstring newTACANCallsign);
|
||||
void setTACAN();
|
||||
void setRadioOn(bool newRadioOn);
|
||||
void setEPLRS(bool state);
|
||||
void setRadioFrequency(int newRadioFrequency);
|
||||
void setRadioCallsign(int newRadioCallsign);
|
||||
void setRadioCallsignNumber(int newRadioCallsignNumber);
|
||||
@ -116,11 +115,9 @@ public:
|
||||
int getTargetID() { return targetID; }
|
||||
bool getIsTanker() { return isTanker; }
|
||||
bool getIsAWACS() { return isAWACS; }
|
||||
bool getTACANOn() { return TACANOn; }
|
||||
int getTACANChannel() { return TACANChannel; }
|
||||
wstring getTACANXY() { return TACANXY; }
|
||||
wstring getTACANCallsign() { return TACANCallsign; }
|
||||
bool getRadioOn() { return radioOn; }
|
||||
int getRadioFrequency() { return radioFrequency; }
|
||||
int getRadioCallsign() { return radioCallsign; }
|
||||
int getRadioCallsignNumber() { return radioCallsignNumber; }
|
||||
@ -182,11 +179,9 @@ protected:
|
||||
int targetID = NULL;
|
||||
bool isTanker = false;
|
||||
bool isAWACS = false;
|
||||
bool TACANOn = false;
|
||||
int TACANChannel = 40;
|
||||
wstring TACANXY = L"X";
|
||||
wstring TACANCallsign = L"TKR";
|
||||
bool radioOn = false;
|
||||
int radioFrequency = 260000000; // MHz
|
||||
int radioCallsign = 1;
|
||||
int radioCallsignNumber = 1;
|
||||
|
||||
@ -251,13 +251,11 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
unit->setIsTanker(value[L"isTanker"].as_bool());
|
||||
unit->setIsAWACS(value[L"isAWACS"].as_bool());
|
||||
|
||||
unit->setTACANOn(true); // TODO Remove
|
||||
unit->setTACANChannel(value[L"TACANChannel"].as_number().to_int32());
|
||||
unit->setTACANXY(value[L"TACANXY"].as_string());
|
||||
unit->setTACANCallsign(value[L"TACANCallsign"].as_string());
|
||||
unit->setTACAN();
|
||||
|
||||
unit->setRadioOn(true); // TODO Remove
|
||||
unit->setRadioFrequency(value[L"radioFrequency"].as_number().to_int32());
|
||||
unit->setRadioCallsign(value[L"radioCallsign"].as_number().to_int32());
|
||||
unit->setRadioCallsignNumber(value[L"radioCallsignNumber"].as_number().to_int32());
|
||||
|
||||
@ -6,9 +6,11 @@
|
||||
#include "luatools.h"
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include "base64.hpp"
|
||||
|
||||
#include <chrono>
|
||||
using namespace std::chrono;
|
||||
using namespace base64;
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
extern Scheduler* scheduler;
|
||||
@ -54,10 +56,10 @@ void Server::stop(lua_State* L)
|
||||
void Server::handle_options(http_request request)
|
||||
{
|
||||
http_response response(status_codes::OK);
|
||||
response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
|
||||
|
||||
request.reply(response);
|
||||
}
|
||||
@ -68,87 +70,102 @@ void Server::handle_get(http_request request)
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
http_response response(status_codes::OK);
|
||||
response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
|
||||
string authorization = to_base64("admin:" + to_string(password));
|
||||
if (password == L"" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
|
||||
{
|
||||
std::exception_ptr eptr;
|
||||
try {
|
||||
auto answer = json::value::object();
|
||||
auto path = uri::split_path(uri::decode(request.relative_uri().path()));
|
||||
|
||||
std::exception_ptr eptr;
|
||||
try {
|
||||
auto answer = json::value::object();
|
||||
auto path = uri::split_path(uri::decode(request.relative_uri().path()));
|
||||
|
||||
if (path.size() > 0)
|
||||
{
|
||||
if (path[0] == UNITS_URI)
|
||||
if (path.size() > 0)
|
||||
{
|
||||
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
|
||||
long long time = 0;
|
||||
if (query.find(L"time") != query.end())
|
||||
if (path[0] == UNITS_URI)
|
||||
{
|
||||
try {
|
||||
time = stoll((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
time = 0;
|
||||
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
|
||||
long long time = 0;
|
||||
if (query.find(L"time") != query.end())
|
||||
{
|
||||
try {
|
||||
time = stoll((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
unitsManager->getData(answer, time);
|
||||
}
|
||||
unitsManager->getData(answer, time);
|
||||
}
|
||||
else if (path[0] == LOGS_URI)
|
||||
{
|
||||
auto logs = json::value::object();
|
||||
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (path[0] == AIRBASES_URI)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (path[0] == BULLSEYE_URI)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (path[0] == MISSION_URI)
|
||||
answer[L"mission"] = mission;
|
||||
else if (path[0] == LOGS_URI)
|
||||
{
|
||||
auto logs = json::value::object();
|
||||
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (path[0] == AIRBASES_URI)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (path[0] == BULLSEYE_URI)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (path[0] == MISSION_URI)
|
||||
answer[L"mission"] = mission;
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
}
|
||||
|
||||
response.set_body(answer);
|
||||
}
|
||||
catch (...) {
|
||||
eptr = std::current_exception(); // capture
|
||||
}
|
||||
handle_eptr(eptr);
|
||||
}
|
||||
else {
|
||||
response = status_codes::Unauthorized;
|
||||
}
|
||||
|
||||
response.set_body(answer);
|
||||
}
|
||||
catch (...) {
|
||||
eptr = std::current_exception(); // capture
|
||||
}
|
||||
handle_eptr(eptr);
|
||||
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
|
||||
|
||||
request.reply(response);
|
||||
}
|
||||
|
||||
void Server::handle_request(http_request request, function<void(json::value const&, json::value&)> action)
|
||||
{
|
||||
auto answer = json::value::object();
|
||||
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const& jvalue = task.get();
|
||||
|
||||
if (!jvalue.is_null())
|
||||
{
|
||||
action(jvalue, answer);
|
||||
}
|
||||
}
|
||||
catch (http_exception const& e)
|
||||
{
|
||||
log(e.what());
|
||||
}
|
||||
}).wait();
|
||||
|
||||
http_response response(status_codes::OK);
|
||||
response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS"));
|
||||
string authorization = to_base64("admin:" + to_string(password));
|
||||
if (password == L"" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
|
||||
{
|
||||
auto answer = json::value::object();
|
||||
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const& jvalue = task.get();
|
||||
|
||||
if (!jvalue.is_null())
|
||||
{
|
||||
action(jvalue, answer);
|
||||
}
|
||||
}
|
||||
catch (http_exception const& e)
|
||||
{
|
||||
log(e.what());
|
||||
}
|
||||
}).wait();
|
||||
response.set_body(answer);
|
||||
}
|
||||
else {
|
||||
response = status_codes::Unauthorized;
|
||||
}
|
||||
|
||||
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
|
||||
response.set_body(answer);
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
|
||||
|
||||
request.reply(response);
|
||||
}
|
||||
|
||||
@ -197,9 +214,15 @@ void Server::task()
|
||||
log(L"Starting server on " + address);
|
||||
}
|
||||
else
|
||||
{
|
||||
log(L"Error reading configuration file. Starting server on " + address);
|
||||
|
||||
if (config.is_object() && config.has_object_field(L"authentication") &&
|
||||
config[L"authentication"].has_string_field(L"password"))
|
||||
{
|
||||
password = config[L"authentication"][L"password"].as_string();
|
||||
}
|
||||
else
|
||||
log(L"Error reading configuration file. No password set.");
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
|
||||
@ -337,9 +337,17 @@ void Unit::landAt(Coords loc) {
|
||||
setState(State::LAND);
|
||||
}
|
||||
|
||||
void Unit::setTACANOn(bool newTACANOn) {
|
||||
TACANOn = newTACANOn;
|
||||
addMeasure(L"TACANOn", json::value(newTACANOn));
|
||||
void Unit::setIsTanker(bool newIsTanker) {
|
||||
isTanker = newIsTanker;
|
||||
resetTask();
|
||||
addMeasure(L"isTanker", json::value(newIsTanker));
|
||||
}
|
||||
|
||||
void Unit::setIsAWACS(bool newIsAWACS) {
|
||||
isAWACS = newIsAWACS;
|
||||
resetTask();
|
||||
addMeasure(L"isAWACS", json::value(newIsAWACS));
|
||||
setEPLRS(true);
|
||||
}
|
||||
|
||||
void Unit::setTACANChannel(int newTACANChannel) {
|
||||
@ -356,11 +364,6 @@ void Unit::setTACANCallsign(wstring newTACANCallsign) {
|
||||
addMeasure(L"TACANCallsign", json::value(newTACANCallsign));
|
||||
}
|
||||
|
||||
void Unit::setRadioOn(bool newRadioOn) {
|
||||
radioOn = newRadioOn;
|
||||
addMeasure(L"radioOn", json::value(newRadioOn));
|
||||
}
|
||||
|
||||
void Unit::setRadioFrequency(int newRadioFrequency) {
|
||||
radioFrequency = newRadioFrequency;
|
||||
addMeasure(L"radioFrequency", json::value(newRadioFrequency));
|
||||
@ -376,6 +379,19 @@ void Unit::setRadioCallsignNumber(int newRadioCallsignNumber) {
|
||||
addMeasure(L"radioCallsignNumber", json::value(newRadioCallsignNumber));
|
||||
}
|
||||
|
||||
void Unit::setEPLRS(bool state)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS << "{"
|
||||
<< "id = 'EPLRS',"
|
||||
<< "params = {"
|
||||
<< "value = " << (state? "true": "false") << ", "
|
||||
<< "}"
|
||||
<< "}";
|
||||
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
|
||||
void Unit::setTACAN()
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
@ -383,9 +399,9 @@ void Unit::setTACAN()
|
||||
<< "id = 'ActivateBeacon',"
|
||||
<< "params = {"
|
||||
<< "type = " << ((TACANXY.compare(L"X") == 0)? 4: 5) << ","
|
||||
<< "system = 4,"
|
||||
<< "name = Olympus_TACAN,"
|
||||
<< "callsign = " << TACANCallsign << ", "
|
||||
<< "system = 3,"
|
||||
<< "name = \"Olympus_TACAN\","
|
||||
<< "callsign = \"" << TACANCallsign << "\", "
|
||||
<< "frequency = " << TACANChannelToFrequency(TACANChannel, TACANXY) << ","
|
||||
<< "}"
|
||||
<< "}";
|
||||
|
||||
81
third-party/base64/include/base64.hpp
vendored
Normal file
81
third-party/base64/include/base64.hpp
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef BASE_64_HPP
|
||||
#define BASE_64_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace base64 {
|
||||
|
||||
inline std::string get_base64_chars() {
|
||||
static std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
return base64_chars;
|
||||
}
|
||||
|
||||
inline std::string to_base64(std::string const &data) {
|
||||
int counter = 0;
|
||||
uint32_t bit_stream = 0;
|
||||
const std::string base64_chars = get_base64_chars();
|
||||
std::string encoded;
|
||||
int offset = 0;
|
||||
for (unsigned char c : data) {
|
||||
auto num_val = static_cast<unsigned int>(c);
|
||||
offset = 16 - counter % 3 * 8;
|
||||
bit_stream += num_val << offset;
|
||||
if (offset == 16) {
|
||||
encoded += base64_chars.at(bit_stream >> 18 & 0x3f);
|
||||
}
|
||||
if (offset == 8) {
|
||||
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
|
||||
}
|
||||
if (offset == 0 && counter != 3) {
|
||||
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
|
||||
encoded += base64_chars.at(bit_stream & 0x3f);
|
||||
bit_stream = 0;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
if (offset == 16) {
|
||||
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
|
||||
encoded += "==";
|
||||
}
|
||||
if (offset == 8) {
|
||||
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
|
||||
encoded += '=';
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
inline std::string from_base64(std::string const &data) {
|
||||
int counter = 0;
|
||||
uint32_t bit_stream = 0;
|
||||
std::string decoded;
|
||||
int offset = 0;
|
||||
const std::string base64_chars = get_base64_chars();
|
||||
for (unsigned char c : data) {
|
||||
auto num_val = base64_chars.find(c);
|
||||
if (num_val != std::string::npos) {
|
||||
offset = 18 - counter % 4 * 6;
|
||||
bit_stream += num_val << offset;
|
||||
if (offset == 12) {
|
||||
decoded += static_cast<char>(bit_stream >> 16 & 0xff);
|
||||
}
|
||||
if (offset == 6) {
|
||||
decoded += static_cast<char>(bit_stream >> 8 & 0xff);
|
||||
}
|
||||
if (offset == 0 && counter != 4) {
|
||||
decoded += static_cast<char>(bit_stream & 0xff);
|
||||
bit_stream = 0;
|
||||
}
|
||||
} else if (c != '=') {
|
||||
return std::string();
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BASE_64_HPP
|
||||
Loading…
x
Reference in New Issue
Block a user