Reimplementing ban/unban/messages

This commit is contained in:
David Négrier 2020-12-11 12:23:50 +01:00
parent 24cb85cc7c
commit ea3aa3d128
7 changed files with 172 additions and 64 deletions

View File

@ -17,7 +17,7 @@ export type ConnectCallback = (user: User, group: Group) => void;
export type DisconnectCallback = (user: User, group: Group) => void; export type DisconnectCallback = (user: User, group: Group) => void;
export enum GameRoomPolicyTypes { export enum GameRoomPolicyTypes {
ANONYMUS_POLICY = 1, ANONYMOUS_POLICY = 1,
MEMBERS_ONLY_POLICY, MEMBERS_ONLY_POLICY,
USE_TAGS_POLICY, USE_TAGS_POLICY,
} }
@ -28,6 +28,7 @@ export class GameRoom {
// Users, sorted by ID // Users, sorted by ID
private readonly users: Map<number, User>; private readonly users: Map<number, User>;
private readonly usersByUuid: Map<string, User>;
private readonly groups: Set<Group>; private readonly groups: Set<Group>;
private readonly admins: Set<Admin>; private readonly admins: Set<Admin>;
@ -58,7 +59,7 @@ export class GameRoom {
this.roomId = roomId; this.roomId = roomId;
this.anonymous = isRoomAnonymous(roomId); this.anonymous = isRoomAnonymous(roomId);
this.tags = []; this.tags = [];
this.policyType = GameRoomPolicyTypes.ANONYMUS_POLICY; this.policyType = GameRoomPolicyTypes.ANONYMOUS_POLICY;
if (this.anonymous) { if (this.anonymous) {
this.roomSlug = extractRoomSlugPublicRoomId(this.roomId); this.roomSlug = extractRoomSlugPublicRoomId(this.roomId);
@ -71,6 +72,7 @@ export class GameRoom {
this.users = new Map<number, User>(); this.users = new Map<number, User>();
this.usersByUuid = new Map<string, User>();
this.admins = new Set<Admin>(); this.admins = new Set<Admin>();
this.groups = new Set<Group>(); this.groups = new Set<Group>();
this.connectCallback = connectCallback; this.connectCallback = connectCallback;
@ -89,6 +91,10 @@ export class GameRoom {
return this.users; return this.users;
} }
public getUserByUuid(uuid: string): User|undefined {
return this.usersByUuid.get(uuid);
}
public join(socket : UserSocket, joinRoomMessage: JoinRoomMessage): User { public join(socket : UserSocket, joinRoomMessage: JoinRoomMessage): User {
const positionMessage = joinRoomMessage.getPositionmessage(); const positionMessage = joinRoomMessage.getPositionmessage();
if (positionMessage === undefined) { if (positionMessage === undefined) {
@ -99,6 +105,7 @@ export class GameRoom {
const user = new User(this.nextUserId, joinRoomMessage.getUseruuid(), position, false, this.positionNotifier, socket, joinRoomMessage.getTagList(), joinRoomMessage.getName(), ProtobufUtils.toCharacterLayerObjects(joinRoomMessage.getCharacterlayerList())); const user = new User(this.nextUserId, joinRoomMessage.getUseruuid(), position, false, this.positionNotifier, socket, joinRoomMessage.getTagList(), joinRoomMessage.getName(), ProtobufUtils.toCharacterLayerObjects(joinRoomMessage.getCharacterlayerList()));
this.nextUserId++; this.nextUserId++;
this.users.set(user.id, user); this.users.set(user.id, user);
this.usersByUuid.set(user.uuid, user);
// Let's call update position to trigger the join / leave room // Let's call update position to trigger the join / leave room
//this.updatePosition(socket, userPosition); //this.updatePosition(socket, userPosition);
this.updateUserGroup(user); this.updateUserGroup(user);
@ -120,6 +127,7 @@ export class GameRoom {
this.leaveGroup(userObj); this.leaveGroup(userObj);
} }
this.users.delete(user.id); this.users.delete(user.id);
this.usersByUuid.delete(user.uuid);
if (userObj !== undefined) { if (userObj !== undefined) {
this.positionNotifier.leave(userObj); this.positionNotifier.leave(userObj);

View File

@ -1,12 +1,25 @@
import {IRoomManagerServer} from "./Messages/generated/messages_grpc_pb"; import {IRoomManagerServer} from "./Messages/generated/messages_grpc_pb";
import { import {
AdminPusherToBackMessage, AdminGlobalMessage,
ClientToServerMessage, ItemEventMessage, AdminMessage,
JoinRoomMessage, PlayGlobalMessage, PusherToBackMessage, QueryJitsiJwtMessage, ReportPlayerMessage, AdminPusherToBackMessage, BanMessage,
RoomJoinedMessage, ServerToAdminClientMessage, ClientToServerMessage, EmptyMessage,
ServerToClientMessage, SilentMessage, UserMovesMessage, ViewportMessage, WebRtcSignalToServerMessage, ZoneMessage ItemEventMessage,
JoinRoomMessage,
PlayGlobalMessage,
PusherToBackMessage,
QueryJitsiJwtMessage,
ReportPlayerMessage,
RoomJoinedMessage,
ServerToAdminClientMessage,
ServerToClientMessage,
SilentMessage,
UserMovesMessage,
ViewportMessage,
WebRtcSignalToServerMessage,
ZoneMessage
} from "./Messages/generated/messages_pb"; } from "./Messages/generated/messages_pb";
import grpc, {ServerDuplexStream, ServerWritableStream} from "grpc"; import grpc, {sendUnaryData, ServerDuplexStream, ServerUnaryCall, ServerWritableStream} from "grpc";
import {Empty} from "google-protobuf/google/protobuf/empty_pb"; import {Empty} from "google-protobuf/google/protobuf/empty_pb";
import {socketManager} from "./Services/SocketManager"; import {socketManager} from "./Services/SocketManager";
import {emitError} from "./Services/MessageHelpers"; import {emitError} from "./Services/MessageHelpers";
@ -171,6 +184,23 @@ const roomManager: IRoomManagerServer = {
console.error('An error occurred in joinAdminRoom stream:', err); console.error('An error occurred in joinAdminRoom stream:', err);
}); });
}, },
sendAdminMessage(call: ServerUnaryCall<AdminMessage>, callback: sendUnaryData<EmptyMessage>): void {
socketManager.sendAdminMessage(call.request.getRoomid(), call.request.getRecipientuuid(), call.request.getMessage());
callback(null, new EmptyMessage());
},
sendGlobalAdminMessage(call: ServerUnaryCall<AdminGlobalMessage>, callback: sendUnaryData<EmptyMessage>): void {
throw new Error('Not implemented yet');
// TODO
callback(null, new EmptyMessage());
},
ban(call: ServerUnaryCall<BanMessage>, callback: sendUnaryData<EmptyMessage>): void {
socketManager.banUser(call.request.getRoomid(), call.request.getRecipientuuid());
callback(null, new EmptyMessage());
},
}; };
export {roomManager}; export {roomManager};

View File

@ -31,7 +31,7 @@ import {
BatchMessage, BatchMessage,
BatchToPusherMessage, BatchToPusherMessage,
SubToPusherMessage, SubToPusherMessage,
UserJoinedZoneMessage, GroupUpdateZoneMessage, GroupLeftZoneMessage, UserLeftZoneMessage UserJoinedZoneMessage, GroupUpdateZoneMessage, GroupLeftZoneMessage, UserLeftZoneMessage, AdminMessage, BanMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {User, UserSocket} from "../Model/User"; import {User, UserSocket} from "../Model/User";
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils"; import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
@ -164,25 +164,6 @@ export class SocketManager {
console.log('SENDING MESSAGE roomJoinedMessage'); console.log('SENDING MESSAGE roomJoinedMessage');
socket.write(serverToClientMessage); socket.write(serverToClientMessage);
//get data information and show messages
if (ADMIN_API_URL) {
adminApi.fetchMemberDataByUuid(user.uuid).then((res: FetchMemberDataByUuidResponse) => {
if (!res.messages) {
return;
}
res.messages.forEach((c: unknown) => {
const messageToSend = c as { type: string, message: string };
socketManager.emitSendUserMessage({
userUuid: user.uuid,
type: messageToSend.type,
message: messageToSend.message
})
});
}).catch((err) => {
console.error('fetchMemberDataByUuid => err', err);
});
}
return { return {
room, room,
user user
@ -643,27 +624,6 @@ export class SocketManager {
user.socket.write(serverToClientMessage); user.socket.write(serverToClientMessage);
} }
public emitSendUserMessage(messageToSend: {userUuid: string, message: string, type: string}): void {
// TODO: move this to room (findByUuid)
throw new Error("Not yet reimplemented");
/*const socket = this.searchClientByUuid(messageToSend.userUuid);
if(!socket){
throw 'socket was not found';
}
const sendUserMessage = new SendUserMessage();
sendUserMessage.setMessage(messageToSend.message);
sendUserMessage.setType(messageToSend.type);
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setSendusermessage(sendUserMessage);
if (!socket.disconnecting) {
socket.send(serverToClientMessage.serializeBinary().buffer, true);
}
return socket;*/
}
/** /**
* Merges the characterLayers received from the front (as an array of string) with the custom textures from the back. * Merges the characterLayers received from the front (as an array of string) with the custom textures from the back.
*/ */
@ -762,6 +722,56 @@ export class SocketManager {
} }
} }
public sendAdminMessage(roomId: string, recipientUuid: string, message: string): void {
const room = this.rooms.get(roomId);
if (!room) {
console.error("In sendAdminMessage, could not find room with id '" + roomId + "'. Maybe the room was closed a few milliseconds ago and there was a race condition?");
return;
}
const recipient = room.getUserByUuid(recipientUuid);
if (recipient === undefined) {
console.error("In sendAdminMessage, could not find user with id '" + recipientUuid + "'. Maybe the user left the room a few milliseconds ago and there was a race condition?");
return;
}
const sendUserMessage = new SendUserMessage();
sendUserMessage.setMessage(message);
sendUserMessage.setType('ban');
const subToPusherMessage = new SubToPusherMessage();
subToPusherMessage.setSendusermessage(sendUserMessage);
recipient.socket.write(subToPusherMessage);
}
public banUser(roomId: string, recipientUuid: string): void {
const room = this.rooms.get(roomId);
if (!room) {
console.error("In banUser, could not find room with id '" + roomId + "'. Maybe the room was closed a few milliseconds ago and there was a race condition?");
return;
}
const recipient = room.getUserByUuid(recipientUuid);
if (recipient === undefined) {
console.error("In banUser, could not find user with id '" + recipientUuid + "'. Maybe the user left the room a few milliseconds ago and there was a race condition?");
return;
}
// Let's leave the room now.
room.leave(recipient);
const sendUserMessage = new SendUserMessage();
sendUserMessage.setType('banned');
const subToPusherMessage = new SubToPusherMessage();
subToPusherMessage.setSendusermessage(sendUserMessage);
recipient.socket.write(subToPusherMessage);
// Let's close the connection when the user is banned.
recipient.socket.end();
}
} }
export const socketManager = new SocketManager(); export const socketManager = new SocketManager();

View File

@ -288,6 +288,7 @@ message SubToPusherMessage {
GroupLeftZoneMessage groupLeftZoneMessage = 4; GroupLeftZoneMessage groupLeftZoneMessage = 4;
UserLeftZoneMessage userLeftZoneMessage = 5; UserLeftZoneMessage userLeftZoneMessage = 5;
ItemEventMessage itemEventMessage = 6; ItemEventMessage itemEventMessage = 6;
SendUserMessage sendUserMessage = 7;
} }
} }
@ -320,9 +321,32 @@ message AdminPusherToBackMessage {
} }
} }
// A message sent by an administrator to a recipient
message AdminMessage {
string message = 1;
string recipientUuid = 2;
string roomId = 3;
}
// A message sent by an administrator to absolutely everybody
message AdminGlobalMessage {
string message = 1;
}
message BanMessage {
string recipientUuid = 1;
string roomId = 2;
}
message EmptyMessage {
}
service RoomManager { service RoomManager {
rpc joinRoom(stream PusherToBackMessage) returns (stream ServerToClientMessage); rpc joinRoom(stream PusherToBackMessage) returns (stream ServerToClientMessage);
rpc listenZone(ZoneMessage) returns (stream BatchToPusherMessage); rpc listenZone(ZoneMessage) returns (stream BatchToPusherMessage);
rpc adminRoom(stream AdminPusherToBackMessage) returns (stream ServerToAdminClientMessage); rpc adminRoom(stream AdminPusherToBackMessage) returns (stream ServerToAdminClientMessage);
rpc sendAdminMessage(AdminMessage) returns (EmptyMessage);
rpc sendGlobalAdminMessage(AdminGlobalMessage) returns (EmptyMessage);
rpc ban(BanMessage) returns (EmptyMessage);
} }

View File

@ -12,7 +12,7 @@ import {
WebRtcSignalToServerMessage, WebRtcSignalToServerMessage,
PlayGlobalMessage, PlayGlobalMessage,
ReportPlayerMessage, ReportPlayerMessage,
QueryJitsiJwtMessage QueryJitsiJwtMessage, SendUserMessage, ServerToClientMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {UserMovesMessage} from "../Messages/generated/messages_pb"; import {UserMovesMessage} from "../Messages/generated/messages_pb";
import {TemplatedApp} from "uWebSockets.js" import {TemplatedApp} from "uWebSockets.js"
@ -61,7 +61,6 @@ export class IoSocketController {
}, },
open: (ws) => { open: (ws) => {
console.log('Admin socket connect for room: '+ws.roomId); console.log('Admin socket connect for room: '+ws.roomId);
const roomId = ws.roomId;
ws.disconnecting = false; ws.disconnecting = false;
socketManager.handleAdminRoom(ws as ExAdminSocketInterface, ws.roomId as string); socketManager.handleAdminRoom(ws as ExAdminSocketInterface, ws.roomId as string);
@ -84,6 +83,8 @@ export class IoSocketController {
}, },
message: (ws, arrayBuffer, isBinary): void => { message: (ws, arrayBuffer, isBinary): void => {
try { try {
const roomId = ws.roomId as string;
//TODO refactor message type and data //TODO refactor message type and data
const message: {event: string, message: {type: string, message: unknown, userUuid: string}} = const message: {event: string, message: {type: string, message: unknown, userUuid: string}} =
JSON.parse(new TextDecoder("utf-8").decode(new Uint8Array(arrayBuffer))); JSON.parse(new TextDecoder("utf-8").decode(new Uint8Array(arrayBuffer)));
@ -92,14 +93,11 @@ export class IoSocketController {
const messageToEmit = (message.message as { message: string, type: string, userUuid: string }); const messageToEmit = (message.message as { message: string, type: string, userUuid: string });
switch (message.message.type) { switch (message.message.type) {
case 'ban': { case 'ban': {
socketManager.emitSendUserMessage(messageToEmit); socketManager.emitSendUserMessage(messageToEmit.userUuid, messageToEmit.message, roomId);
break; break;
} }
case 'banned': { case 'banned': {
const socketUser = socketManager.emitSendUserMessage(messageToEmit); socketManager.emitBan(messageToEmit.userUuid, messageToEmit.message, roomId);
setTimeout(() => {
socketUser.close();
}, 10000);
break; break;
} }
default: { default: {
@ -269,11 +267,17 @@ export class IoSocketController {
} }
res.messages.forEach((c: unknown) => { res.messages.forEach((c: unknown) => {
const messageToSend = c as { type: string, message: string }; const messageToSend = c as { type: string, message: string };
socketManager.emitSendUserMessage({
userUuid: client.userUuid, const sendUserMessage = new SendUserMessage();
type: messageToSend.type, sendUserMessage.setType(messageToSend.type);
message: messageToSend.message sendUserMessage.setMessage(messageToSend.message);
})
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setSendusermessage(sendUserMessage);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
}); });
}).catch((err) => { }).catch((err) => {
console.error('fetchMemberDataByUuid => err', err); console.error('fetchMemberDataByUuid => err', err);

View File

@ -15,6 +15,10 @@ class ApiClientRepository {
} }
return Promise.resolve(this.roomManagerClient); return Promise.resolve(this.roomManagerClient);
} }
public async getAllClients(): Promise<RoomManagerClient[]> {
return [await this.getClient('')];
}
} }
const apiClientRepository = new ApiClientRepository(); const apiClientRepository = new ApiClientRepository();

View File

@ -30,7 +30,7 @@ import {
CharacterLayerMessage, CharacterLayerMessage,
PusherToBackMessage, PusherToBackMessage,
AdminPusherToBackMessage, AdminPusherToBackMessage,
ServerToAdminClientMessage ServerToAdminClientMessage, AdminMessage, BanMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {PointInterface} from "../Model/Websocket/PointInterface"; import {PointInterface} from "../Model/Websocket/PointInterface";
import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils"; import {ProtobufUtils} from "../Model/Websocket/ProtobufUtils";
@ -593,7 +593,21 @@ export class SocketManager implements ZoneEventListener {
client.send(serverToClientMessage.serializeBinary().buffer, true); client.send(serverToClientMessage.serializeBinary().buffer, true);
} }
public emitSendUserMessage(messageToSend: {userUuid: string, message: string, type: string}): ExSocketInterface { public async emitSendUserMessage(userUuid: string, message: string, roomId: string): Promise<void> {
const backConnection = await apiClientRepository.getClient(roomId);
const adminMessage = new AdminMessage();
adminMessage.setRecipientuuid(userUuid);
adminMessage.setMessage(message);
adminMessage.setRoomid(roomId);
backConnection.sendAdminMessage(adminMessage, (error) => {
if (error !== null) {
console.error('Error while sending admin message', error);
}
});
/*
const socket = this.searchClientByUuid(messageToSend.userUuid); const socket = this.searchClientByUuid(messageToSend.userUuid);
if(!socket){ if(!socket){
throw 'socket was not found'; throw 'socket was not found';
@ -609,7 +623,21 @@ export class SocketManager implements ZoneEventListener {
if (!socket.disconnecting) { if (!socket.disconnecting) {
socket.send(serverToClientMessage.serializeBinary().buffer, true); socket.send(serverToClientMessage.serializeBinary().buffer, true);
} }
return socket; return socket;*/
}
public async emitBan(userUuid: string, message: string, roomId: string): Promise<void> {
const backConnection = await apiClientRepository.getClient(roomId);
const banMessage = new BanMessage();
banMessage.setRecipientuuid(userUuid);
banMessage.setRoomid(roomId);
backConnection.ban(banMessage, (error) => {
if (error !== null) {
console.error('Error while sending ban message', error);
}
});
} }
/** /**