blob: 829010ce365787b0bb45aa5df9de2182fd742934 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
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
|