source: src/main/webapp/newsession.xhtml@ 15

Last change on this file since 15 was 15, checked in by bart, 4 years ago

Tries harder to kill parties after deadline

File size: 18.2 KB
RevLine 
[1]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>Session</h1>
10
11 On this page you can configure the settings for running a new session
12 and start the session.
13
14 <br /> Protocol:
[8]15 <select id="selectedprotocol" onchange="selectProtocol()">
16 <option value="SAOP">SAOP (stacked alternating offers)</option>
17 <option value="SHAOP">SHAOP (stacked human alternating
18 offers)</option>
[1]19 </select>
20
21 <br /> Deadline:
22 <input type="number" id="deadlinevalue" name="deadline" min="1"
23 max="10000" value="10" />
24 <select id="deadlinetype">
[8]25 <option value="ROUNDS">rounds</option>
[1]26 <option value="TIME">seconds</option>
27 </select>
28
29 <br /> Domain/Profile Server:
30 <input type="url" name="url" id="profilesserverurl"
[15]31 value="localhost:8080/profilesserver-1.4.2"
[1]32 pattern=".*:[0-9]+/profilesserver" size="30"
33 onchange="connectDomain()"> </input>
34 <br /> Domain:
[2]35 <select id="domainselection" onchange="selectDomain()">
[1]36 <!-- <option>Waiting for profiles server</option> -->
37 </select>
38
39 <br />
40 <br />
41
42 <div id="box" class="box">
43 <br /> <b>Participants</b> <br /> Parties Server: <input type="url"
[4]44 name="url" id="partiesserverurl"
[15]45 value="localhost:8080/partiesserver-1.4.2"
[1]46 pattern=".*:[0-9]+/partiesserver" size="30"
[8]47 onchange="connectParties()"> </input> <br /> <br /> <b>Party
48 settings</b> <br /> Party : <select id="partyselection">
49 </select> <br /> Profile: <select id="profileselection"></select> Filter: <input
50 type="text" id="filter" value="" maxlength="40" /> <br />
51 Parameters: { <input type="text" id="parameters"
52 onchange="updateParameters()" value="" maxlength="100" /> } <br />
53 <br />
[1]54
[8]55 <div id="cobsetting">
56 <input type="checkbox" id="advancedCobSettings" onchange="advancedCobSet()" ></input>
57 Advanced COB settings<br/>
58 <div id="advancedsettings" style="display:none">
59 <b>COB party settings</b> <br /> Party : <select
60 id="cobpartyselection">
61 </select> <br /> Profile: <select id="cobprofileselection"></select>
62 Filter: <input type="text" id="cobfilter" value=""
63 maxlength="40" /> <br /> Parameters: { <input
64 type="text" id="cobparameters" onchange="updateCobParameters()"
65 value="" maxlength="100" /> } <br /> <br />
66 </div>
67 </div>
68
[1]69 <button onclick="addParty()">Add</button>
70
71
72 <br /> <br /> <b>Selected Profiles, Parties for the session</b>
[8]73 <table id="selectedpartiestable" width="100%">
74 <colgroup>
75 <col />
76 <col />
77 <col />
78 <col />
79 <col />
80 <col />
81 </colgroup>
[1]82 <thead>
[8]83 <tr>
84 <th align="center">Party</th>
85 <th align="center">Parameters</th>
86 <th align="center">Profile</th>
87
88 <th align="center">COB Party</th>
89 <th align="center">COB Parameters</th>
90 <th align="center">COB Profile</th>
91 </tr>
[1]92 </thead>
93 <tbody id="partiesList">
94 </tbody>
95 </table>
96
97 </div>
98
99 <form>
100 <input id="startbutton" type="button" value="Start Session"
101 onclick="start()" />
102 </form>
103
104 <div id="started" style="visibility: hidden">
[4]105 Your session started. Waiting for the results. <br />
106 </div>
107 <div id="results" style="visibility: hidden">
[6]108 Session completed. <a href="" id="logref">view the log file</a> <br />
109 <a href="" id="plotref">render a utilities plot</a>.
[1]110 </div>
111
112</body>
113
114<script type="application/javascript">
115
116
[2]117
[4]118
[6]119
[8]120
121
122
[1]123 // FIXME quick and dirty code. No clean MVC
124
125
126 <![CDATA[
[2]127 //"use strict";
[1]128
129 var domainwebsocket = null;
130 var partieswebsocket=null;
[6]131 // current setting of parameters
132 var parameters = {};
133
[1]134 // currently known domains (and profiles) as coming from domainwebsocket.
135 // keys are domain names, values are list of profile names
136 var knowndomains={};
137
[6]138
[1]139 /**
140 List of created participants for the session. Each participant is a dictionary.
141 Each dict element contains keys
142 "party" and "profile", both containing a String containing
143 a valid IRI to the party resp. the profile to use.
144 The party should contain a IRI that gives a new instance of the required party.
145 The profile should contain an IRI that gives the profile contents.
146 */
147 var partyprofiles=[];
[8]148
149 var cobpartyprofiles=[];
[1]150
[2]151 /** from http://fitzgeraldnick.com/2010/08/10/settimeout-patterns.html */
152
[8]153 function getAdvancedCobSettings() {
154 return document.getElementById('advancedCobSettings').checked;
155 }
156
157 function advancedCobSet() {
158 document.getElementById('advancedsettings').style.display=(getAdvancedCobSettings()?'':'none');
159 }
160
[2]161 function async (fn) {
162 setTimeout(fn, 1000);
163 }
164
165 function sometimeWhen (test, then) {
166 async(function () {
167 if ( test() ) {
168 then();
169 } else {
170 async(arguments.callee);
171 }
172 });
173 }
174
[8]175 /**
176 Called when user changes the protocol */
177 function selectProtocol() {
178 var visible=getSelectedProtocol() == "SHAOP";
179
180 document.getElementById("cobsetting").style.display=(visible ? 'block': 'none');
181 var tbl = document.getElementById('selectedpartiestable');
182 tbl.getElementsByTagName('col')[3].style.visibility=(visible?'':'collapse');
183 tbl.getElementsByTagName('col')[4].style.visibility=(visible?'':'collapse');
184 tbl.getElementsByTagName('col')[5].style.visibility=(visible?'':'collapse');
185
186 }
[2]187
[1]188 /**
189 Refresh known domains using given profilesserver URL.
190 Called when user enters URL for domain server.
191 */
192 function connectDomain() {
193 if (domainwebsocket!=null) {
194 domainwebsocket.close();
195 domainwebsocket=null;
196 }
197 var url=document.getElementById("profilesserverurl").value;
198 var target = "ws://"+url+"/websocket/liststream";
199 if ('WebSocket' in window) {
200 domainwebsocket = new WebSocket(target);
201 } else if ('MozWebSocket' in window) {
202 domainwebsocket = new MozWebSocket(target);
203 } else {
204 alert('WebSocket is not supported by this browser. Please use a newer browser');
205 return;
206 }
207 domainwebsocket.onopen = function () {
208 // whatever.
209 };
210 domainwebsocket.onmessage = function (event) {
211 updateDomainComboBox(JSON.parse(event.data));
212 };
213 domainwebsocket.onclose = function (event) {
214 alert('Info: Server closed connection. Code: ' + event.code +
215 (event.reason == "" ? "" : ", Reason: " + event.reason));
216 domainwebsocket=null;
217 updateDomainComboBox({});
218 };
219 }
220
221 /**
222 Sets a new knowndomains value and Updates the contents of the domain selector combobox.
223 @param the known domains, a map of the form {"jobs":["jobs1","jobs2"]}
224 where the keys are the names of the available domains nd the values a list of the available profiles in that domain.
225
226 */
227 function updateDomainComboBox(newdomains) {
228 knowndomains=newdomains
229 var combobox = document.getElementById("domainselection");
230 combobox.options.length=0;
231 for (var domain in knowndomains) {
232 var option = document.createElement('option');
233 option.text = option.value = domain;
234 combobox.add(option, 0);
235 }
236 selectDomain();
237 }
238 /**
239 Refresh known parties using given partiesserver URL.
240 Called when user enters URL for parties server.
241 */
242 function connectParties() {
243 if (partieswebsocket!=null) {
244 partieswebsocket.close();
245 partieswebsocket=null;
246 }
247 var url=document.getElementById("partiesserverurl").value;
248 var target = "ws://"+url+"/available";
249 if ('WebSocket' in window) {
250 partieswebsocket = new WebSocket(target);
251 } else if ('MozWebSocket' in window) {
252 partieswebsocket = new MozWebSocket(target);
253 } else {
254 alert('WebSocket is not supported by this browser. Please use a newer browser');
255 return;
256 }
257 partieswebsocket.onopen = function () {
258 // whatever.
259 };
260 partieswebsocket.onmessage = function (event) {
261 updateParties(JSON.parse(event.data));
262 };
263 partieswebsocket.onclose = function (event) {
264 alert('Info: Server closed connection. Code: ' + event.code +
265 (event.reason == "" ? "" : ", Reason: " + event.reason));
266 partieswebsocket=null;
267 updateParties({});
268 };
269 }
270
271
272 /**
273 refresh table: copy all parties elements in there.
274 Typically parties is something like
[15]275 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-1.4.2",
[1]276 "capabilities":{"protocols":["SAOP"]},
277 "description":"places random bids until it can accept an offer with utility >0.6",
[15]278 "id":"randomparty-1.4.2",
[1]279 "partyClass":"geniusweb.exampleparties.randomparty.RandomParty"},
280 ...]
281 */
282 function updateParties(parties) {
[8]283 updatePartiesCombobox(parties, document.getElementById("partyselection"),['SAOP','SHAOP']);
284 updatePartiesCombobox(parties, document.getElementById("cobpartyselection"),['COB']);
285 }
286
287 /**
288 @param parties a list of parties r(as received from the server)
289 @param combobox a combobox element to put the party URLs in
290 @param behaviours a list of behaviours for the parties. Only these are put in the combobox.
291 */
292 function updatePartiesCombobox(parties, combobox, behaviours) {
[1]293 combobox.options.length=0;
[8]294 for (var p in parties) {
295 var party = parties[p];
296 if (intersect(party.capabilities.behaviours, behaviours).length==0)
297 continue;
[1]298 var option = document.createElement('option');
[8]299 option.text = option.value = party.uri;
[1]300 combobox.add(option, 0);
301 }
302
[8]303 }
304
[6]305 /**
[8]306 @param a a list
307 @param b another list
308 @return intersection of a and b
309 */
310 function intersect(a, b) {
311 var t;
312 if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
313 return a.filter(function (e) {
314 return b.indexOf(e) > -1;
315 });
316 }
317
318
319 /**
[6]320 updates parameters field to match the given text.
321 */
322 function updateParameters() {
323 var text="{"+document.getElementById("parameters").value+"}";
324 try {
325 parameters=JSON.parse(text);
326 } catch(e) {
327 alert("Parameters can not be parsed. "+e);
328 return;
329 }
330 }
[1]331
332 /**
333 Called when the selected domain changes. Assumes knowndomains has been set.
334 Updates the available profiles in the profile combobox.
335 @param selection the name of the selected domain.
336 */
337 function selectDomain() {
338 // determined current selection
339 var domaincombobox = document.getElementById("domainselection");
340 if (domaincombobox.options.length==0) return; // fixme clean profiles options?
341 var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
342
[8]343 updateProfileComboBox(document.getElementById("profileselection"), knowndomains[domain]);
344 updateProfileComboBox(document.getElementById("cobprofileselection"), knowndomains[domain]);
345 }
346
347 function updateProfileComboBox(profilecombo, options) {
[1]348 profilecombo.options.length=0;
[8]349 for (var profile in options) {
[1]350 var option = document.createElement('option');
[8]351 option.text = option.value = options[profile];
[1]352 profilecombo.add(option, 0);
353 }
[8]354
[1]355 }
356
357 /**
358 Called when user clicks "Add"
359 */
360 function addParty() {
[8]361 addNormalParty();
362 addCobParty();
363 updatePartyProfileTable(); // what, MVC?
364 }
365
366 function addNormalParty() {
[1]367 var partycombo = document.getElementById("partyselection");
368 var profilecombo = document.getElementById("profileselection");
[8]369 var filteroptions = document.getElementById("filter").value;
[1]370
371 if (partycombo.options.length==0) {
372 alert("Please set partier server and select a party");
373 return;
374 }
375 if (profilecombo.options.length==0) {
376 alert("Please set domain/profile server and select a domain and a profile");
377 return;
378 }
[8]379
380 if (filteroptions!="") {
381 filteroptions="?"+filteroptions;
382 }
[1]383 var newpartyprof = {};
[8]384 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
[6]385 "parameters":parameters };
[8]386 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
[1]387
388 partyprofiles.push(newpartyprof)
389 }
390
[8]391
392 function addCobParty() {
393 // we assume a sensible default has been loaded into the combo and set,
394 // regardless it being invisible
395 var partycombo = document.getElementById("cobpartyselection");
396 if (partycombo.options.length==0) {
397 alert("Please set cpb partier server and select a party");
398 return;
399 }
400
401 var newpartyprof = {};
402 if (getAdvancedCobSettings()) {
403 var profilecombo = document.getElementById("cobprofileselection");
404 var filteroptions = document.getElementById("cobfilter").value;
405
406 if (profilecombo.options.length==0) {
407 alert("Please set a cob profile");
408 return;
409 }
410 if (filteroptions!="") {
411 filteroptions="?"+filteroptions;
412 }
413 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
414 "parameters":parameters };
415 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
416 } else {
417 var profilecombo = document.getElementById("profileselection");
418 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
419 "parameters":{} };
420 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value;
421 }
422 cobpartyprofiles.push(newpartyprof)
423 }
424
425
[1]426 /** updates the party and profiles table, to match the #partyprofiles list. */
427 function updatePartyProfileTable() {
428 var table = document.getElementById("partiesList");
429 table.innerHTML = ""; // clear table
430 for ( var pp in partyprofiles) {
431 var row = table.insertRow(-1);
432 var cell1 = row.insertCell(-1);
433 var cell2 = row.insertCell(-1);
[6]434 var cell3 = row.insertCell(-1);
[8]435 var cell4 = row.insertCell(-1);
436 var cell5 = row.insertCell(-1);
437 var cell6 = row.insertCell(-1);
438
[6]439 cell1.innerHTML = partyprofiles[pp]["party"]["partyref"];
440 cell2.innerHTML = JSON.stringify(partyprofiles[pp]["party"]["parameters"]);
441 cell3.innerHTML = partyprofiles[pp]["profile"];
[8]442 cell4.innerHTML = cobpartyprofiles[pp]["party"]["partyref"];
443 cell5.innerHTML = JSON.stringify(cobpartyprofiles[pp]["party"]["parameters"]);
444 cell6.innerHTML = cobpartyprofiles[pp]["profile"];
[1]445 }
446
447 }
448
[2]449 var x=1;
[1]450 /**
451 start the session as currently set on this page.
452 We need to send a SessionSettings object to the server, which typically looks like this
453 but is protocol dependent (currently we do SAOP)
454
455 {"SAOPSettings":
456 {"participants":[
[6]457 {"party":{"partyref":"http://party1","parameters":{}},"profile":"ws://profile1"},
458 {"party":{"partyref",}"http://party2","parameters":{}},"profile":"ws://profile2"}],
[1]459 "deadline":{"deadlinetime":{"durationms":100}}}}
460
461 participants are already in the global partyprofiles dictionary
462 */
463 function start() {
464 if (Object.keys(partyprofiles).length <2) {
465 alert("At least 2 parties are needed to run a session.");
466 return;
467 }
468
469 // see https://www.w3schools.com/xml/dom_httprequest.asp
[5]470 document.getElementById("startbutton").disabled=true;
471 document.getElementById("started").setAttribute("style","");
472
473 var xmlHttp = new XMLHttpRequest();
[1]474 xmlHttp.onreadystatechange = function() {
475 if (this.readyState == 4) {
476 if (this.status == 200) {
[4]477 var logurl="log/"+this.responseText+".json";
478 document.getElementById("logref").href=logurl;
[1]479 document.getElementById("plotref").href="plotlog.xhtml?id="+this.responseText;
480
[4]481 sometimeWhen(function() { return urlExists(logurl) },
482 function() { document.getElementById("results").setAttribute("style",""); });
[2]483
[1]484 }
485 else
486 alert("request failed:"+this.statusText);
487 }
488 }
489 xmlHttp.open("POST", "run", true);
490 xmlHttp.send(makeRequest());
491
492 }
493
[4]494
495 /**
496 @return true iff the URL exists.
497 */
498 function urlExists(urlToFile) {
499 // Warning. Synchronous XMLHttpRequest on the main thread is
500 // deprecated because of its detrimental effects to the end user’s
501 // experience. For more help http://xhr.spec.whatwg.org/
502 var xhr = new XMLHttpRequest();
503 xhr.open('HEAD', urlToFile, false);
504 xhr.send();
505
506 return (xhr.status == "200")
507 }
[1]508
[8]509 function getSelectedProtocol() {
510 var protocolcombo = document.getElementById("selectedprotocol");
511 return protocolcombo.options[protocolcombo.selectedIndex].value;
512 }
[1]513 /**
514 @return a json request package for the run server
515 */
516 function makeRequest() {
[8]517
518 if (getSelectedProtocol()=="SHAOP") {
519 return makeShaopRequest();
520 } else {
521 return makeSaopRequest();
522 }
523 }
524
525 /**
526 @return a SAOP request
527 */
528 function makeSaopRequest() {
[1]529 var deadline={};
530 var value = document.getElementById("deadlinevalue").value;
531 var dtypecombo = document.getElementById("deadlinetype");
532 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
533 deadline["deadlinetime"] = { "durationms": 1000*value};
534 } else {
535 // ROUNDS
536 deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
537 }
538
539 return JSON.stringify({"SAOPSettings": { "participants": partyprofiles, "deadline":deadline }});
[8]540 }
[1]541
[8]542 /**
543 @return a SHAOP request
544 */
545 function makeShaopRequest() {
546 var deadline={};
547 var value = document.getElementById("deadlinevalue").value;
548 var dtypecombo = document.getElementById("deadlinetype");
549 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
550 deadline["deadlinetime"] = { "durationms": 1000*value};
551 } else {
552 // ROUNDS
553 deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
554 }
555
556 var parties=[];
557 for (let i=0; i< partyprofiles.length; i++) {
558 var group={};
559 group['shaop'] = partyprofiles[i];
560 group['cob'] = cobpartyprofiles[i];
561
562 parties.push(group);
563 }
564 return JSON.stringify({"SHAOPSettings": { "participants": parties, "deadline":deadline }});
[1]565 }
[8]566
[1]567
568 /**
569 Initialize the page after html is loaded.
570 */
571 function init() {
[8]572 selectProtocol();
[15]573 document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.4.2"
574 document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.4.2"
[1]575 connectDomain();
576 connectParties();
577
578 }
579 ]]>
580
581
[4]582
[6]583
[8]584
585
586
[1]587</script>
588
589</html>
Note: See TracBrowser for help on using the repository browser.