122 lines
3.2 KiB
D
122 lines
3.2 KiB
D
/**
|
|
Following along the tutorial at
|
|
https://vibed.org/blog/posts/a-scalable-chat-room-service-in-d
|
|
|
|
More notes at https://wiki.jon.geek.nz/D
|
|
|
|
Add the D apt respository in /etc/apt/sources.list.d/dlang.list:
|
|
|
|
deb http://netcologne.dl.sourceforge.net/project/d-apt/ d-apt main
|
|
|
|
Then get the apt key, and install the things:
|
|
|
|
sudo apt-get update
|
|
sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring
|
|
sudo apt-get install dmd-bin dcd dub
|
|
*/
|
|
|
|
import vibe.d;
|
|
|
|
final class Room {
|
|
RedisDatabase db;
|
|
string room;
|
|
RedisList!string messages;
|
|
ManualEvent messageEvent;
|
|
|
|
this(RedisDatabase db, string room) {
|
|
this.db = db;
|
|
this.room = room;
|
|
this.messages = db.getAsList!string("webchat_" ~ room);
|
|
messageEvent = createManualEvent();
|
|
}
|
|
|
|
void addMessage(string nick, string message) {
|
|
messages.insertBack(nick ~ ": " ~ message);
|
|
messageEvent.emit();
|
|
//messages ~= nick ~ ": " ~ message;
|
|
}
|
|
|
|
void waitForMessage(long next_message) {
|
|
while (messages.length <= next_message) {
|
|
messageEvent.wait();
|
|
}
|
|
}
|
|
}
|
|
|
|
final class WebChat {
|
|
private {
|
|
Room[string] rooms;
|
|
RedisDatabase db;
|
|
}
|
|
|
|
this() {
|
|
db = connectRedis("127.0.0.1").getDatabase(0);
|
|
}
|
|
|
|
// Uses vibe.d magic method names - in this case, GET /
|
|
void get() {
|
|
render!("index.dt");
|
|
}
|
|
|
|
// Uses vibe.d magic method names - in this case, GET /hello
|
|
void getHello() {
|
|
render!("hello.dt");
|
|
}
|
|
|
|
// GET /room
|
|
void getRoom(string room, string nick) {
|
|
auto messages = getOrCreateRoom(room).messages;
|
|
render!("room.dt", room, nick, messages);
|
|
}
|
|
|
|
// POST /room
|
|
void postRoom(string room, string nick, string message) {
|
|
if (message.length)
|
|
getOrCreateRoom(room).addMessage(nick, message);
|
|
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(db, room);
|
|
}
|
|
}
|
|
|
|
shared static this()
|
|
{
|
|
auto router = new URLRouter;
|
|
router.registerWebInterface(new WebChat);
|
|
|
|
// If nothing else matches, try serving it from public
|
|
router.get("*", serveStaticFiles("public/"));
|
|
|
|
auto settings = new HTTPServerSettings;
|
|
settings.port = 8083;
|
|
// settings.bindAddresses = ["::", "0.0.0.0"];
|
|
listenHTTP(settings, router);
|
|
|
|
logInfo("Please open http://127.0.0.1:%d/ in your browser.".format(settings.port));
|
|
}
|