Merge pull request #659 from thecodingmachine/develop

Deploy 2020-01-25
This commit is contained in:
David Négrier 2021-01-25 22:55:12 +01:00 committed by GitHub
commit 6432d2459b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 126 additions and 59 deletions

View File

@ -5,3 +5,4 @@ JITSI_PRIVATE_MODE=false
JITSI_ISS= JITSI_ISS=
SECRET_JITSI_KEY= SECRET_JITSI_KEY=
ADMIN_API_TOKEN=123 ADMIN_API_TOKEN=123
START_ROOM_URL=/_/global/maps.workadventure.localhost/Floor0/floor0.json

View File

@ -39,6 +39,10 @@ jobs:
run: yarn run proto && yarn run copy-to-front run: yarn run proto && yarn run copy-to-front
working-directory: "messages" working-directory: "messages"
- name: "Create index.html"
run: ./templater.sh
working-directory: "front"
- name: "Build" - name: "Build"
run: yarn run build run: yarn run build
env: env:

View File

@ -1,5 +1,4 @@
const SECRET_KEY = process.env.SECRET_KEY || "THECODINGMACHINE_SECRET_KEY"; const SECRET_KEY = process.env.SECRET_KEY || "THECODINGMACHINE_SECRET_KEY";
const URL_ROOM_STARTED = "/Floor0/floor0.json";
const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64; const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64;
const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48; const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48;
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;
@ -16,7 +15,6 @@ export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as strin
export { export {
SECRET_KEY, SECRET_KEY,
URL_ROOM_STARTED,
MINIMUM_DISTANCE, MINIMUM_DISTANCE,
ADMIN_API_URL, ADMIN_API_URL,
ADMIN_API_TOKEN, ADMIN_API_TOKEN,

View File

@ -72,13 +72,15 @@
"env": { "env": {
"API_URL": "pusher."+url, "API_URL": "pusher."+url,
"UPLOADER_URL": "uploader."+url, "UPLOADER_URL": "uploader."+url,
"ADMIN_URL": "admin."+url, "ADMIN_URL": url,
"JITSI_URL": env.JITSI_URL, "JITSI_URL": env.JITSI_URL,
"SECRET_JITSI_KEY": env.SECRET_JITSI_KEY, "SECRET_JITSI_KEY": env.SECRET_JITSI_KEY,
"TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443", "TURN_SERVER": "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443",
"TURN_USER": "workadventure", "TURN_USER": "workadventure",
"TURN_PASSWORD": "WorkAdventure123", "TURN_PASSWORD": "WorkAdventure123",
"JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false" "JITSI_PRIVATE_MODE": if env.SECRET_JITSI_KEY != '' then "true" else "false",
"START_ROOM_URL": "/_/global/maps."+url+"/Floor0/floor0.json"
//"GA_TRACKING_ID": "UA-10196481-11"
} }
}, },
"uploader": { "uploader": {

View File

@ -28,11 +28,13 @@ services:
NODE_ENV: development NODE_ENV: development
API_URL: pusher.workadventure.localhost API_URL: pusher.workadventure.localhost
UPLOADER_URL: uploader.workadventure.localhost UPLOADER_URL: uploader.workadventure.localhost
ADMIN_URL: admin.workadventure.localhost ADMIN_URL: workadventure.localhost
STARTUP_COMMAND_1: yarn install STARTUP_COMMAND_1: ./templater.sh
STARTUP_COMMAND_2: yarn install
TURN_SERVER: "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443" TURN_SERVER: "turn:coturn.workadventu.re:443,turns:coturn.workadventu.re:443"
TURN_USER: workadventure TURN_USER: workadventure
TURN_PASSWORD: WorkAdventure123 TURN_PASSWORD: WorkAdventure123
START_ROOM_URL: "$START_ROOM_URL"
command: yarn run start command: yarn run start
volumes: volumes:
- ./front:/usr/src/app - ./front:/usr/src/app

1
front/.gitignore vendored
View File

@ -6,3 +6,4 @@
/dist/webpack.config.js.map /dist/webpack.config.js.map
/dist/src /dist/src
*.sh *.sh
!templater.sh

View File

@ -11,5 +11,6 @@ COPY --from=builder --chown=docker:docker /var/www/messages/generated /var/www/h
RUN yarn install RUN yarn install
ENV NODE_ENV=production ENV NODE_ENV=production
ENV STARTUP_COMMAND_0="./templater.sh"
ENV STARTUP_COMMAND_1="yarn run build" ENV STARTUP_COMMAND_1="yarn run build"
ENV APACHE_DOCUMENT_ROOT=dist/ ENV APACHE_DOCUMENT_ROOT=dist/

9
front/dist/ga.html.tmpl vendored Normal file
View File

@ -0,0 +1,9 @@
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=<!-- TRACKING NUMBER -->"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '<!-- TRACKING NUMBER -->');
</script>

View File

@ -6,15 +6,8 @@
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- TRACK CODE -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-10196481-11"></script> <!-- END TRACK CODE -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-10196481-11');
</script>
<link rel="apple-touch-icon" sizes="57x57" href="static/images/favicons/apple-icon-57x57.png"> <link rel="apple-touch-icon" sizes="57x57" href="static/images/favicons/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="static/images/favicons/apple-icon-60x60.png"> <link rel="apple-touch-icon" sizes="60x60" href="static/images/favicons/apple-icon-60x60.png">

View File

@ -1,5 +1,5 @@
import Axios from "axios"; import Axios from "axios";
import {API_URL} from "../Enum/EnvironmentVariable"; import {API_URL, START_ROOM_URL} from "../Enum/EnvironmentVariable";
import {RoomConnection} from "./RoomConnection"; import {RoomConnection} from "./RoomConnection";
import {OnConnectInterface, PositionInterface, ViewportInterface} from "./ConnexionModels"; import {OnConnectInterface, PositionInterface, ViewportInterface} from "./ConnexionModels";
import {GameConnexionTypes, urlManager} from "../Url/UrlManager"; import {GameConnexionTypes, urlManager} from "../Url/UrlManager";
@ -7,8 +7,6 @@ import {localUserStore} from "./LocalUserStore";
import {LocalUser} from "./LocalUser"; import {LocalUser} from "./LocalUser";
import {Room} from "./Room"; import {Room} from "./Room";
const URL_ROOM_STARTED = 'tcm/workadventure/floor0';
class ConnectionManager { class ConnectionManager {
private localUser!:LocalUser; private localUser!:LocalUser;
@ -29,9 +27,9 @@ class ConnectionManager {
const organizationSlug = data.organizationSlug; const organizationSlug = data.organizationSlug;
const worldSlug = data.worldSlug; const worldSlug = data.worldSlug;
const roomSlug = data.roomSlug; const roomSlug = data.roomSlug;
urlManager.editUrlForRoom(roomSlug, organizationSlug, worldSlug);
const room = new Room(window.location.pathname + window.location.hash); const room = new Room('/@/'+organizationSlug+'/'+worldSlug+'/'+roomSlug + window.location.hash);
urlManager.pushRoomIdToUrl(room);
return Promise.resolve(room); return Promise.resolve(room);
} else if (connexionType === GameConnexionTypes.organization || connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) { } else if (connexionType === GameConnexionTypes.organization || connexionType === GameConnexionTypes.anonymous || connexionType === GameConnexionTypes.empty) {
const localUser = localUserStore.getLocalUser(); const localUser = localUserStore.getLocalUser();
@ -50,7 +48,7 @@ class ConnectionManager {
} }
let roomId: string let roomId: string
if (connexionType === GameConnexionTypes.empty) { if (connexionType === GameConnexionTypes.empty) {
roomId = urlManager.editUrlForRoom(URL_ROOM_STARTED, null, null); roomId = START_ROOM_URL;
} else { } else {
roomId = window.location.pathname + window.location.hash; roomId = window.location.pathname + window.location.hash;
} }

View File

@ -1,7 +1,8 @@
const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true"; const DEBUG_MODE: boolean = process.env.DEBUG_MODE == "true";
const START_ROOM_URL : string = process.env.START_ROOM_URL || '/_/global/maps.workadventure.localhost/Floor0/floor0.json';
const API_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.API_URL || "pusher.workadventure.localhost"); const API_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.API_URL || "pusher.workadventure.localhost");
const UPLOADER_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.UPLOADER_URL || 'uploader.workadventure.localhost'); const UPLOADER_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.UPLOADER_URL || 'uploader.workadventure.localhost');
const ADMIN_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.ADMIN_URL || "admin.workadventure.localhost"); const ADMIN_URL = (process.env.API_PROTOCOL || (typeof(window) !== 'undefined' ? window.location.protocol : 'http:')) + '//' + (process.env.ADMIN_URL || "workadventure.localhost");
const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca"; const TURN_SERVER: string = process.env.TURN_SERVER || "turn:numb.viagenie.ca";
const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com'; const TURN_USER: string = process.env.TURN_USER || 'g.parant@thecodingmachine.com';
const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$'; const TURN_PASSWORD: string = process.env.TURN_PASSWORD || 'itcugcOHxle9Acqi$';
@ -14,6 +15,7 @@ const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new
export { export {
DEBUG_MODE, DEBUG_MODE,
START_ROOM_URL,
API_URL, API_URL,
UPLOADER_URL, UPLOADER_URL,
ADMIN_URL, ADMIN_URL,

View File

@ -600,8 +600,18 @@ export class GameScene extends ResizableScene implements CenterListener {
if (url === undefined) { if (url === undefined) {
audioManager.unloadAudio(); audioManager.unloadAudio();
} else { } else {
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); const audioPath = url as string;
const realAudioPath = mapDirUrl + '/' + url; let realAudioPath = '';
if (audioPath.indexOf('://') > 0) {
// remote file or stream
realAudioPath = audioPath;
} else {
// local file, include it relative to map directory
const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/'));
realAudioPath = mapDirUrl + '/' + url;
}
audioManager.loadAudio(realAudioPath); audioManager.loadAudio(realAudioPath);
if (loop) { if (loop) {
@ -698,6 +708,10 @@ export class GameScene extends ResizableScene implements CenterListener {
} }
public cleanupClosingScene(): void { public cleanupClosingScene(): void {
// stop playing audio, close any open website, stop any open Jitsi
coWebsiteManager.closeCoWebsite();
this.stopJitsi();
this.playAudio(undefined);
// We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map. // We are completely destroying the current scene to avoid using a half-backed instance when coming back to the same map.
if(this.connection) { if(this.connection) {
this.connection.closeConnection(); this.connection.closeConnection();

View File

@ -32,20 +32,6 @@ class UrlManager {
return match ? match [1] : null; return match ? match [1] : null;
} }
//todo: simply use the roomId
//todo: test this with cypress
public editUrlForRoom(roomSlug: string, organizationSlug: string|null, worldSlug: string |null): string {
let newUrl:string;
if (organizationSlug) {
newUrl = '/@/'+organizationSlug+'/'+worldSlug+'/'+roomSlug;
} else {
newUrl = '/@/'+roomSlug;
}
history.pushState({}, 'WorkAdventure', newUrl);
return newUrl;
}
public pushRoomIdToUrl(room:Room): void { public pushRoomIdToUrl(room:Room): void {
if (window.location.pathname === room.id) return; if (window.location.pathname === room.id) return;
const hash = window.location.hash; const hash = window.location.hash;

View File

@ -151,15 +151,6 @@ export class DiscussionManager {
this.nbpParticipants.innerText = `PARTICIPANTS (${nb})`; this.nbpParticipants.innerText = `PARTICIPANTS (${nb})`;
} }
private urlify(text: string) {
const urlRegex = /(https?:\/\/[^\s]+)/g;
return text.replace(urlRegex, (url: string) => {
return '<a href="' + url + '" target="_blank">' + url + '</a>';
})
// or alternatively
// return text.replace(urlRegex, '<a href="$1">$1</a>')
}
public addMessage(name: string, message: string, isMe: boolean = false) { public addMessage(name: string, message: string, isMe: boolean = false) {
const divMessage: HTMLDivElement = document.createElement('div'); const divMessage: HTMLDivElement = document.createElement('div');
divMessage.classList.add('message'); divMessage.classList.add('message');
@ -170,7 +161,7 @@ export class DiscussionManager {
const pMessage: HTMLParagraphElement = document.createElement('p'); const pMessage: HTMLParagraphElement = document.createElement('p');
const date = new Date(); const date = new Date();
if(isMe){ if(isMe){
name = 'Moi'; name = 'Me';
} }
pMessage.innerHTML = `<span style="font-weight: bold">${name}</span> pMessage.innerHTML = `<span style="font-weight: bold">${name}</span>
<span style="color:#bac2cc;display:inline-block;font-size:12px;"> <span style="color:#bac2cc;display:inline-block;font-size:12px;">
@ -179,7 +170,7 @@ export class DiscussionManager {
divMessage.appendChild(pMessage); divMessage.appendChild(pMessage);
const userMessage: HTMLParagraphElement = document.createElement('p'); const userMessage: HTMLParagraphElement = document.createElement('p');
userMessage.innerHTML = this.urlify(message); userMessage.innerHTML = HtmlUtils.urlify(message);
userMessage.classList.add('body'); userMessage.classList.add('body');
divMessage.appendChild(userMessage); divMessage.appendChild(userMessage);
this.divMessages?.appendChild(divMessage); this.divMessages?.appendChild(divMessage);

View File

@ -17,4 +17,11 @@ export class HtmlUtils {
elem.remove(); elem.remove();
return elem as T; return elem as T;
} }
public static urlify(text: string): string {
const urlRegex = /(https?:\/\/[^\s]+)/g;
return text.replace(urlRegex, (url: string) => {
return '<a href="' + url + '" target="_blank" style=":visited {color: white}">' + url + '</a>';
})
}
} }

View File

@ -13,7 +13,7 @@ if(localValueVideo){
let videoConstraint: boolean|MediaTrackConstraints = { let videoConstraint: boolean|MediaTrackConstraints = {
width: { min: 640, ideal: 1280, max: 1920 }, width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 400, ideal: 720 }, height: { min: 400, ideal: 720 },
frameRate: {exact: valueVideo, ideal: valueVideo}, frameRate: { ideal: valueVideo },
facingMode: "user", facingMode: "user",
resizeMode: 'crop-and-scale', resizeMode: 'crop-and-scale',
aspectRatio: 1.777777778 aspectRatio: 1.777777778

View File

@ -53,8 +53,28 @@ const fps : Phaser.Types.Core.FPSConfig = {
smoothStep: false smoothStep: false
} }
// the ?phaserMode=canvas parameter can be used to force Canvas usage
const params = new URLSearchParams(document.location.search.substring(1));
const phaserMode = params.get("phaserMode");
let mode: number;
switch (phaserMode) {
case 'auto':
case null:
mode = Phaser.AUTO;
break;
case 'canvas':
mode = Phaser.CANVAS;
break;
case 'webgl':
mode = Phaser.WEBGL;
break;
default:
throw new Error('phaserMode parameter must be one of "auto", "canvas" or "webgl"');
}
const config: GameConfig = { const config: GameConfig = {
type: Phaser.AUTO, type: mode,
title: "WorkAdventure", title: "WorkAdventure",
width: width / RESOLUTION, width: width / RESOLUTION,
height: height / RESOLUTION, height: height / RESOLUTION,

26
front/templater.sh Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -x
set -o nounset errexit
template_file_index=dist/index.html.tmpl
generated_file_index=dist/index.html
tmp_trackcodefile=/tmp/trackcode
# To inject tracking code, you have two choices:
# 1) Template using the provided google analytics
# 2) Insert with your own provided code, by overriding the ANALYTICS_CODE_PATH
# The ANALYTICS_CODE_PATH is the location of a file inside the container
ANALYTICS_CODE_PATH="${ANALYTICS_CODE_PATH:-dist/ga.html.tmpl}"
if [[ "${INSERT_ANALYTICS:-NO}" == "NO" ]]; then
echo "" > "${tmp_trackcodefile}"
fi
# Automatically insert analytics if GA_TRACKING_ID is set
if [[ "${GA_TRACKING_ID:-}" != "" || "${INSERT_ANALYTICS:-NO}" != "NO" ]]; then
echo "Templating code from ${ANALYTICS_CODE_PATH}"
sed "s#<!-- TRACKING NUMBER -->#${GA_TRACKING_ID:-}#g" "${ANALYTICS_CODE_PATH}" > "$tmp_trackcodefile"
fi
echo "Templating ${generated_file_index} from ${template_file_index}"
sed "/<!-- TRACK CODE -->/r ${tmp_trackcodefile}" "${template_file_index}" > "${generated_file_index}"
rm "${tmp_trackcodefile}"

View File

@ -0,0 +1,14 @@
import "jasmine";
import {HtmlUtils} from "../../../src/WebRtc/HtmlUtils";
describe("urlify()", () => {
it("should transform an url into a link", () => {
const text = HtmlUtils.urlify('https://google.com');
expect(text).toEqual('<a href="https://google.com" target="_blank" style=":visited {color: white}">https://google.com</a>');
});
it("should not transform a normal text into a link", () => {
const text = HtmlUtils.urlify('hello');
expect(text).toEqual('hello');
});
});

View File

@ -45,7 +45,7 @@ module.exports = {
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
Phaser: 'phaser' Phaser: 'phaser'
}), }),
new webpack.EnvironmentPlugin(['API_URL', 'UPLOADER_URL', 'ADMIN_URL', 'DEBUG_MODE', 'TURN_SERVER', 'TURN_USER', 'TURN_PASSWORD', 'JITSI_URL', 'JITSI_PRIVATE_MODE']) new webpack.EnvironmentPlugin(['API_URL', 'UPLOADER_URL', 'ADMIN_URL', 'DEBUG_MODE', 'TURN_SERVER', 'TURN_USER', 'TURN_PASSWORD', 'JITSI_URL', 'JITSI_PRIVATE_MODE', 'START_ROOM_URL'])
], ],
}; };

View File

@ -1,5 +1,4 @@
const SECRET_KEY = process.env.SECRET_KEY || "THECODINGMACHINE_SECRET_KEY"; const SECRET_KEY = process.env.SECRET_KEY || "THECODINGMACHINE_SECRET_KEY";
const URL_ROOM_STARTED = "/Floor0/floor0.json";
const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64; const MINIMUM_DISTANCE = process.env.MINIMUM_DISTANCE ? Number(process.env.MINIMUM_DISTANCE) : 64;
const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48; const GROUP_RADIUS = process.env.GROUP_RADIUS ? Number(process.env.GROUP_RADIUS) : 48;
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;
@ -16,7 +15,6 @@ export const SOCKET_IDLE_TIMER = parseInt(process.env.SOCKET_IDLE_TIMER as strin
export { export {
SECRET_KEY, SECRET_KEY,
URL_ROOM_STARTED,
MINIMUM_DISTANCE, MINIMUM_DISTANCE,
API_URL, API_URL,
ADMIN_API_URL, ADMIN_API_URL,