Skip to content

Instantly share code, notes, and snippets.

@tomsmeding
Created June 14, 2015 07:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomsmeding/493e9930411dcf021c9e to your computer and use it in GitHub Desktop.
Save tomsmeding/493e9930411dcf021c9e to your computer and use it in GitHub Desktop.
Simple wscat implementation that works. The npm wscat uses readline a bit strangely.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>wscat</title>
<script>
var address="",conn=null;
var inputhistory=[],historyidx=null,droppedCurrent=null;
function log(src,s){
var tr,td;
tr=document.createElement("tr");
td=document.createElement("td");
td.appendChild(document.createTextNode(src));
tr.appendChild(td);
td=document.createElement("td");
td.appendChild(document.createTextNode(s));
tr.appendChild(td);
var wslog=document.getElementById("wslog");
wslog.appendChild(tr);
wslog.scrollTop=wslog.scrollHeight;
var lastlog=wslog.children[wslog.children.length-1];
if(lastlog.scrollIntoView)lastlog.scrollIntoView();
}
function reconnect(){
if(address==""){
log("","Cannot connect to empty address.");
return;
}
if(address.slice(0,5)!="ws://"&&address.slice(0,6)!="wss://")address="ws://"+address;
if(conn){
conn.close();
log("","Reconnecting...");
} else {
log("","Connecting to '"+address+"'...");
}
conn=new WebSocket(address);
conn.addEventListener("open",function(){
log("","Connected.");
});
conn.addEventListener("message",function(msg){
log(">",msg.data);
});
conn.addEventListener("close",function(ev){
log("","Connection closed with code "+ev.code+(ev.reason?", reason '"+ev.reason+"'":""));
});
conn.onerror=function(ev){
log("","Websocket error: "+ev.message);
};
}
function sendMessage(s){
log("<",s);
conn.send(s);
}
function closeConnection(){
if(!conn){
log("","Connection already closed.");
return;
}
log("","Closing connection...");
conn.close();
conn=null;
}
var numthemes=3,themeidx=0;
function cycleTheme(){
document.body.classList.remove("theme"+themeidx);
themeidx=(themeidx+1)%numthemes;
document.body.classList.add("theme"+themeidx);
if(localStorage){
localStorage.setItem("theme",themeidx);
}
}
document.addEventListener("keydown",function(ev){
switch(ev.keyCode){
case 82: //r
if(ev.altKey){
reconnect();
ev.preventDefault();
return false;
}
break;
case 84: //t
if(ev.altKey){
cycleTheme();
ev.preventDefault();
return false;
}
break;
case 190: //.
if(ev.metaKey||ev.ctrlKey){
closeConnection();
ev.preventDefault();
return false;
}
break;
}
});
window.addEventListener("load",function(){
if(localStorage&&localStorage.getItem("theme")){
themeidx=+localStorage.getItem("theme");
document.body.classList.add("theme"+themeidx);
}
log("","Type an address to connect.");
var wsinput=document.getElementById("wsinput");
wsinput.focus();
wsinput.addEventListener("keypress",function(ev){
if(ev.keyCode==13){
if(conn)sendMessage(ev.target.value);
else {
address=ev.target.value;
reconnect();
}
droppedCurrent=null;
historyidx=null;
if(ev.target.value!=inputhistory[inputhistory.length-1])inputhistory.push(ev.target.value);
ev.target.value="";
}
});
wsinput.addEventListener("keydown",function(ev){
if(ev.keyCode==38){ //up
if(historyidx==0||inputhistory.length==0)return;
if(droppedCurrent==null){
droppedCurrent=ev.target.value;
historyidx=inputhistory.length-1;
} else {
historyidx--;
}
ev.target.value=inputhistory[historyidx];
}
if(ev.keyCode==40){ //down
if(droppedCurrent==null)return;
historyidx++;
if(historyidx==inputhistory.length){
ev.target.value=droppedCurrent;
droppedCurrent=null;
} else {
ev.target.value=inputhistory[historyidx];
}
}
});
});
window.addEventListener("beforeunload",function(ev){
var msg="You still have a connection open."
if(conn){
(ev||window.event).returnValue=msg;
return msg;
}
});
</script>
<style>
html{
height:100%;
}
body{
height:calc(100% - 20px);
margin:8px;
}
body{
font-family:Monaco,"Menlo Sans","Courier New",Courier;
font-size:14px;
}
body.theme0{
background-color:#112;
color:#b8b8b8;
}
body.theme1{
background-color:#000;
color:#bbe;
}
body.theme2{
background-color:#fff;
color:#000;
}
code{
background-color:rgba(128,128,128,0.3);
border:1px rgba(96,96,96,0.3) solid;
border-radius:4px;
}
div#wscontainer{
height:calc(100% - 200px);
/*border:1px rgba(128,128,128,0.6) solid;*/
}
div#wslogcontainer{
height:calc(100% - 20px);
overflow-y:scroll;
}
table#wslogtable{
width:100%;
}
tbody#wslog{
width:100%;
}
tbody#wslog > tr{
width:100%;
}
tbody#wslog > tr > td:first-child{
width:15px;
}
tbody#wslog > tr:nth-child(2n){
background-color:#181828;
}
input#wsinput{
background-color:#445;
border-width:0;
height:17px;
width:calc(100% - 4px);
margin-left:2px;
color:#b8b8b8;
}
/*input#wsinput:focus{outline:none;}*/
footer{
margin-top:80px;
font-size:11px;
}
</style>
</head>
<body class="theme0">
<div style="float:right">
<!--<span><code>alt-t</code>: switch theme</span>-->
<span><code>alt-r</code>: reconnect</span><br>
<span><code>cmd/ctrl-.</code>: disconnect</span>
</div>
<h1>wscat</h1>
<div id="wscontainer">
<div id="wslogcontainer"><table id="wslogtable"><tbody id="wslog"></tbody></table></div>
<input type="text" id="wsinput">
</div>
<footer>&copy; 2015 Tom Smeding</footer>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment