Added first version.

This commit is contained in:
Andrew Lalis 2023-07-22 18:04:30 -04:00
parent ef88bbde8c
commit a8400b2796
4 changed files with 173 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
.dub
docs.json
__dummy.html
docs/
/web-logbook
web-logbook.so
web-logbook.dylib
web-logbook.dll
web-logbook.a
web-logbook.lib
web-logbook-test-*
*.exe
*.pdb
*.o
*.obj
*.lst
logbook.sqlite

17
dub.json Normal file
View File

@ -0,0 +1,17 @@
{
"authors": [
"Andrew Lalis"
],
"copyright": "Copyright © 2023, Andrew Lalis",
"dependencies": {
"d-properties": "~>1.0.4",
"d2sqlite3": "~>1.0.0",
"handy-httpd": "~>7.6.4"
},
"subConfigurations": {
"d2sqlite3": "all-included"
},
"description": "A minimal D application.",
"license": "MIT",
"name": "web-logbook"
}

11
dub.selections.json Normal file
View File

@ -0,0 +1,11 @@
{
"fileVersion": 1,
"versions": {
"d-properties": "1.0.4",
"d2sqlite3": "1.0.0",
"handy-httpd": "7.6.4",
"httparsed": "1.2.1",
"slf4d": "2.4.2",
"streams": "3.5.0"
}
}

128
source/app.d Normal file
View File

@ -0,0 +1,128 @@
import handy_httpd;
import handy_httpd.handlers.path_delegating_handler;
import slf4d;
import d_properties;
import d2sqlite3;
import std.file;
import std.conv;
import std.json;
import std.datetime;
void main() {
ServerConfig config = ServerConfig.defaultValues();
if (exists("application.properties")) {
Properties props = Properties("application.properties");
if (props.has("hostname")) {
config.hostname = props.get("hostname");
}
if (props.has("port")) {
config.port = props.get("port").to!ushort;
}
}
initDb();
HttpServer server = new HttpServer((ref HttpRequestContext ctx) {
ctx.response.addHeader("Access-Control-Allow-Origin", "*");
ctx.response.addHeader("Access-Control-Allow-Headers", "*");
if (ctx.request.method == Method.GET) {
handleLogbookRequest(ctx);
} else if (ctx.request.method == Method.POST) {
handleVisitorLog(ctx);
} else if (ctx.request.method == Method.OPTIONS) {
ctx.response.setStatus(HttpStatus.OK);
} else {
ctx.response.setStatus(HttpStatus.METHOD_NOT_ALLOWED);
}
}, config);
server.start();
}
void handleVisitorLog(ref HttpRequestContext ctx) {
infoF!"Got visitor log from %s"(ctx.request.remoteAddress);
JSONValue logBody = ctx.request.readBodyAsJson();
string name = logBody.object["name"].str;
string message = logBody.object["message"].str;
string remoteAddress = "UNKNOWN";
if (ctx.request.remoteAddress !is null) {
remoteAddress = ctx.request.remoteAddress.toString();
}
insertLogEntry(remoteAddress, name, message);
}
void handleLogbookRequest(ref HttpRequestContext ctx) {
LogEntry[] entries = getRecentLogEntries();
JSONValue entriesJson = JSONValue(JSONValue[].init);
foreach (LogEntry entry; entries) {
entriesJson.array ~= entry.toJson();
}
ctx.response.writeBodyString(entriesJson.toString(), "application/json");
}
struct LogEntry {
ulong id;
SysTime createdAt;
string remoteAddress;
string name;
string message;
JSONValue toJson() const {
JSONValue obj = JSONValue(string[string].init);
obj["id"] = JSONValue(id);
obj["createdAt"] = JSONValue(createdAt.toISOString());
obj["remoteAddress"] = JSONValue(remoteAddress);
obj["name"] = JSONValue(name);
obj["message"] = JSONValue(message);
return obj;
}
}
void initDb() {
Database db = Database("logbook.sqlite");
db.run(q"SQL
CREATE TABLE IF NOT EXISTS log_entry (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
remote_address TEXT NOT NULL,
name TEXT NOT NULL,
message TEXT NOT NULL
);
SQL");
db.close();
info("Initialized database.");
}
void insertLogEntry(string remoteAddress, string name, string message) {
Database db = Database("logbook.sqlite");
Statement stmt = db.prepare(q"SQL
INSERT INTO log_entry (remote_address, name, message)
VALUES (:addr, :name, :msg);
SQL");
stmt.bind(1, remoteAddress);
stmt.bind(2, name);
stmt.bind(3, message);
stmt.execute();
stmt.finalize();
db.close();
infoF!"Added log entry for %s @ %s"(name, remoteAddress);
}
LogEntry[] getRecentLogEntries() {
Database db = Database("logbook.sqlite");
ResultRange results = db.execute("SELECT * FROM log_entry ORDER BY created_at DESC LIMIT 5");
LogEntry[] entries;
foreach (Row row; results) {
LogEntry entry;
entry.id = row.peek!ulong(0);
string createdAtStr = row.peek!string(1);
string isoCreatedAt = createdAtStr[0 .. 4] ~ createdAtStr[5 .. 7] ~ createdAtStr[8 .. 10] ~ 'T' ~
createdAtStr[11 .. 13] ~ createdAtStr[14 .. 16] ~ createdAtStr[17 .. $];
entry.createdAt = SysTime.fromISOString(isoCreatedAt);
entry.remoteAddress = row.peek!string(2);
entry.name = row.peek!string(3);
entry.message = row.peek!string(4);
entries ~= entry;
}
return entries;
}