Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(92): watcher leaving a room, no room deletion #186

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions backend/functions/disconnect.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import { success } from '../libs/response';
import { APIGatewayProxyResult } from 'aws-lambda';
import { dynamoDB } from '../libs/dynamodb-utils';
import { IEvent, success } from '../libs/response';
import { leaveRoom, findRoomOfWatcher } from '../libs/room-operations';
import { Room } from '../../extension/src/types';

export const main = async (event: IEvent): Promise<APIGatewayProxyResult> => {
const watcherId: string = event.requestContext.connectionId;

const room: Room = await findRoomOfWatcher(
process.env.ROOM_TABLE!,
watcherId,
dynamoDB,
);

await leaveRoom(room, process.env.ROOM_TABLE!, watcherId, dynamoDB);

console.log(
`[WS-S] User ${watcherId} successfully deconnected from room ${room.roomId}`,
);

// TODO log the deletion of the room if there is no watcher

export const main = async () => {
return success();
};
28 changes: 1 addition & 27 deletions backend/functions/update_watcher_state.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,9 @@
import { DocumentClient } from 'aws-sdk/clients/dynamodb';
import { UpdateWatcherState } from '../../extension/src/communications/from-extension-to-server';
import { Room } from '../../extension/src/types';
import { dynamoDB } from '../libs/dynamodb-utils';
import { IEvent, success } from '../libs/response';
import { ensureRoomJoined, findRoomById } from '../libs/room-operations';
import { findAndEnsureRoomJoined } from '../libs/room-operations';
import { updateWatcherVideoStatus } from '../libs/watcher-operations';

const findAndEnsureRoomJoined = async (
roomId: string,
watcherConnectionString: string,
dynamoDB: DocumentClient,
): Promise<Room> => {
if (!process.env.ROOM_TABLE) {
throw new Error('env.ROOM_TABLE must be defined');
}

if (!roomId) {
console.log(
'[WS-S] Could not find an existing roomId in the join room request',
);
throw new Error('A room ID must be provided');
}
const room = await findRoomById(roomId, process.env.ROOM_TABLE, dynamoDB);
if (!room) {
console.log('[WS-S] Could not find room ', roomId);
throw new Error('Room ${roomId} does not exist and cannot be joined');
}
ensureRoomJoined(room, watcherConnectionString);
return room;
};

export const main = async (event: IEvent) => {
const updateWatcherEvent = JSON.parse(event.body) as UpdateWatcherState;
const { roomId, playerEvent } = updateWatcherEvent;
Expand Down
103 changes: 96 additions & 7 deletions backend/libs/room-operations.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
import { DocumentClient } from 'aws-sdk/clients/dynamodb';
import {
Room,
Expand All @@ -8,6 +9,21 @@ import {
import { marshallRoom, unmarshallRoom } from './room-marshalling';
import { updateWatcher } from './watcher-operations';

export const ensureRoomJoined = (
room: Room,
watcherConnectionString: string,
) => {
if (!room.watchers[watcherConnectionString]) {
console.log(
'[WS-S] A media event was received for someone ho has not joined the room. Dropping',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'[WS-S] A media event was received for someone ho has not joined the room. Dropping',
'[WS-S] A media event was received from someone who has not joined the room. Dropping',

);
throw new Error(
`The room was not joined by watcher ${watcherConnectionString}`,
);
}
return room;
};

/**
* Find a room by ID in DDB
*/
Expand Down Expand Up @@ -37,6 +53,53 @@ export const findRoomById = async (
}
};

export const findRoomOfWatcher = async (
tableName: string,
watcherConnectionString: string,
dynamoDb: DocumentClient,
): Promise<Room> => {
const params: DocumentClient.QueryInput = {
TableName: tableName,
};
try {
console.debug(
`Trying to find room of watcher ${watcherConnectionString}`,
);
const data = await dynamoDb.query(params).promise();
if (data.Items) {
const roomDDB:
| DocumentClient.AttributeMap
| undefined = data.Items.find(
(r: DocumentClient.AttributeMap) => {
const watchers: DocumentClient.AttributeMap = r.watchers;
return (
Object.keys(watchers).find(
(watcherId) =>
watcherId === watcherConnectionString,
) !== undefined
);
},
);

if (!roomDDB) {
console.log(
`Could not find the room of watcher ${watcherConnectionString}`,
);
throw new Error(
`Could not find the room of watcher ${watcherConnectionString}`,
);
}
return unmarshallRoom(roomDDB);
} else {
console.log('There is no room in the DB');
throw new Error('There is no room in the DB');
}
} catch (e) {
console.error('Failed to find or unmarshall room on DDB', e);
throw e;
}
};

/**
* Create a new room in DDB
*/
Expand Down Expand Up @@ -137,17 +200,43 @@ export const joinExistingRoom = async (
return updateWatcher(room, tableName, newWatcher, dynamoDb);
};

export const ensureRoomJoined = (
/**
* Removes a watcher from a room if there are 2 or more watchers
* If there is only 1 watcher, delete the room after removing the watcher
*/
export const leaveRoom = async (
room: Room,
tableName: string,
watcherConnectionString: string,
) => {
if (!room.watchers[watcherConnectionString]) {
dynamoDb: DocumentClient,
): Promise<Room | undefined> => {
ensureRoomJoined(room, watcherConnectionString);
delete room.watchers[watcherConnectionString];

// TODO delete the room if there is no watcher
return updateRoom(room, tableName, dynamoDb);
Copy link
Contributor

@Startouf Startouf Jul 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non pour le coup pas possible d'utiliser updateRoom pour retirer un watcher. Il nous faut obligatoirement une commande AWS DynamoDB qui supprime la clé + le sous-doc uniquement, et pas une fonction qui mette à jour toute la liste des watchers (ce qui est le cas d'updateRoom ajd je crois).

EDIT : non en réalité justement pour cette raison, la méthode updateRoom ne met pas à jour la liste des watchers, donc ce code ne marchera tt simplement pas

SInon, ça va péter car on aura des pb de race condition avec les autres watchers.

};

export const findAndEnsureRoomJoined = async (
roomId: string,
watcherConnectionString: string,
dynamoDB: DocumentClient,
): Promise<Room> => {
if (!process.env.ROOM_TABLE) {
throw new Error('env.ROOM_TABLE must be defined');
}

if (!roomId) {
console.log(
'[WS-S] A media event was received for someone ho has not joined the room. Dropping',
);
throw new Error(
`The room was not joined by watcher ${watcherConnectionString}`,
'[WS-S] Could not find an existing roomId in the join room request',
);
throw new Error('A room ID must be provided');
}
const room = await findRoomById(roomId, process.env.ROOM_TABLE, dynamoDB);
if (!room) {
console.log('[WS-S] Could not find room ', roomId);
throw new Error('Room ${roomId} does not exist and cannot be joined');
}
ensureRoomJoined(room, watcherConnectionString);
return room;
};