diff --git a/public/chat.js b/public/chat.js new file mode 100644 index 0000000..8b2c24a --- /dev/null +++ b/public/chat.js @@ -0,0 +1,25 @@ +function sendMessage() +{ + var msg = document.getElementById("inputLine") + socket.send(msg.value); + msg.value = ""; + return false; +} + +function connect(room, name) +{ + socket = new WebSocket("ws://127.0.0.1:8080/ws?room="+encodeURIComponent(room)+"&name="+encodeURIComponent(name)); + + socket.onmessage = function(message) { + var history = document.getElementById("history"); + var previous = history.innerHTML.trim(); + if (previous.length) previous = previous + "\n"; + history.innerHTML = previous + message.data; + history.scrollTop = history.scrollHeight; + } + + socket.onclose = function() { + console.log("socket closed - reconnecting..."); + connect(); + } +} diff --git a/public/main.css b/public/main.css new file mode 100644 index 0000000..50c28c2 --- /dev/null +++ b/public/main.css @@ -0,0 +1,7 @@ +textarea, input { + width: 40em; +} + +textarea { + resize: vertical; +} diff --git a/source/app.d b/source/app.d index ef5798f..0770166 100644 --- a/source/app.d +++ b/source/app.d @@ -19,10 +19,21 @@ import vibe.d; final class Room { string[] messages; + ManualEvent messageEvent; + + this() { + messageEvent = createManualEvent(); + } void addMessage(string nick, string message) { messages ~= nick ~ ": " ~ message; } + + void waitForMessage(size_t next_message) { + while (messages.length <= next_message) { + messageEvent.wait(); + } + } } final class WebChat { @@ -51,6 +62,29 @@ final class WebChat { redirect("room?room=" ~ room.urlEncode ~ "&nick=" ~ nick.urlEncode); } + // /ws?room=...&nick=... + void getWS(string room, string nick, scope WebSocket socket) { + auto r = getOrCreateRoom(room); + auto writer = runTask({ + auto next_message = r.messages.length; + while (socket.connected) { + while (next_message < r.messages.length) { + socket.send(r.messages[next_message++]); + } + r.waitForMessage(next_message); + } + }); + + while (socket.waitForData) { + auto message = socket.receiveText(); + if (message.length) { + r.addMessage(nick, message); + } + } + + writer.join(); + } + private Room getOrCreateRoom(string room) { if (auto pr = room in rooms) return *pr; return rooms[room] = new Room; @@ -67,7 +101,7 @@ shared static this() auto settings = new HTTPServerSettings; settings.port = 8083; - settings.bindAddresses = ["::1", "127.0.0.1"]; + // settings.bindAddresses = ["::", "0.0.0.0"]; listenHTTP(settings, router); logInfo("Please open http://127.0.0.1:%d/ in your browser.".format(settings.port)); diff --git a/views/room.dt b/views/room.dt index f7d65f5..2b1177b 100644 --- a/views/room.dt +++ b/views/room.dt @@ -1,17 +1,19 @@ doctype html html head + title #{room} - Webchat - style. - textarea, input { width: 100%; } - textarea { resize: vertical; } + style(type="text/css", src="main.css") body + - import vibe.data.json; + script(src="chat.js") + script connect(#{Json(room)}, #{Json(nick)}) h1 Room '#{room}' textarea#history(rows=20, readonly=true) - foreach (m; messages) |= m - form(action="room", method="POST") + form(action="room", method="POST", autocomplete="off", onsubmit="return sendMessage()") input(type="hidden", name="room", value=room) input(type="hidden", name="nick", value=nick) input#inputLine(type="text", name="message", autofocus=true)