{ inputs, stdenv, runCommand, writeText, ...}: let SpeakerDaemon = writeText "speakerDaemon.c" '' #include #include #include #include #include #include #include #include #include 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"); // check if dock is connected if (system("ioreg -p IOUSB | grep '3-Port USB 2.1 Hub' 1> /dev/null") != 0) break; 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\": \"${inputs.local-secrets.hosts.lollo.smartied.accessToken}\", \"type\": \"SwitchStateAction\", \"deviceName\": \"relay-pc-speakers\", \"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\": \"${inputs.local-secrets.hosts.lollo.smartied.accessToken}\", \"type\": \"SwitchStateAction\", \"deviceName\": \"relay-pc-speakers\", \"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, ¬ifyPortRef, MySleepCallBack, ¬ifierObject ); 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/ ''; }