Nymlist; status; connection state

This commit is contained in:
Tony Garnock-Jones 2013-10-31 17:38:38 +00:00
parent 2203795902
commit 671c5dbda6
3 changed files with 135 additions and 31 deletions

View File

@ -15,11 +15,11 @@
</head> </head>
<body> <body>
<div class="container-fluid"> <div class="container-fluid">
<div class="row-fluid"> <!-- <div class="row-fluid"> -->
<div class="span12"> <!-- <div class="span12"> -->
<h1>JS Marketplace</h1> <!-- <h1>JS Marketplace</h1> -->
</div> <!-- </div> -->
</div> <!-- </div> -->
<div class="row-fluid"> <div class="row-fluid">
<div class="span12"> <div class="span12">
<form class="form-horizontal" name="nym_form"> <form class="form-horizontal" name="nym_form">
@ -29,13 +29,23 @@
<div class="controls"> <div class="controls">
<input type="text" id="nym" name="nym" value="pseud"> <input type="text" id="nym" name="nym" value="pseud">
</div> </div>
<label class="control-label" for="status">Status:</label>
<div class="controls">
<input type="text" id="status" name="status" value="">
</div>
</div> </div>
</fieldset> </fieldset>
</form> </form>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">
<div id="chat_output" class="span12"> <div class="span9">
<h2>Messages</h2>
<div id="chat_output"></div>
</div>
<div class="span3">
<h2>Active Users</h2>
<div id="nymlist"></div>
</div> </div>
</div> </div>
<div class="row-fluid"> <div class="row-fluid">

View File

@ -100,9 +100,15 @@ function WebSocketConnection(label, wsurl, shouldReconnect) {
this.deduplicator = new Deduplicator(); this.deduplicator = new Deduplicator();
} }
WebSocketConnection.prototype.statusRoute = function (status) {
return pub([this.label + "_state", status]);
};
WebSocketConnection.prototype.relayRoutes = function () { WebSocketConnection.prototype.relayRoutes = function () {
// fresh copy each time, suitable for in-place extension/mutation // fresh copy each time, suitable for in-place extension/mutation
return [pub([this.label, __, __], 0, 1000), sub([this.label, __, __], 0, 1000)]; return [this.statusRoute(this.isConnected() ? "connected" : "disconnected"),
pub([this.label, __, __], 0, 1000),
sub([this.label, __, __], 0, 1000)];
}; };
WebSocketConnection.prototype.aggregateRoutes = function () { WebSocketConnection.prototype.aggregateRoutes = function () {
@ -119,7 +125,6 @@ WebSocketConnection.prototype.aggregateRoutes = function () {
}; };
WebSocketConnection.prototype.boot = function () { WebSocketConnection.prototype.boot = function () {
World.updateRoutes(this.aggregateRoutes());
this.reconnect(); this.reconnect();
}; };
@ -224,6 +229,10 @@ WebSocketConnection.prototype.onmessage = function (wse) {
WebSocketConnection.prototype.onclose = function (e) { WebSocketConnection.prototype.onclose = function (e) {
var self = this; var self = this;
// console.log("onclose", e); // console.log("onclose", e);
// Update routes to give clients some indication of the discontinuity
World.updateRoutes(this.aggregateRoutes());
if (this.shouldReconnect) { if (this.shouldReconnect) {
console.log("reconnecting to " + this.wsurl + " in " + this.reconnectDelay + "ms"); console.log("reconnecting to " + this.wsurl + " in " + this.reconnectDelay + "ms");
setTimeout(World.wrap(function () { self.reconnect(); }), this.reconnectDelay); setTimeout(World.wrap(function () { self.reconnect(); }), this.reconnectDelay);
@ -238,34 +247,55 @@ WebSocketConnection.prototype.onclose = function (e) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Main // Main
function outputItem(item) {
var stamp = $("<span/>").text((new Date()).toGMTString()).addClass("timestamp");
var item = $("<div/>").append([stamp].concat(item));
var o = $("#chat_output");
o.append(item);
o[0].scrollTop = o[0].scrollHeight;
return item;
}
function updateNymList(rs) { function updateNymList(rs) {
var nyms = []; var nyms = [];
var statuses = {};
for (var i = 0; i < rs.length; i++) { for (var i = 0; i < rs.length; i++) {
var p = rs[i].pattern; var p = rs[i].pattern;
if (p[0] === "broker" if (p[0] === "broker" && p[1] === 0 && p[2][1] === "says") {
&& p[1] === 0
&& p[2][1] === "says")
{
nyms.push(p[2][0]); nyms.push(p[2][0]);
} }
if (p[0] === "broker" && p[1] === 0 && p[2][1] === "status") {
statuses[p[2][0]] = p[2][2];
}
} }
console.log(nyms);
var container = $("#nymlist");
container[0].innerHTML = ""; // remove all children
for (var i = 0; i < nyms.length; i++) {
var n = $("<span/>").text(nyms[i]).addClass("nym");
var s = statuses[nyms[i]];
if (s) {
container.append($("<div/>").append([n, $("<span/>").text(s).addClass("nym_status")]));
} else {
container.append($("<div/>").append(n));
}
}
}
function outputState(state) {
outputItem([$("<span/>").text(state).addClass(state).addClass("state")])
.addClass("state_" + state);
} }
function outputUtterance(who, what) { function outputUtterance(who, what) {
var stamp = $("<span/>").text((new Date()).toGMTString()).addClass("timestamp"); outputItem([$("<span/>").text(who).addClass("nym"),
var nymLabel = $("<span/>").text(who).addClass("nym"); $("<span/>").text(what).addClass("utterance")]).addClass("utterance");
var utterance = $("<span/>").text(what).addClass("utterance");
var o = $("#chat_output");
o.append($("<div/>")
.append([stamp, nymLabel, utterance])
.addClass("utterance"));
o[0].scrollTop = o[0].scrollHeight;
} }
$(document).ready(function () { $(document).ready(function () {
$("#chat_form").submit(function (e) { e.preventDefault(); return false; }); $("#chat_form").submit(function (e) { e.preventDefault(); return false; });
$("#nym_form").submit(function (e) { e.preventDefault(); return false; }); $("#nym_form").submit(function (e) { e.preventDefault(); return false; });
$("#nym").val("nym" + Math.floor(Math.random() * 65536));
var g = new Ground(function () { var g = new Ground(function () {
console.log('starting ground boot'); console.log('starting ground boot');
@ -273,20 +303,43 @@ $(document).ready(function () {
spawnJQueryDriver(); spawnJQueryDriver();
World.spawn(new WebSocketConnection("broker", "ws://localhost:8000/", true)); World.spawn(new WebSocketConnection("broker", "ws://localhost:8000/", true));
World.spawn({ World.spawn({
// step: function () { console.log('dummy step'); }, // Monitor connection, notifying connectivity changes
state: null,
boot: function () {
World.updateRoutes([sub(["broker_state", __], 0, 1)]);
},
handleEvent: function (e) {
if (e.type === "routes") {
if (e.routes.length > 0) {
var newState = e.routes[0].pattern[1];
if (this.state != newState) {
outputState(newState);
this.state = newState;
}
}
}
}
});
World.spawn({
// Actual chat functionality
peers: new PresenceDetector(),
peerMap: {},
boot: function () { boot: function () {
World.updateRoutes(this.subscriptions()); World.updateRoutes(this.subscriptions());
}, },
nym: function () { nym: function () { return $("#nym").val(); },
return $("#nym").val(); currentStatus: function () { return $("#status").val(); },
},
subscriptions: function () { subscriptions: function () {
return [sub(["jQuery", "#send_chat", "click", __]), return [sub(["jQuery", "#send_chat", "click", __]),
sub(["jQuery", "#nym", "change", __]), sub(["jQuery", "#nym", "change", __]),
sub(["jQuery", "#status", "change", __]),
pub(["broker", 0, [this.nym(), "says", __]]), pub(["broker", 0, [this.nym(), "says", __]]),
sub(["broker", 0, [__, "says", __]], 0, 1)]; pub(["broker", 0, [this.nym(), "status", this.currentStatus()]]),
sub(["broker", 0, [__, "says", __]], 0, 1),
sub(["broker", 0, [__, "status", __]], 0, 1)];
}, },
handleEvent: function (e) { handleEvent: function (e) {
var self = this;
switch (e.type) { switch (e.type) {
case "routes": case "routes":
updateNymList(e.routes); updateNymList(e.routes);
@ -304,6 +357,7 @@ $(document).ready(function () {
} }
break; break;
case "#nym": case "#nym":
case "#status":
World.updateRoutes(this.subscriptions()); World.updateRoutes(this.subscriptions());
break; break;
default: default:

View File

@ -1,17 +1,41 @@
div.utterance span.timestamp { span.timestamp {
color: #d0d0d0; color: #d0d0d0;
} }
div.utterance span.timestamp:after { span.timestamp:after {
content: " "; content: " ";
} }
div.utterance span.nym { .utterance span.nym:after {
content: ": ";
}
span.arrived:after {
content: " arrived";
}
span.departed:after {
content: " departed";
}
div.notification {
background-color: #eeeeff;
}
span.state.connected, span.arrived {
color: #00c000; color: #00c000;
} }
div.utterance span.nym:after { span.state.disconnected, span.departed {
content: ": "; color: #c00000;
}
div.state_disconnected {
background-color: #ffeeee;
}
div.state_connected {
background-color: #eeffee;
} }
#chat_output { #chat_output {
@ -22,3 +46,19 @@ div.utterance span.nym:after {
#chat_input { #chat_input {
width: 80%; width: 80%;
} }
.nym {
color: #00c000;
}
.nym_status:before {
content: " (";
}
.nym_status:after {
content: ")";
}
.nym_status {
font-size: smaller;
}