source: src/main/webapp/newtournament.xhtml@ 8

Last change on this file since 8 was 8, checked in by bart, 5 years ago

Update 28 jan 2020

File size: 13.0 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3<head>
4<title>Profiles and Domains list</title>
5<link rel="stylesheet" type="text/css" href="style.css" />
6
7</head>
8<body onload="init()">
9 <h1>Tournament</h1>
10
11 On this page you can configure the settings for running a new
12 tournament and start the tournament.
13 <br />
14 <br />
15
16 <select>
17 <option value="APP">All Permutations Tournament Protocol
18 (APP)</option>
19 </select>
20 <br />
21 <br />
22 <input type="number" id="partiespersession" name="tentacles" min="2"
23 max="10" value="2" /> Number of parties in each session
24 <br />
25
26 <input type="checkbox" id="reuseparties" /> Pick parties with return
27 when creating sessions
28 <br />
29
30 <br />
31 <div id="box" class="box">
32 Session Protocol settings <br /> Session Protocol:
33 <select id="protocolselection">
34 <option value="SAOP">SAOP</option>
35 <option value="SHAOP">SHAOP</option>
36 </select>
37
38 <br /> Deadline: <input type="number" id="deadlinevalue"
39 name="deadline" min="1" max="10000" value="10" /> <select
40 id="deadlinetype">
41 <option value="ROUNDS">rounds</option>
42 <option value="TIME">seconds</option>
43 </select>
44 </div>
45 <br />
46
47 <div id="box" class="box">
48 <br /> Domain/Profile Server: <input type="url" name="url"
49 id="profilesserverurl" value="localhost:8080/profilesserver-1.1.0"
50 pattern=".*:[0-9]+/profilesserver" size="30"
51 onchange="connectDomain()"> </input> <br /> Domain: <select
52 id="domainselection" onchange="selectDomain()">
53 <!-- <option>Waiting for profiles server</option> -->
54 </select> <br /> <br />
55 <button onclick="addProfile()">Add</button>
56 Profile: <select id="profileselection">
57 <!-- <option>Waiting for partiesserver</option> -->
58 </select>
59 Filter: <input type="text" id="filter" value="" maxlength="40" />
60
61 <br /> <br />
62
63 <table id="profiles">
64 <thead>
65 <th align="left">Selected Profiles</th>
66 </thead>
67 <tbody id="profilesList">
68 <tr>
69 </tr>
70
71 </tbody>
72 </table>
73 <br />
74 </div>
75 <br />
76 <div id="box" class="box">
77 <br /> Parties Server: <input type="url" name="url"
78 id="partiesserverurl" value="localhost:8080/partiesserver-1.1.0"
79 pattern=".*:[0-9]+/partiesserver" size="30"
80 onchange="connectParties()"> </input> <br /> <br />
81 Party: <select id="partyselection">
82 <!-- <option>Waiting for partiesserver</option> -->
83 </select> <br /> Parameters: { <input type="text" id="parameters"
84 onchange="updateParameters()" value="" maxlength="100" /> } <br />
85 <button onclick="addParty()">Add</button>
86
87 <br /> <br />
88 <table>
89 <thead>
90 <th align="left">Party</th>
91 <th align="left">Parameters</th>
92 </thead>
93 <tbody id="partiesList">
94 <tr id="partiesList">
95 </tr>
96
97 </tbody>
98 </table>
99
100 </div>
101 <br />
102 <form>
103 <input id="startbutton" type="button" value="Start Tournament"
104 onclick="start()" />
105 </form>
106 <div id="started" style="visibility: hidden">
107 Your tournament started. Click <a href="" id="logref">here</a> to view
108 the log file.
109 </div>
110
111</body>
112
113<script type="application/javascript">
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 // FIXME quick and dirty code. No clean MVC
134
135
136 <![CDATA[
137 "use strict";
138
139 var domainwebsocket = null;
140 var partieswebsocket=null;
141 // currently known domains (and profiles) as coming from domainwebsocket.
142 // keys are domain names, values are list of profile names
143 var knowndomains={};
144
145 var parties=[];
146 var profiles=[]
147 // current setting of parameters
148 var parameters = {};
149
150
151 /**
152 Refresh known domains using given profilesserver URL.
153 Called when user enters URL for domain server.
154 */
155 function connectDomain() {
156 if (domainwebsocket!=null) {
157 domainwebsocket.close();
158 domainwebsocket=null;
159 }
160 var url=document.getElementById("profilesserverurl").value;
161 var target = "ws://"+url+"/websocket/liststream";
162 if ('WebSocket' in window) {
163 domainwebsocket = new WebSocket(target);
164 } else if ('MozWebSocket' in window) {
165 domainwebsocket = new MozWebSocket(target);
166 } else {
167 alert('WebSocket is not supported by this browser. Please use a newer browser');
168 return;
169 }
170 domainwebsocket.onopen = function () {
171 // whatever.
172 };
173 domainwebsocket.onmessage = function (event) {
174 updateDomainComboBox(JSON.parse(event.data));
175 };
176 domainwebsocket.onclose = function (event) {
177 alert('Info: Server closed connection. Code: ' + event.code +
178 (event.reason == "" ? "" : ", Reason: " + event.reason));
179 domainwebsocket=null;
180 updateDomainComboBox({});
181 };
182 }
183
184 /**
185 Sets a new knowndomains value and Updates the contents of the domain selector combobox.
186 @param the known domains, a map of the form {"jobs":["jobs1","jobs2"]}
187 where the keys are the names of the available domains nd the values a list of the available profiles in that domain.
188
189 */
190 function updateDomainComboBox(newdomains) {
191 knowndomains=newdomains
192 var combobox = document.getElementById("domainselection");
193 combobox.options.length=0;
194 for (var domain in knowndomains) {
195 var option = document.createElement('option');
196 option.text = option.value = domain;
197 combobox.add(option, 0);
198 }
199 selectDomain();
200 }
201 /**
202 Refresh known parties using given partiesserver URL.
203 Called when user enters URL for parties server.
204 */
205 function connectParties() {
206 if (partieswebsocket!=null) {
207 partieswebsocket.close();
208 partieswebsocket=null;
209 }
210 var url=document.getElementById("partiesserverurl").value;
211 var target = "ws://"+url+"/available";
212 if ('WebSocket' in window) {
213 partieswebsocket = new WebSocket(target);
214 } else if ('MozWebSocket' in window) {
215 partieswebsocket = new MozWebSocket(target);
216 } else {
217 alert('WebSocket is not supported by this browser. Please use a newer browser');
218 return;
219 }
220 partieswebsocket.onopen = function () {
221 // whatever.
222 };
223 partieswebsocket.onmessage = function (event) {
224 updateParties(JSON.parse(event.data));
225 };
226 partieswebsocket.onclose = function (event) {
227 alert('Info: Server closed connection. Code: ' + event.code +
228 (event.reason == "" ? "" : ", Reason: " + event.reason));
229 partieswebsocket=null;
230 updateParties({});
231 };
232 }
233
234
235 function updateParties(parties) {
236 var combobox = document.getElementById("partyselection");
237 combobox.options.length=0;
238 for (var party in parties) {
239 var option = document.createElement('option');
240 option.text = option.value = parties[party].uri;
241 combobox.add(option, 0);
242 }
243 }
244
245
246
247 /**
248 updates parameters field to match the given text.
249 */
250 function updateParameters() {
251 var text="{"+document.getElementById("parameters").value+"}";
252 try {
253 parameters=JSON.parse(text);
254 } catch(e) {
255 alert("Parameters can not be parsed. "+e);
256 return;
257 }
258 }
259
260 /**
261 Called when the selected domain changes. Assumes knowndomains has been set.
262 Updates the available profiles in the profile combobox.
263 @param selection the name of the selected domain.
264 */
265 function selectDomain() {
266 // determined current selection
267 var domaincombobox = document.getElementById("domainselection");
268 if (domaincombobox.options.length==0) return; // fixme clean profiles options?
269 var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
270
271 var profilecombo = document.getElementById("profileselection");
272 profilecombo.options.length=0;
273 for (var profile in knowndomains[domain]) {
274 var option = document.createElement('option');
275 option.text = option.value = knowndomains[domain][profile];
276 profilecombo.add(option, 0);
277 }
278 }
279
280 /**
281 Called when user clicks "Add"
282 */
283 function addParty() {
284 var partycombo = document.getElementById("partyselection");
285
286 if (partycombo.options.length==0) {
287 alert("Please set partier server and select a party");
288 return;
289 }
290 parties.push({"partyref":partycombo.options[partycombo.selectedIndex].value, "parameters":parameters})
291 updatePartyTable();
292 }
293
294 /** updates the party table, to match the #partyprofiles list. */
295 function updatePartyTable() {
296 var table = document.getElementById("partiesList");
297 table.innerHTML = ""; // clear table
298 for ( var party in parties) {
299 var row = table.insertRow(-1);
300 var cell1 = row.insertCell(-1);
301 var cell2 = row.insertCell(-1);
302 cell1.innerHTML = parties[party]["partyref"];
303 cell2.innerHTML = JSON.stringify(parties[party]["parameters"]);
304 }
305
306 }
307
308 /**
309 Called when user clicks "Add" to add a profile
310 */
311 function addProfile() {
312 var profilecombo = document.getElementById("profileselection");
313
314 if (profilecombo.options.length==0) {
315 alert("Please set domain/profile server and select a domain and a profile");
316 return;
317 }
318 var filteroptions = document.getElementById("filter").value;
319 if (filteroptions!="") {
320 filteroptions="?"+filteroptions;
321 }
322
323 profiles.push(profilecombo.options[profilecombo.selectedIndex].value + filteroptions)
324 updateProfileTable(); // what, MVC?
325 }
326
327 /** updates the party table, to match the #partyprofiles list. */
328 function updateProfileTable() {
329 var table = document.getElementById("profilesList");
330 table.innerHTML = ""; // clear table
331 for ( var profile in profiles) {
332 var row = table.insertRow(-1);
333 var cell1 = row.insertCell(-1);
334 cell1.innerHTML = profiles[profile];
335 }
336
337 }
338
339 /**
340 start the tournament as currently set on this page.
341 We need to send a TournamentSettings object to the server, which typically looks like this with SAOP
342 <code>
343 {"AllPermutationsSettings":{"parties":["party1","party2"],
344 "profiles":["profile1","profile2","profile3"],
345 "reuseParties":false,
346 "partiesPerSession":2,
347 "sessionsettings":{"SAOPSettings":{"participants":[],"deadline":{"deadlinetime":{"durationms":10}}}}}}
348 </code>
349 participants are already in the global partyprofiles dictionary
350
351 With SHAOP, it looks like this
352 <code>
353 {
354 "AllPermutationsSettings": {
355 "parties": [ { "partyref": "classpath:geniusweb.exampleparties.simpleshaop.ShaopParty", "parameters": { } },
356 { "partyref": "classpath:geniusweb.exampleparties.randomparty.RandomParty", "parameters": { }}
357 ],
358 "reuseParties": false,
359 "profiles": [ "prof1?partial=10", "prof2?partial=15"],
360 "partiesPerSession": 2,
361 "sessionsettings": { "SHAOPSettings": {
362 "participants": [ ],
363 "deadline": { "deadlinerounds": { "rounds": 10, "durationms": 10000 } } } } } }
364 </code>
365 */
366 function start() {
367 var npersession = document.getElementById("partiespersession").value;
368
369 if (parties.length < npersession || npersession <2) {
370 alert("At least "+npersession+" parties are needed.");
371 return;
372 }
373
374 if (profiles.length < npersession) {
375 alert("At least "+npersession+" profiles are needed.");
376 return;
377 }
378
379 // see https://www.w3schools.com/xml/dom_httprequest.asp
380 var xmlHttp = new XMLHttpRequest();
381 xmlHttp.onreadystatechange = function() {
382 if (this.readyState == 4) {
383 if (this.status == 200) {
384 document.getElementById("startbutton").disabled=true;
385 document.getElementById("started").setAttribute("style","");
386 document.getElementById("logref").href="log/"+this.responseText+".json";
387 } else
388 alert("request failed:"+this.statusText);
389 }
390 }
391 xmlHttp.open("POST", "run", true);
392 xmlHttp.send(makeRequest());
393 }
394
395 /**
396 @return a json request package containing a AllPermutationsSettings
397 */
398 function makeRequest() {
399 var deadline={};
400 var value = document.getElementById("deadlinevalue").value;
401 var dtypecombo = document.getElementById("deadlinetype");
402 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
403 deadline["deadlinetime"] = { "durationms": 1000*value};
404 } else {
405 // ROUNDS
406 deadline["deadlinerounds"] = {"rounds": value, "durationms": 10000};
407 }
408 var reuseParties = document.getElementById("reuseparties").checked;
409
410 var protocolcombobox = document.getElementById("protocolselection");
411 var protocol = protocolcombobox.options[protocolcombobox.selectedIndex].value;
412 var header=protocol+"Settings";
413
414 // create S(H)AOPSettings. [header] is a weird ECMA script workaround for javascript issue.
415 var sessionSettings = { [header]:{"participants":[],"deadline":deadline}};
416 return JSON.stringify({"AllPermutationsSettings":{"parties":parties,"profiles":profiles,"reuseParties":reuseParties,"partiesPerSession":2,"sessionsettings":sessionSettings}});
417 }
418
419 /**
420 Initialize the page after html is loaded.
421 */
422 function init() {
423 document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.1.0";
424 document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.1.0";
425
426
427 connectDomain();
428 connectParties();
429 }
430
431
432 ]]>
433
434
435
436
437
438</script>
439
440</html>
Note: See TracBrowser for help on using the repository browser.