2021-06-24 10:09:10 +02:00
|
|
|
import { ExSocketInterface } from "_Model/Websocket/ExSocketInterface";
|
|
|
|
import { PositionDispatcher } from "./PositionDispatcher";
|
|
|
|
import { ViewportInterface } from "_Model/Websocket/ViewportMessage";
|
|
|
|
import { extractDataFromPrivateRoomId, extractRoomSlugPublicRoomId, isRoomAnonymous } from "./RoomIdentifier";
|
|
|
|
import { arrayIntersect } from "../Services/ArrayHelper";
|
2021-07-06 15:30:49 +02:00
|
|
|
import {GroupDescriptor, UserDescriptor, ZoneEventListener} from "_Model/Zone";
|
|
|
|
import {apiClientRepository} from "../Services/ApiClientRepository";
|
|
|
|
import {
|
|
|
|
BatchToPusherMessage, BatchToPusherRoomMessage, EmoteEventMessage, GroupLeftZoneMessage,
|
|
|
|
GroupUpdateZoneMessage, RoomMessage, SubMessage,
|
|
|
|
UserJoinedZoneMessage, UserLeftZoneMessage, UserMovedMessage, VariableMessage,
|
|
|
|
ZoneMessage
|
|
|
|
} from "../Messages/generated/messages_pb";
|
|
|
|
import Debug from "debug";
|
|
|
|
import {ClientReadableStream} from "grpc";
|
|
|
|
|
|
|
|
const debug = Debug("room");
|
2020-11-13 18:00:22 +01:00
|
|
|
|
|
|
|
export enum GameRoomPolicyTypes {
|
2021-07-06 15:30:49 +02:00
|
|
|
ANONYMOUS_POLICY = 1,
|
2020-11-13 18:00:22 +01:00
|
|
|
MEMBERS_ONLY_POLICY,
|
|
|
|
USE_TAGS_POLICY,
|
|
|
|
}
|
|
|
|
|
|
|
|
export class PusherRoom {
|
|
|
|
private readonly positionNotifier: PositionDispatcher;
|
2021-04-01 16:43:12 +02:00
|
|
|
public readonly public: boolean;
|
2020-11-13 18:00:22 +01:00
|
|
|
public tags: string[];
|
|
|
|
public policyType: GameRoomPolicyTypes;
|
|
|
|
public readonly roomSlug: string;
|
2021-06-24 10:09:10 +02:00
|
|
|
public readonly worldSlug: string = "";
|
|
|
|
public readonly organizationSlug: string = "";
|
2021-04-01 16:43:12 +02:00
|
|
|
private versionNumber: number = 1;
|
2021-07-06 15:30:49 +02:00
|
|
|
private backConnection!: ClientReadableStream<BatchToPusherRoomMessage>;
|
|
|
|
private isClosing: boolean = false;
|
|
|
|
private listeners: Set<ExSocketInterface> = new Set<ExSocketInterface>();
|
2020-11-13 18:00:22 +01:00
|
|
|
|
2021-07-06 15:30:49 +02:00
|
|
|
constructor(public readonly roomId: string, private socketListener: ZoneEventListener, private onBackFailure: (e: Error | null, room: PusherRoom) => void) {
|
2021-04-01 16:43:12 +02:00
|
|
|
this.public = isRoomAnonymous(roomId);
|
2020-11-13 18:00:22 +01:00
|
|
|
this.tags = [];
|
2021-07-06 15:30:49 +02:00
|
|
|
this.policyType = GameRoomPolicyTypes.ANONYMOUS_POLICY;
|
2020-11-13 18:00:22 +01:00
|
|
|
|
2021-04-01 16:43:12 +02:00
|
|
|
if (this.public) {
|
2020-11-13 18:00:22 +01:00
|
|
|
this.roomSlug = extractRoomSlugPublicRoomId(this.roomId);
|
|
|
|
} else {
|
2021-06-24 10:09:10 +02:00
|
|
|
const { organizationSlug, worldSlug, roomSlug } = extractDataFromPrivateRoomId(this.roomId);
|
2020-11-13 18:00:22 +01:00
|
|
|
this.roomSlug = roomSlug;
|
|
|
|
this.organizationSlug = organizationSlug;
|
|
|
|
this.worldSlug = worldSlug;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A zone is 10 sprites wide.
|
|
|
|
this.positionNotifier = new PositionDispatcher(this.roomId, 320, 320, this.socketListener);
|
|
|
|
}
|
|
|
|
|
2021-06-24 10:09:10 +02:00
|
|
|
public setViewport(socket: ExSocketInterface, viewport: ViewportInterface): void {
|
2020-11-13 18:00:22 +01:00
|
|
|
this.positionNotifier.setViewport(socket, viewport);
|
|
|
|
}
|
|
|
|
|
2021-07-06 15:30:49 +02:00
|
|
|
public join(socket: ExSocketInterface) {
|
|
|
|
this.listeners.add(socket);
|
|
|
|
}
|
|
|
|
|
2021-06-24 10:09:10 +02:00
|
|
|
public leave(socket: ExSocketInterface) {
|
2020-11-13 18:00:22 +01:00
|
|
|
this.positionNotifier.removeViewport(socket);
|
2021-07-06 15:30:49 +02:00
|
|
|
this.listeners.delete(socket);
|
2020-11-13 18:00:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public canAccess(userTags: string[]): boolean {
|
|
|
|
return arrayIntersect(userTags, this.tags);
|
|
|
|
}
|
|
|
|
|
|
|
|
public isEmpty(): boolean {
|
|
|
|
return this.positionNotifier.isEmpty();
|
|
|
|
}
|
2021-04-01 16:43:12 +02:00
|
|
|
|
|
|
|
public needsUpdate(versionNumber: number): boolean {
|
|
|
|
if (this.versionNumber < versionNumber) {
|
|
|
|
this.versionNumber = versionNumber;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-07-06 15:30:49 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a connection to the back server to track global messages relative to this room (like variable changes).
|
|
|
|
*/
|
|
|
|
public async init(): Promise<void> {
|
|
|
|
debug("Opening connection to room %s on back server", this.roomId);
|
|
|
|
const apiClient = await apiClientRepository.getClient(this.roomId);
|
|
|
|
const roomMessage = new RoomMessage();
|
|
|
|
roomMessage.setRoomid(this.roomId);
|
|
|
|
this.backConnection = apiClient.listenRoom(roomMessage);
|
|
|
|
this.backConnection.on("data", (batch: BatchToPusherRoomMessage) => {
|
|
|
|
for (const message of batch.getPayloadList()) {
|
|
|
|
if (message.hasVariablemessage()) {
|
|
|
|
const variableMessage = message.getVariablemessage() as VariableMessage;
|
|
|
|
// We need to dispatch this variable to all the listeners
|
|
|
|
for (const listener of this.listeners) {
|
|
|
|
const subMessage = new SubMessage();
|
|
|
|
subMessage.setVariablemessage(variableMessage);
|
|
|
|
listener.emitInBatch(subMessage);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new Error("Unexpected message");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.backConnection.on("error", (e) => {
|
|
|
|
if (!this.isClosing) {
|
|
|
|
debug("Error on back connection");
|
|
|
|
this.close();
|
|
|
|
this.onBackFailure(e, this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.backConnection.on("close", () => {
|
|
|
|
if (!this.isClosing) {
|
|
|
|
debug("Close on back connection");
|
|
|
|
this.close();
|
|
|
|
this.onBackFailure(null, this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public close(): void {
|
|
|
|
debug("Closing connection to room %s on back server", this.roomId);
|
|
|
|
this.isClosing = true;
|
|
|
|
this.backConnection.cancel();
|
|
|
|
|
|
|
|
// Let's close all connections linked to that room
|
|
|
|
for (const listener of this.listeners) {
|
|
|
|
listener.close();
|
|
|
|
}
|
|
|
|
}
|
2020-11-13 18:00:22 +01:00
|
|
|
}
|