Skip to content

Commit

Permalink
separate metadata and state in storage API
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolodavis committed Mar 18, 2020
1 parent e653681 commit c96e228
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 100 deletions.
2 changes: 1 addition & 1 deletion src/master/master.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe('sync', () => {
},
},
};
db.set('gameID:metadata', dbMetadata);
db.setMetadata('gameID', dbMetadata);
const masterWithMetadata = new Master(game, db, TransportAPI(send));
await masterWithMetadata.onSync('gameID', '0', 2);

Expand Down
33 changes: 16 additions & 17 deletions src/master/master.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import {
LogEntry,
PlayerID,
} from '../types';

const GameMetadataKey = (gameID: string) => `${gameID}:metadata`;
import StorageAPI from '../server/db/base';

export const getPlayerMetadata = (
gameMetadata: Server.GameMetadata,
Expand Down Expand Up @@ -130,7 +129,7 @@ type CallbackFn = (arg: {
*/
export class Master {
game: ReturnType<typeof Game>;
storageAPI;
storageAPI: StorageAPI;
transportAPI;
subscribeCallback: CallbackFn;
auth: null | AuthFn;
Expand Down Expand Up @@ -180,13 +179,13 @@ export class Master {
? action.payload.credentials
: undefined;
if (this.executeSynchronously) {
const gameMetadata = this.storageAPI.get(GameMetadataKey(gameID));
const gameMetadata = this.storageAPI.getMetadata(gameID);
const playerMetadata = getPlayerMetadata(gameMetadata, playerID);
isActionAuthentic = this.shouldAuth(gameMetadata)
? this.auth(credentials, playerMetadata)
: true;
} else {
const gameMetadata = await this.storageAPI.get(GameMetadataKey(gameID));
const gameMetadata = await this.storageAPI.getMetadata(gameID);
const playerMetadata = getPlayerMetadata(gameMetadata, playerID);
isActionAuthentic = this.shouldAuth(gameMetadata)
? await this.auth(credentials, playerMetadata)
Expand All @@ -202,9 +201,9 @@ export class Master {

let state: State;
if (this.executeSynchronously) {
state = this.storageAPI.get(key);
state = this.storageAPI.getState(key);
} else {
state = await this.storageAPI.get(key);
state = await this.storageAPI.getState(key);
}

if (state === undefined) {
Expand Down Expand Up @@ -302,9 +301,9 @@ export class Master {
const stateWithLog = { ...state, log };

if (this.executeSynchronously) {
this.storageAPI.set(key, stateWithLog);
this.storageAPI.setState(key, stateWithLog);
} else {
await this.storageAPI.set(key, stateWithLog);
await this.storageAPI.setState(key, stateWithLog);
}
}

Expand All @@ -320,11 +319,11 @@ export class Master {
let filteredGameMetadata: { id: number; name?: string }[];

if (this.executeSynchronously) {
state = this.storageAPI.get(key);
gameMetadata = this.storageAPI.get(GameMetadataKey(gameID));
state = this.storageAPI.getState(key);
gameMetadata = this.storageAPI.getMetadata(gameID);
} else {
state = await this.storageAPI.get(key);
gameMetadata = await this.storageAPI.get(GameMetadataKey(gameID));
state = await this.storageAPI.getState(key);
gameMetadata = await this.storageAPI.getMetadata(gameID);
}
if (gameMetadata) {
filteredGameMetadata = Object.values(gameMetadata.players).map(player => {
Expand All @@ -342,11 +341,11 @@ export class Master {
});

if (this.executeSynchronously) {
this.storageAPI.set(key, state);
state = this.storageAPI.get(key);
this.storageAPI.setState(key, state);
state = this.storageAPI.getState(key);
} else {
await this.storageAPI.set(key, state);
state = await this.storageAPI.get(key);
await this.storageAPI.setState(key, state);
state = await this.storageAPI.getState(key);
}
}

Expand Down
47 changes: 47 additions & 0 deletions src/server/db/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { State, Server } from '../../types';

abstract class StorageAPI {
/**
* Connect.
*/
connect() {
return;
}

/**
* Update the game state.
*/
abstract setState(gameID: string, state: State): void;

/**
* Read the latest game state.
*/
abstract getState(gameID: string): State;

/**
* Check if a particular game id exists.
*/
abstract has(gameID: string): boolean;

/**
* Update the game metadata.
*/
abstract setMetadata(gameID: string, metadata: Server.GameMetadata): void;

/**
* Fetch the game metadata.
*/
abstract getMetadata(gameID: string): Server.GameMetadata;

/**
* Remove the game state.
*/
abstract remove(gameID: string): void;

/**
* Return all games.
*/
abstract list(): Array<string>;
}

export default StorageAPI;
File renamed without changes.
File renamed without changes.
72 changes: 0 additions & 72 deletions src/server/db/inmemory.js

This file was deleted.

23 changes: 13 additions & 10 deletions src/server/db/inmemory.test.js → src/server/db/inmemory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,35 @@
*/

import { InMemory } from './inmemory';
import { State } from '../../types';

test('inmemory db', async () => {
const db = new InMemory();
await db.connect();
db.connect();

// Must return undefined when no game exists.
let state = await db.get('gameID');
let state = await db.getState('gameID');
expect(state).toEqual(undefined);

let stateEntry: unknown = { a: 1 };

// Create game.
await db.set('gameID', { a: 1 });
db.setState('gameID', stateEntry as State);
// Must return created game.
state = await db.get('gameID');
expect(state).toEqual({ a: 1 });
state = db.getState('gameID');
expect(state).toEqual(stateEntry);

// Must return true if game exists
let has = await db.has('gameID');
let has = db.has('gameID');
expect(has).toEqual(true);

// Must return all keys
let keys = await db.list();
let keys = db.list();
expect(keys).toEqual(['gameID']);

// Must remove game from DB
await db.remove('gameID');
expect(await db.has('gameID')).toEqual(false);
db.remove('gameID');
expect(db.has('gameID')).toEqual(false);
// Shall not return error
await db.remove('gameID');
db.remove('gameID');
});
77 changes: 77 additions & 0 deletions src/server/db/inmemory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { State, Server } from '../../types';
import StorageAPI from './base';

/*
* Copyright 2017 The boardgame.io Authors
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

/**
* InMemory data storage.
*/
export class InMemory extends StorageAPI {
private games: Map<string, State>;
private metadata: Map<string, Server.GameMetadata>;

/**
* Creates a new InMemory storage.
*/
constructor() {
super();
this.games = new Map();
this.metadata = new Map();
}

/**
* Write the game metadata to the in-memory object.
*/
setMetadata(gameID: string, metadata: Server.GameMetadata) {
this.metadata.set(gameID, metadata);
}

/**
* Read the game metadata from the in-memory object.
*/
getMetadata(gameID: string): Server.GameMetadata {
return this.metadata.get(gameID);
}

/**
* Write the game state to the in-memory object.
*/
setState(gameID: string, state: State): void {
this.games.set(gameID, state);
}

/**
* Read the game state from the in-memory object.
*/
getState(gameID: string): State {
return this.games.get(gameID);
}

/**
* Check if a particular game id exists.
*/
has(gameID: string): boolean {
return this.games.has(gameID);
}

/**
* Remove the game state from the in-memory object.
*/
remove(gameID: string) {
if (!this.games.has(gameID)) return;
this.games.delete(gameID);
}

/**
* Return all keys.
*/
list(): string[] {
return [...this.games.keys()];
}
}

0 comments on commit c96e228

Please sign in to comment.