143 lines
3.6 KiB
D
143 lines
3.6 KiB
D
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) {
|
|
|
|
}
|
|
}
|
|
|
|
}
|