diff options
Diffstat (limited to 'src/ch/epfl/xblast/server/Server.java')
-rw-r--r-- | src/ch/epfl/xblast/server/Server.java | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/src/ch/epfl/xblast/server/Server.java b/src/ch/epfl/xblast/server/Server.java new file mode 100644 index 0000000..074b2a7 --- /dev/null +++ b/src/ch/epfl/xblast/server/Server.java | |||
@@ -0,0 +1,341 @@ | |||
1 | package ch.epfl.xblast.server; | ||
2 | |||
3 | import ch.epfl.xblast.Lists; | ||
4 | import ch.epfl.xblast.PlayerAction; | ||
5 | import ch.epfl.xblast.PlayerID; | ||
6 | import ch.epfl.xblast.Time; | ||
7 | import ch.epfl.xblast.server.painter.BoardPainter; | ||
8 | |||
9 | import java.io.IOException; | ||
10 | import java.net.InetSocketAddress; | ||
11 | import java.net.SocketAddress; | ||
12 | import java.net.StandardProtocolFamily; | ||
13 | import java.nio.ByteBuffer; | ||
14 | import java.nio.channels.DatagramChannel; | ||
15 | import java.util.*; | ||
16 | |||
17 | /** | ||
18 | * The Server class. | ||
19 | * | ||
20 | * @author Pacien TRAN-GIRARD (261948) | ||
21 | */ | ||
22 | public class Server { | ||
23 | |||
24 | /** | ||
25 | * Default parameters of the server. | ||
26 | */ | ||
27 | private static final long REFRESH_RATE = (long) (50 * 1E6); // nanosecond | ||
28 | private static final int DEFAULT_EXPECTED_CLIENTS = PlayerID.values().length; | ||
29 | public static final int DEFAULT_PORT = 2016; | ||
30 | |||
31 | /** | ||
32 | * ID of an observer. | ||
33 | */ | ||
34 | public static final byte OBSERVER = -1; | ||
35 | |||
36 | /** | ||
37 | * Prints a log message on the console. | ||
38 | * | ||
39 | * @param message message to be printed | ||
40 | */ | ||
41 | private static void log(String message) { | ||
42 | System.out.println("[LOG] " + message); | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * A Channel. | ||
47 | */ | ||
48 | private static class Channel { | ||
49 | |||
50 | /** | ||
51 | * Transforms a list of bytes to an array of bytes. | ||
52 | * | ||
53 | * @param l the given list of bytes | ||
54 | * @return the array built from the given list | ||
55 | */ | ||
56 | private static byte[] toByteArray(List<Byte> l) { | ||
57 | byte[] arr = new byte[l.size()]; | ||
58 | |||
59 | for (int i = 0; i < l.size(); ++i) | ||
60 | arr[i] = l.get(i); | ||
61 | |||
62 | return arr; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Creates the socket which will be listened to. | ||
67 | * | ||
68 | * @param host hostname | ||
69 | * @param port port to be listened | ||
70 | * @return the socket build from the given params | ||
71 | */ | ||
72 | private static InetSocketAddress listeningInterface(String host, int port) { | ||
73 | if (Objects.isNull(host)) | ||
74 | return new InetSocketAddress(port); | ||
75 | else | ||
76 | return new InetSocketAddress(host, port); | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * Open an UDP channel. | ||
81 | * | ||
82 | * @param iface listened socket | ||
83 | * @return a UDP channel | ||
84 | */ | ||
85 | private static DatagramChannel openChannel(InetSocketAddress iface) { | ||
86 | try { | ||
87 | DatagramChannel chan = DatagramChannel.open(StandardProtocolFamily.INET); | ||
88 | chan.bind(iface); | ||
89 | return chan; | ||
90 | } catch (IOException e) { | ||
91 | e.printStackTrace(); | ||
92 | System.exit(1); | ||
93 | return null; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * The UDP communication channel. | ||
99 | */ | ||
100 | private final DatagramChannel channel; | ||
101 | |||
102 | /** | ||
103 | * Instantiates a new Channel. | ||
104 | * | ||
105 | * @param iface listened socket | ||
106 | */ | ||
107 | Channel(InetSocketAddress iface) { | ||
108 | this.channel = openChannel(iface); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Instantiates a new Channel. | ||
113 | * | ||
114 | * @param host hostname | ||
115 | * @param port port to be listened | ||
116 | */ | ||
117 | Channel(String host, Integer port) { | ||
118 | this(listeningInterface(host, Optional.ofNullable(port).orElse(DEFAULT_PORT))); | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * Closes the channel. | ||
123 | */ | ||
124 | void closeChannel() { | ||
125 | try { | ||
126 | this.channel.close(); | ||
127 | } catch (IOException e) { | ||
128 | e.printStackTrace(); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Accepts the registration of a new client. | ||
134 | * | ||
135 | * @param registrations number of expected registrations | ||
136 | * @return a list of the clients. | ||
137 | */ | ||
138 | List<SocketAddress> acceptRegistrations(int registrations) { | ||
139 | List<SocketAddress> clients = new ArrayList<>(registrations); | ||
140 | |||
141 | while (clients.size() < registrations) { | ||
142 | SocketAddress client = this.acceptRegistration(); | ||
143 | if (!clients.contains(client)) | ||
144 | clients.add(client); | ||
145 | } | ||
146 | |||
147 | return Collections.unmodifiableList(clients); | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Collects actions from the players. | ||
152 | * | ||
153 | * @return a list map containing the actions related to each player | ||
154 | */ | ||
155 | Map<SocketAddress, PlayerAction> collectActions() { | ||
156 | Map<SocketAddress, PlayerAction> actions = new HashMap<>(); | ||
157 | Optional<Map.Entry<SocketAddress, PlayerAction>> action; | ||
158 | |||
159 | while (true) { | ||
160 | action = this.receiveAction(false); | ||
161 | if (!action.isPresent()) break; | ||
162 | actions.put(action.get().getKey(), action.get().getValue()); | ||
163 | } | ||
164 | |||
165 | return Collections.unmodifiableMap(actions); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * Sends data through the socket. | ||
170 | * | ||
171 | * @param content data to be send | ||
172 | * @param dst recipient of the data | ||
173 | */ | ||
174 | void send(List<Byte> content, SocketAddress dst) { | ||
175 | try { | ||
176 | ByteBuffer buf = ByteBuffer.wrap(toByteArray(content)); | ||
177 | this.channel.send(buf, dst); | ||
178 | } catch (IOException e) { | ||
179 | e.printStackTrace(); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * Receives a Byte from the socket. | ||
185 | * | ||
186 | * @param block wait for an incoming byte before returning | ||
187 | * @return an Optional containing the received data | ||
188 | */ | ||
189 | private Optional<Map.Entry<SocketAddress, Byte>> receiveByte(boolean block) { | ||
190 | try { | ||
191 | ByteBuffer buf = ByteBuffer.allocate(1); | ||
192 | this.channel.configureBlocking(block); | ||
193 | SocketAddress client = this.channel.receive(buf); | ||
194 | |||
195 | if (Objects.isNull(client) || buf.position() == 0) | ||
196 | throw new IOException(); | ||
197 | |||
198 | return Optional.of(new AbstractMap.SimpleImmutableEntry<>(client, buf.get(0))); | ||
199 | } catch (IOException e) { | ||
200 | return Optional.empty(); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * Receives a player action from the socket. | ||
206 | * | ||
207 | * @param block wait for an incoming action before returning | ||
208 | * @return an Optional containing the received player action | ||
209 | */ | ||
210 | private Optional<Map.Entry<SocketAddress, PlayerAction>> receiveAction(boolean block) { | ||
211 | try { | ||
212 | Map.Entry<SocketAddress, Byte> actionByte = this.receiveByte(block).get(); | ||
213 | PlayerAction playerAction = PlayerAction.fromByte(actionByte.getValue()); | ||
214 | return Optional.of(new AbstractMap.SimpleImmutableEntry<>(actionByte.getKey(), playerAction)); | ||
215 | } catch (NoSuchElementException | IllegalArgumentException e) { | ||
216 | return Optional.empty(); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * Accepts an action from the socket. | ||
222 | * | ||
223 | * @return the accepted action | ||
224 | */ | ||
225 | private Map.Entry<SocketAddress, PlayerAction> acceptAction() { | ||
226 | Optional<Map.Entry<SocketAddress, PlayerAction>> action; | ||
227 | |||
228 | do { | ||
229 | action = this.receiveAction(true); | ||
230 | } while (!action.isPresent()); | ||
231 | |||
232 | return action.get(); | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * Accepts the registration of a player. | ||
237 | * | ||