Herschrijf logica, voeg RPC-bouwoptie toe

This commit is contained in:
Chris Josten 2021-04-09 14:46:21 +02:00
parent 94cc2a7512
commit e0f0e6b05c
8 changed files with 156 additions and 104 deletions

View file

@ -11,5 +11,16 @@
"description": "Automatisch In-Uitschakelen Ober", "description": "Automatisch In-Uitschakelen Ober",
"license": "MIT", "license": "MIT",
"name": "mvoau", "name": "mvoau",
"configurations": [
{
"name": "WithoutRPC",
"targetType": "executable",
"versions": [] "versions": []
},
{
"name": "WithRPC",
"targetType": "executable",
"versions": ["WithRPC"]
}
]
} }

View file

@ -21,13 +21,17 @@ vibe_core_dep = dependency('vibe-core', version: '>=1.13')
systemd_dep = dependency('systemd') systemd_dep = dependency('systemd')
mvoau_ober_deps = [ddbus_dep, msgpack_d_dep, vibe_core_dep] mvoau_ober_deps = [ddbus_dep, msgpack_d_dep, vibe_core_dep]
mvoau_ober_versions = []
if get_option('RPC').enabled()
mvoau_ober_versions += ['WithRPC']
endif
executable('mvoau', executable('mvoau',
mvoau_ober_src, mvoau_ober_src,
include_directories: mvoau_ober_src_dir, include_directories: mvoau_ober_src_dir,
dependencies: [ddbus_dep, dependencies: [ddbus_dep, msgpack_d_dep, vibe_core_dep],
msgpack_d_dep, d_module_versions: mvoau_ober_versions,
vibe_core_dep],
install: true) install: true)
if systemd_dep.found() if systemd_dep.found()
@ -35,12 +39,12 @@ if systemd_dep.found()
install_dir: systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')) install_dir: systemd_dep.get_pkgconfig_variable('systemdsystemunitdir'))
endif endif
dlang = import('dlang') # dlang = import('dlang')
dlang.generate_dub_file(meson.project_name().to_lower(), meson.source_root(), #dlang.generate_dub_file(meson.project_name().to_lower(), meson.source_root(),
authors: 'Meson Team', #authors: 'Meson Team',
copyright: 'Copyright © 2018, Meson Team', #copyright: 'Copyright © 2018, Meson Team',
license: meson.project_license(), #license: meson.project_license(),
sourceFiles: mvoau_ober_src, #sourceFiles: mvoau_ober_src,
targetType: 'executable', #targetType: 'executable',
dependencies: mvoau_ober_deps #dependencies: mvoau_ober_deps
) #)

1
ober/meson_options.txt Normal file
View file

@ -0,0 +1 @@
option('RPC', type : 'feature', value : 'disabled')

View file

@ -10,7 +10,7 @@ import vibe.core.process;
import ddbus; import ddbus;
import ddbus.c_lib; import ddbus.c_lib;
import msgpackrpc; version(WithRPC) import msgpackrpc;
string appName = "Automatisch In- en Uitschakelen Ober"; string appName = "Automatisch In- en Uitschakelen Ober";
@ -21,11 +21,26 @@ extern (C) void close(int fileNo);
*/ */
struct Toep { struct Toep {
public: public:
/**
* Tijd die tussen het schakelen van GebruikerActief -> SpelerActief en SpelerActief -> Uit
* moet zitten.
*/
immutable float m_waitingTime; immutable float m_waitingTime;
/// Aantal keer dat moet worden gecontroleerd of er een gebruiker actief is.
immutable int CHECK_COUNT = 4; immutable int CHECK_COUNT = 4;
Connection m_dbusCon; Connection m_dbusCon;
bool m_keepRunning = true; bool m_keepRunning = true;
enum Staat {
Inactief,
/// Een (Unix-)gebruiker is actief op het rekentuig
GebruikersActief,
/// Een speler is actief op de mijnvervaardigingsober
SpelersActief,
/// Het rekentuig moet uit
Uit
}
this(float waitingTime) { this(float waitingTime) {
this.m_waitingTime = waitingTime / CHECK_COUNT; this.m_waitingTime = waitingTime / CHECK_COUNT;
this.m_dbusCon = connectToBus(DBusBusType.DBUS_BUS_SYSTEM); this.m_dbusCon = connectToBus(DBusBusType.DBUS_BUS_SYSTEM);
@ -43,22 +58,28 @@ public:
} }
} }
/**
* Voer de toepassing uit en treed de gebeurtenissenlus binnen.
*
* return: Afsluitcode die geretourneerd moet worden binnen main()
*/
int exec() { int exec() {
info ("Moet blokkeren:", moetBlokkeren()); info ("Gebruikers actief:", gebruikersActief());
info ("Kan afsluiten:", kanAfsluiten()); info ("Spelers actief:", spelersActief());
version(WithRPC) { version(WithRPC) {
TCPConnection conn = connectTCP(m_clientAddress, PORT); TCPConnection conn = connectTCP(m_clientAddress, PORT);
Duration sleepTime = 500.msecs; Duration sleepTime = 500.msecs;
while(!conn) { while(!conn) {
infof("Not connected, trying again in %s", sleepTime); infof("Niet verbonden, opnieuw proberen in %s", sleepTime);
sleep(sleepTime); sleep(sleepTime);
conn = connectTCP(m_clientAddress, PORT); conn = connectTCP(m_clientAddress, PORT);
} }
info("Connected!"); info("Verbonden!");
m_client = new Client(conn); m_client = new Client(conn);
writeln("Receive response: '", m_client.call!(string)("GetBootReason"), "'"); writeln("Antwoord ontvangen: '", m_client.call!(string)("GetBootReason"), "'");
} }
// Start de D-Bus-gebeurtenissenlus.
runTask({ runTask({
import vibe.core.core : yield; import vibe.core.core : yield;
while(m_dbusCon.tick() && m_keepRunning) { while(m_dbusCon.tick() && m_keepRunning) {
@ -66,12 +87,13 @@ public:
} }
}); });
// Start de gebeurtenissenlus voor de hoofdlogica.
auto taak = runTask({ auto taak = runTask({
FileDescriptor inhibitLock = FileDescriptor.none; FileDescriptor inhibitLock = FileDescriptor.none;
version(WithRPC) { /+version(WithRPC) {
FileDescriptor sleepLock = FileDescriptor.none; FileDescriptor sleepLock = FileDescriptor.none;
FileDescriptor shutdownLock = FileDescriptor.none; FileDescriptor shutdownLock = FileDescriptor.none;
} }+/
// Get interfaces // Get interfaces
BusName loginBus = busName("org.freedesktop.login1"); BusName loginBus = busName("org.freedesktop.login1");
@ -80,6 +102,7 @@ public:
PathIface loginManager = new PathIface(m_dbusCon, loginBus, loginPath, loginIFace); PathIface loginManager = new PathIface(m_dbusCon, loginBus, loginPath, loginIFace);
PathIface loginManagerProps = new PathIface(m_dbusCon, loginBus, loginPath, interfaceName("org.freedesktop.DBus.Properties")); PathIface loginManagerProps = new PathIface(m_dbusCon, loginBus, loginPath, interfaceName("org.freedesktop.DBus.Properties"));
/// Laat een slot los.
void releaseLock(ref FileDescriptor fd) { void releaseLock(ref FileDescriptor fd) {
if (fd != FileDescriptor.none) { if (fd != FileDescriptor.none) {
close(cast(int) fd); close(cast(int) fd);
@ -87,18 +110,10 @@ public:
} }
} }
MessageRouter testRouter = new MessageRouter();
MessagePattern desktopChangePattern = MessagePattern(ObjectPath("/VirtualDesktopManager"), interfaceName("org.kde.KWin.VirtualDesktopManager"), "currentChanged", true);
dbus_bus_add_match(m_dbusCon.conn, "type='signal',sender='org.kde.KWin',interface='org.kde.KWin.VirtualDesktopManager,path='/VirtualDesktopManager',member='currentChanged'", null);
testRouter.setHandler!(void, string)(desktopChangePattern, (string id) {
logf("Desktop changed: %s", id);
});
registerRouter(m_dbusCon, testRouter);
version(WithRPC) { version(WithRPC) {
// Register signal listeners // Register signal listeners
// FIXME: this does not work yet. // FIXME: this does not work yet.
MessageRouter router = new MessageRouter(); /+MessageRouter router = new MessageRouter();
MessagePattern sleepPattern = MessagePattern(loginPath, loginIFace, "PrepareForSleep", true); MessagePattern sleepPattern = MessagePattern(loginPath, loginIFace, "PrepareForSleep", true);
MessagePattern shutdownPattern = MessagePattern(loginPath, loginIFace, "PrepareForShutdown", true); MessagePattern shutdownPattern = MessagePattern(loginPath, loginIFace, "PrepareForShutdown", true);
router.setHandler!(void, bool)(sleepPattern, (bool active) { router.setHandler!(void, bool)(sleepPattern, (bool active) {
@ -124,13 +139,13 @@ public:
sleepLock = loginManager.Inhibit("sleep", appName, "Systeem op de hoogte brengen dat de ober gaat slapen", sleepLock = loginManager.Inhibit("sleep", appName, "Systeem op de hoogte brengen dat de ober gaat slapen",
"delay").to!FileDescriptor; "delay").to!FileDescriptor;
shutdownLock = loginManager.Inhibit("shutdown", appName, "Systeem op de hoogte brengen dat de ober gaat sluiten", shutdownLock = loginManager.Inhibit("shutdown", appName, "Systeem op de hoogte brengen dat de ober gaat sluiten",
"delay").to!FileDescriptor; "delay").to!FileDescriptor;+/
} }
void block() { void blokkeerAfsluiten() {
if (inhibitLock != FileDescriptor.none) return; if (inhibitLock != FileDescriptor.none) return;
Message mesg = loginManager.Inhibit("shutdown:sleep:idle:handle-suspend-key:handle-power-key", appName, "Er zijn spelers op de server", "block"); Message mesg = loginManager.Inhibit("shutdown:sleep:idle:handle-suspend-key", appName, "Er zijn spelers op de ober", "block");
inhibitLock = mesg.to!FileDescriptor; inhibitLock = mesg.to!FileDescriptor;
} }
@ -139,90 +154,97 @@ public:
// Als we om een of andere redenen deze functie verlaten, laat het slot los! // Als we om een of andere redenen deze functie verlaten, laat het slot los!
releaseLock(inhibitLock); releaseLock(inhibitLock);
version(WithRPC) { version(WithRPC) {
releaseLock(sleepLock); /+releaseLock(sleepLock);
releaseLock(shutdownLock); releaseLock(shutdownLock);+/
} }
} }
int checkCount = CHECK_COUNT; // Teller die bijhoudt wanneer we bepaalde van bepaalde staten mogen wisselen.
int afsluitNakijkTeller = CHECK_COUNT; Staat staat = Staat.Inactief;
int teller = CHECK_COUNT;
void werkAfsluitNakijkTellerBij() {
if (kanAfsluiten()) {
afsluitNakijkTeller--;
} else {
afsluitNakijkTeller = CHECK_COUNT;
}
}
while(m_keepRunning) { while(m_keepRunning) {
Staat oudeStaat = staat;
sleep(seconds(cast(long) (m_waitingTime * 60))); sleep(seconds(cast(long) (m_waitingTime * 60)));
// Check if we are already preventing shutdown // Staattransities die vanuit elke staat kunnen plaatsvinden.
if (inhibitLock != FileDescriptor.none) { if (spelersActief()) {
// We zijn op dit moment het afsluiten niet aan het blokkeren. Kijken of dat wel moet. staat = Staat.SpelersActief;
if (moetBlokkeren()) {
if (checkCount == 1) {
// Laat het slot los
releaseLock(inhibitLock);
info("Afsluitslot losgelaten.");
} else {
// Kijk nog 1 of meer maal
checkCount--;
tracef("Nog %d maal kijken of we het afsluitslot los kunnen laten", checkCount);
} }
} else { final switch(staat) {
// We kunnen niet afsluiten. De nakijkteller herstellen. case Staat.Inactief:
checkCount = CHECK_COUNT; if (spelersActief()) {
afsluitNakijkTeller = CHECK_COUNT; staat = Staat.SpelersActief;
tracef("Spelers zijn nog steeds actief. NIet afsluiten."); teller = 3;
} else if (gebruikersActief) {
staat = Staat.GebruikersActief;
teller = 3;
} else if (--teller <= 0) {
sluitAf();
staat = Staat.Uit;
} }
werkAfsluitNakijkTellerBij(); break;
} else if (moetBlokkeren()) { case Staat.GebruikersActief:
if (spelersActief()) {
teller = 3;
staat = Staat.SpelersActief;
} else if (gebruikersActief()) {
teller = 3;
} else if (--teller <= 0) {
staat = Staat.Uit;
sluitAf();
}
break;
case Staat.SpelersActief:
try { try {
block(); blokkeerAfsluiten();
info("Afsluitslot verkregen.");
} catch(DBusException e) { } catch(DBusException e) {
warning("Kon afsluitslot niet verkrijgen: ", e); warning("Kon afsluitslot niet verkrijgen: ", e);
} }
werkAfsluitNakijkTellerBij(); if (spelersActief()) {
} else if (kanAfsluiten()){ teller = 3;
if (afsluitNakijkTeller <= 1) { } else if (--teller <= 0) {
trace("We kunnen afsluiten!"); releaseLock(inhibitLock);
execute(["shutdown", "+1", "Systeem gaat afsluiten vanwege inactiviteit"]); staat = Staat.GebruikersActief;
teller = 3;
}
break;
case Staat.Uit:
info("We gaan dit programma afsluiten");
m_keepRunning = false; m_keepRunning = false;
exitEventLoop(); exitEventLoop();
} else { return;
afsluitNakijkTeller--;
tracef("Nog %s keer, dan kunnen we afsluiten!", afsluitNakijkTeller);
}
} else {
afsluitNakijkTeller = CHECK_COUNT;
trace("Niets om te doen.");
} }
tracef("Oude -> nieuwe staat: %s -> %s (teller: %d)", oudeStaat, staat, teller);
} }
}); });
int exitCode = runEventLoop(); int exitCode = runEventLoop();
// cleanup // Rommel opruimen
info("Rotzooi opruimen."); info("Rommel opruimen.");
return exitCode; return exitCode;
} }
/** /**
* Kijkt of we het afsluiten moeten blokkeren * Kijkt of we het afsluiten moeten blokkeren, oftewel, of we naar de SpelerActief-staat moeten.
*/ */
bool moetBlokkeren() { bool spelersActief() {
// Kijk of er verbindingen actief zijn naar poort ":minecraft"
auto resultaat = execute(["ss", "-H", "--query=tcp", "state", "established", "sport", "=", ":minecraft"]); auto resultaat = execute(["ss", "-H", "--query=tcp", "state", "established", "sport", "=", ":minecraft"]);
return resultaat.output.splitLines().length != 0; return resultaat.output.splitLines().length != 0;
} }
/** /**
* Kijkt of we direct af kunnen sluiten. * Kijkt of we direct af kunnen sluiten, oftewel dat we naar de Uit-staat mogen.
*/ */
bool kanAfsluiten() { bool gebruikersActief() {
auto resultaat = execute(["who"]); auto resultaat = execute(["who"]);
return resultaat.output.splitLines().length == 0; return resultaat.output.splitLines().length == 0;
} }
void sluitAf() {
version(WithRPC) m_client.notify("NotifyShutdown");
execute(["shutdown", "+1", "Systeem gaat afsluiten vanwege inactiviteit"]);
}
} }

View file

@ -1,4 +1,6 @@
module msgpackrpc.client; module msgpackrpc.client;
version(WithRPC) {
import core.atomic; import core.atomic;
import std.array; import std.array;
@ -133,3 +135,5 @@ private:
}); });
} }
} }
} // version(WithRPC)

View file

@ -1,3 +1,7 @@
module msgpackrpc; module msgpackrpc;
version(WithRPC) {
public import msgpackrpc.client; public import msgpackrpc.client;
public import msgpackrpc.server; public import msgpackrpc.server;
} // version(WithRPC)

View file

@ -1,5 +1,6 @@
module msgpackrpc.protocol; module msgpackrpc.protocol;
version(WithRPC) {
import std.exception; import std.exception;
import msgpack; import msgpack;
@ -32,3 +33,5 @@ public:
@property Value value() { return m_value; } @property Value value() { return m_value; }
} }
} // version(WithRPC)

View file

@ -1 +1,4 @@
module msgpackrpc.server; module msgpackrpc.server;
version(WithRPC) {
}