From 58028ca68ecd9310bd447e459268ef8b70bfe6c7 Mon Sep 17 00:00:00 2001 From: marisa Date: Mon, 19 Feb 2024 01:03:40 -0300 Subject: [PATCH] Initial WebFinger - Add headers to PRequest --- source/main.d | 87 +++++++++++++++++++++++++-------------- source/net/request_pool.d | 19 ++++++--- source/singletons.d | 2 + source/webfinger.d | 51 +++++++++++++++++++++++ 4 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 source/webfinger.d diff --git a/source/main.d b/source/main.d index deec66b..07284a9 100644 --- a/source/main.d +++ b/source/main.d @@ -1,48 +1,73 @@ module main; +import std.json; + +import requests; import slf4d; import slf4d.default_provider; import config; import singletons; import db.db; +import net.request_pool; +import webfinger; -int main() { +void commonInit() { auto provider = new DefaultProvider(true, Levels.DEBUG); configureLoggingProvider(provider); - Config cfg = new Config(); + RP = new RequestPool(); + RP.startBackground(); +} - try { - cfg.load(); - } catch (Exception e) { - error(e); - return 21; - } - - DBSettings dbSettings; - auto dbCfg = cfg.v["db"]; - with (dbSettings) { - host = dbCfg["host"].str; - port = cast(ushort) dbCfg["port"].integer; - username = dbCfg["username"].str; - password = dbCfg["password"].str; - dbname = dbCfg["dbName"].str; - - switch (dbCfg["connector"].str) { - case "postgresql": - connector = DBConnector.DB_PGSQL; - break; - default: - break; - } - } - - Db = new DB(dbSettings); - Db.connect(); +void main() { + commonInit(); scope (exit) - Db.close(); + RP.stop(); - return 0; + JSONValue js = requestAcct("localhost:8080", "admin"); + + infoF!"Response body: %s"(js.toJSON(true)); } + +//int main() { +// auto provider = new DefaultProvider(true, Levels.DEBUG); +// configureLoggingProvider(provider); +// +// Config cfg = new Config(); +// +// try { +// cfg.load(); +// } catch (Exception e) { +// error(e); +// return 21; +// } +// +// DBSettings dbSettings; +// auto dbCfg = cfg.v["db"]; +// with (dbSettings) { +// host = dbCfg["host"].str; +// port = cast(ushort) dbCfg["port"].integer; +// username = dbCfg["username"].str; +// password = dbCfg["password"].str; +// dbname = dbCfg["dbName"].str; +// +// switch (dbCfg["connector"].str) { +// case "postgresql": +// connector = DBConnector.DB_PGSQL; +// break; +// default: +// break; +// } +// } +// +// Db = new DB(dbSettings); +// Db.connect(); +// +// scope (exit) +// Db.close(); +// +// return 0; +//} +// diff --git a/source/net/request_pool.d b/source/net/request_pool.d index 9453465..78c9a5e 100644 --- a/source/net/request_pool.d +++ b/source/net/request_pool.d @@ -13,6 +13,7 @@ struct PRequest { string url; string method = "GET"; QueryParam[] params; + string[string] headers; string body = ""; string contentType = "text/plain"; @@ -33,19 +34,25 @@ class RequestPool { this.m_taskPool = new TaskPool(this.m_totalWorkers); } - void request(PRequest request) { + Response request(PRequest request, bool blocking = false) { auto t = task(&this.m_run, request); this.m_taskPool.put(t); + + if (blocking) + return t.yieldForce(); + + return null; } void stop() { this.m_taskPool.finish(true); } - private void m_run(PRequest request) { + Response m_run(PRequest request) { Request rq = Request(); + rq.addHeaders(request.headers); - _l.debugF!"Requesting [%s] %s"(request.method, request.url); + _l.debugF!"[%s] %s"(request.method, request.url); Response rs; @@ -60,10 +67,10 @@ class RequestPool { default: errorF!"Unknown request method: %s"(request.method); - return; - break; + return null; } - _l.debugF!"Request %s result code: %d"(request.url, rs.code); + _l.debugF!"[%s] %s result code: %d"(request.method, request.url, rs.code); + return rs; } } diff --git a/source/singletons.d b/source/singletons.d index d91aea1..7fdaf29 100644 --- a/source/singletons.d +++ b/source/singletons.d @@ -1,5 +1,7 @@ module singletons; import db.db; +import net.request_pool; DB Db; +RequestPool RP; diff --git a/source/webfinger.d b/source/webfinger.d new file mode 100644 index 0000000..c917b3a --- /dev/null +++ b/source/webfinger.d @@ -0,0 +1,51 @@ +module webfinger; + +import std.algorithm; +import std.array; +import std.format; +import std.json; +import std.typecons; + +import requests; + +import net.request_pool; +import singletons; + +enum AcceptedWebfingerContentType = "application/jrd+json, application/json"; + +private bool checkValidWebfingerResponse(Response rs) { + + return AcceptedWebfingerContentType.canFind(rs.responseHeaders()["content-type"].split(";")[0]); +} + +PRequest buildRequest(string uri, string[string] params) { + PRequest rq = PRequest(); + + rq.method = "GET"; + rq.url = format("http://%s/.well-known/webfinger", uri); + rq.headers["Accept"] = AcceptedWebfingerContentType; + + QueryParam[] p; + + foreach (k, v; params) + p ~= tuple!("key", "value")(k, v); + + rq.params = p; + + return rq; +} + +PRequest buildAcctRequest(string uri, string acct) { + string[string] params = ["resource": format("acct:%s@%s", acct, uri)]; + + return buildRequest(uri, params); +} + +JSONValue requestAcct(string uri, string acct) { + Response rs = RP.request(buildAcctRequest(uri, acct), true); + + if (checkValidWebfingerResponse(rs) == false) + throw new Exception("Invalid webfinger response"); + + return parseJSON(rs.responseBody().toString()); +}