aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/Server/Clients.scala
blob: 786a09a3b65efb4a61e2763a651ce73dcc8a66ad (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
package o1game.Server

import scala.util.Try

class Clients(maxClients: Int):
	private val clients: Array[Option[Client]] = Array.fill(maxClients)(None)

	/** Adds `client` to this collection of clients.
	  *
	  * @param client the Client to add
	  * @return true if there was room for the client
	  *         i.e. fewer clients than `maxClients`, false otherwise
	  */
	def addClient(client: Client): Boolean =
		val i = this.clients.indexOf(None)
		if i == -1 then
			false
		else
			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)

	/** Returns true if the predicate `f` stands for all clients,
	  * false otherwise
	  *
	  * @param f the predicate to check for all clients
	  * @return whether `f` stands for all clients
	  */
	def forall(f: Client => Boolean): Boolean = this.clients.flatten.forall(f)

	/** Gets the names of all the clients stored by this object.
	  *
	  * @return the names of the clients
	  */
	def names: Vector[String] = this.clients.flatten.flatMap(_.getName).toVector

	def isEmpty: Boolean = this.clients.flatten.isEmpty

	/** 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 =>

	/** Removes clients that have not behaved according to protocol */
	def removeNonCompliant(): Unit =
		this.removeNonSatisfying(_.isIntactProtocolWise)

	/** 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)