UNPKG

boardgame.io

Version:
159 lines (139 loc) 4.33 kB
/* * 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. */ import Koa from 'koa'; import { addApiToServer, createApiServer } from './api'; import { DBFromEnv } from './db'; import { ProcessGameConfig } from '../core/game'; import * as logger from '../core/logger'; import { SocketIO } from './transport/socketio'; import { Server as ServerTypes, Game, StorageAPI } from '../types'; export type KoaServer = ReturnType<Koa['listen']>; interface ServerConfig { port?: number; callback?: () => void; lobbyConfig?: { apiPort: number; apiCallback?: () => void; }; } interface HttpsOptions { cert: string; key: string; } /** * Build config object from server run arguments. */ export const createServerRunConfig = ( portOrConfig: number | ServerConfig, callback?: () => void ): ServerConfig => { const config: ServerConfig = {}; if (portOrConfig && typeof portOrConfig === 'object') { const serverConfig = portOrConfig as ServerConfig; config.port = serverConfig.port; config.callback = serverConfig.callback || callback; config.lobbyConfig = serverConfig.lobbyConfig; } else { config.port = portOrConfig as number; config.callback = callback; } return config; }; const getPortFromServer = (server: KoaServer): string | number | null => { const address = server.address(); if (typeof address === 'string') return address; if (address === null) return null; return address.port; }; interface ServerOpts { games: Game[]; db?: StorageAPI.Async | StorageAPI.Sync; transport?: SocketIO; authenticateCredentials?: ServerTypes.AuthenticateCredentials; generateCredentials?: ServerTypes.GenerateCredentials; https?: HttpsOptions; } /** * Instantiate a game server. * * @param games - The games that this server will handle. * @param db - The interface with the database. * @param transport - The interface with the clients. * @param authenticateCredentials - Function to test player credentials. * @param generateCredentials - Method for API to generate player credentials. * @param https - HTTPS configuration options passed through to the TLS module. */ export function Server({ games, db, transport, authenticateCredentials, generateCredentials, https, }: ServerOpts) { const app = new Koa(); games = games.map(ProcessGameConfig); if (db === undefined) { db = DBFromEnv(); } app.context.db = db; if (transport === undefined) { const auth = typeof authenticateCredentials === 'function' ? authenticateCredentials : true; transport = new SocketIO({ auth, https, }); } transport.init(app, games); return { app, db, transport, run: async (portOrConfig: number | object, callback?: () => void) => { const serverRunConfig = createServerRunConfig(portOrConfig, callback); // DB await db.connect(); // Lobby API const lobbyConfig: ServerTypes.LobbyConfig = serverRunConfig.lobbyConfig; let apiServer: KoaServer | undefined; if (!lobbyConfig || !lobbyConfig.apiPort) { addApiToServer({ app, db, games, lobbyConfig, generateCredentials }); } else { // Run API in a separate Koa app. const api = createApiServer({ db, games, lobbyConfig, generateCredentials, }); await new Promise(resolve => { apiServer = api.listen(lobbyConfig.apiPort, resolve); }); if (lobbyConfig.apiCallback) lobbyConfig.apiCallback(); logger.info(`API serving on ${getPortFromServer(apiServer)}...`); } // Run Game Server (+ API, if necessary). let appServer: KoaServer; await new Promise(resolve => { appServer = app.listen(serverRunConfig.port, resolve); }); if (serverRunConfig.callback) serverRunConfig.callback(); logger.info(`App serving on ${getPortFromServer(appServer)}...`); return { apiServer, appServer }; }, kill: (servers: { apiServer?: KoaServer; appServer: KoaServer }) => { if (servers.apiServer) { servers.apiServer.close(); } servers.appServer.close(); }, }; }