ctucx.git: nixfiles

ctucx' nixfiles

commit 8b069b9e827ea846f18206cf0acd56ce03a80aee
parent 3af21cdd895bdc92af9fb4f4df9f654736fa47d2
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sat, 2 Apr 2022 22:58:24 +0200

pkgs: add SpeakerDaemon (tiny daemon that switches my desktop speakers on or off based on sleep-state of the mac)
1 file changed, 133 insertions(+), 0 deletions(-)
A
pkgs/SpeakerDaemon/default.nix
|
133
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/pkgs/SpeakerDaemon/default.nix b/pkgs/SpeakerDaemon/default.nix
@@ -0,0 +1,133 @@
+{stdenv, runCommand, writeText, ...}:
+
+let
+  secrets = import ../../secrets;
+
+  SpeakerDaemon = writeText "speakerDaemon.c" ''
+    #include <ctype.h>
+    #include <stdlib.h>
+    #include <stdio.h>
+
+    #include <mach/mach_port.h>
+    #include <mach/mach_interface.h>
+    #include <mach/mach_init.h>
+
+    #include <IOKit/pwr_mgt/IOPMLib.h>
+    #include <IOKit/IOMessage.h>
+
+    #include <curl/curl.h>
+
+    io_connect_t  root_port; // a reference to the Root Power Domain IOService
+
+    void MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument ) {
+        CURL *curl;
+        CURLcode res;
+        FILE *dummy_writer = fopen("/dev/null", "w");
+
+        curl_global_init(CURL_GLOBAL_ALL);
+
+        switch ( messageType ) {
+            case kIOMessageCanSystemSleep:
+                IOAllowPowerChange( root_port, (long)messageArgument );
+                break;
+
+            case kIOMessageSystemWillSleep:
+                printf("Sleep-Event!\n");
+
+                curl = curl_easy_init();
+                if (curl) {
+                    curl_easy_setopt(curl, CURLOPT_WRITEDATA,   dummy_writer);
+                    curl_easy_setopt(curl, CURLOPT_URL,         "http://10.0.0.1:5000");
+                    curl_easy_setopt(curl, CURLOPT_POSTFIELDS,  "{\"accessToken\": \"${secrets.hosts.lollo.smartied.accessToken}\", \"type\": \"SwitchStateAction\", \"deviceName\": \"modbus-20\", \"relay\": 0, \"state\": false}");
+
+                    res = curl_easy_perform(curl);
+                    if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
+
+                    curl_easy_cleanup(curl);
+                }
+
+                IOAllowPowerChange(root_port, (long)messageArgument );
+                break;
+
+            case kIOMessageSystemWillPowerOn:
+                //System has started the wake up process...
+                break;
+
+            case kIOMessageSystemHasPoweredOn:
+                printf("WakeUp-Event!\n");
+
+                curl = curl_easy_init();
+                if (curl) {
+                    curl_easy_setopt(curl, CURLOPT_WRITEDATA,  dummy_writer);
+                    curl_easy_setopt(curl, CURLOPT_URL,        "http://10.0.0.1:5000");
+                    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"accessToken\": \"${secrets.hosts.lollo.smartied.accessToken}\", \"type\": \"SwitchStateAction\", \"deviceName\": \"modbus-20\", \"relay\": 0, \"state\": true}");
+
+                    res = curl_easy_perform(curl);
+                    if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
+
+                    curl_easy_cleanup(curl);
+                }
+                break;
+
+            default:
+                break;
+        }
+        curl_global_cleanup();
+    }
+
+
+    int main( int argc, char **argv ) {
+        // notification port allocated by IORegisterForSystemPower
+        IONotificationPortRef  notifyPortRef;
+
+        // notifier object, used to deregister later
+        io_object_t notifierObject;
+        // this parameter is passed to the callback
+        void*       refCon;
+
+        // register to receive system sleep notifications
+        root_port = IORegisterForSystemPower( refCon, &notifyPortRef, MySleepCallBack, &notifierObject );
+        if ( root_port == 0 ) {
+            printf("IORegisterForSystemPower failed\n");
+            return 1;
+        }
+
+        // add the notification port to the application runloop
+        CFRunLoopAddSource( CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes );
+
+        /* Start the run loop to receive sleep notifications. Don't call CFRunLoopRun if this code
+           is running on the main thread of a Cocoa or Carbon application. Cocoa and Carbon
+           manage the main thread's run loop for you as part of their event handling
+           mechanisms.
+        */
+        CFRunLoopRun();
+
+        //Not reached, CFRunLoopRun doesn't return in this case.
+        return (0);
+    }
+  '';
+
+  buildSymlinks = runCommand "macvim-build-symlinks" {} ''
+    mkdir -p $out/bin
+    ln -s /usr/bin/gcc $out/bin
+  '';
+
+in stdenv.mkDerivation {
+  name = "SpeakerDaemon";
+  src = ./.;
+
+  nativeBuildInputs = [ buildSymlinks ];
+
+  sandboxProfile = ''
+     (allow file-read* file-write* process-exec mach-lookup)
+     ; block homebrew dependencies
+     (deny file-read* file-write* process-exec mach-lookup (subpath "/usr/local") (with no-log))
+  '';
+
+  buildPhase = "gcc -framework IOKit -framework Cocoa -lcurl -o SpeakerDaemon ${SpeakerDaemon}";
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp SpeakerDaemon $out/bin/
+  '';
+}