latest dev
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import { requestedScreenSharingState, screenSharingAvailableStore } from "../Stores/ScreenSharingStore";
|
import { requestedScreenSharingState, screenSharingAvailableStore } from "../Stores/ScreenSharingStore";
|
||||||
import {requestedCameraState, requestedMicrophoneState} from "../Stores/MediaStore";
|
import { isSilentStore, requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
||||||
import monitorImg from "./images/monitor.svg";
|
import monitorImg from "./images/monitor.svg";
|
||||||
import monitorCloseImg from "./images/monitor-close.svg";
|
import monitorCloseImg from "./images/monitor-close.svg";
|
||||||
import cinemaImg from "./images/cinema.svg";
|
import cinemaImg from "./images/cinema.svg";
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
import { layoutModeStore } from "../Stores/StreamableCollectionStore";
|
import { layoutModeStore } from "../Stores/StreamableCollectionStore";
|
||||||
import { LayoutMode } from "../WebRtc/LayoutManager";
|
import { LayoutMode } from "../WebRtc/LayoutManager";
|
||||||
import { peerStore } from "../Stores/PeerStore";
|
import { peerStore } from "../Stores/PeerStore";
|
||||||
|
import { onDestroy } from "svelte";
|
||||||
|
|
||||||
function screenSharingClick(): void {
|
function screenSharingClick(): void {
|
||||||
if ($requestedScreenSharingState === true) {
|
if ($requestedScreenSharingState === true) {
|
||||||
@@ -44,6 +45,12 @@
|
|||||||
$layoutModeStore = LayoutMode.Presentation;
|
$layoutModeStore = LayoutMode.Presentation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isSilent: boolean;
|
||||||
|
const unsubscribeIsSilent = isSilentStore.subscribe(value => {
|
||||||
|
isSilent = value;
|
||||||
|
});
|
||||||
|
onDestroy(unsubscribeIsSilent);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -55,22 +62,26 @@
|
|||||||
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode">
|
<img src={layoutChatImg} style="padding: 2px" alt="Switch to presentation mode">
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-micro nes-btn is-dark" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState}>
|
<div class="btn-micro nes-btn is-dark" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState ||
|
||||||
{#if $requestedMicrophoneState}
|
isSilent}>
|
||||||
|
{#if $requestedMicrophoneState && !isSilent}
|
||||||
<img src={microphoneImg} alt="Turn on microphone">
|
<img src={microphoneImg} alt="Turn on microphone">
|
||||||
{:else}
|
{:else}
|
||||||
|
|
||||||
<img src={microphoneCloseImg} alt="Turn off microphone">
|
<img src={microphoneCloseImg} alt="Turn off microphone">
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-video nes-btn is-dark" on:click={cameraClick} class:disabled={!$requestedCameraState}>
|
<div class="btn-video nes-btn is-dark" on:click={cameraClick} class:disabled={!$requestedCameraState ||
|
||||||
{#if $requestedCameraState}
|
isSilent}>
|
||||||
|
{#if $requestedCameraState && !isSilent}
|
||||||
<img src={cinemaImg} alt="Turn on webcam">
|
<img src={cinemaImg} alt="Turn on webcam">
|
||||||
{:else}
|
{:else}
|
||||||
<img src={cinemaCloseImg} alt="Turn off webcam">
|
<img src={cinemaCloseImg} alt="Turn off webcam">
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-monitor nes-btn is-dark" on:click={screenSharingClick} class:hide={!$screenSharingAvailableStore} class:enabled={$requestedScreenSharingState}>
|
<div class="btn-monitor nes-btn is-dark" on:click={screenSharingClick} class:hide={!$screenSharingAvailableStore
|
||||||
{#if $requestedScreenSharingState}
|
|| isSilent} class:enabled={$requestedScreenSharingState}>
|
||||||
|
{#if $requestedScreenSharingState && !isSilent}
|
||||||
<img src={monitorImg} alt="Start screen sharing">
|
<img src={monitorImg} alt="Start screen sharing">
|
||||||
{:else}
|
{:else}
|
||||||
<img src={monitorCloseImg} alt="Stop screen sharing">
|
<img src={monitorCloseImg} alt="Stop screen sharing">
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {gameManager} from "../../Phaser/Game/GameManager";
|
import {gameManager} from "../../Phaser/Game/GameManager";
|
||||||
import {SelectCompanionScene, SelectCompanionSceneName} from "../../Phaser/Login/SelectCompanionScene";
|
import {SelectCompanionScene, SelectCompanionSceneName} from "../../Phaser/Login/SelectCompanionScene";
|
||||||
import {menuIconVisiblilityStore, menuVisiblilityStore} from "../../Stores/MenuStore";
|
import {menuIconVisiblilityStore, menuVisiblilityStore, userIsConnected} from "../../Stores/MenuStore";
|
||||||
import {selectCompanionSceneVisibleStore} from "../../Stores/SelectCompanionStore";
|
import {selectCompanionSceneVisibleStore} from "../../Stores/SelectCompanionStore";
|
||||||
import {LoginScene, LoginSceneName} from "../../Phaser/Login/LoginScene";
|
import {LoginScene, LoginSceneName} from "../../Phaser/Login/LoginScene";
|
||||||
import {loginSceneVisibleStore} from "../../Stores/LoginSceneStore";
|
import {loginSceneVisibleStore} from "../../Stores/LoginSceneStore";
|
||||||
import {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore";
|
import {selectCharacterSceneVisibleStore} from "../../Stores/SelectCharacterStore";
|
||||||
import {SelectCharacterScene, SelectCharacterSceneName} from "../../Phaser/Login/SelectCharacterScene";
|
import {SelectCharacterScene, SelectCharacterSceneName} from "../../Phaser/Login/SelectCharacterScene";
|
||||||
//import {connectionManager} from "../../Connexion/ConnectionManager";
|
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||||
|
import {PROFILE_URL} from "../../Enum/EnvironmentVariable";
|
||||||
|
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||||
|
import {EnableCameraScene, EnableCameraSceneName} from "../../Phaser/Login/EnableCameraScene";
|
||||||
|
import {enableCameraSceneVisibilityStore} from "../../Stores/MediaStore";
|
||||||
|
|
||||||
|
|
||||||
function disableMenuStores(){
|
function disableMenuStores(){
|
||||||
@@ -33,23 +37,51 @@
|
|||||||
gameManager.leaveGame(SelectCharacterSceneName,new SelectCharacterScene());
|
gameManager.leaveGame(SelectCharacterSceneName,new SelectCharacterScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logOut(){
|
||||||
|
disableMenuStores();
|
||||||
|
loginSceneVisibleStore.set(true);
|
||||||
|
connectionManager.logout();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProfileUrl(){
|
||||||
|
return PROFILE_URL + `?token=${localUserStore.getAuthToken()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openEnableCameraScene(){
|
||||||
|
disableMenuStores();
|
||||||
|
enableCameraSceneVisibilityStore.showEnableCameraScene();
|
||||||
|
gameManager.leaveGame(EnableCameraSceneName,new EnableCameraScene());
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: Uncomment when login will be completely developed
|
//TODO: Uncomment when login will be completely developed
|
||||||
/*function clickLogin() {
|
/*function clickLogin() {
|
||||||
connectionManager.loadOpenIDScreen();
|
connectionManager.loadOpenIDScreen();
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="customize-main">
|
<div class="customize-main">
|
||||||
<!-- <section>
|
{#if $userIsConnected}
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>Edit Name</button>
|
|
||||||
</section> -->
|
|
||||||
<section>
|
<section>
|
||||||
<button type="button" class="nes-btn is-rounded" on:click|preventDefault={openEditSkinScene}>Edit Skin</button>
|
{#if PROFILE_URL != undefined}
|
||||||
|
<iframe title="profile" src="{getProfileUrl()}"></iframe>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={logOut}>Log out</button>
|
||||||
|
</section>
|
||||||
|
{:else}
|
||||||
|
<section>
|
||||||
|
<a type="button" class="nes-btn" href="/login">Sing in</a>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
<section>
|
||||||
|
<!-- <button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}>Edit Name</button> -->
|
||||||
|
<button type="button" class="nes-btn is-rounded" on:click|preventDefault={openEditSkinScene}>Edit Skin</button>
|
||||||
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>Edit Companion</button>
|
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}>Edit Companion</button>
|
||||||
</section>
|
</section>
|
||||||
|
<section>
|
||||||
|
<button type="button" class="nes-btn" on:click|preventDefault={openEnableCameraScene}>Setup camera</button>
|
||||||
|
</section>
|
||||||
<!-- <section>
|
<!-- <section>
|
||||||
<button type="button" class="nes-btn is-primary" on:click|preventDefault={clickLogin}>Login</button>
|
<button type="button" class="nes-btn is-primary" on:click|preventDefault={clickLogin}>Login</button>
|
||||||
</section>-->
|
</section>-->
|
||||||
@@ -63,6 +95,12 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
iframe{
|
||||||
|
width: 100%;
|
||||||
|
height: 50vh;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import {obtainedMediaConstraintStore} from "../Stores/MediaStore";
|
import {obtainedMediaConstraintStore} from "../Stores/MediaStore";
|
||||||
import {localStreamStore} from "../Stores/MediaStore";
|
import {localStreamStore, isSilentStore} from "../Stores/MediaStore";
|
||||||
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
import SoundMeterWidget from "./SoundMeterWidget.svelte";
|
||||||
import {onDestroy} from "svelte";
|
import {onDestroy} from "svelte";
|
||||||
import {srcObject} from "./Video/utils";
|
import {srcObject} from "./Video/utils";
|
||||||
@@ -17,14 +17,25 @@
|
|||||||
|
|
||||||
onDestroy(unsubscribe);
|
onDestroy(unsubscribe);
|
||||||
|
|
||||||
|
|
||||||
|
let isSilent: boolean;
|
||||||
|
const unsubscribeIsSilent = isSilentStore.subscribe(value => {
|
||||||
|
isSilent = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(unsubscribeIsSilent);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="video-container nes-container is-rounded is-dark div-myCamVideo" class:hide={!$obtainedMediaConstraintStore.video}>
|
<div class="video-container nes-container is-rounded is-dark div-myCamVideo" class:hide={!$obtainedMediaConstraintStore.video || isSilent}>
|
||||||
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
|
{#if $localStreamStore.type === "success" && $localStreamStore.stream}
|
||||||
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline></video>
|
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline></video>
|
||||||
<SoundMeterWidget stream={stream}></SoundMeterWidget>
|
<SoundMeterWidget stream={stream}></SoundMeterWidget>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="is-silent" class:hide={isSilent}>
|
||||||
|
Silent zone
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { localUserStore } from "./LocalUserStore";
|
|||||||
import { CharacterTexture, LocalUser } from "./LocalUser";
|
import { CharacterTexture, LocalUser } from "./LocalUser";
|
||||||
import { Room } from "./Room";
|
import { Room } from "./Room";
|
||||||
import { _ServiceWorker } from "../Network/ServiceWorker";
|
import { _ServiceWorker } from "../Network/ServiceWorker";
|
||||||
|
import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore";
|
||||||
|
import { userIsConnected } from "../Stores/MenuStore";
|
||||||
|
|
||||||
class ConnectionManager {
|
class ConnectionManager {
|
||||||
private localUser!: LocalUser;
|
private localUser!: LocalUser;
|
||||||
@@ -15,6 +17,7 @@ class ConnectionManager {
|
|||||||
private reconnectingTimeout: NodeJS.Timeout | null = null;
|
private reconnectingTimeout: NodeJS.Timeout | null = null;
|
||||||
private _unloading: boolean = false;
|
private _unloading: boolean = false;
|
||||||
private authToken: string | null = null;
|
private authToken: string | null = null;
|
||||||
|
private _currentRoom: Room | null = null;
|
||||||
|
|
||||||
private serviceWorker?: _ServiceWorker;
|
private serviceWorker?: _ServiceWorker;
|
||||||
|
|
||||||
@@ -30,9 +33,9 @@ class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Promise<void>
|
* TODO fix me to be move in game manager
|
||||||
*/
|
*/
|
||||||
public loadOpenIDScreen(): Promise<void> {
|
public loadOpenIDScreen() {
|
||||||
const state = localUserStore.generateState();
|
const state = localUserStore.generateState();
|
||||||
const nonce = localUserStore.generateNonce();
|
const nonce = localUserStore.generateNonce();
|
||||||
|
|
||||||
@@ -49,21 +52,32 @@ class ConnectionManager {
|
|||||||
|
|
||||||
localUserStore.setAuthToken(null);
|
localUserStore.setAuthToken(null);
|
||||||
|
|
||||||
//TODO refactor this and don't realise previous call
|
//TODO fix me to redirect this URL by pusher
|
||||||
return Axios.get(loginUrl)
|
if (!this._currentRoom || !this._currentRoom.iframeAuthentication) {
|
||||||
.then(() => {
|
loginSceneVisibleIframeStore.set(false);
|
||||||
window.location.assign(loginUrl);
|
return null;
|
||||||
})
|
}
|
||||||
.catch((err) => {
|
const redirectUrl = `${this._currentRoom.iframeAuthentication}?state=${state}&nonce=${nonce}`;
|
||||||
console.error(err, "We don't have URL to regenerate authentication user");
|
window.location.assign(redirectUrl);
|
||||||
//TODO show modal login
|
return redirectUrl;
|
||||||
window.location.reload();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public logout() {
|
/**
|
||||||
|
* Logout
|
||||||
|
*/
|
||||||
|
public async logout() {
|
||||||
|
//user logout, set connected store for menu at false
|
||||||
|
userIsConnected.set(false);
|
||||||
|
|
||||||
|
//Logout user in pusher and hydra
|
||||||
|
const token = localUserStore.getAuthToken();
|
||||||
|
const { authToken } = await Axios.get(`${PUSHER_URL}/logout-callback`, { params: { token } }).then(
|
||||||
|
(res) => res.data
|
||||||
|
);
|
||||||
localUserStore.setAuthToken(null);
|
localUserStore.setAuthToken(null);
|
||||||
window.location.reload();
|
|
||||||
|
//Go on login page can permit to clear token and start authentication process
|
||||||
|
window.location.assign("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,8 +86,13 @@ class ConnectionManager {
|
|||||||
public async initGameConnexion(): Promise<Room> {
|
public async initGameConnexion(): Promise<Room> {
|
||||||
const connexionType = urlManager.getGameConnexionType();
|
const connexionType = urlManager.getGameConnexionType();
|
||||||
this.connexionType = connexionType;
|
this.connexionType = connexionType;
|
||||||
let room: Room | null = null;
|
this._currentRoom = null;
|
||||||
if (connexionType === GameConnexionTypes.jwt) {
|
if (connexionType === GameConnexionTypes.login) {
|
||||||
|
//TODO clear all cash and redirect on login scene (iframe)
|
||||||
|
localUserStore.setAuthToken(null);
|
||||||
|
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
||||||
|
urlManager.pushRoomIdToUrl(this._currentRoom);
|
||||||
|
} else if (connexionType === GameConnexionTypes.jwt) {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const code = urlParams.get("code");
|
const code = urlParams.get("code");
|
||||||
const state = urlParams.get("state");
|
const state = urlParams.get("state");
|
||||||
@@ -83,24 +102,15 @@ class ConnectionManager {
|
|||||||
if (!code) {
|
if (!code) {
|
||||||
throw "No Auth code provided";
|
throw "No Auth code provided";
|
||||||
}
|
}
|
||||||
const nonce = localUserStore.getNonce();
|
localUserStore.setCode(code);
|
||||||
const { authToken } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce } }).then(
|
try {
|
||||||
(res) => res.data
|
await this.checkAuthUserConnexion();
|
||||||
);
|
} catch (err) {
|
||||||
localUserStore.setAuthToken(authToken);
|
console.error(err);
|
||||||
this.authToken = authToken;
|
this.loadOpenIDScreen();
|
||||||
|
|
||||||
let roomPath: string;
|
|
||||||
|
|
||||||
roomPath = window.location.protocol + "//" + window.location.host + START_ROOM_URL;
|
|
||||||
|
|
||||||
const lastRoomUrl = localUserStore.getLastRoomUrl();
|
|
||||||
if (lastRoomUrl != undefined && lastRoomUrl != "") {
|
|
||||||
roomPath = lastRoomUrl;
|
|
||||||
}
|
}
|
||||||
|
this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl()));
|
||||||
room = await Room.createRoom(new URL(roomPath));
|
urlManager.pushRoomIdToUrl(this._currentRoom);
|
||||||
urlManager.pushRoomIdToUrl(room);
|
|
||||||
} else if (connexionType === GameConnexionTypes.register) {
|
} else if (connexionType === GameConnexionTypes.register) {
|
||||||
//@deprecated
|
//@deprecated
|
||||||
const organizationMemberToken = urlManager.getOrganizationToken();
|
const organizationMemberToken = urlManager.getOrganizationToken();
|
||||||
@@ -114,7 +124,7 @@ class ConnectionManager {
|
|||||||
|
|
||||||
const roomUrl = data.roomUrl;
|
const roomUrl = data.roomUrl;
|
||||||
|
|
||||||
room = await Room.createRoom(
|
this._currentRoom = await Room.createRoom(
|
||||||
new URL(
|
new URL(
|
||||||
window.location.protocol +
|
window.location.protocol +
|
||||||
"//" +
|
"//" +
|
||||||
@@ -124,7 +134,7 @@ class ConnectionManager {
|
|||||||
window.location.hash
|
window.location.hash
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
urlManager.pushRoomIdToUrl(room);
|
urlManager.pushRoomIdToUrl(this._currentRoom);
|
||||||
} else if (
|
} else if (
|
||||||
connexionType === GameConnexionTypes.organization ||
|
connexionType === GameConnexionTypes.organization ||
|
||||||
connexionType === GameConnexionTypes.anonymous ||
|
connexionType === GameConnexionTypes.anonymous ||
|
||||||
@@ -134,13 +144,18 @@ class ConnectionManager {
|
|||||||
//todo: add here some kind of warning if authToken has expired.
|
//todo: add here some kind of warning if authToken has expired.
|
||||||
if (!this.authToken) {
|
if (!this.authToken) {
|
||||||
await this.anonymousLogin();
|
await this.anonymousLogin();
|
||||||
// this.loadOpenIDScreen();
|
} else {
|
||||||
|
try {
|
||||||
|
await this.checkAuthUserConnexion();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
this.localUser = localUserStore.getLocalUser() as LocalUser; //if authToken exist in localStorage then localUser cannot be null
|
||||||
|
|
||||||
let roomPath: string;
|
let roomPath: string;
|
||||||
if (connexionType === GameConnexionTypes.empty) {
|
if (connexionType === GameConnexionTypes.empty) {
|
||||||
roomPath = window.location.protocol + "//" + window.location.host + START_ROOM_URL;
|
roomPath = localUserStore.getLastRoomUrl();
|
||||||
//get last room path from cache api
|
//get last room path from cache api
|
||||||
try {
|
try {
|
||||||
const lastRoomUrl = await localUserStore.getLastRoomUrlCacheApi();
|
const lastRoomUrl = await localUserStore.getLastRoomUrlCacheApi();
|
||||||
@@ -161,13 +176,13 @@ class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get detail map for anonymous login and set texture in local storage
|
//get detail map for anonymous login and set texture in local storage
|
||||||
room = await Room.createRoom(new URL(roomPath));
|
this._currentRoom = await Room.createRoom(new URL(roomPath));
|
||||||
if (room.textures != undefined && room.textures.length > 0) {
|
if (this._currentRoom.textures != undefined && this._currentRoom.textures.length > 0) {
|
||||||
//check if texture was changed
|
//check if texture was changed
|
||||||
if (this.localUser.textures.length === 0) {
|
if (this.localUser.textures.length === 0) {
|
||||||
this.localUser.textures = room.textures;
|
this.localUser.textures = this._currentRoom.textures;
|
||||||
} else {
|
} else {
|
||||||
room.textures.forEach((newTexture) => {
|
this._currentRoom.textures.forEach((newTexture) => {
|
||||||
const alreadyExistTexture = this.localUser.textures.find((c) => newTexture.id === c.id);
|
const alreadyExistTexture = this.localUser.textures.find((c) => newTexture.id === c.id);
|
||||||
if (this.localUser.textures.findIndex((c) => newTexture.id === c.id) !== -1) {
|
if (this.localUser.textures.findIndex((c) => newTexture.id === c.id) !== -1) {
|
||||||
return;
|
return;
|
||||||
@@ -178,12 +193,12 @@ class ConnectionManager {
|
|||||||
localUserStore.saveUser(this.localUser);
|
localUserStore.saveUser(this.localUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (room == undefined) {
|
if (this._currentRoom == undefined) {
|
||||||
return Promise.reject(new Error("Invalid URL"));
|
return Promise.reject(new Error("Invalid URL"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.serviceWorker = new _ServiceWorker();
|
this.serviceWorker = new _ServiceWorker();
|
||||||
return Promise.resolve(room);
|
return Promise.resolve(this._currentRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
|
public async anonymousLogin(isBenchmark: boolean = false): Promise<void> {
|
||||||
@@ -238,9 +253,6 @@ class ConnectionManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
connection.onConnect((connect: OnConnectInterface) => {
|
connection.onConnect((connect: OnConnectInterface) => {
|
||||||
//save last room url connected
|
|
||||||
localUserStore.setLastRoomUrl(roomUrl);
|
|
||||||
|
|
||||||
resolve(connect);
|
resolve(connect);
|
||||||
});
|
});
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
@@ -260,6 +272,34 @@ class ConnectionManager {
|
|||||||
get getConnexionType() {
|
get getConnexionType() {
|
||||||
return this.connexionType;
|
return this.connexionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkAuthUserConnexion() {
|
||||||
|
//set connected store for menu at false
|
||||||
|
userIsConnected.set(false);
|
||||||
|
|
||||||
|
const state = localUserStore.getState();
|
||||||
|
const code = localUserStore.getCode();
|
||||||
|
if (!state || !localUserStore.verifyState(state)) {
|
||||||
|
throw "Could not validate state!";
|
||||||
|
}
|
||||||
|
if (!code) {
|
||||||
|
throw "No Auth code provided";
|
||||||
|
}
|
||||||
|
const nonce = localUserStore.getNonce();
|
||||||
|
const token = localUserStore.getAuthToken();
|
||||||
|
const { authToken } = await Axios.get(`${PUSHER_URL}/login-callback`, { params: { code, nonce, token } }).then(
|
||||||
|
(res) => res.data
|
||||||
|
);
|
||||||
|
localUserStore.setAuthToken(authToken);
|
||||||
|
this.authToken = authToken;
|
||||||
|
|
||||||
|
//user connected, set connected store for menu at true
|
||||||
|
userIsConnected.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentRoom() {
|
||||||
|
return this._currentRoom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const connectionManager = new ConnectionManager();
|
export const connectionManager = new ConnectionManager();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { areCharacterLayersValid, isUserNameValid, LocalUser } from "./LocalUser";
|
import { areCharacterLayersValid, isUserNameValid, LocalUser } from "./LocalUser";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import { START_ROOM_URL } from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
const playerNameKey = "playerName";
|
const playerNameKey = "playerName";
|
||||||
const selectedPlayerKey = "selectedPlayer";
|
const selectedPlayerKey = "selectedPlayer";
|
||||||
@@ -17,6 +18,8 @@ const authToken = "authToken";
|
|||||||
const state = "state";
|
const state = "state";
|
||||||
const nonce = "nonce";
|
const nonce = "nonce";
|
||||||
const notification = "notificationPermission";
|
const notification = "notificationPermission";
|
||||||
|
const code = "code";
|
||||||
|
const cameraSetup = "cameraSetup";
|
||||||
|
|
||||||
const cacheAPIIndex = "workavdenture-cache";
|
const cacheAPIIndex = "workavdenture-cache";
|
||||||
|
|
||||||
@@ -125,7 +128,9 @@ class LocalUserStore {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
getLastRoomUrl(): string {
|
getLastRoomUrl(): string {
|
||||||
return localStorage.getItem(lastRoomUrl) ?? "";
|
return (
|
||||||
|
localStorage.getItem(lastRoomUrl) ?? window.location.protocol + "//" + window.location.host + START_ROOM_URL
|
||||||
|
);
|
||||||
}
|
}
|
||||||
getLastRoomUrlCacheApi(): Promise<string | undefined> {
|
getLastRoomUrlCacheApi(): Promise<string | undefined> {
|
||||||
return caches.open(cacheAPIIndex).then((cache) => {
|
return caches.open(cacheAPIIndex).then((cache) => {
|
||||||
@@ -160,19 +165,32 @@ class LocalUserStore {
|
|||||||
|
|
||||||
verifyState(value: string): boolean {
|
verifyState(value: string): boolean {
|
||||||
const oldValue = localStorage.getItem(state);
|
const oldValue = localStorage.getItem(state);
|
||||||
localStorage.removeItem(state);
|
|
||||||
return oldValue === value;
|
return oldValue === value;
|
||||||
}
|
}
|
||||||
|
getState(): string | null {
|
||||||
|
return localStorage.getItem(state);
|
||||||
|
}
|
||||||
generateNonce(): string {
|
generateNonce(): string {
|
||||||
const newNonce = uuidv4();
|
const newNonce = uuidv4();
|
||||||
localStorage.setItem(nonce, newNonce);
|
localStorage.setItem(nonce, newNonce);
|
||||||
return newNonce;
|
return newNonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNonce(): string | null {
|
getNonce(): string | null {
|
||||||
const oldValue = localStorage.getItem(nonce);
|
return localStorage.getItem(nonce);
|
||||||
localStorage.removeItem(nonce);
|
}
|
||||||
return oldValue;
|
setCode(value: string): void {
|
||||||
|
localStorage.setItem(code, value);
|
||||||
|
}
|
||||||
|
getCode(): string | null {
|
||||||
|
return localStorage.getItem(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCameraSetup(cameraId: string) {
|
||||||
|
localStorage.setItem(cameraSetup, cameraId);
|
||||||
|
}
|
||||||
|
getCameraSetup(): { video: unknown; audio: unknown } | undefined {
|
||||||
|
const cameraSetupValues = localStorage.getItem(cameraSetup);
|
||||||
|
return cameraSetupValues != undefined ? JSON.parse(cameraSetupValues) : undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export interface RoomRedirect {
|
|||||||
export class Room {
|
export class Room {
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
public readonly isPublic: boolean;
|
public readonly isPublic: boolean;
|
||||||
|
private _authenticationMandatory: boolean = false;
|
||||||
|
private _iframeAuthentication?: string;
|
||||||
private _mapUrl: string | undefined;
|
private _mapUrl: string | undefined;
|
||||||
private _textures: CharacterTexture[] | undefined;
|
private _textures: CharacterTexture[] | undefined;
|
||||||
private instance: string | undefined;
|
private instance: string | undefined;
|
||||||
@@ -101,6 +103,8 @@ export class Room {
|
|||||||
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
|
||||||
this._mapUrl = data.mapUrl;
|
this._mapUrl = data.mapUrl;
|
||||||
this._textures = data.textures;
|
this._textures = data.textures;
|
||||||
|
this._authenticationMandatory = data.authenticationMandatory || false;
|
||||||
|
this._iframeAuthentication = data.iframeAuthentication;
|
||||||
return new MapDetail(data.mapUrl, data.textures);
|
return new MapDetail(data.mapUrl, data.textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,4 +190,12 @@ export class Room {
|
|||||||
}
|
}
|
||||||
return this._mapUrl;
|
return this._mapUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get authenticationMandatory(): boolean {
|
||||||
|
return this._authenticationMandatory;
|
||||||
|
}
|
||||||
|
|
||||||
|
get iframeAuthentication(): string | undefined {
|
||||||
|
return this._iframeAuthentication;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,11 @@ export class RoomConnection implements RoomConnection {
|
|||||||
*
|
*
|
||||||
* @param token A JWT token containing the email of the user
|
* @param token A JWT token containing the email of the user
|
||||||
* @param roomUrl The URL of the room in the form "https://example.com/_/[instance]/[map_url]" or "https://example.com/@/[org]/[event]/[map]"
|
* @param roomUrl The URL of the room in the form "https://example.com/_/[instance]/[map_url]" or "https://example.com/@/[org]/[event]/[map]"
|
||||||
|
* @param name
|
||||||
|
* @param characterLayers
|
||||||
|
* @param position
|
||||||
|
* @param viewport
|
||||||
|
* @param companion
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
token: string | null,
|
token: string | null,
|
||||||
@@ -218,7 +223,7 @@ export class RoomConnection implements RoomConnection {
|
|||||||
worldFullMessageStream.onMessage();
|
worldFullMessageStream.onMessage();
|
||||||
this.closed = true;
|
this.closed = true;
|
||||||
} else if (message.hasTokenexpiredmessage()) {
|
} else if (message.hasTokenexpiredmessage()) {
|
||||||
connectionManager.loadOpenIDScreen();
|
connectionManager.logout();
|
||||||
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
|
this.closed = true; //technically, this isn't needed since loadOpenIDScreen() will do window.location.assign() but I prefer to leave it for consistency
|
||||||
} else if (message.hasWorldconnexionmessage()) {
|
} else if (message.hasWorldconnexionmessage()) {
|
||||||
worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage());
|
worldFullMessageStream.onMessage(message.getWorldconnexionmessage()?.getMessage());
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export const MAX_PER_GROUP = parseInt(process.env.MAX_PER_GROUP || "4");
|
|||||||
export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true";
|
export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true";
|
||||||
export const NODE_ENV = process.env.NODE_ENV || "development";
|
export const NODE_ENV = process.env.NODE_ENV || "development";
|
||||||
export const CONTACT_URL = process.env.CONTACT_URL || undefined;
|
export const CONTACT_URL = process.env.CONTACT_URL || undefined;
|
||||||
|
export const PROFILE_URL = process.env.PROFILE_URL || undefined;
|
||||||
|
|
||||||
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600;
|
||||||
|
|
||||||
|
|||||||
@@ -70,3 +70,9 @@ export const addLoader = (scene: Phaser.Scene): void => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const removeLoader = (scene: Phaser.Scene): void => {
|
||||||
|
if (scene.load.textureManager.exists(LogoNameIndex)) {
|
||||||
|
scene.load.textureManager.remove(LogoNameIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type {GameScene} from "../Game/GameScene";
|
|||||||
import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes";
|
import { DEPTH_INGAME_TEXT_INDEX } from "../Game/DepthIndexes";
|
||||||
import { waScaleManager } from "../Services/WaScaleManager";
|
import { waScaleManager } from "../Services/WaScaleManager";
|
||||||
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
import type OutlinePipelinePlugin from "phaser3-rex-plugins/plugins/outlinepipeline-plugin.js";
|
||||||
|
import { isSilentStore } from "../../Stores/MediaStore";
|
||||||
|
|
||||||
const playerNameY = -25;
|
const playerNameY = -25;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ interface AnimationData {
|
|||||||
frameRate: number;
|
frameRate: number;
|
||||||
repeat: number;
|
repeat: number;
|
||||||
frameModel: string; //todo use an enum
|
frameModel: string; //todo use an enum
|
||||||
frames : number[]
|
frames: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const interactiveRadius = 35;
|
const interactiveRadius = 35;
|
||||||
@@ -35,7 +36,8 @@ export abstract class Character extends Container {
|
|||||||
private emoteTween: Phaser.Tweens.Tween|null = null;
|
private emoteTween: Phaser.Tweens.Tween|null = null;
|
||||||
scene: GameScene;
|
scene: GameScene;
|
||||||
|
|
||||||
constructor(scene: GameScene,
|
constructor(
|
||||||
|
scene: GameScene,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
texturesPromise: Promise<string[]>,
|
texturesPromise: Promise<string[]>,
|
||||||
@@ -50,17 +52,22 @@ export abstract class Character extends Container {
|
|||||||
super(scene, x, y /*, texture, frame*/);
|
super(scene, x, y /*, texture, frame*/);
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.PlayerValue = name;
|
this.PlayerValue = name;
|
||||||
this.invisible = true
|
this.invisible = true;
|
||||||
|
|
||||||
this.sprites = new Map<string, Sprite>();
|
this.sprites = new Map<string, Sprite>();
|
||||||
|
|
||||||
//textures are inside a Promise in case they need to be lazyloaded before use.
|
//textures are inside a Promise in case they need to be lazyloaded before use.
|
||||||
texturesPromise.then((textures) => {
|
texturesPromise.then((textures) => {
|
||||||
this.addTextures(textures, frame);
|
this.addTextures(textures, frame);
|
||||||
this.invisible = false
|
this.invisible = false;
|
||||||
})
|
});
|
||||||
|
|
||||||
this.playerName = new Text(scene, 0, playerNameY, name, {fontFamily: '"Press Start 2P"', fontSize: '8px', strokeThickness: 2, stroke: "#000"});
|
this.playerName = new Text(scene, 0, playerNameY, name, {
|
||||||
|
fontFamily: '"Press Start 2P"',
|
||||||
|
fontSize: "8px",
|
||||||
|
strokeThickness: 2,
|
||||||
|
stroke: "#000",
|
||||||
|
});
|
||||||
this.playerName.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
this.playerName.setOrigin(0.5).setDepth(DEPTH_INGAME_TEXT_INDEX);
|
||||||
this.add(this.playerName);
|
this.add(this.playerName);
|
||||||
|
|
||||||
@@ -71,18 +78,17 @@ export abstract class Character extends Container {
|
|||||||
useHandCursor: true,
|
useHandCursor: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('pointerover',() => {
|
this.on("pointerover", () => {
|
||||||
this.getOutlinePlugin()?.add(this.playerName, {
|
this.getOutlinePlugin()?.add(this.playerName, {
|
||||||
thickness: 2,
|
thickness: 2,
|
||||||
outlineColor: 0xffff00
|
outlineColor: 0xffff00,
|
||||||
});
|
});
|
||||||
this.scene.markDirty();
|
this.scene.markDirty();
|
||||||
});
|
});
|
||||||
this.on('pointerout',() => {
|
this.on("pointerout", () => {
|
||||||
this.getOutlinePlugin()?.remove(this.playerName);
|
this.getOutlinePlugin()?.remove(this.playerName);
|
||||||
this.scene.markDirty();
|
this.scene.markDirty();
|
||||||
})
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.add.existing(this);
|
scene.add.existing(this);
|
||||||
@@ -97,17 +103,17 @@ export abstract class Character extends Container {
|
|||||||
|
|
||||||
this.playAnimation(direction, moving);
|
this.playAnimation(direction, moving);
|
||||||
|
|
||||||
if (typeof companion === 'string') {
|
if (typeof companion === "string") {
|
||||||
this.addCompanion(companion, companionTexturePromise);
|
this.addCompanion(companion, companionTexturePromise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOutlinePlugin(): OutlinePipelinePlugin | undefined {
|
private getOutlinePlugin(): OutlinePipelinePlugin | undefined {
|
||||||
return this.scene.plugins.get('rexOutlinePipeline') as unknown as OutlinePipelinePlugin|undefined;
|
return this.scene.plugins.get("rexOutlinePipeline") as unknown as OutlinePipelinePlugin | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addCompanion(name: string, texturePromise?: Promise<string>): void {
|
public addCompanion(name: string, texturePromise?: Promise<string>): void {
|
||||||
if (typeof texturePromise !== 'undefined') {
|
if (typeof texturePromise !== "undefined") {
|
||||||
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
this.companion = new Companion(this.scene, this.x, this.y, name, texturePromise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,18 +121,18 @@ export abstract class Character extends Container {
|
|||||||
public addTextures(textures: string[], frame?: string | number): void {
|
public addTextures(textures: string[], frame?: string | number): void {
|
||||||
for (const texture of textures) {
|
for (const texture of textures) {
|
||||||
if (this.scene && !this.scene.textures.exists(texture)) {
|
if (this.scene && !this.scene.textures.exists(texture)) {
|
||||||
throw new TextureError('texture not found');
|
throw new TextureError("texture not found");
|
||||||
}
|
}
|
||||||
const sprite = new Sprite(this.scene, 0, 0, texture, frame);
|
const sprite = new Sprite(this.scene, 0, 0, texture, frame);
|
||||||
this.add(sprite);
|
this.add(sprite);
|
||||||
this.getPlayerAnimations(texture).forEach(d => {
|
this.getPlayerAnimations(texture).forEach((d) => {
|
||||||
this.scene.anims.create({
|
this.scene.anims.create({
|
||||||
key: d.key,
|
key: d.key,
|
||||||
frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }),
|
frames: this.scene.anims.generateFrameNumbers(d.frameModel, { frames: d.frames }),
|
||||||
frameRate: d.frameRate,
|
frameRate: d.frameRate,
|
||||||
repeat: d.repeat
|
repeat: d.repeat,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
// Needed, otherwise, animations are not handled correctly.
|
// Needed, otherwise, animations are not handled correctly.
|
||||||
if (this.scene) {
|
if (this.scene) {
|
||||||
this.scene.sys.updateList.add(sprite);
|
this.scene.sys.updateList.add(sprite);
|
||||||
@@ -136,68 +142,77 @@ export abstract class Character extends Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getPlayerAnimations(name: string): AnimationData[] {
|
private getPlayerAnimations(name: string): AnimationData[] {
|
||||||
return [{
|
return [
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`,
|
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Walk}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [0, 1, 2, 1],
|
frames: [0, 1, 2, 1],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: -1
|
repeat: -1,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`,
|
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Walk}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [3, 4, 5, 4],
|
frames: [3, 4, 5, 4],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: -1
|
repeat: -1,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`,
|
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Walk}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [6, 7, 8, 7],
|
frames: [6, 7, 8, 7],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: -1
|
repeat: -1,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`,
|
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Walk}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [9, 10, 11, 10],
|
frames: [9, 10, 11, 10],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: -1
|
repeat: -1,
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`,
|
key: `${name}-${PlayerAnimationDirections.Down}-${PlayerAnimationTypes.Idle}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [1],
|
frames: [1],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: 1
|
repeat: 1,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`,
|
key: `${name}-${PlayerAnimationDirections.Left}-${PlayerAnimationTypes.Idle}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [4],
|
frames: [4],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: 1
|
repeat: 1,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`,
|
key: `${name}-${PlayerAnimationDirections.Right}-${PlayerAnimationTypes.Idle}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [7],
|
frames: [7],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: 1
|
repeat: 1,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`,
|
key: `${name}-${PlayerAnimationDirections.Up}-${PlayerAnimationTypes.Idle}`,
|
||||||
frameModel: name,
|
frameModel: name,
|
||||||
frames: [10],
|
frames: [10],
|
||||||
frameRate: 10,
|
frameRate: 10,
|
||||||
repeat: 1
|
repeat: 1,
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected playAnimation(direction: PlayerAnimationDirections, moving: boolean): void {
|
protected playAnimation(direction: PlayerAnimationDirections, moving: boolean): void {
|
||||||
if (this.invisible) return;
|
if (this.invisible) return;
|
||||||
for (const [texture, sprite] of this.sprites.entries()) {
|
for (const [texture, sprite] of this.sprites.entries()) {
|
||||||
if (!sprite.anims) {
|
if (!sprite.anims) {
|
||||||
console.error('ANIMS IS NOT DEFINED!!!');
|
console.error("ANIMS IS NOT DEFINED!!!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) {
|
if (moving && (!sprite.anims.currentAnim || sprite.anims.currentAnim.key !== direction)) {
|
||||||
sprite.play(texture+'-'+direction+'-'+PlayerAnimationTypes.Walk, true);
|
sprite.play(texture + "-" + direction + "-" + PlayerAnimationTypes.Walk, true);
|
||||||
} else if (!moving) {
|
} else if (!moving) {
|
||||||
sprite.anims.play(texture + '-' + direction + '-'+PlayerAnimationTypes.Idle, true);
|
sprite.anims.play(texture + "-" + direction + "-" + PlayerAnimationTypes.Idle, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +220,7 @@ export abstract class Character extends Container {
|
|||||||
protected getBody(): Phaser.Physics.Arcade.Body {
|
protected getBody(): Phaser.Physics.Arcade.Body {
|
||||||
const body = this.body;
|
const body = this.body;
|
||||||
if (!(body instanceof Phaser.Physics.Arcade.Body)) {
|
if (!(body instanceof Phaser.Physics.Arcade.Body)) {
|
||||||
throw new Error('Container does not have arcade body');
|
throw new Error("Container does not have arcade body");
|
||||||
}
|
}
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
@@ -216,16 +231,20 @@ export abstract class Character extends Container {
|
|||||||
body.setVelocity(x, y);
|
body.setVelocity(x, y);
|
||||||
|
|
||||||
// up or down animations are prioritized over left and right
|
// up or down animations are prioritized over left and right
|
||||||
if (body.velocity.y < 0) { //moving up
|
if (body.velocity.y < 0) {
|
||||||
|
//moving up
|
||||||
this.lastDirection = PlayerAnimationDirections.Up;
|
this.lastDirection = PlayerAnimationDirections.Up;
|
||||||
this.playAnimation(PlayerAnimationDirections.Up, true);
|
this.playAnimation(PlayerAnimationDirections.Up, true);
|
||||||
} else if (body.velocity.y > 0) { //moving down
|
} else if (body.velocity.y > 0) {
|
||||||
|
//moving down
|
||||||
this.lastDirection = PlayerAnimationDirections.Down;
|
this.lastDirection = PlayerAnimationDirections.Down;
|
||||||
this.playAnimation(PlayerAnimationDirections.Down, true);
|
this.playAnimation(PlayerAnimationDirections.Down, true);
|
||||||
} else if (body.velocity.x > 0) { //moving right
|
} else if (body.velocity.x > 0) {
|
||||||
|
//moving right
|
||||||
this.lastDirection = PlayerAnimationDirections.Right;
|
this.lastDirection = PlayerAnimationDirections.Right;
|
||||||
this.playAnimation(PlayerAnimationDirections.Right, true);
|
this.playAnimation(PlayerAnimationDirections.Right, true);
|
||||||
} else if (body.velocity.x < 0) { //moving left
|
} else if (body.velocity.x < 0) {
|
||||||
|
//moving left
|
||||||
this.lastDirection = PlayerAnimationDirections.Left;
|
this.lastDirection = PlayerAnimationDirections.Left;
|
||||||
this.playAnimation(PlayerAnimationDirections.Left, true);
|
this.playAnimation(PlayerAnimationDirections.Left, true);
|
||||||
}
|
}
|
||||||
@@ -244,13 +263,13 @@ export abstract class Character extends Container {
|
|||||||
|
|
||||||
say(text: string) {
|
say(text: string) {
|
||||||
if (this.bubble) return;
|
if (this.bubble) return;
|
||||||
this.bubble = new SpeechBubble(this.scene, this, text)
|
this.bubble = new SpeechBubble(this.scene, this, text);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.bubble !== null) {
|
if (this.bubble !== null) {
|
||||||
this.bubble.destroy();
|
this.bubble.destroy();
|
||||||
this.bubble = null;
|
this.bubble = null;
|
||||||
}
|
}
|
||||||
}, 3000)
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
@@ -259,10 +278,17 @@ export abstract class Character extends Container {
|
|||||||
this.scene.sys.updateList.remove(sprite);
|
this.scene.sys.updateList.remove(sprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.list.forEach(objectContaining => objectContaining.destroy())
|
this.list.forEach((objectContaining) => objectContaining.destroy());
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSilent() {
|
||||||
|
isSilentStore.set(true);
|
||||||
|
}
|
||||||
|
noSilent() {
|
||||||
|
isSilentStore.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
playEmote(emote: string) {
|
playEmote(emote: string) {
|
||||||
this.cancelPreviousEmote();
|
this.cancelPreviousEmote();
|
||||||
|
|
||||||
@@ -284,11 +310,11 @@ export abstract class Character extends Container {
|
|||||||
alpha: 1,
|
alpha: 1,
|
||||||
y: emoteY,
|
y: emoteY,
|
||||||
},
|
},
|
||||||
ease: 'Power2',
|
ease: "Power2",
|
||||||
duration: 500,
|
duration: 500,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.startPulseTransition(emoteY, scalingFactor);
|
this.startPulseTransition(emoteY, scalingFactor);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +323,7 @@ export abstract class Character extends Container {
|
|||||||
targets: this.emote,
|
targets: this.emote,
|
||||||
props: {
|
props: {
|
||||||
y: emoteY * 1.3,
|
y: emoteY * 1.3,
|
||||||
scale: scalingFactor * 1.1
|
scale: scalingFactor * 1.1,
|
||||||
},
|
},
|
||||||
duration: 250,
|
duration: 250,
|
||||||
yoyo: true,
|
yoyo: true,
|
||||||
@@ -305,7 +331,7 @@ export abstract class Character extends Container {
|
|||||||
completeDelay: 200,
|
completeDelay: 200,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.startExitTransition(emoteY);
|
this.startExitTransition(emoteY);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,11 +342,11 @@ export abstract class Character extends Container {
|
|||||||
alpha: 0,
|
alpha: 0,
|
||||||
y: 2 * emoteY,
|
y: 2 * emoteY,
|
||||||
},
|
},
|
||||||
ease: 'Power2',
|
ease: "Power2",
|
||||||
duration: 500,
|
duration: 500,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.destroyEmote();
|
this.destroyEmote();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +354,7 @@ export abstract class Character extends Container {
|
|||||||
if (!this.emote) return;
|
if (!this.emote) return;
|
||||||
|
|
||||||
this.emoteTween?.remove();
|
this.emoteTween?.remove();
|
||||||
this.destroyEmote()
|
this.destroyEmote();
|
||||||
}
|
}
|
||||||
|
|
||||||
private destroyEmote() {
|
private destroyEmote() {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export class EmoteManager {
|
|||||||
if(actor) {
|
if(actor) {
|
||||||
actor.playEmote(event.emote);
|
actor.playEmote(event.emote);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class GameManager {
|
|||||||
private characterLayers: string[] | null;
|
private characterLayers: string[] | null;
|
||||||
private companion: string | null;
|
private companion: string | null;
|
||||||
private startRoom!: Room;
|
private startRoom!: Room;
|
||||||
|
private cameraSetup?: { video: unknown; audio: unknown };
|
||||||
currentGameSceneName: string | null = null;
|
currentGameSceneName: string | null = null;
|
||||||
// Note: this scenePlugin is the scenePlugin of the EntryScene. We should always provide a key in methods called on this scenePlugin.
|
// Note: this scenePlugin is the scenePlugin of the EntryScene. We should always provide a key in methods called on this scenePlugin.
|
||||||
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
private scenePlugin!: Phaser.Scenes.ScenePlugin;
|
||||||
@@ -27,6 +28,7 @@ export class GameManager {
|
|||||||
this.playerName = localUserStore.getName();
|
this.playerName = localUserStore.getName();
|
||||||
this.characterLayers = localUserStore.getCharacterLayers();
|
this.characterLayers = localUserStore.getCharacterLayers();
|
||||||
this.companion = localUserStore.getCompanion();
|
this.companion = localUserStore.getCompanion();
|
||||||
|
this.cameraSetup = localUserStore.getCameraSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async init(scenePlugin: Phaser.Scenes.ScenePlugin): Promise<string> {
|
public async init(scenePlugin: Phaser.Scenes.ScenePlugin): Promise<string> {
|
||||||
@@ -39,12 +41,17 @@ export class GameManager {
|
|||||||
this.playerName = res.headers['bstlyusername'];
|
this.playerName = res.headers['bstlyusername'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.playerName) {
|
//If player name was not set show login scene with player name
|
||||||
|
//If Room si not public and Auth was not set, show login scene to authenticate user (OpenID - SSO - Anonymous)
|
||||||
|
if (!this.playerName || (this.startRoom.authenticationMandatory && !localUserStore.getAuthToken())) {
|
||||||
return LoginSceneName;
|
return LoginSceneName;
|
||||||
} else if (!this.characterLayers || !this.characterLayers.length) {
|
} else if (!this.characterLayers || !this.characterLayers.length) {
|
||||||
return SelectCharacterSceneName;
|
return SelectCharacterSceneName;
|
||||||
} else {
|
} else if (this.cameraSetup == undefined) {
|
||||||
return EnableCameraSceneName;
|
return EnableCameraSceneName;
|
||||||
|
} else {
|
||||||
|
this.activeMenuSceneAndHelpCameraSettings();
|
||||||
|
return this.startRoom.key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +97,14 @@ export class GameManager {
|
|||||||
public goToStartingMap(): void {
|
public goToStartingMap(): void {
|
||||||
console.log("starting " + (this.currentGameSceneName || this.startRoom.key));
|
console.log("starting " + (this.currentGameSceneName || this.startRoom.key));
|
||||||
this.scenePlugin.start(this.currentGameSceneName || this.startRoom.key);
|
this.scenePlugin.start(this.currentGameSceneName || this.startRoom.key);
|
||||||
|
this.activeMenuSceneAndHelpCameraSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private activeMenuSceneAndHelpCameraSettings(): void {
|
||||||
if (
|
if (
|
||||||
!localUserStore.getHelpCameraSettingsShown() &&
|
!localUserStore.getHelpCameraSettingsShown() &&
|
||||||
(!get(requestedMicrophoneState) || !get(requestedCameraState))
|
(!get(requestedMicrophoneState) || !get(requestedCameraState))
|
||||||
@@ -137,6 +151,10 @@ export class GameManager {
|
|||||||
if (this.currentGameSceneName === null) throw "No current scene id set!";
|
if (this.currentGameSceneName === null) throw "No current scene id set!";
|
||||||
return this.scenePlugin.get(this.currentGameSceneName) as GameScene;
|
return this.scenePlugin.get(this.currentGameSceneName) as GameScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get currentStartedRoom() {
|
||||||
|
return this.startRoom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const gameManager = new GameManager();
|
export const gameManager = new GameManager();
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { localUserStore } from "../../Connexion/LocalUserStore";
|
|||||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||||
import { mediaManager } from "../../WebRtc/MediaManager";
|
import { mediaManager } from "../../WebRtc/MediaManager";
|
||||||
import { SimplePeer } from "../../WebRtc/SimplePeer";
|
import { SimplePeer } from "../../WebRtc/SimplePeer";
|
||||||
import { addLoader } from "../Components/Loader";
|
import { addLoader, removeLoader } from "../Components/Loader";
|
||||||
import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon";
|
import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon";
|
||||||
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager";
|
||||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
import { RemotePlayer } from "../Entity/RemotePlayer";
|
||||||
@@ -93,6 +93,7 @@ import { userIsAdminStore } from "../../Stores/GameStore";
|
|||||||
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
||||||
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
||||||
import { GameMapPropertiesListener } from "./GameMapPropertiesListener";
|
import { GameMapPropertiesListener } from "./GameMapPropertiesListener";
|
||||||
|
import type { RadialMenuItem } from "../Components/RadialMenu";
|
||||||
|
|
||||||
export interface GameSceneInitInterface {
|
export interface GameSceneInitInterface {
|
||||||
initPosition: PointInterface | null;
|
initPosition: PointInterface | null;
|
||||||
@@ -291,8 +292,11 @@ export class GameScene extends DirtyScene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//once preloading is over, we don't want loading errors to crash the game, so we need to disable this behavior after preloading.
|
//once preloading is over, we don't want loading errors to crash the game, so we need to disable this behavior after preloading.
|
||||||
console.error("Error when loading: ", file);
|
|
||||||
if (this.preloading) {
|
if (this.preloading) {
|
||||||
|
//remove loader in progress
|
||||||
|
removeLoader(this);
|
||||||
|
|
||||||
|
//display an error scene
|
||||||
this.scene.start(ErrorSceneName, {
|
this.scene.start(ErrorSceneName, {
|
||||||
title: "Network error",
|
title: "Network error",
|
||||||
subTitle: "An error occurred while loading resource:",
|
subTitle: "An error occurred while loading resource:",
|
||||||
@@ -850,8 +854,10 @@ export class GameScene extends DirtyScene {
|
|||||||
this.gameMap.onPropertyChange("silent", (newValue, oldValue) => {
|
this.gameMap.onPropertyChange("silent", (newValue, oldValue) => {
|
||||||
if (newValue === undefined || newValue === false || newValue === "") {
|
if (newValue === undefined || newValue === false || newValue === "") {
|
||||||
this.connection?.setSilent(false);
|
this.connection?.setSilent(false);
|
||||||
|
this.CurrentPlayer.noSilent();
|
||||||
} else {
|
} else {
|
||||||
this.connection?.setSilent(true);
|
this.connection?.setSilent(true);
|
||||||
|
this.CurrentPlayer.isSilent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange("playAudio", (newValue, oldValue, allProps) => {
|
this.gameMap.onPropertyChange("playAudio", (newValue, oldValue, allProps) => {
|
||||||
@@ -1294,7 +1300,9 @@ export class GameScene extends DirtyScene {
|
|||||||
if (!targetRoom.isEqual(this.room)) {
|
if (!targetRoom.isEqual(this.room)) {
|
||||||
if (this.scene.get(targetRoom.key) === null) {
|
if (this.scene.get(targetRoom.key) === null) {
|
||||||
console.error("next room not loaded", targetRoom.key);
|
console.error("next room not loaded", targetRoom.key);
|
||||||
return;
|
// Try to load next dame room from exit URL
|
||||||
|
// The policy of room can to be updated during a session and not load before
|
||||||
|
await this.loadNextGameFromExitUrl(targetRoom.key);
|
||||||
}
|
}
|
||||||
this.cleanupClosingScene();
|
this.cleanupClosingScene();
|
||||||
this.scene.stop();
|
this.scene.stop();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { ResizableScene } from "./ResizableScene";
|
import { ResizableScene } from "./ResizableScene";
|
||||||
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
import { enableCameraSceneVisibilityStore } from "../../Stores/MediaStore";
|
||||||
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
|
|
||||||
export const EnableCameraSceneName = "EnableCameraScene";
|
export const EnableCameraSceneName = "EnableCameraScene";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { gameManager } from "../Game/GameManager";
|
|
||||||
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
import { SelectCharacterSceneName } from "./SelectCharacterScene";
|
||||||
import { ResizableScene } from "./ResizableScene";
|
import { ResizableScene } from "./ResizableScene";
|
||||||
import { loginSceneVisibleStore } from "../../Stores/LoginSceneStore";
|
import { loginSceneVisibleIframeStore, loginSceneVisibleStore } from "../../Stores/LoginSceneStore";
|
||||||
|
import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||||
|
import { connectionManager } from "../../Connexion/ConnectionManager";
|
||||||
|
import { gameManager } from "../Game/GameManager";
|
||||||
|
|
||||||
export const LoginSceneName = "LoginScene";
|
export const LoginSceneName = "LoginScene";
|
||||||
|
|
||||||
@@ -18,6 +20,16 @@ export class LoginScene extends ResizableScene {
|
|||||||
preload() {}
|
preload() {}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
|
loginSceneVisibleIframeStore.set(false);
|
||||||
|
//If authentication is mandatory, push authentication iframe
|
||||||
|
if (
|
||||||
|
localUserStore.getAuthToken() == undefined &&
|
||||||
|
gameManager.currentStartedRoom &&
|
||||||
|
gameManager.currentStartedRoom?.authenticationMandatory
|
||||||
|
) {
|
||||||
|
connectionManager.loadOpenIDScreen();
|
||||||
|
loginSceneVisibleIframeStore.set(true);
|
||||||
|
}
|
||||||
loginSceneVisibleStore.set(true);
|
loginSceneVisibleStore.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import Image = Phaser.GameObjects.Image;
|
|
||||||
import Rectangle = Phaser.GameObjects.Rectangle;
|
|
||||||
import { addLoader } from "../Components/Loader";
|
import { addLoader } from "../Components/Loader";
|
||||||
import { gameManager } from "../Game/GameManager";
|
import { gameManager } from "../Game/GameManager";
|
||||||
import { ResizableScene } from "./ResizableScene";
|
import { ResizableScene } from "./ResizableScene";
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class Player extends Character {
|
|||||||
this.emoteMenu.y = this.y;
|
this.emoteMenu.y = this.y;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.scene.events.addListener('postupdate', this.updateListener);
|
this.scene.events.addListener("postupdate", this.updateListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveUser(delta: number): void {
|
moveUser(delta: number): void {
|
||||||
@@ -117,13 +117,20 @@ export class Player extends Character {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSilent() {
|
||||||
|
super.isSilent();
|
||||||
|
}
|
||||||
|
noSilent() {
|
||||||
|
super.noSilent();
|
||||||
|
}
|
||||||
|
|
||||||
closeEmoteMenu(): void {
|
closeEmoteMenu(): void {
|
||||||
if (!this.emoteMenu) return;
|
if (!this.emoteMenu) return;
|
||||||
this.emoteMenu.closePicker();
|
this.emoteMenu.closePicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.scene.events.removeListener('postupdate', this.updateListener);
|
this.scene.events.removeListener("postupdate", this.updateListener);
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export class MediaStreamConstraintsError extends Error {
|
||||||
|
static NAME = "MediaStreamConstraintsError";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(
|
||||||
|
"Unable to access your camera or microphone. Your browser is too old. Please consider upgrading your browser or try using a recent version of Chrome."
|
||||||
|
);
|
||||||
|
this.name = MediaStreamConstraintsError.NAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
export const loginSceneVisibleStore = writable(false);
|
export const loginSceneVisibleStore = writable(false);
|
||||||
|
export const loginSceneVisibleIframeStore = writable(false);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { WebviewOnOldIOS } from "./Errors/WebviewOnOldIOS";
|
|||||||
import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility";
|
import { gameOverlayVisibilityStore } from "./GameOverlayStoreVisibility";
|
||||||
import { peerStore } from "./PeerStore";
|
import { peerStore } from "./PeerStore";
|
||||||
import { privacyShutdownStore } from "./PrivacyShutdownStore";
|
import { privacyShutdownStore } from "./PrivacyShutdownStore";
|
||||||
|
import { MediaStreamConstraintsError } from "./Errors/MediaStreamConstraintsError";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store that contains the camera state requested by the user (on or off).
|
* A store that contains the camera state requested by the user (on or off).
|
||||||
@@ -255,6 +256,12 @@ export const mediaStreamConstraintsStore = derived(
|
|||||||
video: currentVideoConstraint,
|
video: currentVideoConstraint,
|
||||||
audio: currentAudioConstraint,
|
audio: currentAudioConstraint,
|
||||||
});
|
});
|
||||||
|
localUserStore.setCameraSetup(
|
||||||
|
JSON.stringify({
|
||||||
|
video: currentVideoConstraint,
|
||||||
|
audio: currentAudioConstraint,
|
||||||
|
})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +420,7 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (constraints.video !== false) {
|
if (constraints.video !== false || constraints.audio !== false) {
|
||||||
console.info(
|
console.info(
|
||||||
"Error. Unable to get microphone and/or camera access. Trying audio only.",
|
"Error. Unable to get microphone and/or camera access. Trying audio only.",
|
||||||
$mediaStreamConstraintsStore,
|
$mediaStreamConstraintsStore,
|
||||||
@@ -425,7 +432,17 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||||||
error: e,
|
error: e,
|
||||||
});
|
});
|
||||||
// Let's try without video constraints
|
// Let's try without video constraints
|
||||||
|
if (constraints.video !== false) {
|
||||||
requestedCameraState.disableWebcam();
|
requestedCameraState.disableWebcam();
|
||||||
|
}
|
||||||
|
if (constraints.audio !== false) {
|
||||||
|
requestedMicrophoneState.disableMicrophone();
|
||||||
|
}
|
||||||
|
} else if (!constraints.video && !constraints.audio) {
|
||||||
|
set({
|
||||||
|
type: "error",
|
||||||
|
error: new MediaStreamConstraintsError(),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
console.info(
|
console.info(
|
||||||
"Error. Unable to get microphone and/or camera access.",
|
"Error. Unable to get microphone and/or camera access.",
|
||||||
@@ -561,3 +578,8 @@ localStreamStore.subscribe((streamResult) => {
|
|||||||
* A store containing the real active media is mobile
|
* A store containing the real active media is mobile
|
||||||
*/
|
*/
|
||||||
export const obtainedMediaConstraintIsMobileStore = writable(false);
|
export const obtainedMediaConstraintIsMobileStore = writable(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A store containing if user is silent, so if he is in silent zone. This permit to show et hide camera of user
|
||||||
|
*/
|
||||||
|
export const isSilentStore = writable(false);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { CONTACT_URL } from "../Enum/EnvironmentVariable";
|
|||||||
export const menuIconVisiblilityStore = writable(false);
|
export const menuIconVisiblilityStore = writable(false);
|
||||||
export const menuVisiblilityStore = writable(false);
|
export const menuVisiblilityStore = writable(false);
|
||||||
export const menuInputFocusStore = writable(false);
|
export const menuInputFocusStore = writable(false);
|
||||||
|
export const loginUrlStore = writable(false);
|
||||||
|
export const userIsConnected = writable(false);
|
||||||
|
|
||||||
let warningContainerTimeout: Timeout | null = null;
|
let warningContainerTimeout: Timeout | null = null;
|
||||||
function createWarningContainerStore() {
|
function createWarningContainerStore() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { writable } from "svelte/store";
|
|||||||
import type { PlayerInterface } from "../Phaser/Game/PlayerInterface";
|
import type { PlayerInterface } from "../Phaser/Game/PlayerInterface";
|
||||||
import type { RoomConnection } from "../Connexion/RoomConnection";
|
import type { RoomConnection } from "../Connexion/RoomConnection";
|
||||||
import { getRandomColor } from "../WebRtc/ColorGenerator";
|
import { getRandomColor } from "../WebRtc/ColorGenerator";
|
||||||
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||||
|
|
||||||
let idCount = 0;
|
let idCount = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Room } from "../Connexion/Room";
|
import type { Room } from "../Connexion/Room";
|
||||||
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||||
|
|
||||||
export enum GameConnexionTypes {
|
export enum GameConnexionTypes {
|
||||||
anonymous = 1,
|
anonymous = 1,
|
||||||
@@ -7,13 +8,16 @@ export enum GameConnexionTypes {
|
|||||||
empty,
|
empty,
|
||||||
unknown,
|
unknown,
|
||||||
jwt,
|
jwt,
|
||||||
|
login,
|
||||||
}
|
}
|
||||||
|
|
||||||
//this class is responsible with analysing and editing the game's url
|
//this class is responsible with analysing and editing the game's url
|
||||||
class UrlManager {
|
class UrlManager {
|
||||||
public getGameConnexionType(): GameConnexionTypes {
|
public getGameConnexionType(): GameConnexionTypes {
|
||||||
const url = window.location.pathname.toString();
|
const url = window.location.pathname.toString();
|
||||||
if (url === "/jwt") {
|
if (url === "/login") {
|
||||||
|
return GameConnexionTypes.login;
|
||||||
|
} else if (url === "/jwt") {
|
||||||
return GameConnexionTypes.jwt;
|
return GameConnexionTypes.jwt;
|
||||||
} else if (url.includes("_/")) {
|
} else if (url.includes("_/")) {
|
||||||
return GameConnexionTypes.anonymous;
|
return GameConnexionTypes.anonymous;
|
||||||
@@ -35,6 +39,8 @@ class UrlManager {
|
|||||||
|
|
||||||
public pushRoomIdToUrl(room: Room): void {
|
public pushRoomIdToUrl(room: Room): void {
|
||||||
if (window.location.pathname === room.id) return;
|
if (window.location.pathname === room.id) return;
|
||||||
|
//Set last room visited! (connected or nor, must to be saved in localstorage and cache API)
|
||||||
|
localUserStore.setLastRoomUrl(room.key);
|
||||||
const hash = window.location.hash;
|
const hash = window.location.hash;
|
||||||
const search = room.search.toString();
|
const search = room.search.toString();
|
||||||
history.pushState({}, "WorkAdventure", room.id + (search ? "?" + search : "") + hash);
|
history.pushState({}, "WorkAdventure", room.id + (search ? "?" + search : "") + hash);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { gameOverlayVisibilityStore } from "../Stores/GameOverlayStoreVisibility
|
|||||||
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
import { layoutManagerActionStore, layoutManagerVisibilityStore } from "../Stores/LayoutManagerStore";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
import { localUserStore } from "../Connexion/LocalUserStore";
|
import { localUserStore } from "../Connexion/LocalUserStore";
|
||||||
|
import { MediaStreamConstraintsError } from "../Stores/Errors/MediaStreamConstraintsError";
|
||||||
|
|
||||||
export class MediaManager {
|
export class MediaManager {
|
||||||
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
startScreenSharingCallBacks: Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||||
@@ -24,7 +25,7 @@ export class MediaManager {
|
|||||||
constructor() {
|
constructor() {
|
||||||
localStreamStore.subscribe((result) => {
|
localStreamStore.subscribe((result) => {
|
||||||
if (result.type === "error") {
|
if (result.type === "error") {
|
||||||
console.error(result.error);
|
if (result.error.name !== MediaStreamConstraintsError.NAME) {
|
||||||
layoutManagerActionStore.addAction({
|
layoutManagerActionStore.addAction({
|
||||||
uuid: "cameraAccessDenied",
|
uuid: "cameraAccessDenied",
|
||||||
type: "warning",
|
type: "warning",
|
||||||
@@ -34,6 +35,7 @@ export class MediaManager {
|
|||||||
},
|
},
|
||||||
userInputManager: this.userInputManager,
|
userInputManager: this.userInputManager,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
//remove it after 10 sec
|
//remove it after 10 sec
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layoutManagerActionStore.removeAction("cameraAccessDenied");
|
layoutManagerActionStore.removeAction("cameraAccessDenied");
|
||||||
|
|||||||
@@ -1094,3 +1094,19 @@ div.action.danger p.action-body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.is-silent {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 40px;
|
||||||
|
border-radius: 15px 15px 15px 15px;
|
||||||
|
max-height: 20%;
|
||||||
|
transition: right 350ms;
|
||||||
|
right: -20vw;
|
||||||
|
background-color: black;
|
||||||
|
font-size: 20px;
|
||||||
|
color: white;
|
||||||
|
padding: 30px 20px;
|
||||||
|
}
|
||||||
|
div.is-silent.hide {
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
|||||||
import sveltePreprocess from "svelte-preprocess";
|
import sveltePreprocess from "svelte-preprocess";
|
||||||
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
|
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
|
||||||
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
|
import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
|
||||||
|
import { PROFILE_URL } from "./src/Enum/EnvironmentVariable";
|
||||||
|
|
||||||
const mode = process.env.NODE_ENV ?? "development";
|
const mode = process.env.NODE_ENV ?? "development";
|
||||||
const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS;
|
const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS;
|
||||||
@@ -191,6 +192,7 @@ module.exports = {
|
|||||||
UPLOADER_URL: null,
|
UPLOADER_URL: null,
|
||||||
ADMIN_URL: undefined,
|
ADMIN_URL: undefined,
|
||||||
CONTACT_URL: null,
|
CONTACT_URL: null,
|
||||||
|
PROFILE_URL: null,
|
||||||
DEBUG_MODE: null,
|
DEBUG_MODE: null,
|
||||||
STUN_SERVER: null,
|
STUN_SERVER: null,
|
||||||
TURN_SERVER: null,
|
TURN_SERVER: null,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { v4 } from "uuid";
|
|||||||
import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js";
|
import { HttpRequest, HttpResponse, TemplatedApp } from "uWebSockets.js";
|
||||||
import { BaseController } from "./BaseController";
|
import { BaseController } from "./BaseController";
|
||||||
import { adminApi } from "../Services/AdminApi";
|
import { adminApi } from "../Services/AdminApi";
|
||||||
import { jwtTokenManager } from "../Services/JWTTokenManager";
|
import { AuthTokenData, jwtTokenManager } from "../Services/JWTTokenManager";
|
||||||
import { parse } from "query-string";
|
import { parse } from "query-string";
|
||||||
import { openIDClient } from "../Services/OpenIDClient";
|
import { openIDClient } from "../Services/OpenIDClient";
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ export class AuthenticateController extends BaseController {
|
|||||||
this.openIDCallback();
|
this.openIDCallback();
|
||||||
this.register();
|
this.register();
|
||||||
this.anonymLogin();
|
this.anonymLogin();
|
||||||
|
this.profileCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
openIDLogin() {
|
openIDLogin() {
|
||||||
@@ -48,14 +49,31 @@ export class AuthenticateController extends BaseController {
|
|||||||
res.onAborted(() => {
|
res.onAborted(() => {
|
||||||
console.warn("/message request was aborted");
|
console.warn("/message request was aborted");
|
||||||
});
|
});
|
||||||
const { code, nonce } = parse(req.getQuery());
|
const { code, nonce, token } = parse(req.getQuery());
|
||||||
try {
|
try {
|
||||||
|
//verify connected by token
|
||||||
|
if (token != undefined) {
|
||||||
|
try {
|
||||||
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
|
if (authTokenData.hydraAccessToken == undefined) {
|
||||||
|
throw Error("Token cannot to be check on Hydra");
|
||||||
|
}
|
||||||
|
await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken);
|
||||||
|
res.writeStatus("200");
|
||||||
|
this.addCorsHeaders(res);
|
||||||
|
return res.end(JSON.stringify({ authToken: token }));
|
||||||
|
} catch (err) {
|
||||||
|
console.info("User was not connected", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//user have not token created, check data on hydra and create token
|
||||||
const userInfo = await openIDClient.getUserInfo(code as string, nonce as string);
|
const userInfo = await openIDClient.getUserInfo(code as string, nonce as string);
|
||||||
const sub = userInfo.sub;
|
const sub = userInfo.sub;
|
||||||
if (!sub) {
|
if (!sub) {
|
||||||
throw new Error("No sub in the response");
|
throw new Error("No sub in the response");
|
||||||
}
|
}
|
||||||
const authToken = jwtTokenManager.createAuthToken(sub);
|
const authToken = jwtTokenManager.createAuthToken(sub, userInfo.access_token);
|
||||||
res.writeStatus("200");
|
res.writeStatus("200");
|
||||||
this.addCorsHeaders(res);
|
this.addCorsHeaders(res);
|
||||||
return res.end(JSON.stringify({ authToken }));
|
return res.end(JSON.stringify({ authToken }));
|
||||||
@@ -63,6 +81,30 @@ export class AuthenticateController extends BaseController {
|
|||||||
return this.errorToResponse(e, res);
|
return this.errorToResponse(e, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
this.App.get("/logout-callback", async (res: HttpResponse, req: HttpRequest) => {
|
||||||
|
res.onAborted(() => {
|
||||||
|
console.warn("/message request was aborted");
|
||||||
|
});
|
||||||
|
|
||||||
|
const { token } = parse(req.getQuery());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
|
if (authTokenData.hydraAccessToken == undefined) {
|
||||||
|
throw Error("Token cannot to be logout on Hydra");
|
||||||
|
}
|
||||||
|
await openIDClient.logoutUser(authTokenData.hydraAccessToken);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("openIDCallback => logout-callback", error);
|
||||||
|
} finally {
|
||||||
|
res.writeStatus("200");
|
||||||
|
this.addCorsHeaders(res);
|
||||||
|
// eslint-disable-next-line no-unsafe-finally
|
||||||
|
return res.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Try to login with an admin token
|
//Try to login with an admin token
|
||||||
@@ -136,4 +178,39 @@ export class AuthenticateController extends BaseController {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
profileCallback() {
|
||||||
|
//eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
// @ts-ignore
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
this.App.get("/profile-callback", async (res: HttpResponse, req: HttpRequest) => {
|
||||||
|
res.onAborted(() => {
|
||||||
|
console.warn("/message request was aborted");
|
||||||
|
});
|
||||||
|
const { userIdentify, token } = parse(req.getQuery());
|
||||||
|
try {
|
||||||
|
//verify connected by token
|
||||||
|
if (token != undefined) {
|
||||||
|
try {
|
||||||
|
const authTokenData: AuthTokenData = jwtTokenManager.verifyJWTToken(token as string, false);
|
||||||
|
if (authTokenData.hydraAccessToken == undefined) {
|
||||||
|
throw Error("Token cannot to be check on Hydra");
|
||||||
|
}
|
||||||
|
await openIDClient.checkTokenAuth(authTokenData.hydraAccessToken);
|
||||||
|
|
||||||
|
//get login profile
|
||||||
|
res.writeStatus("302");
|
||||||
|
res.writeHeader("Location", adminApi.getProfileUrl(authTokenData.hydraAccessToken));
|
||||||
|
this.addCorsHeaders(res);
|
||||||
|
// eslint-disable-next-line no-unsafe-finally
|
||||||
|
return res.end();
|
||||||
|
} catch (error) {
|
||||||
|
return this.errorToResponse(error, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.errorToResponse(error, res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const SECRET_KEY = process.env.SECRET_KEY || "THECODINGMACHINE_SECRET_KEY";
|
|||||||
const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == "true" : false;
|
const ALLOW_ARTILLERY = process.env.ALLOW_ARTILLERY ? process.env.ALLOW_ARTILLERY == "true" : false;
|
||||||
const API_URL = process.env.API_URL || "";
|
const API_URL = process.env.API_URL || "";
|
||||||
const ADMIN_API_URL = process.env.ADMIN_API_URL || "";
|
const ADMIN_API_URL = process.env.ADMIN_API_URL || "";
|
||||||
|
const ADMIN_URL = process.env.ADMIN_URL || "";
|
||||||
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || "myapitoken";
|
const ADMIN_API_TOKEN = process.env.ADMIN_API_TOKEN || "myapitoken";
|
||||||
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
|
const CPU_OVERHEAT_THRESHOLD = Number(process.env.CPU_OVERHEAT_THRESHOLD) || 80;
|
||||||
const JITSI_URL: string | undefined = process.env.JITSI_URL === "" ? undefined : process.env.JITSI_URL;
|
const JITSI_URL: string | undefined = process.env.JITSI_URL === "" ? undefined : process.env.JITSI_URL;
|
||||||
@@ -19,6 +20,7 @@ export {
|
|||||||
SECRET_KEY,
|
SECRET_KEY,
|
||||||
API_URL,
|
API_URL,
|
||||||
ADMIN_API_URL,
|
ADMIN_API_URL,
|
||||||
|
ADMIN_URL,
|
||||||
ADMIN_API_TOKEN,
|
ADMIN_API_TOKEN,
|
||||||
ALLOW_ARTILLERY,
|
ALLOW_ARTILLERY,
|
||||||
CPU_OVERHEAT_THRESHOLD,
|
CPU_OVERHEAT_THRESHOLD,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ADMIN_API_TOKEN, ADMIN_API_URL } from "../Enum/EnvironmentVariable";
|
import { ADMIN_API_TOKEN, ADMIN_API_URL, ADMIN_URL } from "../Enum/EnvironmentVariable";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import { GameRoomPolicyTypes } from "_Model/PusherRoom";
|
import { GameRoomPolicyTypes } from "_Model/PusherRoom";
|
||||||
import { CharacterTexture } from "./AdminApi/CharacterTexture";
|
import { CharacterTexture } from "./AdminApi/CharacterTexture";
|
||||||
@@ -141,6 +141,15 @@ class AdminApi {
|
|||||||
return data.data;
|
return data.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*TODO add constant to use profile companny*/
|
||||||
|
getProfileUrl(accessToken: string): string {
|
||||||
|
if (!ADMIN_URL) {
|
||||||
|
throw new Error("No admin backoffice set!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ADMIN_URL + `/profile?token=${accessToken}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const adminApi = new AdminApi();
|
export const adminApi = new AdminApi();
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import { adminApi, AdminBannedData } from "../Services/AdminApi";
|
|||||||
|
|
||||||
export interface AuthTokenData {
|
export interface AuthTokenData {
|
||||||
identifier: string; //will be a email if logged in or an uuid if anonymous
|
identifier: string; //will be a email if logged in or an uuid if anonymous
|
||||||
|
hydraAccessToken?: string;
|
||||||
}
|
}
|
||||||
export const tokenInvalidException = "tokenInvalid";
|
export const tokenInvalidException = "tokenInvalid";
|
||||||
|
|
||||||
class JWTTokenManager {
|
class JWTTokenManager {
|
||||||
public createAuthToken(identifier: string) {
|
public createAuthToken(identifier: string, hydraAccessToken?: string) {
|
||||||
//TODO fix me 200d when ory authentication will be available
|
return Jwt.sign({ identifier, hydraAccessToken }, SECRET_KEY, { expiresIn: "30d" });
|
||||||
return Jwt.sign({ identifier }, SECRET_KEY, { expiresIn: "200d" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData {
|
public verifyJWTToken(token: string, ignoreExpiration: boolean = false): AuthTokenData {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Issuer, Client } from "openid-client";
|
import { Issuer, Client, IntrospectionResponse } from "openid-client";
|
||||||
import { OPID_CLIENT_ID, OPID_CLIENT_SECRET, OPID_CLIENT_ISSUER, FRONT_URL } from "../Enum/EnvironmentVariable";
|
import { OPID_CLIENT_ID, OPID_CLIENT_SECRET, OPID_CLIENT_ISSUER, FRONT_URL } from "../Enum/EnvironmentVariable";
|
||||||
|
|
||||||
const opidRedirectUri = FRONT_URL + "/jwt";
|
const opidRedirectUri = FRONT_URL + "/jwt";
|
||||||
@@ -31,12 +31,31 @@ class OpenIDClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string }> {
|
public getUserInfo(code: string, nonce: string): Promise<{ email: string; sub: string; access_token: string }> {
|
||||||
return this.initClient().then((client) => {
|
return this.initClient().then((client) => {
|
||||||
return client.callback(opidRedirectUri, { code }, { nonce }).then((tokenSet) => {
|
return client.callback(opidRedirectUri, { code }, { nonce }).then((tokenSet) => {
|
||||||
return client.userinfo(tokenSet);
|
return client.userinfo(tokenSet).then((res) => {
|
||||||
|
return {
|
||||||
|
...res,
|
||||||
|
email: res.email as string,
|
||||||
|
sub: res.sub,
|
||||||
|
access_token: tokenSet.access_token as string,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public logoutUser(token: string): Promise<void> {
|
||||||
|
return this.initClient().then((client) => {
|
||||||
|
return client.revoke(token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public checkTokenAuth(token: string): Promise<IntrospectionResponse> {
|
||||||
|
return this.initClient().then((client) => {
|
||||||
|
return client.userinfo(token);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user