Skip to content

Commit

Permalink
feat(master): Update metadata with gameover value on game end (#645)
Browse files Browse the repository at this point in the history
* feat(master): Update game metadata with gameover value on game end

Closes #634

* test(master): Add tests for gameover metadata updates

* refactor(master): Tidy up some typings

Co-authored-by: Nicolo John Davis <nicolodavis@gmail.com>
  • Loading branch information
delucis and nicolodavis authored Apr 26, 2020
1 parent 78113aa commit e4fc7bd
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
38 changes: 38 additions & 0 deletions src/master/master.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,44 @@ describe('update', () => {
await master.onUpdate(event, 3, 'gameID', '0');
expect(error).toHaveBeenCalledWith(`game over - gameID=[gameID]`);
});

test('writes gameover to metadata', async () => {
const id = 'gameWithMetadata';
const db = new InMemory();
const dbMetadata = {
gameName: 'tic-tac-toe',
setupData: {},
players: { '0': { id: 0 }, '1': { id: 1 } },
};
db.setMetadata(id, dbMetadata);
const masterWithMetadata = new Master(game, db, TransportAPI(send));
await masterWithMetadata.onSync(id, '0', 2);

const gameOverArg = 'gameOverArg';
const event = ActionCreators.gameEvent('endGame', gameOverArg);
await masterWithMetadata.onUpdate(event, 0, id, '0');
const { metadata } = db.fetch(id, { metadata: true });
expect(metadata.gameover).toEqual(gameOverArg);
});

test('writes gameover to metadata with async storage API', async () => {
const id = 'gameWithMetadata';
const db = new InMemoryAsync();
const dbMetadata = {
gameName: 'tic-tac-toe',
setupData: {},
players: { '0': { id: 0 }, '1': { id: 1 } },
};
db.setMetadata(id, dbMetadata);
const masterWithMetadata = new Master(game, db, TransportAPI(send));
await masterWithMetadata.onSync(id, '0', 2);

const gameOverArg = 'gameOverArg';
const event = ActionCreators.gameEvent('endGame', gameOverArg);
await masterWithMetadata.onUpdate(event, 0, id, '0');
const { metadata } = db.fetch(id, { metadata: true });
expect(metadata.gameover).toEqual(gameOverArg);
});
});

describe('playerView', () => {
Expand Down
41 changes: 32 additions & 9 deletions src/master/master.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,12 @@ export class Master {
auth: null | AuthFn;
shouldAuth: typeof doesGameRequireAuthentication;

constructor(game: Game, storageAPI, transportAPI, auth?: AuthFn | boolean) {
constructor(
game: Game,
storageAPI: StorageAPI.Sync | StorageAPI.Async,
transportAPI,
auth?: AuthFn | boolean
) {
this.game = ProcessGameConfig(game);
this.storageAPI = storageAPI;
this.transportAPI = transportAPI;
Expand Down Expand Up @@ -171,17 +176,18 @@ export class Master {
playerID: string
) {
let isActionAuthentic;
let metadata: Server.GameMetadata | undefined;
const credentials = credAction.payload.credentials;
if (IsSynchronous(this.storageAPI)) {
const { metadata } = this.storageAPI.fetch(gameID, { metadata: true });
({ metadata } = this.storageAPI.fetch(gameID, { metadata: true }));
const playerMetadata = getPlayerMetadata(metadata, playerID);
isActionAuthentic = this.shouldAuth(metadata)
? this.auth(credentials, playerMetadata)
: true;
} else {
const { metadata } = await this.storageAPI.fetch(gameID, {
({ metadata } = await this.storageAPI.fetch(gameID, {
metadata: true,
});
}));
const playerMetadata = getPlayerMetadata(metadata, playerID);
isActionAuthentic = this.shouldAuth(metadata)
? await this.auth(credentials, playerMetadata)
Expand Down Expand Up @@ -284,10 +290,29 @@ export class Master {

const { deltalog, ...stateWithoutDeltalog } = state;

let newMetadata: Server.GameMetadata | undefined;
if (
metadata &&
!('gameover' in metadata) &&
state.ctx.gameover !== undefined
) {
newMetadata = {
...metadata,
gameover: state.ctx.gameover,
};
}

if (IsSynchronous(this.storageAPI)) {
this.storageAPI.setState(key, stateWithoutDeltalog, deltalog);
if (newMetadata) this.storageAPI.setMetadata(key, newMetadata);
} else {
await this.storageAPI.setState(key, stateWithoutDeltalog, deltalog);
const writes = [
this.storageAPI.setState(key, stateWithoutDeltalog, deltalog),
];
if (newMetadata) {
writes.push(this.storageAPI.setMetadata(key, newMetadata));
}
await Promise.all(writes);
}
}

Expand All @@ -311,8 +336,7 @@ export class Master {
}>;

if (IsSynchronous(this.storageAPI)) {
const api = this.storageAPI as StorageAPI.Sync;
result = api.fetch(key, {
result = this.storageAPI.fetch(key, {
state: true,
metadata: true,
log: true,
Expand Down Expand Up @@ -350,8 +374,7 @@ export class Master {
});

if (IsSynchronous(this.storageAPI)) {
const api = this.storageAPI as StorageAPI.Sync;
api.setState(key, state);
this.storageAPI.setState(key, state);
} else {
await this.storageAPI.setState(key, state);
}
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export namespace Server {
gameName: string;
players: { [id: number]: PlayerMetadata };
setupData: any;
gameover?: any;
nextRoomID?: string;
}

Expand Down

0 comments on commit e4fc7bd

Please sign in to comment.