Eerste commit

This commit is contained in:
Chris Josten 2020-12-12 17:14:09 +01:00
commit f84a4f321c
13 changed files with 438 additions and 0 deletions

76
source/app.d Normal file
View file

@ -0,0 +1,76 @@
import std.functional;
import vibe.vibe;
import kerstezelprotocol;
struct VertaalContext {
import std.typetuple;
// Throw an error when an translation string is missing/mistyped.
enum enforceExistingKeys = true;
// The list of supported languages (the same family of languages will
// automatically be matched to the closest candidate, e.g. en_GB->en_US)
alias languages = TypeTuple!("en_GB", "nl_NL");
// The base name of the translation files - the full names will be
// kerstman.en_US.po and kerstman.de_DE.po. Any number of these mixin
// statements can be used.
mixin translationModule!"kerstman";
}
@translationContext!VertaalContext
class KerstezelService {
@path("/")
void getIndex() {
render!"index.dt";
}
@path("/arreslee")
void getArreslee(scope WebSocket bus) {
runTask((WebSocket bus) {
while(bus.connected) {
string commando = bus.receiveText;
if (commando == "trommel") {
kerstmanTaak.send(TrommelCommando());
} else {
logInfo("Onbekend commando:" ~ commando);
}
}
}, bus);
while (bus.connected) {
int uitzend_aantal = staatGebeurtenis.emitCount;
bus.send(staat.serializeToJsonString());
// Wordt elke 30 seconden wakker om de verbinding in leven
// te houden en/of te detecteren dat deze juist gestopt is.
staatGebeurtenis.wait(30.seconds, uitzend_aantal);
}
}
}
void main() {
import vibe.http.router;
auto settings = new HTTPServerSettings;
settings.port = 8090;
settings.bindAddresses = ["::", "0.0.0.0"];
auto router = new URLRouter;
router.registerWebInterface(new KerstezelService);
auto fsettings = new HTTPFileServerSettings;
fsettings.serverPathPrefix = "/statisch";
router.get("*", serveStaticFiles("statisch/", fsettings));
listenHTTP(settings, router);
logInfo("Please open http://127.0.0.1:8080/ in your browser.");
if (!listenTCP(9305, toDelegate(&kerstezelProtocolLuister), "0.0.0.0")) {
logWarn("Kon kerstezelProtocol niet starten");
}
runApplication();
}

142
source/kerstezelprotocol.d Normal file
View file

@ -0,0 +1,142 @@
import std.array;
import std.algorithm;
import std.datetime;
import std.exception;
import std.format;
import std.random;
import std.range;
import vibe.vibe;
immutable size_t BUF_SIZE = 2048;
struct Staat {
bool verbondenMetKerstman = false;
long trommelenVerbodenTot = 0;
}
shared Staat staat;
shared ManualEvent staatGebeurtenis;
shared Task kerstmanTaak;
__gshared TaskMutex mutex;
shared static this() {
staatGebeurtenis = createSharedManualEvent();
mutex = new TaskMutex();
}
struct TrommelCommando {};
@trusted
void kerstezelProtocolLuister(TCPConnection verbinding) nothrow {
try {
auto lock = scopedMutexLock(mutex);
new Sessie(verbinding).voerUit();
} catch (Exception e) {
logException(e, "Kon mutex niet verkrijgen");
}
}
class UnicodeUitzondering : Exception {
mixin basicExceptionCtors;
}
class ProtocolUitzondering : Exception {
mixin basicExceptionCtors;
}
class Sessie {
private TCPConnection l_verbinding;
private bool blijfBezig = true;
private SysTime trommelenVerbodenTot;
private bool trommelenVerboden = false;
@safe
this(TCPConnection verbinding) nothrow {
this.l_verbinding = verbinding;
}
@trusted
public void voerUit() nothrow {
logInfo("Nieuwe sessie probeert te verbinden");
try {
handGeven();
logInfo("Sessie is verbonden");
staat.verbondenMetKerstman = true;
kerstmanTaak = Task.getThis();
staatGebeurtenis.emit();
while(true) {
auto tijdsduur = trommelenVerboden
? min(trommelenVerbodenTot - Clock.currTime, seconds(30))
: seconds(30);
bool received = receiveTimeout(tijdsduur,
(TrommelCommando com) {
logInfo("Trommelen");
auto now = Clock.currTime();
if (trommelenVerboden) return;
l_verbinding.write("trommel\n");
l_verbinding.flush();
trommelenVerboden = true;
trommelenVerbodenTot = now + seconds(30);
staat.trommelenVerbodenTot = trommelenVerbodenTot.toUnixTime;
staatGebeurtenis.emit();
ubyte[] read = l_verbinding.readLine(BUF_SIZE, "\n");
enforce!ProtocolUitzondering(read.equal("oké"), "Kerstman deed geen erkenning, maar deed %s".format(read));
}
);
if (Clock.currTime() >= trommelenVerbodenTot) {
trommelenVerboden = false;
staatGebeurtenis.emit();
}
if (!received) {
l_verbinding.write("ping\n");
l_verbinding.flush();
ubyte[] read = l_verbinding.readLine(BUF_SIZE, "\n");
enforce!ProtocolUitzondering(read.equal("pong"), "Kerstman pongde niet terug, maar deed %s".format(read));
}
}
} catch (ProtocolUitzondering u) {
logException(u, "Protocoluitzondering");
} catch (Exception e) {
logException(e, "Andere uitzondering");
} finally {
logInfo("Sessie verbroken");
staat.verbondenMetKerstman = false;
staatGebeurtenis.emit();
sluit();
}
}
@safe
private void handGeven () {
// Maak een begroeting
string begroeting2 = "e gaat 'ie?\n";
// Maak het irritant om het met de hand te doen :P
int aantal = cast(int) (rndGen.front % 200) + 100;
logInfo("Aantal: %d".format(aantal));
rndGen.popFront();
string begroeting = "ho".replicate(aantal) ~ begroeting2;
l_verbinding.write(begroeting);
l_verbinding.flush();
// Wacht op een antwoord in de vorm van (aantal * "go" + "ed!")
ubyte[] data = l_verbinding.readLine(BUF_SIZE, "\n");
string expected = "go".replicate(aantal) ~ "ed";
enforce!ProtocolUitzondering(equal(data, expected), "Ongeldige handdruk");
}
@safe
private void sluit() nothrow {
try {
l_verbinding.close();
} catch(Exception e) {
}
}
}