Merge pull request #54 from thecodingmachine/webrtc
Create webrtc connexion
This commit is contained in:
commit
6087b51099
@ -28,7 +28,7 @@ class App {
|
|||||||
private config(): void {
|
private config(): void {
|
||||||
this.app.use(bodyParser.json());
|
this.app.use(bodyParser.json());
|
||||||
this.app.use(bodyParser.urlencoded({extended: false}));
|
this.app.use(bodyParser.urlencoded({extended: false}));
|
||||||
this.app.use(function (req: Request, res: Response, next) {
|
this.app.use((req: Request, res: Response, next) => {
|
||||||
res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
|
res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
|
||||||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||||
next();
|
next();
|
||||||
|
@ -6,10 +6,23 @@ import {ExSocketInterface} from "../Model/Websocket/ExSocketInterface"; //TODO f
|
|||||||
import Jwt, {JsonWebTokenError} from "jsonwebtoken";
|
import Jwt, {JsonWebTokenError} from "jsonwebtoken";
|
||||||
import {SECRET_KEY} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
import {SECRET_KEY} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
||||||
import {ExtRooms, RefreshUserPositionFunction} from "../Model/Websocket/ExtRoom";
|
import {ExtRooms, RefreshUserPositionFunction} from "../Model/Websocket/ExtRoom";
|
||||||
import {ExtRoomsInterface} from "_Model/Websocket/ExtRoomsInterface";
|
import {ExtRoomsInterface} from "../Model/Websocket/ExtRoomsInterface";
|
||||||
|
import {World} from "../Model/World";
|
||||||
|
import { uuid } from 'uuidv4';
|
||||||
|
|
||||||
|
enum SockerIoEvent {
|
||||||
|
CONNECTION = "connection",
|
||||||
|
DISCONNECTION = "disconnect",
|
||||||
|
JOIN_ROOM = "join-room",
|
||||||
|
USER_POSITION = "user-position",
|
||||||
|
WEBRTC_SIGNAL = "webrtc-signal",
|
||||||
|
WEBRTC_START = "webrtc-start",
|
||||||
|
MESSAGE_ERROR = "message-error",
|
||||||
|
}
|
||||||
|
|
||||||
export class IoSocketController{
|
export class IoSocketController{
|
||||||
Io: socketIO.Server;
|
Io: socketIO.Server;
|
||||||
|
World: World;
|
||||||
constructor(server : http.Server) {
|
constructor(server : http.Server) {
|
||||||
this.Io = socketIO(server);
|
this.Io = socketIO(server);
|
||||||
|
|
||||||
@ -29,10 +42,17 @@ export class IoSocketController{
|
|||||||
|
|
||||||
this.ioConnection();
|
this.ioConnection();
|
||||||
this.shareUsersPosition();
|
this.shareUsersPosition();
|
||||||
|
|
||||||
|
//don't send only function because the context will be not this
|
||||||
|
this.World = new World((user1 : string, user2 : string) => {
|
||||||
|
this.connectedUser(user1, user2);
|
||||||
|
}, (user1 : string, user2 : string) => {
|
||||||
|
this.disConnectedUser(user1, user2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ioConnection() {
|
ioConnection() {
|
||||||
this.Io.on('connection', (socket: Socket) => {
|
this.Io.on(SockerIoEvent.CONNECTION, (socket: Socket) => {
|
||||||
/*join-rom event permit to join one room.
|
/*join-rom event permit to join one room.
|
||||||
message :
|
message :
|
||||||
userId : user identification
|
userId : user identification
|
||||||
@ -41,15 +61,18 @@ export class IoSocketController{
|
|||||||
x: user x position on map
|
x: user x position on map
|
||||||
y: user y position on map
|
y: user y position on map
|
||||||
*/
|
*/
|
||||||
socket.on('join-room', (message : string) => {
|
socket.on(SockerIoEvent.JOIN_ROOM, (message : string) => {
|
||||||
let messageUserPosition = this.hydrateMessageReceive(message);
|
let messageUserPosition = this.hydrateMessageReceive(message);
|
||||||
if(messageUserPosition instanceof Error){
|
if(messageUserPosition instanceof Error){
|
||||||
return socket.emit("message-error", JSON.stringify({message: messageUserPosition.message}))
|
return socket.emit(SockerIoEvent.MESSAGE_ERROR, JSON.stringify({message: messageUserPosition.message}))
|
||||||
}
|
}
|
||||||
|
|
||||||
//join user in room
|
//join user in room
|
||||||
socket.join(messageUserPosition.roomId);
|
socket.join(messageUserPosition.roomId);
|
||||||
|
|
||||||
|
//join user in world
|
||||||
|
this.World.join(messageUserPosition);
|
||||||
|
|
||||||
// sending to all clients in room except sender
|
// sending to all clients in room except sender
|
||||||
this.saveUserInformation((socket as ExSocketInterface), messageUserPosition);
|
this.saveUserInformation((socket as ExSocketInterface), messageUserPosition);
|
||||||
|
|
||||||
@ -58,22 +81,96 @@ export class IoSocketController{
|
|||||||
rooms.refreshUserPosition = RefreshUserPositionFunction;
|
rooms.refreshUserPosition = RefreshUserPositionFunction;
|
||||||
rooms.refreshUserPosition(rooms, this.Io);
|
rooms.refreshUserPosition(rooms, this.Io);
|
||||||
|
|
||||||
socket.to(messageUserPosition.roomId).emit('join-room', messageUserPosition.toString());
|
socket.to(messageUserPosition.roomId).emit(SockerIoEvent.JOIN_ROOM, messageUserPosition.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('user-position', (message : string) => {
|
socket.on(SockerIoEvent.USER_POSITION, (message : string) => {
|
||||||
let messageUserPosition = this.hydrateMessageReceive(message);
|
let messageUserPosition = this.hydrateMessageReceive(message);
|
||||||
if (messageUserPosition instanceof Error) {
|
if (messageUserPosition instanceof Error) {
|
||||||
return socket.emit("message-error", JSON.stringify({message: messageUserPosition.message}));
|
return socket.emit(SockerIoEvent.MESSAGE_ERROR, JSON.stringify({message: messageUserPosition.message}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update position in the worl
|
||||||
|
this.World.updatePosition(messageUserPosition);
|
||||||
|
|
||||||
// sending to all clients in room except sender
|
// sending to all clients in room except sender
|
||||||
this.saveUserInformation((socket as ExSocketInterface), messageUserPosition);
|
this.saveUserInformation((socket as ExSocketInterface), messageUserPosition);
|
||||||
|
|
||||||
//refresh position of all user in all rooms in real time
|
//refresh position of all user in all rooms in real time
|
||||||
let rooms = (this.Io.sockets.adapter.rooms as ExtRoomsInterface)
|
let rooms = (this.Io.sockets.adapter.rooms as ExtRoomsInterface);
|
||||||
|
if(!rooms.refreshUserPosition){
|
||||||
|
rooms.refreshUserPosition = RefreshUserPositionFunction;
|
||||||
|
}
|
||||||
rooms.refreshUserPosition(rooms, this.Io);
|
rooms.refreshUserPosition(rooms, this.Io);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on(SockerIoEvent.WEBRTC_SIGNAL, (message : string) => {
|
||||||
|
let data : any = JSON.parse(message);
|
||||||
|
|
||||||
|
//send only at user
|
||||||
|
let clients: Array<any> = Object.values(this.Io.sockets.sockets);
|
||||||
|
for(let i = 0; i < clients.length; i++){
|
||||||
|
let client : ExSocketInterface = clients[i];
|
||||||
|
if(client.userId !== data.receiverId){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
client.emit(SockerIoEvent.WEBRTC_SIGNAL, message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on(SockerIoEvent.DISCONNECTION, (reason : string) => {
|
||||||
|
let Client = (socket as ExSocketInterface);
|
||||||
|
//leave group of user
|
||||||
|
this.World.leave(Client);
|
||||||
|
|
||||||
|
//leave room
|
||||||
|
socket.leave(Client.roomId);
|
||||||
|
socket.leave(Client.webRtcRoomId);
|
||||||
|
|
||||||
|
//delete all socket information
|
||||||
|
delete Client.userId;
|
||||||
|
delete Client.webRtcRoomId;
|
||||||
|
delete Client.roomId;
|
||||||
|
delete Client.token;
|
||||||
|
delete Client.position;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param socket
|
||||||
|
* @param roomId
|
||||||
|
*/
|
||||||
|
joinWebRtcRoom(socket : ExSocketInterface, roomId : string) {
|
||||||
|
if(socket.webRtcRoomId === roomId){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
socket.join(roomId);
|
||||||
|
socket.webRtcRoomId = roomId;
|
||||||
|
//if two persone in room share
|
||||||
|
if (this.Io.sockets.adapter.rooms[roomId].length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let clients: Array<any> = Object.values(this.Io.sockets.sockets);
|
||||||
|
|
||||||
|
//send start at one client to initialise offer webrtc
|
||||||
|
//send all users in room to create PeerConnection in front
|
||||||
|
clients.forEach((client: ExSocketInterface, index: number) => {
|
||||||
|
|
||||||
|
let clientsId = clients.reduce((tabs: Array<any>, clientId: ExSocketInterface, indexClientId: number) => {
|
||||||
|
if (!clientId.userId || clientId.userId === client.userId) {
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
tabs.push({
|
||||||
|
userId: clientId.userId,
|
||||||
|
initiator: index <= indexClientId
|
||||||
|
});
|
||||||
|
return tabs;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
client.emit(SockerIoEvent.WEBRTC_START, JSON.stringify({clients: clientsId, roomId: roomId}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,8 +184,7 @@ export class IoSocketController{
|
|||||||
//Hydrate and manage error
|
//Hydrate and manage error
|
||||||
hydrateMessageReceive(message : string) : MessageUserPosition | Error{
|
hydrateMessageReceive(message : string) : MessageUserPosition | Error{
|
||||||
try {
|
try {
|
||||||
let data = JSON.parse(message);
|
return new MessageUserPosition(JSON.parse(message));
|
||||||
return new MessageUserPosition(data);
|
|
||||||
}catch (err) {
|
}catch (err) {
|
||||||
//TODO log error
|
//TODO log error
|
||||||
return new Error(err);
|
return new Error(err);
|
||||||
@ -132,4 +228,26 @@ export class IoSocketController{
|
|||||||
this.shareUsersPosition();
|
this.shareUsersPosition();
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//connected user
|
||||||
|
connectedUser(user1 : string, user2 : string){
|
||||||
|
/* TODO manager room and group user to enter and leave */
|
||||||
|
let roomId = uuid();
|
||||||
|
let clients : Array<any> = Object.values(this.Io.sockets.sockets);
|
||||||
|
let User1 = clients.find((user : ExSocketInterface) => user.userId === user1);
|
||||||
|
let User2 = clients.find((user : ExSocketInterface) => user.userId === user2);
|
||||||
|
|
||||||
|
if(User1) {
|
||||||
|
this.joinWebRtcRoom(User1, roomId);
|
||||||
|
}
|
||||||
|
if(User2) {
|
||||||
|
this.joinWebRtcRoom(User2, roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//connected user
|
||||||
|
disConnectedUser(user1 : string, user2 : string){
|
||||||
|
console.log("disConnectedUser => user1", user1);
|
||||||
|
console.log("disConnectedUser => user2", user2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import {PointInterface} from "./PointInterface";
|
|||||||
export interface ExSocketInterface extends Socket {
|
export interface ExSocketInterface extends Socket {
|
||||||
token: any;
|
token: any;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
webRtcRoomId: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ export class Message {
|
|||||||
roomId: string;
|
roomId: string;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
if(!data.userId || !data.roomId){
|
if (!data.userId || !data.roomId) {
|
||||||
throw Error("userId or roomId cannot be null");
|
throw Error("userId or roomId cannot be null");
|
||||||
}
|
}
|
||||||
this.userId = data.userId;
|
this.userId = data.userId;
|
||||||
@ -13,7 +13,7 @@ export class Message {
|
|||||||
toJson() {
|
toJson() {
|
||||||
return {
|
return {
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
roomId: this.roomId,
|
roomId: this.roomId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,9 +27,9 @@ export class Point implements PointInterface{
|
|||||||
export class MessageUserPosition extends Message{
|
export class MessageUserPosition extends Message{
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(message: any) {
|
||||||
super(data);
|
super(message);
|
||||||
this.position = new Point(data.position.x, data.position.y, data.position.direction);
|
this.position = new Point(message.position.x, message.position.y, message.position.direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
|
@ -3,6 +3,7 @@ import {PointInterface} from "./Websocket/PointInterface";
|
|||||||
import {Group} from "./Group";
|
import {Group} from "./Group";
|
||||||
import {Distance} from "./Distance";
|
import {Distance} from "./Distance";
|
||||||
import {UserInterface} from "./UserInterface";
|
import {UserInterface} from "./UserInterface";
|
||||||
|
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||||
|
|
||||||
export class World {
|
export class World {
|
||||||
static readonly MIN_DISTANCE = 160;
|
static readonly MIN_DISTANCE = 160;
|
||||||
@ -29,8 +30,12 @@ export class World {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public leave(user : ExSocketInterface){
|
||||||
|
/*TODO leaver user in group*/
|
||||||
|
this.users.delete(user.userId);
|
||||||
|
}
|
||||||
|
|
||||||
public updatePosition(userPosition: MessageUserPosition): void {
|
public updatePosition(userPosition: MessageUserPosition): void {
|
||||||
let context = this;
|
|
||||||
let user = this.users.get(userPosition.userId);
|
let user = this.users.get(userPosition.userId);
|
||||||
if(typeof user === 'undefined') {
|
if(typeof user === 'undefined') {
|
||||||
return;
|
return;
|
||||||
|
42
front/dist/index.html
vendored
42
front/dist/index.html
vendored
@ -1,11 +1,37 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
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">
|
||||||
<title>Document</title>
|
<link rel="stylesheet" href="/resources/style/style.css">
|
||||||
</head>
|
<title>Document</title>
|
||||||
<body style="margin: 0"><script src="bundle.js"></script></body>
|
</head>
|
||||||
|
<body style="margin: 0">
|
||||||
|
<script src="bundle.js"></script>
|
||||||
|
<div id="webRtc" class="webrtc">
|
||||||
|
<div id="activeCam" class="activeCam">
|
||||||
|
</div>
|
||||||
|
<div id="myCam" class="myCam">
|
||||||
|
<video id="myCamVideo" autoplay></video>
|
||||||
|
</div>
|
||||||
|
<div class="btn-cam-action active">
|
||||||
|
<div class="btn-micro">
|
||||||
|
<img id="microphone" src="resources/logos/microphone.svg">
|
||||||
|
<img id="microphone-close" src="resources/logos/microphone-close.svg">
|
||||||
|
</div>
|
||||||
|
<div class="btn-video">
|
||||||
|
<img id="cinema" src="resources/logos/cinema.svg">
|
||||||
|
<img id="cinema-close" src="resources/logos/cinema-close.svg">
|
||||||
|
</div>
|
||||||
|
<div class="btn-call">
|
||||||
|
<img src="resources/logos/phone.svg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="phone-open" class="phone-open">
|
||||||
|
<img src="resources/logos/phone-open.svg">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
41
front/dist/resources/logos/cinema-close.svg
vendored
Normal file
41
front/dist/resources/logos/cinema-close.svg
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 332.8 332.8" style="enable-background:new 0 0 332.8 332.8;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M330.8,171c-3.6-6.4-12-8.8-18.8-4.8l-45.6,26.4l-11.6,6.8v63.2l10.8,6.4c0.4,0,0.4,0.4,0.8,0.4l44.8,26
|
||||||
|
c2,1.6,4.8,2.4,7.6,2.4c7.6,0,13.6-6,13.6-13.6v-53.6l0.4-52.8C332.8,175.4,332.4,173,330.8,171z"/>
|
||||||
|
<path class="st0" d="M193.2,150.6c35.6,0,64.4-28.8,64.4-64.4s-28.8-64.4-64.4-64.4s-64.4,28.8-64.4,64.4
|
||||||
|
C128.8,121.8,157.6,150.6,193.2,150.6z M193.2,59.8c14.8,0,26.4,12,26.4,26.4c0,14.8-12,26.4-26.4,26.4s-26.4-12-26.4-26.4
|
||||||
|
C166.8,71.4,178.4,59.8,193.2,59.8z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<rect x="134.8" y="-45.3" transform="matrix(-0.7402 0.6723 -0.6723 -0.7402 376.0669 224.8258)" class="st0" width="19.6" height="460.7"/>
|
||||||
|
<path class="st0" d="M90.6,83.3c-0.2-2.2-1.3-8.9-6.7-14.9c-5.4-5.9-11.9-7.6-14.1-8.1C59.7,49.2,49.5,38,39.4,26.8
|
||||||
|
c24.3-9.8,52-4.4,70.2,13.6c19.9,19.7,24.7,50.8,11.5,76.4C110.9,105.6,100.8,94.5,90.6,83.3z"/>
|
||||||
|
<path class="st0" d="M10.1,51.6c9.4,10.2,18.8,20.4,28.2,30.6c-0.2,1.8-1.4,11.7,5.5,20.5c8.2,10.3,20.7,10.2,22.1,10.1
|
||||||
|
c9.2,10.3,18.5,20.6,27.7,30.8c-4.8,2.3-24.6,11.2-48.3,4.1c-6-1.8-20.7-7.3-32.1-22C-0.3,108.1-0.2,89.1,0.1,83.4
|
||||||
|
C0.8,68,6.8,56.8,10.1,51.6z"/>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M243.4,178.2c0.1,24.5,0.2,49,0.2,73.5c-30.7-33.8-61.3-67.7-92-101.5c5.9,3.9,20.9,12.4,41.6,12.4
|
||||||
|
c16,0,28.2-5.2,34.4-8.4c2.5,1.5,7,4.6,10.7,10.3C242,170,243,175.4,243.4,178.2z"/>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M211.2,311C150.8,258.7,90.4,206.5,30,154.2c6.1,3.1,18.2,8.4,34.4,8.4c18.1,0,31.5-6.5,37.5-9.9
|
||||||
|
c44.5,49,89.1,98.1,133.6,147.1c-1.8,2.1-5.3,5.5-10.6,8.1C219.2,310.6,214,311,211.2,311z"/>
|
||||||
|
<path class="st0" d="M46.8,311C36,267.7,25.2,224.3,14.4,181c0.1-3.2,0.7-11.3,6.5-18.8c3.1-4.1,6.7-6.6,9.1-8
|
||||||
|
C90.4,206.5,150.8,258.7,211.2,311C156.4,311,101.6,311,46.8,311z"/>
|
||||||
|
<path class="st0" d="M14.4,278.6L14.4,278.6c0-32.5,0-65.1,0-97.6c10.8,43.3,21.6,86.7,32.4,130c-2.6,0-12.7-0.4-21.5-8.1
|
||||||
|
C14.7,293.5,14.4,280.7,14.4,278.6z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
24
front/dist/resources/logos/cinema.svg
vendored
Normal file
24
front/dist/resources/logos/cinema.svg
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 332.8 332.8" style="enable-background:new 0 0 332.8 332.8;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M330.8,171c-3.6-6.4-12-8.8-18.8-4.8l-45.6,26.4l-11.6,6.8v63.2l10.8,6.4c0.4,0,0.4,0.4,0.8,0.4l44.8,26
|
||||||
|
c2,1.6,4.8,2.4,7.6,2.4c7.6,0,13.6-6,13.6-13.6v-53.6l0.4-52.8C332.8,175.4,332.4,173,330.8,171z"/>
|
||||||
|
<path class="st0" d="M64.4,150.6c35.6,0,64.4-28.8,64.4-64.4S100,21.8,64.4,21.8S0,50.6,0,86.2C-0.4,121.8,28.8,150.6,64.4,150.6
|
||||||
|
z M64.4,59.8c14.8,0,26.4,12,26.4,26.4c0,14.8-12,26.4-26.4,26.4S38,100.6,38,86.2C37.6,71.4,49.6,59.8,64.4,59.8z"/>
|
||||||
|
<path class="st0" d="M227.6,154.2c-10.4,5.2-22,8.4-34.4,8.4c-15.2,0-29.6-4.4-41.6-12.4H106c-12,8-26.4,12.4-41.6,12.4
|
||||||
|
c-12.4,0-24-2.8-34.4-8.4c-9.2,5.2-15.6,15.6-15.6,26.8v97.6c0,18,14.8,32.4,32.4,32.4h164.4c18,0,32.4-14.8,32.4-32.4V181
|
||||||
|
C243.2,169.8,236.8,159.4,227.6,154.2z"/>
|
||||||
|
<path class="st0" d="M193.2,150.6c35.6,0,64.4-28.8,64.4-64.4s-28.8-64.4-64.4-64.4s-64.4,28.8-64.4,64.4
|
||||||
|
C128.8,121.8,157.6,150.6,193.2,150.6z M193.2,59.8c14.8,0,26.4,12,26.4,26.4c0,14.8-12,26.4-26.4,26.4s-26.4-12-26.4-26.4
|
||||||
|
C166.8,71.4,178.4,59.8,193.2,59.8z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
27
front/dist/resources/logos/microphone-close.svg
vendored
Normal file
27
front/dist/resources/logos/microphone-close.svg
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<rect x="257" y="-47.9" transform="matrix(-0.7402 0.6723 -0.6723 -0.7402 643.9641 283.6469)" class="st0" width="20.4" height="628.3"/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M333.6,250.3c-52.6-43.9-105.1-87.9-157.7-131.8c0-17.9,0-35.8,0-53.6c6.5-38.6,40.3-67,79.3-66.8
|
||||||
|
c38.6,0.2,71.9,28.5,78.4,66.8C333.6,126.7,333.6,188.5,333.6,250.3z"/>
|
||||||
|
<path class="st0" d="M322.6,279.9c-48.9-53.8-97.8-107.6-146.6-161.4l0,0c52.6,43.9,105.1,87.9,157.7,131.8
|
||||||
|
c-0.2,1.6-0.5,3.3-0.9,5C330.5,265.2,326.6,273.5,322.6,279.9z"/>
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M292.5,308.1c-2.3,1.2-39.5,20.3-76.7-1c-36.4-20.8-39.4-61.2-39.6-64.1c-0.1-21-0.1-42.1-0.2-63.1
|
||||||
|
C214.8,222.6,253.6,265.3,292.5,308.1z"/>
|
||||||
|
</g>
|
||||||
|
<path class="st0" d="M431.6,238.5c-0.9-8.4-8.5-14.4-16.6-13.5c-7.9,0.9-13.9,8.1-13.2,16.3c-0.1,13.3-2.2,34.6-12.6,57.9
|
||||||
|
c-6.3,14.2-14,25.2-20.6,33.1c6.8,7.5,13.6,14.9,20.3,22.4c9.5-10.9,23.4-29.7,32.8-56.3C430.3,273.9,431.8,252.5,431.6,238.5z"/>
|
||||||
|
<line class="st0" x1="354.5" y1="347.2" x2="374.6" y2="369.4"/>
|
||||||
|
<path class="st0" d="M338.5,359.9c6.8,7.4,13.5,14.9,20.3,22.3c-52.6,37.6-121.5,43.7-179.2,15.8c-60.3-29.1-98.9-90.7-99.3-158.2
|
||||||
|
c0-8.2,6.8-15,15-15s15,6.8,15,15c0.1,13.5,2.4,54.4,32.4,91.6c4.2,5.2,45.1,54.1,113.3,54.1C297,385.6,326.7,367.9,338.5,359.9z"/>
|
||||||
|
<rect x="241" y="409.6" class="st0" width="29.9" height="102.3"/>
|
||||||
|
<path class="st0" d="M304.2,511.9h-97.1c-8-0.4-14.3-7.1-14.3-15c0-8.1,6.7-14.9,15-15c31.7,0,63.4,0.1,95.1,0.1
|
||||||
|
c8.9-0.6,16.3,6.5,16.3,14.9C319.2,504.8,312.6,511.7,304.2,511.9z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
21
front/dist/resources/logos/microphone.svg
vendored
Normal file
21
front/dist/resources/logos/microphone.svg
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M431.7,239.9c0-8.3-6.7-15-15-15c-8.3,0-15,6.7-15,15c0,80.3-65.3,145.7-145.7,145.7s-145.7-65.3-145.7-145.7
|
||||||
|
c0-8.3-6.7-15-15-15c-8.3,0-15,6.7-15,15c0,91.8,70.8,167.4,160.7,175v67h-33.2c-8.3,0-15,6.7-15,15s6.7,15,15,15h96.4
|
||||||
|
c8.3,0,15-6.7,15-15s-6.7-15-15-15H271v-67C360.9,407.3,431.7,331.7,431.7,239.9z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M256,0c-43.7,0-79.3,35.6-79.3,79.3v160.7c0,43.7,35.6,79.3,79.3,79.3c43.7,0,79.3-35.6,79.3-79.3V79.3
|
||||||
|
C335.3,35.6,299.7,0,256,0z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 937 B |
16
front/dist/resources/logos/phone-open.svg
vendored
Normal file
16
front/dist/resources/logos/phone-open.svg
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M163.2,351.1c-2.4-23.4-1.1-46.7,3.9-69.2c2.6-11-2.1-23.8-9.4-29.6l-36.8-39.7C142.5,160,170,126.2,216.8,95
|
||||||
|
l45.1,27.2c9,7.3,21.3,9.1,32,4.4c21.2-9.5,43.7-15.4,67.2-17.7c16.9-1.7,29.3-16.8,27.6-33.7L381.5,5
|
||||||
|
c-1.7-16.9-16.8-29.3-33.7-27.6C154-2.8,12.4,170.8,32.1,364.5c1.7,16.9,16.8,29.3,33.7,27.6l69.9-7.1
|
||||||
|
C152.5,383.1,164.9,368,163.2,351.1z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 804 B |
16
front/dist/resources/logos/phone.svg
vendored
Normal file
16
front/dist/resources/logos/phone.svg
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 384 384" style="enable-background:new 0 0 384 384;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M32.6,256.8c17.3-15.9,36.8-28.8,57.8-38.3c10.4-4.5,17.8-15.9,18.1-25.3l9.8-53.2
|
||||||
|
c55-14.2,98.5-12.3,151.6,6.5l5.2,52.4c-0.5,11.6,5.4,22.5,15.6,28.3c20.3,11.3,38.5,25.8,54.4,43.2c11.5,12.5,31,13.4,43.5,1.9
|
||||||
|
l51.9-47.7c12.5-11.5,13.4-31,1.9-43.5c-131.8-143.5-355.6-153-499-21.3c-12.5,11.5-13.4,31-1.9,43.5l47.5,51.8
|
||||||
|
C0.6,267.4,20.1,268.3,32.6,256.8z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 810 B |
153
front/dist/resources/style/style.css
vendored
Normal file
153
front/dist/resources/style/style.css
vendored
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
.webrtc{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.webrtc.active{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.webrtc, .activeCam{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
.activeCam video{
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*CSS size for 2 - 3 elements*/
|
||||||
|
video:nth-child(1):nth-last-child(3),
|
||||||
|
video:nth-child(2):nth-last-child(2),
|
||||||
|
video:nth-child(3):nth-last-child(1),
|
||||||
|
video:nth-child(1):nth-last-child(2),
|
||||||
|
video:nth-child(2):nth-last-child(1){
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
video:nth-child(1):nth-last-child(3),
|
||||||
|
video:nth-child(2):nth-last-child(2),
|
||||||
|
video:nth-child(3):nth-last-child(1){
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*CSS position for 2 elements*/
|
||||||
|
video:nth-child(1):nth-last-child(2){
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
video:nth-child(2):nth-last-child(1){
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*CSS position for 3 elements*/
|
||||||
|
video:nth-child(1):nth-last-child(3){
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
video:nth-child(2):nth-last-child(2){
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
video:nth-child(3):nth-last-child(1) {
|
||||||
|
top: 50%;
|
||||||
|
left: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.myCam{
|
||||||
|
height: 200px;
|
||||||
|
width: 300px;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
background: black;
|
||||||
|
border: none;
|
||||||
|
bottom: 20px;
|
||||||
|
max-height: 17%;
|
||||||
|
max-width: 17%;
|
||||||
|
opacity: 1;
|
||||||
|
display: block;
|
||||||
|
transition: opacity 1s;
|
||||||
|
}
|
||||||
|
.myCam video{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.btn-cam-action div{
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
border: solid 0px black;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
background: #666;
|
||||||
|
left: 6vw;
|
||||||
|
box-shadow: 2px 2px 24px #444;
|
||||||
|
border-radius: 48px;
|
||||||
|
transform: translateX(calc(-6vw - 96px));
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
.webrtc:hover .btn-cam-action.active div{
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
.btn-cam-action div:hover{
|
||||||
|
background: #407cf7;
|
||||||
|
box-shadow: 4px 4px 48px #666;
|
||||||
|
transition: 280ms;
|
||||||
|
}
|
||||||
|
.btn-micro{
|
||||||
|
bottom: 277px;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.btn-video{
|
||||||
|
bottom: 177px;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
.btn-call{
|
||||||
|
bottom: 77px;
|
||||||
|
transition: all .1s;
|
||||||
|
}
|
||||||
|
.btn-cam-action div img{
|
||||||
|
height: 32px;
|
||||||
|
width: 40px;
|
||||||
|
top: calc(48px - 32px);
|
||||||
|
left: calc(48px - 35px);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.phone-open{
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
left: calc(50% - 70px);
|
||||||
|
padding: 20px;
|
||||||
|
bottom: 20px;
|
||||||
|
box-shadow: 2px 2px 24px #444;
|
||||||
|
background-color: green;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all .4s ease-in-out;
|
||||||
|
}
|
||||||
|
.phone-open.active{
|
||||||
|
opacity: 1;
|
||||||
|
animation-name: phone-move;
|
||||||
|
animation-duration: 0.4s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
}
|
||||||
|
.phone-open:hover{
|
||||||
|
animation: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes phone-move {
|
||||||
|
0% {
|
||||||
|
left: calc(50% - 70px);
|
||||||
|
bottom: 20px;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
left: calc(50% - 65px);
|
||||||
|
bottom: 15px;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
left: calc(50% - 75px);
|
||||||
|
bottom: 25px;
|
||||||
|
}
|
||||||
|
}
|
@ -15,8 +15,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/axios": "^0.14.0",
|
"@types/axios": "^0.14.0",
|
||||||
|
"@types/simple-peer": "^9.6.0",
|
||||||
"@types/socket.io-client": "^1.4.32",
|
"@types/socket.io-client": "^1.4.32",
|
||||||
"phaser": "^3.22.0",
|
"phaser": "^3.22.0",
|
||||||
|
"simple-peer": "^9.6.2",
|
||||||
"socket.io-client": "^2.3.0"
|
"socket.io-client": "^2.3.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -4,6 +4,14 @@ const SocketIo = require('socket.io-client');
|
|||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import {API_URL, ROOM} from "./Enum/EnvironmentVariable";
|
import {API_URL, ROOM} from "./Enum/EnvironmentVariable";
|
||||||
|
|
||||||
|
enum EventMessage{
|
||||||
|
WEBRTC_SIGNAL = "webrtc-signal",
|
||||||
|
WEBRTC_START = "webrtc-start",
|
||||||
|
JOIN_ROOM = "join-room",
|
||||||
|
USER_POSITION = "user-position",
|
||||||
|
MESSAGE_ERROR = "message-error"
|
||||||
|
}
|
||||||
|
|
||||||
class Message {
|
class Message {
|
||||||
userId: string;
|
userId: string;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
@ -56,6 +64,7 @@ export interface MessageUserPositionInterface {
|
|||||||
roomId: string;
|
roomId: string;
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageUserPosition extends Message implements MessageUserPositionInterface{
|
class MessageUserPosition extends Message implements MessageUserPositionInterface{
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
|
|
||||||
@ -76,14 +85,15 @@ class MessageUserPosition extends Message implements MessageUserPositionInterfac
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ListMessageUserPositionInterface {
|
export interface ListMessageUserPositionInterface {
|
||||||
roomId : string;
|
roomId: string;
|
||||||
listUsersPosition: Array<MessageUserPosition>;
|
listUsersPosition: Array<MessageUserPosition>;
|
||||||
}
|
}
|
||||||
class ListMessageUserPosition{
|
|
||||||
roomId : string;
|
class ListMessageUserPosition {
|
||||||
|
roomId: string;
|
||||||
listUsersPosition: Array<MessageUserPosition>;
|
listUsersPosition: Array<MessageUserPosition>;
|
||||||
|
|
||||||
constructor(roomId : string, data : any) {
|
constructor(roomId: string, data: any) {
|
||||||
this.roomId = roomId;
|
this.roomId = roomId;
|
||||||
this.listUsersPosition = new Array<MessageUserPosition>();
|
this.listUsersPosition = new Array<MessageUserPosition>();
|
||||||
data.forEach((userPosition: any) => {
|
data.forEach((userPosition: any) => {
|
||||||
@ -99,23 +109,36 @@ class ListMessageUserPosition{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConnexionInterface {
|
export interface ConnexionInterface {
|
||||||
socket : any;
|
socket: any;
|
||||||
token : string;
|
token: string;
|
||||||
email : string;
|
email: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
startedRoom : string;
|
startedRoom: string;
|
||||||
createConnexion() : Promise<any>;
|
|
||||||
joinARoom(roomId : string) : void;
|
createConnexion(): Promise<any>;
|
||||||
sharePosition(x : number, y : number, direction : string) : void;
|
|
||||||
positionOfAllUser() : void;
|
joinARoom(roomId: string): void;
|
||||||
|
|
||||||
|
sharePosition(x: number, y: number, direction: string): void;
|
||||||
|
|
||||||
|
positionOfAllUser(): void;
|
||||||
|
|
||||||
|
/*webrtc*/
|
||||||
|
sendWebrtcSignal(signal: any, roomId: string, userId?: string, receiverId?: string): void;
|
||||||
|
|
||||||
|
receiveWebrtcSignal(callBack: Function): void;
|
||||||
|
|
||||||
|
receiveWebrtcStart(callBack: Function): void;
|
||||||
}
|
}
|
||||||
export class Connexion implements ConnexionInterface{
|
|
||||||
socket : any;
|
export class Connexion implements ConnexionInterface {
|
||||||
token : string;
|
socket: any;
|
||||||
email : string;
|
token: string;
|
||||||
|
email: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
startedRoom : string;
|
startedRoom: string;
|
||||||
|
|
||||||
GameManager: GameManager;
|
GameManager: GameManager;
|
||||||
|
|
||||||
@ -124,7 +147,7 @@ export class Connexion implements ConnexionInterface{
|
|||||||
this.GameManager = GameManager;
|
this.GameManager = GameManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
createConnexion() : Promise<ConnexionInterface>{
|
createConnexion(): Promise<ConnexionInterface> {
|
||||||
return Axios.post(`${API_URL}/login`, {email: this.email})
|
return Axios.post(`${API_URL}/login`, {email: this.email})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.token = res.data.token;
|
this.token = res.data.token;
|
||||||
@ -159,9 +182,9 @@ export class Connexion implements ConnexionInterface{
|
|||||||
* Permit to join a room
|
* Permit to join a room
|
||||||
* @param roomId
|
* @param roomId
|
||||||
*/
|
*/
|
||||||
joinARoom(roomId : string) : void {
|
joinARoom(roomId: string): void {
|
||||||
let messageUserPosition = new MessageUserPosition(this.userId, this.startedRoom, new Point(0, 0));
|
let messageUserPosition = new MessageUserPosition(this.userId, this.startedRoom, new Point(0, 0));
|
||||||
this.socket.emit('join-room', messageUserPosition.toString());
|
this.socket.emit(EventMessage.JOIN_ROOM, messageUserPosition.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,7 +198,7 @@ export class Connexion implements ConnexionInterface{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let messageUserPosition = new MessageUserPosition(this.userId, ROOM[0], new Point(x, y, direction));
|
let messageUserPosition = new MessageUserPosition(this.userId, ROOM[0], new Point(x, y, direction));
|
||||||
this.socket.emit('user-position', messageUserPosition.toString());
|
this.socket.emit(EventMessage.USER_POSITION, messageUserPosition.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,8 +216,8 @@ export class Connexion implements ConnexionInterface{
|
|||||||
* ...
|
* ...
|
||||||
* ]
|
* ]
|
||||||
**/
|
**/
|
||||||
positionOfAllUser() : void {
|
positionOfAllUser(): void {
|
||||||
this.socket.on("user-position", (message: string) => {
|
this.socket.on(EventMessage.USER_POSITION, (message: string) => {
|
||||||
let dataList = JSON.parse(message);
|
let dataList = JSON.parse(message);
|
||||||
dataList.forEach((UserPositions: any) => {
|
dataList.forEach((UserPositions: any) => {
|
||||||
let listMessageUserPosition = new ListMessageUserPosition(UserPositions[0], UserPositions[1]);
|
let listMessageUserPosition = new ListMessageUserPosition(UserPositions[0], UserPositions[1]);
|
||||||
@ -203,9 +226,26 @@ export class Connexion implements ConnexionInterface{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
errorMessage() : void {
|
sendWebrtcSignal(signal: any, roomId: string, userId? : string, receiverId? : string) {
|
||||||
this.socket.on('message-error', (message : string) => {
|
this.socket.emit(EventMessage.WEBRTC_SIGNAL, JSON.stringify({
|
||||||
console.error("message-error", message);
|
userId: userId ? userId : this.userId,
|
||||||
|
receiverId: receiverId ? receiverId : this.userId,
|
||||||
|
roomId: roomId,
|
||||||
|
signal: signal
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveWebrtcStart(callback: Function) {
|
||||||
|
this.socket.on(EventMessage.WEBRTC_START, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveWebrtcSignal(callback: Function) {
|
||||||
|
this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMessage(): void {
|
||||||
|
this.socket.on(EventMessage.MESSAGE_ERROR, (message: string) => {
|
||||||
|
console.error(EventMessage.MESSAGE_ERROR, message);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
import {GameScene} from "./GameScene";
|
import {GameScene} from "./GameScene";
|
||||||
import {ROOM} from "../../Enum/EnvironmentVariable"
|
import {ROOM} from "../../Enum/EnvironmentVariable"
|
||||||
import {Connexion, ConnexionInterface, ListMessageUserPositionInterface} from "../../Connexion";
|
import {Connexion, ConnexionInterface, ListMessageUserPositionInterface} from "../../Connexion";
|
||||||
|
import {SimplePeerInterface, SimplePeer} from "../../WebRtc/SimplePeer";
|
||||||
|
import {LogincScene} from "../Login/LogincScene";
|
||||||
|
|
||||||
export enum StatusGameManagerEnum {
|
export enum StatusGameManagerEnum {
|
||||||
IN_PROGRESS = 1,
|
IN_PROGRESS = 1,
|
||||||
@ -13,6 +15,7 @@ export class GameManager {
|
|||||||
status: number;
|
status: number;
|
||||||
private ConnexionInstance: Connexion;
|
private ConnexionInstance: Connexion;
|
||||||
private currentGameScene: GameScene;
|
private currentGameScene: GameScene;
|
||||||
|
SimplePeer : SimplePeerInterface;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.status = StatusGameManagerEnum.IN_PROGRESS;
|
this.status = StatusGameManagerEnum.IN_PROGRESS;
|
||||||
@ -21,9 +24,11 @@ export class GameManager {
|
|||||||
connect(email:string) {
|
connect(email:string) {
|
||||||
this.ConnexionInstance = new Connexion(email, this);
|
this.ConnexionInstance = new Connexion(email, this);
|
||||||
ConnexionInstance = this.ConnexionInstance;
|
ConnexionInstance = this.ConnexionInstance;
|
||||||
return this.ConnexionInstance.createConnexion()
|
return this.ConnexionInstance.createConnexion().then(() => {
|
||||||
|
this.SimplePeer = new SimplePeer(ConnexionInstance);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentGameScene(gameScene: GameScene) {
|
setCurrentGameScene(gameScene: GameScene) {
|
||||||
this.currentGameScene = gameScene;
|
this.currentGameScene = gameScene;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import KeyboardKeydownCallback = Phaser.Types.Input.Keyboard.KeyboardKeydownCallback;
|
|
||||||
import {gameManager} from "../Game/GameManager";
|
import {gameManager} from "../Game/GameManager";
|
||||||
import {ROOM} from "../../Enum/EnvironmentVariable";
|
|
||||||
import {TextField} from "../Components/TextField";
|
import {TextField} from "../Components/TextField";
|
||||||
import {TextInput} from "../Components/TextInput";
|
import {TextInput} from "../Components/TextInput";
|
||||||
import {ClickButton} from "../Components/ClickButton";
|
import {ClickButton} from "../Components/ClickButton";
|
||||||
|
import {GameSceneInterface} from "../Game/GameScene";
|
||||||
|
import {MessageUserPositionInterface} from "../../Connexion";
|
||||||
|
|
||||||
//todo: put this constants in a dedicated file
|
//todo: put this constants in a dedicated file
|
||||||
export const LoginSceneName = "LoginScene";
|
export const LoginSceneName = "LoginScene";
|
||||||
@ -11,21 +11,22 @@ enum LoginTextures {
|
|||||||
playButton = "play_button",
|
playButton = "play_button",
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LogincScene extends Phaser.Scene {
|
export class LogincScene extends Phaser.Scene implements GameSceneInterface {
|
||||||
private emailInput: TextInput;
|
private emailInput: TextInput;
|
||||||
private textField: TextField;
|
private textField: TextField;
|
||||||
private playButton: ClickButton;
|
private playButton: ClickButton;
|
||||||
private infoTextField: TextField;
|
private infoTextField: TextField;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
key: LoginSceneName
|
key: LoginSceneName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
preload() {
|
preload() {
|
||||||
this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
|
this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
this.textField = new TextField(this, 10, 10, 'Enter your email:');
|
this.textField = new TextField(this, 10, 10, 'Enter your email:');
|
||||||
this.emailInput = new TextInput(this, 10, 50);
|
this.emailInput = new TextInput(this, 10, 50);
|
||||||
@ -37,15 +38,25 @@ export class LogincScene extends Phaser.Scene {
|
|||||||
let infoText = "Commandes de base: \n - Z,Q,S,D (ou les flèches de direction) pour bouger\n - SHIFT pour accélerer";
|
let infoText = "Commandes de base: \n - Z,Q,S,D (ou les flèches de direction) pour bouger\n - SHIFT pour accélerer";
|
||||||
this.infoTextField = new TextField(this, 10, 300, infoText);
|
this.infoTextField = new TextField(this, 10, 300, infoText);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(time: number, delta: number): void {
|
update(time: number, delta: number): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async login() {
|
async login() {
|
||||||
let email = this.emailInput.text;
|
let email = this.emailInput.text;
|
||||||
if (!email) return;
|
if (!email) return;
|
||||||
await gameManager.connect(email);
|
gameManager.connect(email).then(() => {
|
||||||
this.scene.start("GameScene");
|
this.scene.start("GameScene");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Map: Phaser.Tilemaps.Tilemap;
|
||||||
|
RoomId: string;
|
||||||
|
|
||||||
|
createCurrentPlayer(UserId: string): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
shareUserPosition(UsersPosition: Array<MessageUserPositionInterface>): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
141
front/src/WebRtc/MediaManager.ts
Normal file
141
front/src/WebRtc/MediaManager.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
export class MediaManager {
|
||||||
|
localStream: MediaStream;
|
||||||
|
remoteVideo: Array<any> = new Array<any>();
|
||||||
|
myCamVideo: any;
|
||||||
|
cinemaClose: any = null;
|
||||||
|
cinema: any = null;
|
||||||
|
microphoneClose: any = null;
|
||||||
|
microphone: any = null;
|
||||||
|
constraintsMedia = {audio: false, video: true};
|
||||||
|
getCameraPromise : Promise<any> = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.myCamVideo = document.getElementById('myCamVideo');
|
||||||
|
this.microphoneClose = document.getElementById('microphone-close');
|
||||||
|
|
||||||
|
this.microphoneClose.addEventListener('click', (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.enabledMicrophone();
|
||||||
|
//update tracking
|
||||||
|
});
|
||||||
|
this.microphone = document.getElementById('microphone');
|
||||||
|
this.microphone.addEventListener('click', (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.disabledMicrophone();
|
||||||
|
//update tracking
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cinemaClose = document.getElementById('cinema-close');
|
||||||
|
this.cinemaClose.addEventListener('click', (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.enabledCamera();
|
||||||
|
//update tracking
|
||||||
|
});
|
||||||
|
this.cinema = document.getElementById('cinema');
|
||||||
|
this.cinema.addEventListener('click', (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
|
this.disabledCamera();
|
||||||
|
//update tracking
|
||||||
|
});
|
||||||
|
|
||||||
|
this.enabledCamera();
|
||||||
|
this.enabledMicrophone();
|
||||||
|
}
|
||||||
|
|
||||||
|
activeVisio(){
|
||||||
|
let webRtc = document.getElementById('webRtc');
|
||||||
|
webRtc.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledCamera() {
|
||||||
|
this.cinemaClose.style.display = "none";
|
||||||
|
this.cinema.style.display = "block";
|
||||||
|
this.constraintsMedia.video = true;
|
||||||
|
this.localStream = null;
|
||||||
|
this.myCamVideo.srcObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
disabledCamera() {
|
||||||
|
this.cinemaClose.style.display = "block";
|
||||||
|
this.cinema.style.display = "none";
|
||||||
|
this.constraintsMedia.video = false;
|
||||||
|
|
||||||
|
this.myCamVideo.pause();
|
||||||
|
if(this.localStream) {
|
||||||
|
this.localStream.getTracks().forEach((MediaStreamTrack: MediaStreamTrack) => {
|
||||||
|
if (MediaStreamTrack.kind === "video") {
|
||||||
|
MediaStreamTrack.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.localStream = null;
|
||||||
|
this.myCamVideo.srcObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledMicrophone() {
|
||||||
|
this.microphoneClose.style.display = "none";
|
||||||
|
this.microphone.style.display = "block";
|
||||||
|
this.constraintsMedia.audio = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
disabledMicrophone() {
|
||||||
|
this.microphoneClose.style.display = "block";
|
||||||
|
this.microphone.style.display = "none";
|
||||||
|
this.constraintsMedia.audio = false;
|
||||||
|
if(this.localStream) {
|
||||||
|
this.localStream.getTracks().forEach((MediaStreamTrack: MediaStreamTrack) => {
|
||||||
|
if (MediaStreamTrack.kind === "audio") {
|
||||||
|
MediaStreamTrack.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getElementActivePhone(){
|
||||||
|
return document.getElementById('phone-open');
|
||||||
|
}
|
||||||
|
|
||||||
|
activePhoneOpen(){
|
||||||
|
return this.getElementActivePhone().classList.add("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
disablePhoneOpen(){
|
||||||
|
return this.getElementActivePhone().classList.remove("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
//get camera
|
||||||
|
getCamera() {
|
||||||
|
return this.getCameraPromise = navigator.mediaDevices.getUserMedia(this.constraintsMedia)
|
||||||
|
.then((stream: MediaStream) => {
|
||||||
|
this.localStream = stream;
|
||||||
|
this.myCamVideo.srcObject = this.localStream;
|
||||||
|
return stream;
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
this.localStream = null;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
addActiveVideo(userId : string){
|
||||||
|
let elementRemoteVideo = document.getElementById("activeCam");
|
||||||
|
elementRemoteVideo.insertAdjacentHTML('beforeend', '<video id="'+userId+'" autoplay></video>');
|
||||||
|
this.remoteVideo[(userId as any)] = document.getElementById(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
removeActiveVideo(userId : string){
|
||||||
|
let element = document.getElementById(userId);
|
||||||
|
if(!element){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
element.remove();
|
||||||
|
}
|
||||||
|
}
|
150
front/src/WebRtc/SimplePeer.ts
Normal file
150
front/src/WebRtc/SimplePeer.ts
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import {ConnexionInterface} from "../Connexion";
|
||||||
|
import {MediaManager} from "./MediaManager";
|
||||||
|
let Peer = require('simple-peer');
|
||||||
|
|
||||||
|
export interface SimplePeerInterface {
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SimplePeer {
|
||||||
|
Connexion: ConnexionInterface;
|
||||||
|
MediaManager: MediaManager;
|
||||||
|
WebRtcRoomId: string;
|
||||||
|
Users: Array<any>;
|
||||||
|
|
||||||
|
PeerConnexionArray: Array<any> = new Array<any>();
|
||||||
|
|
||||||
|
constructor(Connexion: ConnexionInterface, WebRtcRoomId: string = "test-webrtc") {
|
||||||
|
this.Connexion = Connexion;
|
||||||
|
this.WebRtcRoomId = WebRtcRoomId;
|
||||||
|
this.MediaManager = new MediaManager();
|
||||||
|
this.initialise();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* permit to listen when user could start visio
|
||||||
|
*/
|
||||||
|
private initialise(){
|
||||||
|
|
||||||
|
//receive message start
|
||||||
|
this.Connexion.receiveWebrtcStart((message: string) => {
|
||||||
|
this.receiveWebrtcStart(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
//when button to call is clicked, start video
|
||||||
|
this.MediaManager.getElementActivePhone().addEventListener("click", () => {
|
||||||
|
this.startWebRtc();
|
||||||
|
this.disablePhone();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* server has two person connected, start the meet
|
||||||
|
*/
|
||||||
|
startWebRtc() {
|
||||||
|
this.MediaManager.activeVisio();
|
||||||
|
return this.MediaManager.getCamera().then((stream: MediaStream) => {
|
||||||
|
this.MediaManager.localStream = stream;
|
||||||
|
|
||||||
|
//create pear connexion
|
||||||
|
this.createPeerConnexion();
|
||||||
|
|
||||||
|
//receive signal by gemer
|
||||||
|
this.Connexion.receiveWebrtcSignal((message: string) => {
|
||||||
|
this.receiveWebrtcSignal(message);
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
receiveWebrtcStart(message: string) {
|
||||||
|
let data = JSON.parse(message);
|
||||||
|
this.WebRtcRoomId = data.roomId;
|
||||||
|
this.Users = data.clients;
|
||||||
|
|
||||||
|
//active button for player
|
||||||
|
this.activePhone();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createPeerConnexion() {
|
||||||
|
this.Users.forEach((user: any) => {
|
||||||
|
if(this.PeerConnexionArray[user.userId]){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.MediaManager.addActiveVideo(user.userId);
|
||||||
|
|
||||||
|
this.PeerConnexionArray[user.userId] = new Peer({initiator: user.initiator});
|
||||||
|
|
||||||
|
this.PeerConnexionArray[user.userId].on('signal', (data: any) => {
|
||||||
|
this.sendWebrtcSignal(data, user.userId);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.PeerConnexionArray[user.userId].on('stream', (stream: MediaStream) => {
|
||||||
|
this.stream(user.userId, stream);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.PeerConnexionArray[user.userId].on('close', () => {
|
||||||
|
this.closeConnexion(user.userId);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addMedia(user.userId);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
closeConnexion(userId : string){
|
||||||
|
// @ts-ignore
|
||||||
|
this.PeerConnexionArray[userId] = null;
|
||||||
|
this.MediaManager.removeActiveVideo(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
sendWebrtcSignal(data: any, userId : string) {
|
||||||
|
this.Connexion.sendWebrtcSignal(data, this.WebRtcRoomId, null, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
receiveWebrtcSignal(message: string) {
|
||||||
|
let data = JSON.parse(message);
|
||||||
|
if(!this.PeerConnexionArray[data.userId]){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.PeerConnexionArray[data.userId].signal(data.signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
* @param stream
|
||||||
|
*/
|
||||||
|
stream(userId : any, stream: MediaStream) {
|
||||||
|
this.MediaManager.remoteVideo[userId].srcObject = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userId
|
||||||
|
*/
|
||||||
|
addMedia (userId : any) {
|
||||||
|
this.PeerConnexionArray[userId].addStream(this.MediaManager.localStream) // <- add streams to peer dynamically
|
||||||
|
}
|
||||||
|
|
||||||
|
activePhone(){
|
||||||
|
this.MediaManager.activePhoneOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
disablePhone(){
|
||||||
|
this.MediaManager.disablePhoneOpen();
|
||||||
|
}
|
||||||
|
}
|
@ -65,6 +65,13 @@
|
|||||||
version "13.11.0"
|
version "13.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
|
||||||
|
|
||||||
|
"@types/simple-peer@^9.6.0":
|
||||||
|
version "9.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/simple-peer/-/simple-peer-9.6.0.tgz#b5828d835b7f42dde27db584ba127e7a9f9072f4"
|
||||||
|
integrity sha512-X2y6s+vE/3j03hkI90oqld2JH2J/m1L7yFCYYPyFV/whrOK1h4neYvJL3GIE+UcACJacXZqzdmDKudwec18RbA==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/socket.io-client@^1.4.32":
|
"@types/socket.io-client@^1.4.32":
|
||||||
version "1.4.32"
|
version "1.4.32"
|
||||||
resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.32.tgz#988a65a0386c274b1c22a55377fab6a30789ac14"
|
resolved "https://registry.yarnpkg.com/@types/socket.io-client/-/socket.io-client-1.4.32.tgz#988a65a0386c274b1c22a55377fab6a30789ac14"
|
||||||
@ -1718,6 +1725,11 @@ functional-red-black-tree@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
|
||||||
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
|
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
|
||||||
|
|
||||||
|
get-browser-rtc@^1.0.0:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9"
|
||||||
|
integrity sha1-u81AyEUaftTvXDc7gWmkCd0dEdk=
|
||||||
|
|
||||||
get-caller-file@^1.0.1:
|
get-caller-file@^1.0.1:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
|
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
|
||||||
@ -3097,7 +3109,12 @@ querystringify@^2.1.1:
|
|||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
|
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
|
||||||
|
|
||||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
|
queue-microtask@^1.1.0:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.1.2.tgz#139bf8186db0c545017ec66c2664ac646d5c571e"
|
||||||
|
integrity sha512-F9wwNePtXrzZenAB3ax0Y8TSKGvuB7Qw16J30hspEUTbfUM+H827XyN3rlpwhVmtm5wuZtbKIHjOnwDn7MUxWQ==
|
||||||
|
|
||||||
|
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.3, randombytes@^2.0.5:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3135,7 +3152,7 @@ raw-body@2.4.0:
|
|||||||
string_decoder "~1.1.1"
|
string_decoder "~1.1.1"
|
||||||
util-deprecate "~1.0.1"
|
util-deprecate "~1.0.1"
|
||||||
|
|
||||||
readable-stream@^3.0.6:
|
readable-stream@^3.0.6, readable-stream@^3.4.0:
|
||||||
version "3.6.0"
|
version "3.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3418,6 +3435,17 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
|
|||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||||
|
|
||||||
|
simple-peer@^9.6.2:
|
||||||
|
version "9.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.6.2.tgz#42418e77cf8f9184e4fa22ef1017b195c2bf84d7"
|
||||||
|
integrity sha512-EOKoImCaqtNvXIntxT1CBBK/3pVi7tMAoJ3shdyd9qk3zLm3QPiRLb/sPC1G2xvKJkJc5fkQjCXqRZ0AknwTig==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.0.1"
|
||||||
|
get-browser-rtc "^1.0.0"
|
||||||
|
queue-microtask "^1.1.0"
|
||||||
|
randombytes "^2.0.3"
|
||||||
|
readable-stream "^3.4.0"
|
||||||
|
|
||||||
slice-ansi@^2.1.0:
|
slice-ansi@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
|
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
|
||||||
|
Loading…
Reference in New Issue
Block a user