package o1game.Server // TODO: TLS/SSL / import javax.net.ssl.SSLServerSocketFactory import java.io.IOException import java.lang.Thread.sleep import java.net.{ServerSocket, Socket} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future import scala.util.{Failure, Success, Try} import o1game.constants.* /** `Server` exists to initialize a server for the game * and run it with its method `startServer`. */ class Server(port: Int, maxClients: Int): private val socket = ServerSocket(port) private val clientGetter = ConnectionGetter(socket) private val clients: Clients = Clients(maxClients) private val buffer: Array[Byte] = Array.ofDim(1024) private var bufferIndex = 0 /** Starts the server. Won't terminate under normal circumstances. */ def startServer(): Unit = while true do sleep(POLL_INTERVAL) this.receiveNewClient() this.writeToAll("Test message.") this.readFromAll() clients.foreach(_.executeActions()) /** Receives a new client and stores it in `clients`. * * @return describes if a client was added */ private def receiveNewClient(): Boolean = clientGetter.newClient() match case Some(c) => clients.addClient(Client(c, None)) true case None => false /** Sends `message` to all clients * * @param message the message to send */ private def writeToAll(message: String): Unit = clients.removeNonSatisfying((c: Client) => try val output = c.socket.getOutputStream output.write(message.toVector.map(_.toByte).toArray) output.flush() true catch case e: IOException => false ) /** Reads data sent by clients and stores it in the `Client`s of `clients` */ private def readFromAll(): Unit = clients.removeNonSatisfying((c: Client) => try val input = c.socket.getInputStream while input.available() != 0 do val bytesRead = input.read(buffer) if bytesRead != -1 then c.receiveData(buffer.take(bytesRead).toVector) true catch case e: IOException => false ) end Server class ConnectionGetter(val socket: ServerSocket): private var nextClient: Future[Socket] = Future.failed(IOException()) def newClient(): Option[Socket] = this.nextClient.value match case Some(Success(s)) => nextClient = Future(socket.accept()) Some(s) case Some(Failure(e)) => nextClient = Future(socket.accept()) None case None => None end ConnectionGetter