Persist registrations on disk
This commit is contained in:
parent
e7b3ac3e9f
commit
7265fd0f0d
1
Resources/.gitkeep
Normal file
1
Resources/.gitkeep
Normal file
@ -0,0 +1 @@
|
||||
|
@ -7,10 +7,10 @@ final class Database {
|
||||
|
||||
private let tables: TableManagement
|
||||
|
||||
init() {
|
||||
self.players = PlayerManagement()
|
||||
init(storageFolder: URL) throws {
|
||||
self.players = try PlayerManagement(storageFolder: storageFolder)
|
||||
self.tables = TableManagement()
|
||||
// TODO: Load server data from disk
|
||||
// TODO: Load table data from disk
|
||||
// TODO: Save data to disk
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,75 @@ final class PlayerManagement {
|
||||
|
||||
/// A reverse mapping between generated access tokens and player name
|
||||
private var playerNameForToken = [SessionToken: PlayerName]()
|
||||
|
||||
private let passwordFile: FileHandle
|
||||
|
||||
private let passwordFileUrl: URL
|
||||
|
||||
init() {
|
||||
init(storageFolder: URL) throws {
|
||||
let url = storageFolder.appendingPathComponent("passwords.txt")
|
||||
|
||||
if !FileManager.default.fileExists(atPath: url.path) {
|
||||
try Data().write(to: url)
|
||||
}
|
||||
|
||||
passwordFile = try FileHandle(forUpdating: url)
|
||||
passwordFileUrl = url
|
||||
|
||||
if #available(macOS 10.15.4, *) {
|
||||
guard let data = try passwordFile.readToEnd() else {
|
||||
try passwordFile.seekToEnd()
|
||||
return
|
||||
}
|
||||
try loadPasswords(data: data)
|
||||
} else {
|
||||
let data = passwordFile.readDataToEndOfFile()
|
||||
try loadPasswords(data: data)
|
||||
}
|
||||
print("Loaded \(playerPasswordHashes.count) players")
|
||||
}
|
||||
|
||||
private func loadPasswords(data: Data) throws {
|
||||
String(data: data, encoding: .utf8)!
|
||||
.components(separatedBy: "\n")
|
||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||
.filter { $0 != "" }
|
||||
.forEach { line in
|
||||
let parts = line.components(separatedBy: ":")
|
||||
// Token may contain the separator
|
||||
guard parts.count >= 2 else {
|
||||
print("Invalid line in password file")
|
||||
return
|
||||
}
|
||||
let name = parts[0]
|
||||
let token = parts.dropFirst().joined(separator: ":")
|
||||
if token == "" {
|
||||
playerPasswordHashes[name] = nil
|
||||
} else {
|
||||
playerPasswordHashes[name] = token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func save(password: PasswordHash, forPlayer player: PlayerName) -> Bool {
|
||||
let entry = player + ":" + password + "\n"
|
||||
let data = entry.data(using: .utf8)!
|
||||
do {
|
||||
if #available(macOS 10.15.4, *) {
|
||||
try passwordFile.write(contentsOf: data)
|
||||
} else {
|
||||
passwordFile.write(data)
|
||||
}
|
||||
try passwordFile.synchronize()
|
||||
return true
|
||||
} catch {
|
||||
print("Failed to save password to disk: \(error)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func deletePassword(forPlayer player: PlayerName) -> Bool {
|
||||
save(password: "", forPlayer: player)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,6 +114,9 @@ final class PlayerManagement {
|
||||
guard !hasRegisteredPlayer(named: name) else {
|
||||
return nil
|
||||
}
|
||||
guard save(password: hash, forPlayer: name) else {
|
||||
return nil
|
||||
}
|
||||
self.playerPasswordHashes[name] = hash
|
||||
return startNewSessionForRegisteredPlayer(named: name)
|
||||
}
|
||||
@ -58,6 +127,9 @@ final class PlayerManagement {
|
||||
- Returns: The session token of the current player, if one exists
|
||||
*/
|
||||
func deletePlayer(named name: PlayerName) -> SessionToken? {
|
||||
guard deletePassword(forPlayer: name) else {
|
||||
return nil
|
||||
}
|
||||
playerPasswordHashes.removeValue(forKey: name)
|
||||
guard let sessionToken = sessionTokenForPlayer.removeValue(forKey: name) else {
|
||||
return nil
|
||||
|
@ -7,7 +7,9 @@ public func configure(_ app: Application) throws {
|
||||
// serve files from /Public folder
|
||||
app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
|
||||
|
||||
database = Database()
|
||||
let storageFolder = URL(fileURLWithPath: app.directory.resourcesDirectory)
|
||||
database = try Database(storageFolder: storageFolder)
|
||||
|
||||
// register routes
|
||||
try routes(app)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user