aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/Server/Client.scala27
-rw-r--r--src/main/scala/Server/ConnectionGetter.scala25
-rw-r--r--src/main/scala/Server/Server.scala49
3 files changed, 62 insertions, 39 deletions
diff --git a/src/main/scala/Server/Client.scala b/src/main/scala/Server/Client.scala
index c7ff075..3bc4012 100644
--- a/src/main/scala/Server/Client.scala
+++ b/src/main/scala/Server/Client.scala
@@ -1,6 +1,7 @@
package o1game.Server
import java.net.Socket
+import scala.util.Try
import scala.math.min
import o1game.constants.*
@@ -69,12 +70,36 @@ class Clients(maxClients: Int):
this.clients(i) = Some(client)
true
+ /** Returns all the clients.
+ *
+ * @return an iterable of all the clients
+ */
def allClients: Iterable[Client] = clients.toVector.flatten
+
+ /** Applies the function `f` to all the clients for its side effects. */
def foreach(f: Client => Any): Unit = this.clients.flatten.foreach(f)
+
+ /** Applies the function `f` to all the clients for its side effects
+ * and removes all the clients for which `f([client])` returns false.
+ * This is useful for doing IO with the client and removing clients
+ * with stale sockets.
+ *
+ * @param f the function to apply to all the clients and filter them with
+ */
def removeNonSatisfying(f: Client => Boolean): Unit =
for i <- this.clients.indices do
this.clients(i) match
case Some(c) =>
if !f(c) then
this.clients(i) = None
- case None => \ No newline at end of file
+ case None =>
+
+ /** Applies the function f to all clients for its side effects.
+ * If the function throws an exception, the client is removed.
+ * Probably a more concise alternative to `removeNonSatisfying`,
+ * but might catch exceptions unintentionally.
+ *
+ * @param f the function to apply for its side effects to each client
+ */
+ def mapAndRemove(f: Client => Unit): Unit =
+ this.removeNonSatisfying(c => Try(f(c)).isSuccess) \ No newline at end of file
diff --git a/src/main/scala/Server/ConnectionGetter.scala b/src/main/scala/Server/ConnectionGetter.scala
new file mode 100644
index 0000000..b3246a7
--- /dev/null
+++ b/src/main/scala/Server/ConnectionGetter.scala
@@ -0,0 +1,25 @@
+package o1game.Server
+
+import java.io.IOException
+import java.net.{ServerSocket, Socket}
+import scala.concurrent.Future
+import scala.util.{Failure, Success}
+import scala.concurrent.ExecutionContext.Implicits.global
+
+/** Small helper class for getting new connections using futures */
+class ConnectionGetter(val socket: ServerSocket):
+
+ private var nextClient: Future[Socket] = Future.failed(IOException())
+
+ /** Returns a new socket to a client if there is any new connections. */
+ 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
diff --git a/src/main/scala/Server/Server.scala b/src/main/scala/Server/Server.scala
index 829010c..1f0cbfc 100644
--- a/src/main/scala/Server/Server.scala
+++ b/src/main/scala/Server/Server.scala
@@ -6,9 +6,6 @@ package o1game.Server
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
@@ -47,44 +44,20 @@ class Server(port: Int, maxClients: Int):
* @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
+ clients.mapAndRemove(c =>
+ val output = c.socket.getOutputStream
+ output.write(message.toVector.map(_.toByte).toArray)
+ output.flush()
)
/** 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
+ clients.mapAndRemove(c =>
+ 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)
)
-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
+end Server \ No newline at end of file