From f92b728a8e0e2c8df45f04e3c103a36baaa4a810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 13 Sep 2021 14:48:19 +0200 Subject: [PATCH 01/11] Fixing broken chat API --- front/src/Api/IframeListener.ts | 14 +------------- front/src/Api/ScriptUtils.ts | 8 ++++++++ front/src/WebRtc/DiscussionManager.ts | 14 -------------- front/src/WebRtc/VideoPeer.ts | 6 +----- 4 files changed, 10 insertions(+), 32 deletions(-) delete mode 100644 front/src/WebRtc/DiscussionManager.ts diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 140d2f34..5a9aca85 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -46,30 +46,18 @@ type AnswererCallback = ( * Also allows to send messages to those iframes. */ class IframeListener { - private readonly _readyStream: Subject = new Subject(); - public readonly readyStream = this._readyStream.asObservable(); - - private readonly _chatStream: Subject = new Subject(); - public readonly chatStream = this._chatStream.asObservable(); - private readonly _openPopupStream: Subject = new Subject(); public readonly openPopupStream = this._openPopupStream.asObservable(); private readonly _openTabStream: Subject = new Subject(); public readonly openTabStream = this._openTabStream.asObservable(); - private readonly _goToPageStream: Subject = new Subject(); - public readonly goToPageStream = this._goToPageStream.asObservable(); - private readonly _loadPageStream: Subject = new Subject(); public readonly loadPageStream = this._loadPageStream.asObservable(); private readonly _openCoWebSiteStream: Subject = new Subject(); public readonly openCoWebSiteStream = this._openCoWebSiteStream.asObservable(); - private readonly _closeCoWebSiteStream: Subject = new Subject(); - public readonly closeCoWebSiteStream = this._closeCoWebSiteStream.asObservable(); - private readonly _disablePlayerControlStream: Subject = new Subject(); public readonly disablePlayerControlStream = this._disablePlayerControlStream.asObservable(); @@ -219,7 +207,7 @@ class IframeListener { } else if (payload.type === "setProperty" && isSetPropertyEvent(payload.data)) { this._setPropertyStream.next(payload.data); } else if (payload.type === "chat" && isChatEvent(payload.data)) { - this._chatStream.next(payload.data); + scriptUtils.sendAnonymousChat(payload.data); } else if (payload.type === "openPopup" && isOpenPopupEvent(payload.data)) { this._openPopupStream.next(payload.data); } else if (payload.type === "closePopup" && isClosePopupEvent(payload.data)) { diff --git a/front/src/Api/ScriptUtils.ts b/front/src/Api/ScriptUtils.ts index 0dbe40fe..ad6dcc0f 100644 --- a/front/src/Api/ScriptUtils.ts +++ b/front/src/Api/ScriptUtils.ts @@ -1,4 +1,7 @@ import { coWebsiteManager } from "../WebRtc/CoWebsiteManager"; +import { playersStore } from "../Stores/PlayersStore"; +import { chatMessagesStore } from "../Stores/ChatStore"; +import type { ChatEvent } from "./Events/ChatEvent"; class ScriptUtils { public openTab(url: string) { @@ -16,6 +19,11 @@ class ScriptUtils { public closeCoWebSite() { coWebsiteManager.closeCoWebsite(); } + + public sendAnonymousChat(chatEvent: ChatEvent) { + const userId = playersStore.addFacticePlayer(chatEvent.author); + chatMessagesStore.addExternalMessage(userId, chatEvent.message); + } } export const scriptUtils = new ScriptUtils(); diff --git a/front/src/WebRtc/DiscussionManager.ts b/front/src/WebRtc/DiscussionManager.ts deleted file mode 100644 index fcf04ef1..00000000 --- a/front/src/WebRtc/DiscussionManager.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { iframeListener } from "../Api/IframeListener"; -import { chatMessagesStore } from "../Stores/ChatStore"; -import { playersStore } from "../Stores/PlayersStore"; - -export class DiscussionManager { - constructor() { - iframeListener.chatStream.subscribe((chatEvent) => { - const userId = playersStore.addFacticePlayer(chatEvent.author); - chatMessagesStore.addExternalMessage(userId, chatEvent.message); - }); - } -} - -export const discussionManager = new DiscussionManager(); diff --git a/front/src/WebRtc/VideoPeer.ts b/front/src/WebRtc/VideoPeer.ts index 990adb4e..c3a2af23 100644 --- a/front/src/WebRtc/VideoPeer.ts +++ b/front/src/WebRtc/VideoPeer.ts @@ -5,11 +5,7 @@ import { blackListManager } from "./BlackListManager"; import type { Subscription } from "rxjs"; import type { UserSimplePeerInterface } from "./SimplePeer"; import { readable, Readable, Unsubscriber } from "svelte/store"; -import { - localStreamStore, - obtainedMediaConstraintStore, - ObtainedMediaStreamConstraints, -} from "../Stores/MediaStore"; +import { localStreamStore, obtainedMediaConstraintStore, ObtainedMediaStreamConstraints } from "../Stores/MediaStore"; import { playersStore } from "../Stores/PlayersStore"; import { chatMessagesStore, newChatMessageStore } from "../Stores/ChatStore"; import { getIceServersConfig } from "../Components/Video/utils"; From 01bd36ca3f67faddd46849190ee38825d6de9261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 13 Sep 2021 18:58:00 +0200 Subject: [PATCH 02/11] Removing test in double --- maps/tests/index.html | 8 -------- 1 file changed, 8 deletions(-) diff --git a/maps/tests/index.html b/maps/tests/index.html index 6f298386..29d4f0bb 100644 --- a/maps/tests/index.html +++ b/maps/tests/index.html @@ -224,14 +224,6 @@

WebRTC

- - - - + + + +
- Success Failure Pending - - Test energy consumption -
Success Failure Pending From 34d81b0e6c83222cab3e45666c1c8a7a2cb87647 Mon Sep 17 00:00:00 2001 From: Lurkars Date: Tue, 14 Sep 2021 08:55:15 +0200 Subject: [PATCH 03/11] fix behaviour --- .../AudioManager/AudioManager.svelte | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/front/src/Components/AudioManager/AudioManager.svelte b/front/src/Components/AudioManager/AudioManager.svelte index a448d56c..a7f96f61 100644 --- a/front/src/Components/AudioManager/AudioManager.svelte +++ b/front/src/Components/AudioManager/AudioManager.svelte @@ -5,9 +5,9 @@ audioManagerFileStore, audioManagerVolumeStore, } from "../../Stores/AudioManagerStore"; - import {get} from "svelte/store"; + import { get } from "svelte/store"; import type { Unsubscriber } from "svelte/store"; - import {onDestroy, onMount} from "svelte"; + import { onDestroy, onMount } from "svelte"; let HTMLAudioPlayer: HTMLAudioElement; let audioPlayerVolumeIcon: HTMLElement; @@ -21,9 +21,9 @@ onMount(() => { volume = localUserStore.getAudioPlayerVolume(); audioManagerVolumeStore.setMuted(localUserStore.getAudioPlayerMuted()); - setVolume(); + changeVolume(); - unsubscriberFileStore = audioManagerFileStore.subscribe(() =>{ + unsubscriberFileStore = audioManagerFileStore.subscribe(() => { HTMLAudioPlayer.pause(); HTMLAudioPlayer.loop = get(audioManagerVolumeStore).loop; HTMLAudioPlayer.volume = get(audioManagerVolumeStore).volume; @@ -53,13 +53,7 @@ } }) - function onMute() { - audioManagerVolumeStore.setMuted(!get(audioManagerVolumeStore).muted); - localUserStore.setAudioPlayerMuted(get(audioManagerVolumeStore).muted); - setVolume(); - } - - function setVolume() { + function changeVolume() { if (get(audioManagerVolumeStore).muted) { audioPlayerVolumeIcon.classList.add('muted'); audioPlayerVol.value = "0"; @@ -76,8 +70,22 @@ audioPlayerVolumeIcon.classList.remove('mid'); } } - audioManagerVolumeStore.setVolume(volume) - localUserStore.setAudioPlayerVolume(get(audioManagerVolumeStore).volume); + } + + function onMute() { + const muted = !get(audioManagerVolumeStore).muted; + audioManagerVolumeStore.setMuted(muted); + localUserStore.setAudioPlayerMuted(muted); + changeVolume(); + } + + function setVolume() { + volume = parseFloat(audioPlayerVol.value); + audioManagerVolumeStore.setVolume(volume); + localUserStore.setAudioPlayerVolume(volume); + audioManagerVolumeStore.setMuted(false); + localUserStore.setAudioPlayerMuted(false); + changeVolume(); } function setDecrease() { @@ -108,8 +116,7 @@ - +
+ Success Failure Pending + + Testing Jitsi + silent layer +

Iframe API

diff --git a/maps/tests/jitsi_custom_url.json b/maps/tests/jitsi_custom_url.json index 855582ff..41da68f7 100644 --- a/maps/tests/jitsi_custom_url.json +++ b/maps/tests/jitsi_custom_url.json @@ -8,6 +8,12 @@ "id":1, "name":"floor", "opacity":1, + "properties":[ + { + "name":"silent", + "type":"bool", + "value":true + }], "type":"tilelayer", "visible":true, "width":10, @@ -37,11 +43,6 @@ "name":"jitsiRoom", "type":"string", "value":"myRoom" - }, - { - "name":"jitsiUrl", - "type":"string", - "value":"meet.jit.si" }], "type":"tilelayer", "visible":true, @@ -55,7 +56,7 @@ "name":"floorLayer", "objects":[ { - "height":94.6489098314831, + "height":163.652982988579, "id":1, "name":"", "properties":[ @@ -69,14 +70,14 @@ { "fontfamily":"Sans Serif", "pixelsize":8, - "text":"Test:\nWalk on the carpet and press space\nResult:\nJitsi opens on meet.jit.si (check this in the network tab). Note: this test only makes sense if the default configured Jitsi instance is NOT meet.jit.si (check your .env file)", + "text":"Test:\nThe whole map is silent.\nConnect with 2 users\nResult:\nThe map is silent\n\nTest:\nmove on the carpet with both users\n\nResult:\nA Jitsi opens\n\nTest:\nmove out of the carpet and try to connect both users\nResult:\nThey are still silent\n", "wrap":true }, "type":"", "visible":true, "width":317.361946929159, "x":2.32853056864467, - "y":224.602707451482 + "y":2.25624950083909 }], "opacity":1, "type":"objectgroup", From bb8583872b1f2bc020ab4744f47571b94b863168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Wed, 15 Sep 2021 11:32:32 +0200 Subject: [PATCH 08/11] Fixing messages generation in Front container --- front/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/front/Dockerfile b/front/Dockerfile index 6c503af8..6fef9dc8 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -1,13 +1,13 @@ -FROM thecodingmachine/workadventure-back-base:latest as builder -COPY --chown=docker:docker messages . -WORKDIR /var/www/messages +FROM node:14.15.4-buster-slim@sha256:cbae886186467bbfd274b82a234a1cdfbbd31201c2a6ee63a6893eefcf3c6e76 as builder +WORKDIR /usr/src +COPY messages . RUN yarn install && yarn proto # we are rebuilding on each deploy to cope with the PUSHER_URL environment URL FROM thecodingmachine/nodejs:14-apache COPY --chown=docker:docker front . -COPY --from=builder --chown=docker:docker /var/www/messages/generated /var/www/html/src/Messages/generated +COPY --from=builder --chown=docker:docker /usr/src/generated /var/www/html/src/Messages/generated # Removing the iframe.html file from the final image as this adds a XSS attack. # iframe.html is only in dev mode to circumvent a limitation From 801ec3bf4c5f8561f994e1510900bc414f741b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Wed, 15 Sep 2021 15:28:55 +0200 Subject: [PATCH 09/11] Turn off audio on exit If an exit zone is overlapping an audio zone, when exiting, the audio is stopped. We do this by actually triggering the fact that a user should "leave" all active zones when exiting. --- front/src/Phaser/Game/GameMap.ts | 11 +++++++++++ front/src/Phaser/Game/GameScene.ts | 2 ++ maps/tests/audio.json | 28 +++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 23e5c4e9..0360859b 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -286,4 +286,15 @@ export class GameMap { this.triggerAll(); } + + /** + * Trigger all the callbacks (used when exiting a map) + */ + public triggerExitCallbacks(): void { + const emptyProps = new Map(); + for (const [oldPropName, oldPropValue] of this.lastProperties.entries()) { + // We found a property that disappeared + this.trigger(oldPropName, oldPropValue, undefined, emptyProps); + } + } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index ec387b4f..f5b305b4 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1236,6 +1236,8 @@ ${escapedMessage} if (this.mapTransitioning) return; this.mapTransitioning = true; + this.gameMap.triggerExitCallbacks(); + let targetRoom: Room; try { targetRoom = await Room.createRoom(roomUrl); diff --git a/maps/tests/audio.json b/maps/tests/audio.json index d65e7f47..c9742ef8 100644 --- a/maps/tests/audio.json +++ b/maps/tests/audio.json @@ -49,13 +49,31 @@ "x":0, "y":0 }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":6, + "name":"exit", + "opacity":1, + "properties":[ + { + "name":"exitUrl", + "type":"string", + "value":"Properties\/jitsi_next_to_silent.json" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, { "draworder":"topdown", "id":3, "name":"floorLayer", "objects":[ { - "height":119.194025905366, + "height":308.584234177831, "id":1, "name":"", "rotation":0, @@ -63,14 +81,14 @@ { "fontfamily":"Sans Serif", "pixelsize":13, - "text":"Test:\nWalk on the carpet\nResult:\nA sound is played in loop.\nControls at the top of the screen allow you to control the sound.", + "text":"Test:\nWalk on the carpet\n\nResult:\nA sound is played in loop.\nControls at the top of the screen allow you to control the sound.\n\nTest:\nWalk on the white spot in the carpet\n\nResult:\nThe user is redirected to another map AND sound is shut down", "wrap":true }, "type":"", "visible":true, "width":315.4375, - "x":2.28125, - "y":198.837938422583 + "x":1.74700399641053, + "y":1.43404009627554 }], "opacity":1, "type":"objectgroup", @@ -78,7 +96,7 @@ "x":0, "y":0 }], - "nextlayerid":6, + "nextlayerid":7, "nextobjectid":2, "orientation":"orthogonal", "renderorder":"right-down", From a3eebb05ba445817fd329714e985c7af1813ebab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Thu, 16 Sep 2021 09:58:42 +0200 Subject: [PATCH 10/11] Fixing type of openWebsiteWidth in doc --- docs/maps/opening-a-website.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/maps/opening-a-website.md b/docs/maps/opening-a-website.md index 682306b4..2ca54281 100644 --- a/docs/maps/opening-a-website.md +++ b/docs/maps/opening-a-website.md @@ -12,7 +12,7 @@ In order to create a zone that opens websites: * You must create a specific layer. * In layer properties, you MUST add a "`openWebsite`" property (of type "`string`"). The value of the property is the URL of the website to open (the URL must start with "https://") -* You may also use "`openWebsiteWidth`" property (of type "`number`" between 0 and 100) to control the width of the iframe. +* You may also use "`openWebsiteWidth`" property (of type "`int`" or "`float`" between 0 and 100) to control the width of the iframe. * You may also use "`openTab`" property (of type "`string`") to open in a new tab instead. {.alert.alert-warning} From 2e111aa13afc18a33bdb32a9398fd555aaac51b6 Mon Sep 17 00:00:00 2001 From: Kharhamel Date: Wed, 15 Sep 2021 11:50:25 +0200 Subject: [PATCH 11/11] FEATURE: added posthog as new analytics tool --- deeployer.libsonnet | 3 + front/package.json | 1 + front/src/Administration/AnalyticsClient.ts | 61 +++++++++++++++++++++ front/src/Connexion/ConnectionManager.ts | 6 ++ front/src/Enum/EnvironmentVariable.ts | 2 + front/src/Phaser/Game/GameScene.ts | 4 ++ front/src/Stores/MenuStore.ts | 5 +- front/src/index.ts | 2 +- front/webpack.config.ts | 4 +- front/yarn.lock | 24 ++++++++ 10 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 front/src/Administration/AnalyticsClient.ts diff --git a/deeployer.libsonnet b/deeployer.libsonnet index a2e8970a..75a4de8c 100644 --- a/deeployer.libsonnet +++ b/deeployer.libsonnet @@ -75,6 +75,9 @@ "UPLOADER_URL": "//uploader-"+url, "ADMIN_URL": "//"+url, "JITSI_URL": env.JITSI_URL, + #POSTHOG + "POSTHOG_API_KEY": if namespace == "master" then env.POSTHOG_API_KEY else "", + "POSTHOG_URL": if namespace == "master" then env.POSTHOG_URL else "", "SECRET_JITSI_KEY": env.SECRET_JITSI_KEY, "TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443", "JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false", diff --git a/front/package.json b/front/package.json index d60b6fa6..38c0570f 100644 --- a/front/package.json +++ b/front/package.json @@ -49,6 +49,7 @@ "phaser": "^3.54.0", "phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254", "phaser3-rex-plugins": "^1.1.42", + "posthog-js": "^1.13.12", "queue-typescript": "^1.0.1", "quill": "1.3.6", "quill-delta-to-html": "^0.12.0", diff --git a/front/src/Administration/AnalyticsClient.ts b/front/src/Administration/AnalyticsClient.ts new file mode 100644 index 00000000..f3cde793 --- /dev/null +++ b/front/src/Administration/AnalyticsClient.ts @@ -0,0 +1,61 @@ +import {POSTHOG_API_KEY, POSTHOG_URL} from "../Enum/EnvironmentVariable"; + +class AnalyticsClient { + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private posthogPromise: Promise; + + constructor() { + if (POSTHOG_API_KEY && POSTHOG_URL) { + this.posthogPromise = import('posthog-js').then(({default: posthog}) => { + posthog.init(POSTHOG_API_KEY, { api_host: POSTHOG_URL, disable_cookie: true }); + return posthog; + }); + } else { + this.posthogPromise = Promise.reject(); + } + } + + identifyUser(uuid: string) { + this.posthogPromise.then(posthog => { + posthog.identify(uuid, { uuid, wa: true }); + }).catch(); + } + + loggedWithSso() { + this.posthogPromise.then(posthog => { + posthog.capture('wa-logged-sso'); + }).catch(); + } + + loggedWithToken() { + this.posthogPromise.then(posthog => { + posthog.capture('wa-logged-token'); + }).catch(); + } + + enteredRoom(roomId: string) { + this.posthogPromise.then(posthog => { + posthog.capture('$pageView', {roomId}); + }).catch(); + } + + openedMenu() { + this.posthogPromise.then(posthog => { + posthog.capture('wa-opened-menu'); + }).catch(); + } + + launchEmote(emote: string) { + this.posthogPromise.then(posthog => { + posthog.capture('wa-emote-launch', {emote}); + }).catch(); + } + + enteredJitsi(roomName: string, roomId: string) { + this.posthogPromise.then(posthog => { + posthog.capture('wa-entered-jitsi', {roomName, roomId}); + }).catch(); + } +} +export const analyticsClient = new AnalyticsClient(); diff --git a/front/src/Connexion/ConnectionManager.ts b/front/src/Connexion/ConnectionManager.ts index 0dc3493f..0aba0379 100644 --- a/front/src/Connexion/ConnectionManager.ts +++ b/front/src/Connexion/ConnectionManager.ts @@ -9,6 +9,7 @@ import { Room } from "./Room"; import { _ServiceWorker } from "../Network/ServiceWorker"; import { loginSceneVisibleIframeStore } from "../Stores/LoginSceneStore"; import { userIsConnected } from "../Stores/MenuStore"; +import {analyticsClient} from "../Administration/AnalyticsClient"; class ConnectionManager { private localUser!: LocalUser; @@ -93,6 +94,7 @@ class ConnectionManager { this._currentRoom = await Room.createRoom(new URL(localUserStore.getLastRoomUrl())); try { await this.checkAuthUserConnexion(); + analyticsClient.loggedWithSso(); } catch (err) { console.error(err); this.loadOpenIDScreen(); @@ -109,6 +111,7 @@ class ConnectionManager { this.authToken = data.authToken; localUserStore.saveUser(this.localUser); localUserStore.setAuthToken(this.authToken); + analyticsClient.loggedWithToken(); const roomUrl = data.roomUrl; @@ -184,6 +187,9 @@ class ConnectionManager { if (this._currentRoom == undefined) { return Promise.reject(new Error("Invalid URL")); } + if (this.localUser) { + analyticsClient.identifyUser(this.localUser.uuid) + } this.serviceWorker = new _ServiceWorker(); return Promise.resolve(this._currentRoom); diff --git a/front/src/Enum/EnvironmentVariable.ts b/front/src/Enum/EnvironmentVariable.ts index 60678822..e724599c 100644 --- a/front/src/Enum/EnvironmentVariable.ts +++ b/front/src/Enum/EnvironmentVariable.ts @@ -20,6 +20,8 @@ export const DISPLAY_TERMS_OF_USE = process.env.DISPLAY_TERMS_OF_USE == "true"; export const NODE_ENV = process.env.NODE_ENV || "development"; export const CONTACT_URL = process.env.CONTACT_URL || undefined; export const PROFILE_URL = process.env.PROFILE_URL || undefined; +export const POSTHOG_API_KEY: string = process.env.POSTHOG_API_KEY as string || ''; +export const POSTHOG_URL = process.env.POSTHOG_URL || undefined; export const isMobile = (): boolean => window.innerWidth <= 800 || window.innerHeight <= 600; diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index ec387b4f..77a3b525 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -94,6 +94,7 @@ import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager"; import { GameMapPropertiesListener } from "./GameMapPropertiesListener"; import type { RadialMenuItem } from "../Components/RadialMenu"; +import {analyticsClient} from "../../Administration/AnalyticsClient"; export interface GameSceneInitInterface { initPosition: PointInterface | null; @@ -426,6 +427,7 @@ export class GameScene extends DirtyScene { gameManager.gameSceneIsCreated(this); urlManager.pushRoomIdToUrl(this.room); + analyticsClient.enteredRoom(this.room.id); if (touchScreenManager.supportTouchScreen) { this.pinchManager = new PinchManager(this); @@ -1438,6 +1440,7 @@ ${escapedMessage} }); this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => { this.connection?.emitEmoteEvent(emoteKey); + analyticsClient.launchEmote(emoteKey); }); } catch (err) { if (err instanceof TextureError) { @@ -1805,6 +1808,7 @@ ${escapedMessage} jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl, jitsiWidth); this.connection?.setSilent(true); mediaManager.hideGameOverlay(); + analyticsClient.enteredJitsi(roomName, this.room.id); //permit to stop jitsi when user close iframe mediaManager.addTriggerCloseJitsiFrameButton("close-jitsi", () => { diff --git a/front/src/Stores/MenuStore.ts b/front/src/Stores/MenuStore.ts index 96e731a9..4a30a4e7 100644 --- a/front/src/Stores/MenuStore.ts +++ b/front/src/Stores/MenuStore.ts @@ -2,11 +2,14 @@ import { get, writable } from "svelte/store"; import Timeout = NodeJS.Timeout; import { userIsAdminStore } from "./GameStore"; import { CONTACT_URL } from "../Enum/EnvironmentVariable"; +import {analyticsClient} from "../Administration/AnalyticsClient"; export const menuIconVisiblilityStore = writable(false); export const menuVisiblilityStore = writable(false); +menuVisiblilityStore.subscribe((value) => { + if (value) analyticsClient.openedMenu(); +}) export const menuInputFocusStore = writable(false); -export const loginUrlStore = writable(false); export const userIsConnected = writable(false); let warningContainerTimeout: Timeout | null = null; diff --git a/front/src/index.ts b/front/src/index.ts index 30f25c6e..9842e65d 100644 --- a/front/src/index.ts +++ b/front/src/index.ts @@ -23,9 +23,9 @@ import { Game } from "./Phaser/Game/Game"; import App from "./Components/App.svelte"; import { HtmlUtils } from "./WebRtc/HtmlUtils"; import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer; +import {analyticsClient} from "./Administration/AnalyticsClient"; const { width, height } = coWebsiteManager.getGameSize(); - const valueGameQuality = localUserStore.getGameQualityValue(); const fps: Phaser.Types.Core.FPSConfig = { /** diff --git a/front/webpack.config.ts b/front/webpack.config.ts index 48db1afa..f2e4e7cc 100644 --- a/front/webpack.config.ts +++ b/front/webpack.config.ts @@ -7,7 +7,7 @@ import MiniCssExtractPlugin from "mini-css-extract-plugin"; import sveltePreprocess from "svelte-preprocess"; import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; import NodePolyfillPlugin from "node-polyfill-webpack-plugin"; -import { PROFILE_URL } from "./src/Enum/EnvironmentVariable"; +import {POSTHOG_API_KEY, PROFILE_URL} from "./src/Enum/EnvironmentVariable"; const mode = process.env.NODE_ENV ?? "development"; const buildNpmTypingsForApi = !!process.env.BUILD_TYPINGS; @@ -204,6 +204,8 @@ module.exports = { MAX_USERNAME_LENGTH: 8, MAX_PER_GROUP: 4, DISPLAY_TERMS_OF_USE: false, + POSTHOG_API_KEY: null, + POSTHOG_URL: null, NODE_ENV: mode, }), ], diff --git a/front/yarn.lock b/front/yarn.lock index c4462d98..68cca0cf 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -83,6 +83,11 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" +"@sentry/types@^6.11.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853" + integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA== + "@tsconfig/svelte@^1.0.10": version "1.0.10" resolved "https://registry.yarnpkg.com/@tsconfig/svelte/-/svelte-1.0.10.tgz#30ec7feeee0bdf38b12a50f0686f8a2e7b6b9dc0" @@ -2296,6 +2301,11 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" +fflate@^0.4.1: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -4394,6 +4404,15 @@ postcss@^8.2.10: nanoid "^3.1.23" source-map "^0.6.1" +posthog-js@^1.13.12: + version "1.13.12" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.13.12.tgz#b54efcb92de43724c889048135ccaae3dc4b874c" + integrity sha512-MU1I0zSVhdCcnWI8jAZLtbNJmjfg9AnhUDq5dUzNkb0qPXtNz17BekalnNwDMKs0Zlek3UCOVsIpyc85M+VRNA== + dependencies: + "@sentry/types" "^6.11.0" + fflate "^0.4.1" + rrweb-snapshot "^1.1.7" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -4785,6 +4804,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rrweb-snapshot@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/rrweb-snapshot/-/rrweb-snapshot-1.1.8.tgz#57c3a8003a6ebbe4a2e2f5be29e30a47a8b1eb03" + integrity sha512-wi8T9IVobEwlns7U2m8cbPfoihsNAMpTI+UBe4KUjclU2N+vtowD2U1Rq8PleiFTDvcseHvkQDmEIZoZLXFzwg== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"