[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
<!DOCTYPE html>
<html>
<head>
<!--
Copyright (C) 2010-2013 Mark G.Daniel
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it under the
conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version.
http://www.gnu.org/licenses/gpl.txt
-->
<title>WebSocket Scripting - Chat Demonstration</title>

<style type="text/css">
body { font-family: sans-serif, arial, helvetica; font-size:11pt; }
.demo { font-size:130%; font-weight:bold; text-decoration:underline; text-align:center; }
.application th { text-align:right; vertical-align:top; }
.clientab th { padding:0.2em 0 0.2em 1em; text-align:right; }
.clientab td { padding:0.2em 0 0.2em 1em; text-align:right; font-family:monospace; }
.chatter { width:95%; margin:1em; background-color:whiteSmoke; }
.chatter th,td { vertical-align:top; padding-left:0.5em; }
.revealhide { font-weight:bold; }
.documentation { display:none; padding:0 2em 0 2em; }
</style>

<script language="JavaScript">
function testWebSocketSupport()
{
   try {
      var ws = new WebSocket("wss://localhost/");
      if (typeof ws.protocol == "undefined")
         return -1;
      else
         return +1;
   }
   catch (err) {
      return 0;
   }
}
function reportWebSocketSupport()
{
   var level = testWebSocketSupport();
   if (level != 1)
      document.getElementById("nowebsocket").innerHTML =
'<span style="background-color:#ff0000;padding:1px;font-size:120%;">\
This browser does not support WebSocket!\
</span><br /><i>' + navigator.userAgent + '</i>';
}
if (window.addEventListener)
   window.addEventListener("load", reportWebSocketSupport, false);
else
if (window.attachEvent)
   window.attachEvent("onload", reportWebSocketSupport);
</script>

</head>
<body>

<div id="dbug"></div>
<table class="application" cellpadding="5" cellspacing="5" border="0">
<tr><td colspan="2" class="demo">WebSocket Scripting &nbsp;&mdash;&nbsp; Chat Demonstration</td></tr>
<tr><td id="OnNext" colspan="3" style="text-align:center;"></td></tr>
<tr><td id="nowebsocket" colspan="2" style="text-align:center;"></td></tr>
<tr>
<th align="left">Chatter:</th>
<td id="chatter" class="chatter">[closed]</td>
</tr>
<tr id="handrow">
<th align="left">Handle:</th>
<td id="handle" class="handle">
<input id="handtxt" class="handtxt" type="text" size="15" value="">
</td>
</tr>
<tr id="chatrow" style="display:none;">
<th align="left">Yours:</th>
<td id="yours" class="yours">
<input id="chatmsg" class="chatmsg" type="text" size="80" value=""
onmouseover="webSocketOpen()">
</td>
</tr>
</table>

<br>
<div class="revealhide">Description&nbsp;<tt>[<a name="descrip" href="javascript:revealHide('descrip')">+</a>]</tt></div>

<div name="descrip" class="documentation">

<p>This (must be a classic) demonstrator for the <b>asynchronous,
bi-directional</b> network channel provided by a WebSocket.</p>

<p>To begin, enter a nick-name into the handle field.  This is replaced with a
chat field and a WebSocket connection will be established with the server-side
application (script).  This application obviously <b>handles multiple,
concurrent clients</b>.  The entered text is sent to the chat application and
is echoed to all connected clients.  An entered question mark displays all
participants.  If left unused the WebSocket is disconnected by the server-side
application and can be reestablished by entering further chat.</p>

<p>This demonstration is JavaScript-driven at the browser end</p>

<p style="margin-left:2em;"><tt>WASD_ROOT:[SRC.WEBSOCKET]<a target="_blank"
href="ws_chat.html?httpd=content&type=text/plain">WS_CHAT.HTML</a></tt></p>

<p>and uses a WebSocket protocol application (script) at the WASD server end</p>

<p style="margin-left:2em;"><tt>WASD_ROOT:[SRC.WEBSOCKET]<a target="_blank"
href="ws_chat.c">WS_CHAT.C</a></tt></p>

<p>All of these interactions can be observed using the WASD WATCH facility;
[x]CGI, [x]DCL and [x]Network Data items.</p>

</div>

<div class="revealhide">Configuration&nbsp;<tt>[<a name="config" href="javascript:revealHide('config')">+</a>]</tt></div>

<div name="config" class="documentation">

<p>The script is a native WebSocket protocol application and so the executable
should only need placing in the script directory.</p>

<p> To effectively display multiple clients the script must rely on there being
only a single instance of it executing (a particular issue when employing
multiple WASD instances).  Generally the server will only need to instantiate a
single WS_CHAT script to handle multiple clients, however there is a small
window when the client request is being accepted by the script where it is
unavailable.

<p> Suppress host name lookup by defining the logical name WS_CHAT_NO_LOOKUP.
</div>

<script language="JavaScript">

if (window.location.protocol == "http:")
   var URL = "ws://";
else
   var URL = "wss://";
URL += window.location.host + "/cgiplus-bin/ws_chat"

var ws = null;
var meIdent = null;
var sendMsg = null;
var sendTimer = null;
var updateRate = 200;
var webSocketConnected = false;
var webSocketNotSupported = false;
var handle = null;
var chatab = "";
var chatrowObj = document.getElementById("chatrow");
var chatterObj = document.getElementById("chatter");
var chatmsgObj = document.getElementById("chatmsg");
var handrowObj = document.getElementById("handrow");
var handtxtObj = document.getElementById("handtxt");
var dbugObj = document.getElementById("dbug");

chatmsgObj.onkeypress = chatKeyPress;
handtxtObj.onkeypress = handKeyPress;
handtxtObj.disabled = false;
handtxtObj.value = "";

function dbugOut (text) { dbugObj.innerHTML = text; }

function displayData (data) {

   var tstamp = new Date();
   tstamp = lead0(tstamp.getDate()) + " " + lead0(tstamp.getHours()) + ":" +
            lead0(tstamp.getMinutes()) + ":" + lead0(tstamp.getSeconds())
   data = data.split("\n");
   if (data[0] == meIdent) data[1] = "<u>" + data[1] + "</u>";
   chatab += "<tr><td style=\"font-family:monospace;white-space:nowrap\">" +
             tstamp + "</td><th style=\"white-space:nowrap\">" +
             data[1] + ":</th><td>" + data[2] + "</td></tr>"
   chatterObj.innerHTML = "<table id=\"\" class=\"\">" + chatab + "</table>";
}

function lead0 (number) {
   if (number < 10)
      return "0" + number.toString();
   else
      return number.toString();
}

function chatKeyPress (evt) {
   var ch = String.fromCharCode(evt.charCode);
   // hmmm, Firefox 4.0b2 transmits a 0x00 - suppress!
   if (evt.charCode != 13 && evt.charCode != 0) return true;
   if (chatmsgObj.value.replace(/^\s+|\s+$/g, '').length <= 0) return false;
   ws.send(chatmsgObj.value);
   chatmsgObj.value = "";
   return false;
}

function handKeyPress (evt) {
   var ch = String.fromCharCode(evt.charCode);
   // hmmm, Firefox 4.0b2 transmits a 0x00 - suppress!
   if (evt.charCode != 13 && evt.charCode != 0) return true;
   if (handtxtObj.value.replace(/^\s+|\s+$/g, '').length <= 0) {
      handtxtObj.value = "";
      return false;
   }
   handle = handtxtObj.value;
   handrowObj.style.display = "none";
   chatrowObj.style.display = "table-row";
   webSocketOpen();
   return false;
}

function webSocketOpen () {

   if ("WebSocket" in window) {

      if (ws) return;

      ws = new WebSocket(URL);

      ws.onopen = function(evt) {
         chatterObj.innerHTML = "[open]";
         webSocketConnected = true;
         ws.send(handle);
      };

      ws.onclose = function(evt) {
         chatterObj.innerHTML += "[disconnected]";
         ws = null;
         webSocketConnected = false;
      };

      ws.onmessage = function (evt) { 
         if (evt.data == "update=max")
            updateRate = 0;
         else
         if (evt.data.substr(0,4) == "you=")
            meIdent = evt.data.substr(4);
         else
         if (evt.data.substr(0,6) == "OnNext")
            document.getElementById("OnNext").innerHTML =
               "WsLibOnNextRequest()";
         else
            displayData (evt.data);
      };

      updateRate = 200;
      chatterObj.innerHTML = "[connecting...]";
      chatmsgObj.focus();

   } else {
     if (!webSocketNotSupported) {
        chatterObj.innerHTML = "WebSocket not supported!";
        webSocketNotSupported = true;
     }
   }

   return false;
}

function revealHide (name) {
   var nameAry = document.getElementsByName(name);
   var ancObj = nameAry[0];
   var divObj = nameAry[1];
   if (divObj.style.display == "block") {
      ancObj.innerHTML = "+";
      divObj.style.display = "none";
   }
   else {
      ancObj.innerHTML = "-";
      divObj.style.display = "block";
   }
}

</script>
</body>
</html>