import Foundation import Vapor let playerPerTable = 4 typealias TableId = String typealias TableName = String final class Database { private let players: PlayerManagement private let tables: TableManagement private var sessions: [SessionToken : WebSocket] init() { self.players = PlayerManagement() self.tables = TableManagement() self.sessions = [:] // TODO: Load server data from disk // TODO: Save data to disk } // 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) { if let sessionToken = players.deletePlayer(named: name) { closeAndRemoveSession(for: sessionToken) } // TODO: Delete player from tables } func isValid(sessionToken token: SessionToken) -> Bool { players.isValid(sessionToken: token) } func startSession(socket: WebSocket, sessionToken: SessionToken) { closeAndRemoveSession(for: sessionToken) sessions[sessionToken] = socket socket.onText { [weak self] socket, text in self?.didReceive(message: text, forSessionToken: sessionToken) } } private func didReceive(message: String, forSessionToken token: SessionToken) { // TODO: Handle client requests print("Session \(token.prefix(6)): \(message)") } func endSession(forSessionToken token: SessionToken) { players.endSession(forSessionToken: token) closeAndRemoveSession(for: token) } private func closeAndRemoveSession(for token: SessionToken) { _ = sessions.removeValue(forKey: token)?.close() } /** 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) } // MARK: Tables func tableExists(withId id: TableId) -> Bool { tables.tableExists(withId: id) } func tableIsFull(withId id: TableId) -> Bool { tables.tableIsFull(withId: id) } /** Create a new table with optional players. - Parameter name: The name of the table - Parameter players: The player creating the table - Parameter visible: Indicates that this is a game joinable by everyone - Returns: The table id */ func createTable(named name: TableName, player: PlayerName, visible: Bool) -> TableId { tables.createTable(named: name, player: player, visible: visible) } func getPublicTableInfos() -> [TableInfo] { tables.getPublicTableInfos() } func join(tableId: TableId, player: PlayerName) { let playersAtTable = tables.join(tableId: tableId, player: player) playersAtTable .compactMap { players.sessionToken(forPlayer: $0) } // Session Tokens .compactMap { sessions[$0] } // Sockets .forEach { socket in // TODO: Notify sessions about changed players // socket.send("") } } }