From 5b894550915496ebe978c02b3255cf0033724409 Mon Sep 17 00:00:00 2001 From: Lyncredible Date: Tue, 23 Nov 2021 07:50:48 -0800 Subject: [PATCH] Make OneDriveWebhook a Singleton class --- src/main.d | 4 ++-- src/onedrive.d | 65 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/main.d b/src/main.d index a94bfd888..2829c1e7e 100644 --- a/src/main.d +++ b/src/main.d @@ -870,7 +870,7 @@ int main(string[] args) // Do we configure to disable the upload validation routine if (cfg.getValueBool("disable_upload_validation")) sync.setDisableUploadValidation(); - + // Do we configure to disable the download validation routine if (cfg.getValueBool("disable_download_validation")) sync.setDisableDownloadValidation(); @@ -1135,7 +1135,7 @@ int main(string[] args) // delta endpoint to sync to latest. Therefore, only one sync run is // good enough to catch up for multiple notifications. for (int signalCount = 0;; signalCount++) { - const auto signalExists = receiveTimeout(dur!"seconds"(-1), (ulong _) => {}); + const auto signalExists = receiveTimeout(dur!"seconds"(-1), (ulong _) {}); if (signalExists) { notificationReceived = true; } else { diff --git a/src/onedrive.d b/src/onedrive.d index 6fc1f2665..b5cee70d7 100644 --- a/src/onedrive.d +++ b/src/onedrive.d @@ -105,28 +105,68 @@ class OneDriveException: Exception } } -shared class OneDriveWebhook { +class OneDriveWebhook { + // We need OneDriveWebhook.serve to be a static function, otherwise we would hit the member function + // "requires a dual-context, which is deprecated" warning. The root cause is described here: + // - https://issues.dlang.org/show_bug.cgi?id=5710 + // - https://forum.dlang.org/post/fkyppfxzegenniyzztos@forum.dlang.org + // The problem is deemed a bug and should be fixed in the compilers eventually. The singleton stuff + // could be undone when it is fixed. + // + // Following the singleton pattern described here: https://wiki.dlang.org/Low-Lock_Singleton_Pattern + // Cache instantiation flag in thread-local bool + // Thread local + private static bool instantiated_; + + // Thread global + private __gshared OneDriveWebhook instance_; + private string host; private ushort port; - private uint count; + private Tid parentTid; + private shared uint count; + + static OneDriveWebhook getOrCreate(string host, ushort port, Tid parentTid) { + if (!instantiated_) { + synchronized(OneDriveWebhook.classinfo) { + if (!instance_) { + instance_ = new OneDriveWebhook(host, port, parentTid); + } + + instantiated_ = true; + } + } - this(string host, ushort port) { + return instance_; + } + + private this(string host, ushort port, Tid parentTid) { this.host = host; this.port = port; + this.parentTid = parentTid; this.count = 0; } // The static serve() is necessary because spawn() does not like instance methods - static serve(shared OneDriveWebhook webhook, Tid parentTid) { - webhook.serve(parentTid); + static serve() { + // we won't create the singleton instance if it hasn't been created already + // such case is a bug which should crash the program and gets fixed + instance_.serveImpl(); + } + + // The static handle() is necessary to work around the dual-context warning mentioned above + private static void handle(Cgi cgi) { + // we won't create the singleton instance if it hasn't been created already + // such case is a bug which should crash the program and gets fixed + instance_.handleImpl(cgi); } - private void serve(Tid parentTid) { + private void serveImpl() { auto server = new RequestServer(host, port); - server.serveEmbeddedHttp!(cgi => handle(cgi, parentTid))(); + server.serveEmbeddedHttp!handle(); } - private void handle(Cgi cgi, Tid parentTid) { + private void handleImpl(Cgi cgi) { if (.debugResponse) { log.log("Webhook request: ", cgi.requestMethod, " ", cgi.requestUri); if (!cgi.postBody.empty) { @@ -159,7 +199,7 @@ final class OneDriveApi private string refreshToken, accessToken, subscriptionId; private SysTime accessTokenExpiration; private HTTP http; - private shared OneDriveWebhook webhook; + private OneDriveWebhook webhook; private SysTime subscriptionExpiration; private Duration subscriptionExpirationInterval, subscriptionRenewalInterval; private string notificationUrl; @@ -910,11 +950,12 @@ final class OneDriveApi // Kick off the webhook server first if (webhook is null) { - webhook = new shared OneDriveWebhook( + webhook = OneDriveWebhook.getOrCreate( cfg.getValueString("webhook_listening_host"), - to!ushort(cfg.getValueLong("webhook_listening_port")) + to!ushort(cfg.getValueLong("webhook_listening_port")), + thisTid ); - spawn(&OneDriveWebhook.serve, webhook, thisTid); + spawn(&OneDriveWebhook.serve); } if (!hasValidSubscription()) {