Migrating user position messages to protobuf
This commit is contained in:
parent
e9ca8721a6
commit
df0636c513
@ -10,7 +10,6 @@ import {Group} from "../Model/Group";
|
|||||||
import {User} from "../Model/User";
|
import {User} from "../Model/User";
|
||||||
import {isSetPlayerDetailsMessage,} from "../Model/Websocket/SetPlayerDetailsMessage";
|
import {isSetPlayerDetailsMessage,} from "../Model/Websocket/SetPlayerDetailsMessage";
|
||||||
import {MessageUserJoined} from "../Model/Websocket/MessageUserJoined";
|
import {MessageUserJoined} from "../Model/Websocket/MessageUserJoined";
|
||||||
import {MessageUserMoved} from "../Model/Websocket/MessageUserMoved";
|
|
||||||
import si from "systeminformation";
|
import si from "systeminformation";
|
||||||
import {Gauge} from "prom-client";
|
import {Gauge} from "prom-client";
|
||||||
import {TokenInterface} from "../Controller/AuthenticateController";
|
import {TokenInterface} from "../Controller/AuthenticateController";
|
||||||
@ -23,9 +22,17 @@ import {uuid} from 'uuidv4';
|
|||||||
import {isViewport} from "../Model/Websocket/ViewportMessage";
|
import {isViewport} from "../Model/Websocket/ViewportMessage";
|
||||||
import {GroupUpdateInterface} from "_Model/Websocket/GroupUpdateInterface";
|
import {GroupUpdateInterface} from "_Model/Websocket/GroupUpdateInterface";
|
||||||
import {Movable} from "../Model/Movable";
|
import {Movable} from "../Model/Movable";
|
||||||
import {PositionMessage, SetPlayerDetailsMessage} from "../../../messages/generated/messages_pb";
|
import {
|
||||||
|
PositionMessage,
|
||||||
|
SetPlayerDetailsMessage,
|
||||||
|
SubMessage,
|
||||||
|
UserMovedMessage,
|
||||||
|
BatchMessage
|
||||||
|
} from "../../../messages/generated/messages_pb";
|
||||||
import {UserMovesMessage} from "../../../messages/generated/messages_pb";
|
import {UserMovesMessage} from "../../../messages/generated/messages_pb";
|
||||||
import Direction = PositionMessage.Direction;
|
import Direction = PositionMessage.Direction;
|
||||||
|
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
|
||||||
|
import toPositionMessage = ProtobufUtils.toPositionMessage;
|
||||||
|
|
||||||
enum SocketIoEvent {
|
enum SocketIoEvent {
|
||||||
CONNECTION = "connection",
|
CONNECTION = "connection",
|
||||||
@ -48,13 +55,13 @@ enum SocketIoEvent {
|
|||||||
BATCH = "batch",
|
BATCH = "batch",
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitInBatch(socket: ExSocketInterface, event: string | symbol, payload: unknown): void {
|
function emitInBatch(socket: ExSocketInterface, event: string, payload: SubMessage): void {
|
||||||
socket.batchedMessages.push({ event, payload});
|
socket.batchedMessages.addPayload(payload);
|
||||||
|
|
||||||
if (socket.batchTimeout === null) {
|
if (socket.batchTimeout === null) {
|
||||||
socket.batchTimeout = setTimeout(() => {
|
socket.batchTimeout = setTimeout(() => {
|
||||||
socket.emit(SocketIoEvent.BATCH, socket.batchedMessages);
|
socket.binary(true).emit(SocketIoEvent.BATCH, socket.batchedMessages.serializeBinary().buffer);
|
||||||
socket.batchedMessages = [];
|
socket.batchedMessages = new BatchMessage();
|
||||||
socket.batchTimeout = null;
|
socket.batchTimeout = null;
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
@ -159,9 +166,9 @@ export class IoSocketController {
|
|||||||
ioConnection() {
|
ioConnection() {
|
||||||
this.Io.on(SocketIoEvent.CONNECTION, (socket: Socket) => {
|
this.Io.on(SocketIoEvent.CONNECTION, (socket: Socket) => {
|
||||||
const client : ExSocketInterface = socket as ExSocketInterface;
|
const client : ExSocketInterface = socket as ExSocketInterface;
|
||||||
client.batchedMessages = [];
|
client.batchedMessages = new BatchMessage();
|
||||||
client.batchTimeout = null;
|
client.batchTimeout = null;
|
||||||
client.emitInBatch = (event: string | symbol, payload: unknown): void => {
|
client.emitInBatch = (event: string, payload: SubMessage): void => {
|
||||||
emitInBatch(client, event, payload);
|
emitInBatch(client, event, payload);
|
||||||
}
|
}
|
||||||
this.sockets.set(client.userId, client);
|
this.sockets.set(client.userId, client);
|
||||||
@ -538,7 +545,14 @@ export class IoSocketController {
|
|||||||
if (thing instanceof User) {
|
if (thing instanceof User) {
|
||||||
const clientUser = this.searchClientByIdOrFail(thing.id);
|
const clientUser = this.searchClientByIdOrFail(thing.id);
|
||||||
|
|
||||||
clientListener.emitInBatch(SocketIoEvent.USER_MOVED, new MessageUserMoved(clientUser.userId, clientUser.position));
|
const userMovedMessage = new UserMovedMessage();
|
||||||
|
userMovedMessage.setUserid(clientUser.userId);
|
||||||
|
userMovedMessage.setPosition(toPositionMessage(clientUser.position));
|
||||||
|
|
||||||
|
const subMessage = new SubMessage();
|
||||||
|
subMessage.setUsermovedmessage(userMovedMessage);
|
||||||
|
|
||||||
|
clientListener.emitInBatch(SocketIoEvent.USER_MOVED, subMessage);
|
||||||
//console.log("Sending USER_MOVED event");
|
//console.log("Sending USER_MOVED event");
|
||||||
} else if (thing instanceof Group) {
|
} else if (thing instanceof Group) {
|
||||||
clientListener.emit(SocketIoEvent.GROUP_CREATE_UPDATE, {
|
clientListener.emit(SocketIoEvent.GROUP_CREATE_UPDATE, {
|
||||||
|
@ -3,6 +3,7 @@ import {PointInterface} from "./PointInterface";
|
|||||||
import {Identificable} from "./Identificable";
|
import {Identificable} from "./Identificable";
|
||||||
import {TokenInterface} from "../../Controller/AuthenticateController";
|
import {TokenInterface} from "../../Controller/AuthenticateController";
|
||||||
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
|
||||||
|
import {BatchMessage, SubMessage} from "../../../../messages/generated/messages_pb";
|
||||||
|
|
||||||
export interface ExSocketInterface extends Socket, Identificable {
|
export interface ExSocketInterface extends Socket, Identificable {
|
||||||
token: string;
|
token: string;
|
||||||
@ -18,7 +19,7 @@ export interface ExSocketInterface extends Socket, Identificable {
|
|||||||
/**
|
/**
|
||||||
* Pushes an event that will be sent in the next batch of events
|
* Pushes an event that will be sent in the next batch of events
|
||||||
*/
|
*/
|
||||||
emitInBatch: (event: string | symbol, payload: unknown) => void;
|
emitInBatch: (event: string, payload: SubMessage) => void;
|
||||||
batchedMessages: Array<{ event: string | symbol, payload: unknown }>;
|
batchedMessages: BatchMessage;
|
||||||
batchTimeout: NodeJS.Timeout|null;
|
batchTimeout: NodeJS.Timeout|null;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import {PointInterface} from "./PointInterface";
|
|
||||||
|
|
||||||
export class MessageUserMoved {
|
|
||||||
constructor(public userId: number, public position: PointInterface) {
|
|
||||||
}
|
|
||||||
}
|
|
35
back/src/Model/Websocket/ProtobufUtils.ts
Normal file
35
back/src/Model/Websocket/ProtobufUtils.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {PointInterface} from "./PointInterface";
|
||||||
|
import {PositionMessage} from "../../../../messages/generated/messages_pb";
|
||||||
|
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
|
||||||
|
|
||||||
|
export namespace ProtobufUtils {
|
||||||
|
import Direction = PositionMessage.Direction;
|
||||||
|
|
||||||
|
export function toPositionMessage(point: PointInterface): PositionMessage {
|
||||||
|
let direction: PositionMessage.DirectionMap[keyof PositionMessage.DirectionMap];
|
||||||
|
switch (point.direction) {
|
||||||
|
case 'up':
|
||||||
|
direction = Direction.UP;
|
||||||
|
break;
|
||||||
|
case 'down':
|
||||||
|
direction = Direction.DOWN;
|
||||||
|
break;
|
||||||
|
case 'left':
|
||||||
|
direction = Direction.LEFT;
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
direction = Direction.RIGHT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('unexpected direction');
|
||||||
|
}
|
||||||
|
|
||||||
|
const position = new PositionMessage();
|
||||||
|
position.setX(point.x);
|
||||||
|
position.setY(point.y);
|
||||||
|
position.setMoving(point.moving);
|
||||||
|
position.setDirection(direction);
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ config:
|
|||||||
token: "test"
|
token: "test"
|
||||||
phases:
|
phases:
|
||||||
- duration: 20
|
- duration: 20
|
||||||
arrivalRate: 2
|
arrivalRate: 3
|
||||||
processor: "./socketioLoadTest.js"
|
processor: "./socketioLoadTest.js"
|
||||||
scenarios:
|
scenarios:
|
||||||
- name: "Connects and moves player for 20 seconds"
|
- name: "Connects and moves player for 20 seconds"
|
||||||
@ -22,7 +22,7 @@ scenarios:
|
|||||||
- emit:
|
- emit:
|
||||||
channel: "join-room"
|
channel: "join-room"
|
||||||
data:
|
data:
|
||||||
roomId: 'global__api.workadventure.localhost/map/files/Floor0/floor0'
|
roomId: 'global__maps.workadventure.localhost/Floor0/floor0'
|
||||||
position:
|
position:
|
||||||
x: 783
|
x: 783
|
||||||
y: 170
|
y: 170
|
||||||
@ -35,20 +35,10 @@ scenarios:
|
|||||||
bottom: 200
|
bottom: 200
|
||||||
- think: 1
|
- think: 1
|
||||||
- loop:
|
- loop:
|
||||||
- function: "setYRandom"
|
- function: "setUserMovesMessage"
|
||||||
- emit:
|
- emit:
|
||||||
channel: "user-position"
|
channel: "user-position"
|
||||||
data:
|
data: "{{ message }}"
|
||||||
position:
|
|
||||||
x: "{{ x }}"
|
|
||||||
y: "{{ y }}"
|
|
||||||
direction: 'down'
|
|
||||||
moving: false
|
|
||||||
viewport:
|
|
||||||
left: "{{ left }}"
|
|
||||||
top: "{{ top }}"
|
|
||||||
right: "{{ right }}"
|
|
||||||
bottom: "{{ bottom }}"
|
|
||||||
- think: 0.2
|
- think: 0.2
|
||||||
count: 100
|
count: 100
|
||||||
- think: 10
|
- think: 10
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
require("../messages/generated/messages_pb");
|
||||||
|
//import {PositionMessage, UserMovesMessage, ViewportMessage} from "../messages/generated/messages_pb";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
setYRandom
|
setYRandom
|
||||||
};
|
};
|
||||||
@ -18,3 +21,33 @@ function setYRandom(context, events, done) {
|
|||||||
context.vars.bottom = context.vars.y + 200;
|
context.vars.bottom = context.vars.y + 200;
|
||||||
return done();
|
return done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setUserMovesMessage(context, events, done) {
|
||||||
|
if (context.angle === undefined) {
|
||||||
|
context.angle = Math.random() * Math.PI * 2;
|
||||||
|
}
|
||||||
|
context.angle += 0.05;
|
||||||
|
|
||||||
|
const x = Math.floor(320 + 1472/2 * (1 + Math.sin(context.angle)));
|
||||||
|
const y = Math.floor(200 + 1090/2 * (1 + Math.cos(context.angle)));
|
||||||
|
|
||||||
|
const positionMessage = new PositionMessage();
|
||||||
|
positionMessage.setX(x);
|
||||||
|
positionMessage.setY(y);
|
||||||
|
positionMessage.setDirection(PositionMessage.Direction.UP);
|
||||||
|
positionMessage.setMoving(false);
|
||||||
|
|
||||||
|
const viewportMessage = new ViewportMessage();
|
||||||
|
viewportMessage.setTop(y - 200);
|
||||||
|
viewportMessage.setBottom(y + 200);
|
||||||
|
viewportMessage.setLeft(x - 320);
|
||||||
|
viewportMessage.setRight(x + 320);
|
||||||
|
|
||||||
|
const userMovesMessage = new UserMovesMessage();
|
||||||
|
userMovesMessage.setPosition(positionMessage);
|
||||||
|
userMovesMessage.setViewport(viewportMessage);
|
||||||
|
|
||||||
|
context.vars.message = userMovesMessage.serializeBinary().buffer;
|
||||||
|
console.log(context.vars.message);
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
@ -2,8 +2,9 @@ import Axios from "axios";
|
|||||||
import {API_URL} from "./Enum/EnvironmentVariable";
|
import {API_URL} from "./Enum/EnvironmentVariable";
|
||||||
import {MessageUI} from "./Logger/MessageUI";
|
import {MessageUI} from "./Logger/MessageUI";
|
||||||
import {
|
import {
|
||||||
|
BatchMessage,
|
||||||
PositionMessage,
|
PositionMessage,
|
||||||
SetPlayerDetailsMessage,
|
SetPlayerDetailsMessage, UserMovedMessage,
|
||||||
UserMovesMessage,
|
UserMovesMessage,
|
||||||
ViewportMessage
|
ViewportMessage
|
||||||
} from "../../messages/generated/messages_pb"
|
} from "../../messages/generated/messages_pb"
|
||||||
@ -132,6 +133,7 @@ export interface RoomJoinedMessageInterface {
|
|||||||
export class Connection implements Connection {
|
export class Connection implements Connection {
|
||||||
private readonly socket: Socket;
|
private readonly socket: Socket;
|
||||||
private userId: number|null = null;
|
private userId: number|null = null;
|
||||||
|
private batchCallbacks: Map<string, Function[]> = new Map<string, Function[]>();
|
||||||
|
|
||||||
private constructor(token: string) {
|
private constructor(token: string) {
|
||||||
|
|
||||||
@ -149,11 +151,25 @@ export class Connection implements Connection {
|
|||||||
/**
|
/**
|
||||||
* Messages inside batched messages are extracted and sent to listeners directly.
|
* Messages inside batched messages are extracted and sent to listeners directly.
|
||||||
*/
|
*/
|
||||||
this.socket.on(EventMessage.BATCH, (batchedMessages: BatchedMessageInterface[]) => {
|
this.socket.on(EventMessage.BATCH, (batchedMessagesBinary: ArrayBuffer) => {
|
||||||
for (const message of batchedMessages) {
|
const batchMessage = BatchMessage.deserializeBinary(new Uint8Array(batchedMessagesBinary as ArrayBuffer));
|
||||||
const listeners = this.socket.listeners(message.event);
|
|
||||||
|
for (const message of batchMessage.getPayloadList()) {
|
||||||
|
let event: string;
|
||||||
|
let payload;
|
||||||
|
if (message.hasUsermovedmessage()) {
|
||||||
|
event = EventMessage.USER_MOVED;
|
||||||
|
payload = message.getUsermovedmessage();
|
||||||
|
} else {
|
||||||
|
throw new Error('Unexpected batch message type');
|
||||||
|
}
|
||||||
|
|
||||||
|
const listeners = this.batchCallbacks.get(event);
|
||||||
|
if (listeners === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const listener of listeners) {
|
for (const listener of listeners) {
|
||||||
listener(message.payload);
|
listener(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -263,8 +279,21 @@ export class Connection implements Connection {
|
|||||||
this.socket.on(EventMessage.JOIN_ROOM, callback);
|
this.socket.on(EventMessage.JOIN_ROOM, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onUserMoved(callback: (message: MessageUserMovedInterface) => void): void {
|
public onUserMoved(callback: (message: UserMovedMessage) => void): void {
|
||||||
this.socket.on(EventMessage.USER_MOVED, callback);
|
this.onBatchMessage(EventMessage.USER_MOVED, callback);
|
||||||
|
//this.socket.on(EventMessage.USER_MOVED, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a listener on a message that is part of a batch
|
||||||
|
*/
|
||||||
|
private onBatchMessage(eventName: string, callback: Function): void {
|
||||||
|
let callbacks = this.batchCallbacks.get(eventName);
|
||||||
|
if (callbacks === undefined) {
|
||||||
|
callbacks = new Array<Function>();
|
||||||
|
this.batchCallbacks.set(eventName, callbacks);
|
||||||
|
}
|
||||||
|
callbacks.push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onUserLeft(callback: (userId: number) => void): void {
|
public onUserLeft(callback: (userId: number) => void): void {
|
||||||
|
34
front/src/Network/ProtobufClientUtils.ts
Normal file
34
front/src/Network/ProtobufClientUtils.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import {PositionMessage} from "../../../messages/generated/messages_pb";
|
||||||
|
import {PointInterface} from "../Connection";
|
||||||
|
|
||||||
|
export namespace ProtobufClientUtils {
|
||||||
|
import Direction = PositionMessage.Direction;
|
||||||
|
|
||||||
|
export function toPointInterface(position: PositionMessage): PointInterface {
|
||||||
|
let direction: string;
|
||||||
|
switch (position.getDirection()) {
|
||||||
|
case Direction.UP:
|
||||||
|
direction = 'up';
|
||||||
|
break;
|
||||||
|
case Direction.DOWN:
|
||||||
|
direction = 'down';
|
||||||
|
break;
|
||||||
|
case Direction.LEFT:
|
||||||
|
direction = 'left';
|
||||||
|
break;
|
||||||
|
case Direction.RIGHT:
|
||||||
|
direction = 'right';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unexpected direction");
|
||||||
|
}
|
||||||
|
|
||||||
|
// sending to all clients in room except sender
|
||||||
|
return {
|
||||||
|
x: position.getX(),
|
||||||
|
y: position.getY(),
|
||||||
|
direction,
|
||||||
|
moving: position.getMoving(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,9 @@ import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
|
|||||||
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
|
||||||
import {ActionableItem} from "../Items/ActionableItem";
|
import {ActionableItem} from "../Items/ActionableItem";
|
||||||
import {UserInputManager} from "../UserInput/UserInputManager";
|
import {UserInputManager} from "../UserInput/UserInputManager";
|
||||||
|
import {UserMovedMessage} from "../../../../messages/generated/messages_pb";
|
||||||
|
import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils";
|
||||||
|
import toPointInterface = ProtobufClientUtils.toPointInterface;
|
||||||
|
|
||||||
|
|
||||||
export enum Textures {
|
export enum Textures {
|
||||||
@ -213,8 +216,18 @@ export class GameScene extends Phaser.Scene implements CenterListener {
|
|||||||
this.addPlayer(userMessage);
|
this.addPlayer(userMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.onUserMoved((message: MessageUserMovedInterface) => {
|
connection.onUserMoved((message: UserMovedMessage) => {
|
||||||
this.updatePlayerPosition(message);
|
const position = message.getPosition();
|
||||||
|
if (position === undefined) {
|
||||||
|
throw new Error('Position missing from UserMovedMessage');
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageUserMoved: MessageUserMovedInterface = {
|
||||||
|
userId: message.getUserid(),
|
||||||
|
position: toPointInterface(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updatePlayerPosition(messageUserMoved);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.onUserLeft((userId: number) => {
|
connection.onUserLeft((userId: number) => {
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
/*********** CLIENT TO SERVER MESSAGES *************/
|
/*********** PARTIAL MESSAGES **************/
|
||||||
|
|
||||||
message SetPlayerDetailsMessage {
|
|
||||||
string name = 1;
|
|
||||||
repeated string characterLayers = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message PositionMessage {
|
message PositionMessage {
|
||||||
int32 x = 1;
|
int32 x = 1;
|
||||||
@ -27,6 +22,13 @@ message ViewportMessage {
|
|||||||
int32 bottom = 4;
|
int32 bottom = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********** CLIENT TO SERVER MESSAGES *************/
|
||||||
|
|
||||||
|
message SetPlayerDetailsMessage {
|
||||||
|
string name = 1;
|
||||||
|
repeated string characterLayers = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message UserMovesMessage {
|
message UserMovesMessage {
|
||||||
PositionMessage position = 1;
|
PositionMessage position = 1;
|
||||||
ViewportMessage viewport = 2;
|
ViewportMessage viewport = 2;
|
||||||
@ -39,3 +41,14 @@ message UserMovedMessage {
|
|||||||
int32 userId = 1;
|
int32 userId = 1;
|
||||||
PositionMessage position = 2;
|
PositionMessage position = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SubMessage {
|
||||||
|
oneof message {
|
||||||
|
UserMovedMessage userMovedMessage = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message BatchMessage {
|
||||||
|
string event = 1;
|
||||||
|
repeated SubMessage payload = 2;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user