More work on login connection logic

This commit is contained in:
Davide Passoni 2024-05-02 10:05:12 +02:00
parent 2cb3287d1f
commit f5aca98e49
7 changed files with 99 additions and 42 deletions

View File

@ -23,4 +23,12 @@
.z-ui-2 {
z-index: 2002;
}
.z-ui-3 {
z-index: 2003;
}
.z-ui-4 {
z-index: 2004;
}

View File

@ -41,8 +41,8 @@ import { navyUnitDatabase } from "./unit/databases/navyunitdatabase";
//import { ContextManager } from "./context/contextmanager";
//import { Context } from "./context/context";
export var VERSION = "{{OLYMPUS_VERSION_NUMBER}}";
export var IP = "{{IP ADDRESS OF SERVER}}";
export var connectedToServer = true;
export var IP = window.location.toString();
export var connectedToServer = true; // Temporary
export class OlympusApp {
/* Global data */
@ -271,6 +271,7 @@ export class OlympusApp {
})
/* Load the config file from the server */
// Temporary
const configRequest = new Request("http://localhost:3000/" + "resources/config");
fetch(configRequest).then((response) => {
if (response.status === 200) {

View File

@ -12,7 +12,7 @@ export class ServerManager {
#connected: boolean = false;
#paused: boolean = false;
#REST_ADDRESS = "http://localhost:3001/olympus";
#username = "";
#username = "no-username";
#password = "";
#sessionHash: string | null = null;
#lastUpdateTimes: { [key: string]: number } = {}
@ -30,12 +30,15 @@ export class ServerManager {
this.#lastUpdateTimes[MISSION_URI] = Date.now();
}
setCredentials(newUsername: string, newPassword: string) {
setUsername(newUsername: string) {
this.#username = newUsername;
}
setPassword(newPassword: string) {
this.#password = newPassword;
}
GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType: string = 'text', force: boolean = false) {
GET(callback: CallableFunction, errorCallback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType: string = 'text', force: boolean = false) {
var xmlHttp = new XMLHttpRequest();
/* If a request on this uri is still pending (meaning it's not done or did not yet fail), skip the request, to avoid clogging the TCP workers */
@ -84,15 +87,18 @@ export class ServerManager {
/* Bad credentials */
console.error("Incorrect username/password");
getApp().setLoginStatus("failed");
errorCallback && errorCallback(xmlHttp.status);
} else {
/* Failure, probably disconnected */
this.setConnected(false);
errorCallback && errorCallback(xmlHttp.status);
}
};
xmlHttp.onreadystatechange = (res) => {
if (xmlHttp.readyState == 4 && xmlHttp.status === 0) {
console.error("An error occurred during the XMLHttpRequest");
this.setConnected(false);
errorCallback && errorCallback(xmlHttp.status);
}
};
xmlHttp.send(null);
@ -131,32 +137,32 @@ export class ServerManager {
console.log(`Setting REST address to ${this.#REST_ADDRESS}`)
}
getAirbases(callback: CallableFunction) {
this.GET(callback, AIRBASES_URI);
getAirbases(callback: CallableFunction, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, AIRBASES_URI);
}
getBullseye(callback: CallableFunction) {
this.GET(callback, BULLSEYE_URI);
getBullseye(callback: CallableFunction, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, BULLSEYE_URI);
}
getLogs(callback: CallableFunction, refresh: boolean = false) {
this.GET(callback, LOGS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI] }, 'text', refresh);
getLogs(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, LOGS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI] }, 'text', refresh);
}
getMission(callback: CallableFunction) {
this.GET(callback, MISSION_URI);
getMission(callback: CallableFunction, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, MISSION_URI);
}
getUnits(callback: CallableFunction, refresh: boolean = false) {
this.GET(callback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, 'arraybuffer', refresh);
getUnits(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, 'arraybuffer', refresh);
}
getWeapons(callback: CallableFunction, refresh: boolean = false) {
this.GET(callback, WEAPONS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer', refresh);
getWeapons(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, WEAPONS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer', refresh);
}
isCommandExecuted(callback: CallableFunction, commandHash: string) {
this.GET(callback, COMMANDS_URI, { commandHash: commandHash });
isCommandExecuted(callback: CallableFunction, commandHash: string, errorCallback: CallableFunction = () => {}) {
this.GET(callback, errorCallback, COMMANDS_URI, { commandHash: commandHash });
}
addDestination(ID: number, path: any, callback: CallableFunction = () => { }) {

View File

@ -1,4 +1,3 @@
/* Types definition */
export type MapMarkerVisibilityControl = {
"category"?: string;

View File

@ -5,7 +5,7 @@ export function Modal(props: {
children?: JSX.Element | JSX.Element[],
className?: string
}) {
return <div className={props.className + "fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-48%] z-ui-2 rounded-xl border-solid border-[1px] border-gray-500 drop-shadow"}>
return <div className={props.className + "fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-48%] z-ui-4 rounded-xl border-solid border-[1px] border-gray-500 drop-shadow"}>
{props.children}
</div>
}

View File

@ -8,11 +8,15 @@ import { VERSION, connectedToServer } from '../../olympusapp'
export function LoginModal(props: {
checkingPassword: boolean,
loginError: boolean,
onLogin: (password: string) => void
commandMode: string | null,
onLogin: (password: string) => void,
onContinue: (username: string) => void,
onBack: () => void
}) {
const [password, setPassword] = useState("");
const [displayName, setDisplayName] = useState("");
return <Modal className="flex inline-flex max-h-[600px] overflow-y-auto h-[75%] scroll-smooth w-[80%] bg-white dark:bg-olympus-800 ">
return <Modal className="inline-flex max-h-[600px] overflow-y-auto h-[75%] scroll-smooth w-[80%] bg-white dark:bg-olympus-800 ">
<div className='absolute gap-8 flex flex-col p-16 max-lg:p-12 w-full'>
<div className="flex flex-row max-lg:flex-col w-full gap-6">
<div className="flex flex-grow flex-col gap-5 w-[40%] max-lg:w-[100%] content-center justify-start">
@ -30,18 +34,37 @@ export function LoginModal(props: {
{
!props.loginError ?
<>
<div className="flex flex-col items-start gap-2">
<label className=" text-gray-800 dark:text-white text-md">Password</label>
<input type="text" onChange={(ev) => setPassword(ev.currentTarget.value)} className="w-full max-w-80 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Enter password" required />
</div>
<div className='flex'>
<button type="button" onClick={() => props.onLogin(password)} className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm">
Login <FontAwesomeIcon className="my-auto" icon={faArrowRight} />
</button>
<button type="button" className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm dark:border-gray-600 border-[1px] dark:text-gray-400">
View Guide <FontAwesomeIcon className="my-auto" icon={faExternalLink} />
</button>
</div>
{ props.commandMode === null?
<>
<div className="flex flex-col items-start gap-2">
<label className=" text-gray-800 dark:text-white text-md">Password</label>
<input type="text" onChange={(ev) => setPassword(ev.currentTarget.value)} className="w-full max-w-80 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Enter password" required />
</div>
<div className='flex'>
<button type="button" onClick={() => props.onLogin(password)} className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm">
Login <FontAwesomeIcon className="my-auto" icon={faArrowRight} />
</button>
<button type="button" className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm dark:border-gray-600 border-[1px] dark:text-gray-400">
View Guide <FontAwesomeIcon className="my-auto" icon={faExternalLink} />
</button>
</div>
</>
:
<>
<div className="flex flex-col items-start gap-2">
<label className=" text-gray-800 dark:text-white text-md">Set display name</label>
<input type="text" onChange={(ev) => setDisplayName(ev.currentTarget.value)} className="w-full max-w-80 bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Enter display name" required />
</div>
<div className='flex'>
<button type="button" onClick={() => props.onContinue(displayName)} className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm">
Continue <FontAwesomeIcon className="my-auto" icon={faArrowRight} />
</button>
<button type="button" className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm dark:border-gray-600 border-[1px] dark:text-gray-400">
Back
</button>
</div>
</>
}
</>
:
<div>

View File

@ -28,6 +28,7 @@ export type OlympusState = {
}
export function UI() {
var [loginModalVisible, setLoginModalVisible] = useState(true);
var [mainMenuVisible, setMainMenuVisible] = useState(false);
var [spawnMenuVisible, setSpawnMenuVisible] = useState(false);
var [unitControlMenuVisible, setUnitControlMenuVisible] = useState(false);
@ -60,7 +61,7 @@ export function UI() {
function checkPassword(password: string) {
setCheckingPassword(true);
var hash = sha256.create();
getApp().getServerManager().setCredentials("no-username", hash.update(password).hex());
getApp().getServerManager().setPassword(hash.update(password).hex());
getApp().getServerManager().getMission((response) => {
const commandMode = response.mission.commandModeOptions.commandMode;
try {
@ -69,7 +70,18 @@ export function UI() {
setLoginError(true);
}
setCheckingPassword(false);
})
},
() => {
setLoginError(true);
setCheckingPassword(false);
},
)
}
function connect(username: string) {
getApp().getServerManager().setUsername(username);
getApp().getServerManager().startUpdate();
setLoginModalVisible(false);
}
return (
@ -103,11 +115,19 @@ export function UI() {
<div className='absolute top-0 left-0 h-full w-full flex flex-col'>
<Header />
<div className='flex h-full'>
<LoginModal
onLogin={(password) => { checkPassword(password) }}
checkingPassword={checkingPassword}
loginError={loginError}
/>
{loginModalVisible &&
<>
<div className="fixed top-0 left-0 w-full h-full z-ui-3 bg-black opacity-60"></div>
<LoginModal
onLogin={(password) => { checkPassword(password) }}
onContinue={(username) => { connect(username) }}
onBack={() => { setCommandMode(null) }}
checkingPassword={checkingPassword}
loginError={loginError}
commandMode={commandMode}
/>
</>
}
<SideBar />
<MainMenu
open={mainMenuVisible}