import Foundation import Vapor final class Database { private let players: PlayerManagement private let tables: TableManagement init(storageFolder: URL) throws { self.players = try PlayerManagement(storageFolder: storageFolder) self.tables = try TableManagement(storageFolder: storageFolder) } // MARK: Players & Sessions func registerPlayer(named name: PlayerName, hash: PasswordHash) -> SessionToken? { players.registerPlayer(named: name, hash: hash) } func passwordHashForExistingPlayer(named name: PlayerName) -> PasswordHash? { players.passwordHash(ofRegisteredPlayer: name) } func deletePlayer(named name: PlayerName) { _ = players.deletePlayer(named: name) tables.leaveTable(player: name) } func isValid(sessionToken token: SessionToken) -> Bool { players.isValid(sessionToken: token) } func startSession(socket: WebSocket, sessionToken: SessionToken) -> Bool { guard let player = players.registeredPlayerExists(withSessionToken: sessionToken) else { return false } return tables.connect(player: player, using: socket) } private func didReceive(message: String, forSessionToken token: SessionToken) { // TODO: Handle client requests print("Session \(token.prefix(6)): \(message)") } func endSession(forSessionToken sessionToken: SessionToken) { guard let player = players.endSession(forSessionToken: sessionToken) else { return } tables.disconnect(player: player) } /** Start a new session for an existing user. - Parameter name: The user name - Returns: The generated access token for the session */ func startNewSessionForRegisteredPlayer(named name: PlayerName) -> SessionToken { players.startNewSessionForRegisteredPlayer(named: name) } func registeredPlayerExists(withSessionToken token: SessionToken) -> PlayerName? { players.registeredPlayerExists(withSessionToken: token) } func currentTableOfPlayer(named player: PlayerName) -> TableInfo? { tables.tableInfo(player: player) } // MARK: Tables /** Create a new table with optional players. - Parameter name: The name of the table - Parameter players: The player creating the table - Parameter isPublic: Indicates that this is a game joinable by everyone - Returns: The table id */ func createTable(named name: TableName, player: PlayerName, isPublic: Bool) -> TableInfo { tables.createTable(named: name, player: player, isPublic: isPublic) } func getPublicTableInfos() -> [PublicTableInfo] { tables.publicTableList } func join(tableId: TableId, playerToken: SessionToken) -> Result { guard let player = players.registeredPlayerExists(withSessionToken: playerToken) else { return .failure(.invalidToken) } return tables.join(tableId: tableId, player: player) } func leaveTable(playerToken: SessionToken) -> Bool { guard let player = players.registeredPlayerExists(withSessionToken: playerToken) else { return false } tables.leaveTable(player: player) return true } func performAction(playerToken: SessionToken, action: PlayerAction) -> PlayerActionResult { guard let player = players.registeredPlayerExists(withSessionToken: playerToken) else { return .invalidToken } return tables.performAction(player: player, action: action) } func select(game: GameType, playerToken: SessionToken) -> PlayerActionResult { guard let player = players.registeredPlayerExists(withSessionToken: playerToken) else { return .invalidToken } return tables.select(game: game, player: player) } func play(card: Card, playerToken: SessionToken) -> PlayerActionResult { guard let player = players.registeredPlayerExists(withSessionToken: playerToken) else { return .invalidToken } return tables.play(card: card, player: player) } }