This commit is contained in:
Mars 2025-05-10 14:02:49 -04:00
parent 8809421181
commit 3c154878d3
Signed by: pupbrained
GPG key ID: 874E22DF2F9DFCB5
4 changed files with 79 additions and 42 deletions

View file

@ -142,7 +142,7 @@ namespace {
if (getsockopt(fileDescriptor, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1) if (getsockopt(fileDescriptor, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
return Err(DracError("Failed to get socket credentials (SO_PEERCRED)")); return Err(DracError("Failed to get socket credentials (SO_PEERCRED)"));
Array<char, 128> exeLinkPathBuf; Array<char, 128> exeLinkPathBuf {};
auto [out, size] = std::format_to_n(exeLinkPathBuf.data(), exeLinkPathBuf.size() - 1, "/proc/{}/exe", cred.pid); auto [out, size] = std::format_to_n(exeLinkPathBuf.data(), exeLinkPathBuf.size() - 1, "/proc/{}/exe", cred.pid);
@ -153,7 +153,7 @@ namespace {
const char* exeLinkPath = exeLinkPathBuf.data(); const char* exeLinkPath = exeLinkPathBuf.data();
Array<char, PATH_MAX> exeRealPathBuf; // NOLINT(misc-include-cleaner) - PATH_MAX is in <climits> Array<char, PATH_MAX> exeRealPathBuf {}; // NOLINT(misc-include-cleaner) - PATH_MAX is in <climits>
const isize bytesRead = readlink(exeLinkPath, exeRealPathBuf.data(), exeRealPathBuf.size() - 1); const isize bytesRead = readlink(exeLinkPath, exeRealPathBuf.data(), exeRealPathBuf.size() - 1);

View file

@ -1,9 +1,9 @@
#ifdef __APPLE__ #ifdef __APPLE__
// clang-format off // clang-format off
#include <flat_map> #include <flat_map> // std::flat_map
#include <sys/statvfs.h> #include <sys/statvfs.h> // statvfs
#include <sys/sysctl.h> #include <sys/sysctl.h> // {CTL_KERN, KERN_PROC, KERN_PROC_ALL, kinfo_proc, sysctl, sysctlbyname}
#include "src/core/package.hpp" #include "src/core/package.hpp"
#include "src/util/defs.hpp" #include "src/util/defs.hpp"
@ -292,8 +292,10 @@ namespace os {
if (statvfs("/", &vfs) != 0) if (statvfs("/", &vfs) != 0)
return Err(DracError("Failed to get disk usage")); return Err(DracError("Failed to get disk usage"));
return DiskSpace { .usedBytes = (vfs.f_blocks - vfs.f_bfree) * vfs.f_frsize, return DiskSpace {
.totalBytes = vfs.f_blocks * vfs.f_frsize }; .usedBytes = (vfs.f_blocks - vfs.f_bfree) * vfs.f_frsize,
.totalBytes = vfs.f_blocks * vfs.f_frsize,
};
} }
fn GetShell() -> Result<String> { fn GetShell() -> Result<String> {

View file

@ -7,15 +7,16 @@
#include "src/util/error.hpp" #include "src/util/error.hpp"
#include "src/util/types.hpp" #include "src/util/types.hpp"
// clang-format on // clang-format on
using util::error::DracError; using util::error::DracError;
using util::types::MediaInfo, util::types::String, util::types::Result; using util::types::MediaInfo, util::types::String, util::types::Result;
#ifdef __OBJC__ #ifdef __OBJC__
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h> // Foundation
@interface Bridge : NSObject @interface Bridge : NSObject
+ (void)fetchCurrentPlayingMetadata:(void (^)(Result<NSDictionary*, const char*>))completion; + (void)fetchCurrentPlayingMetadata:(void (^_Nonnull)(NSDictionary* __nullable, NSError* __nullable))completion;
+ (Result<String, DracError>)macOSVersion; + (NSString* __nullable)macOSVersion;
@end @end
#else #else
extern "C++" { extern "C++" {

View file

@ -4,30 +4,34 @@
#import "bridge.hpp" #import "bridge.hpp"
#import <dispatch/dispatch.h> #import <dispatch/dispatch.h>
#import <objc/runtime.h>
#include <expected> #include <expected>
#include <functional> #include <functional>
#include <memory> #include <memory>
#import <objc/runtime.h>
#include <string> #include <string>
#include <utility> #include <utility>
#include "src/util/error.hpp" #include "src/util/error.hpp"
// clang-format on // clang-format on
using util::error::DracErrorCode; using util::error::DracError, util::error::DracErrorCode;
using util::types::Err, util::types::Option, util::types::None; using util::types::Err, util::types::Option, util::types::None, util::types::Result;
using MRMediaRemoteGetNowPlayingInfoFunction = using MRMediaRemoteGetNowPlayingInfoFunction =
void (*)(dispatch_queue_t queue, void (^handler)(NSDictionary* information)); void (*)(dispatch_queue_t queue, void (^handler)(NSDictionary* information));
@implementation Bridge @implementation Bridge
+ (void)fetchCurrentPlayingMetadata:(void (^)(std::expected<NSDictionary*, const char*>))completion { + (void)fetchCurrentPlayingMetadata:(void (^)(NSDictionary* __nullable, NSError* __nullable))completion {
CFURLRef urlRef = CFURLCreateWithFileSystemPath( CFURLRef urlRef = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault, CFSTR("/System/Library/PrivateFrameworks/MediaRemote.framework"), kCFURLPOSIXPathStyle, false kCFAllocatorDefault,
CFSTR("/System/Library/PrivateFrameworks/MediaRemote.framework"),
kCFURLPOSIXPathStyle,
false
); );
if (!urlRef) { if (!urlRef) {
completion(std::unexpected("Failed to create CFURL for MediaRemote framework")); completion(nil, [NSError errorWithDomain:@"com.draconis.error" code:1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed to create CFURL for MediaRemote framework" }]);
return; return;
} }
@ -36,7 +40,7 @@ using MRMediaRemoteGetNowPlayingInfoFunction =
CFRelease(urlRef); CFRelease(urlRef);
if (!bundleRef) { if (!bundleRef) {
completion(std::unexpected("Failed to create bundle for MediaRemote framework")); completion(nil, [NSError errorWithDomain:@"com.draconis.error" code:1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed to create bundle for MediaRemote framework" }]);
return; return;
} }
@ -46,7 +50,7 @@ using MRMediaRemoteGetNowPlayingInfoFunction =
if (!mrMediaRemoteGetNowPlayingInfo) { if (!mrMediaRemoteGetNowPlayingInfo) {
CFRelease(bundleRef); CFRelease(bundleRef);
completion(std::unexpected("Failed to get MRMediaRemoteGetNowPlayingInfo function pointer")); completion(nil, [NSError errorWithDomain:@"com.draconis.error" code:1 userInfo:@{ NSLocalizedDescriptionKey : @"Failed to get MRMediaRemoteGetNowPlayingInfo function pointer" }]);
return; return;
} }
@ -58,34 +62,54 @@ using MRMediaRemoteGetNowPlayingInfoFunction =
mrMediaRemoteGetNowPlayingInfo( mrMediaRemoteGetNowPlayingInfo(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(NSDictionary* information) { ^(NSDictionary* information) {
completion( if (!information) {
information ? std::expected<NSDictionary*, const char*>(information) completion(nil, [NSError errorWithDomain:@"com.draconis.error" code:1 userInfo:@ { NSLocalizedDescriptionKey : @"No now playing information" }]);
: std::unexpected("No now playing information") return;
); }
completion(information, nil);
} }
); );
} }
+ (Result<String>)macOSVersion { + (NSString*)macOSVersion {
NSProcessInfo* processInfo = [NSProcessInfo processInfo]; NSProcessInfo* processInfo = [NSProcessInfo processInfo];
NSOperatingSystemVersion osVersion = [processInfo operatingSystemVersion]; if (!processInfo)
return nil;
NSOperatingSystemVersion osVersion = [processInfo operatingSystemVersion];
if (osVersion.majorVersion == 0)
return nil;
NSString* versionNumber = nil; NSString* versionNumber = nil;
if (osVersion.patchVersion == 0) { if (osVersion.patchVersion == 0)
versionNumber = [NSString stringWithFormat:@"%ld.%ld", osVersion.majorVersion, osVersion.minorVersion]; versionNumber = [NSString stringWithFormat:@"%ld.%ld",
} else { osVersion.majorVersion,
versionNumber = [NSString osVersion.minorVersion];
stringWithFormat:@"%ld.%ld.%ld", osVersion.majorVersion, osVersion.minorVersion, osVersion.patchVersion]; else
} versionNumber = [NSString stringWithFormat:@"%ld.%ld.%ld",
osVersion.majorVersion,
osVersion.minorVersion,
osVersion.patchVersion];
if (!versionNumber)
return nil;
NSDictionary* versionNames = NSDictionary* versionNames =
@{ @11 : @"Big Sur", @12 : @"Monterey", @13 : @"Ventura", @14 : @"Sonoma", @15 : @"Sequoia" }; @{
@11 : @"Big Sur",
@12 : @"Monterey",
@13 : @"Ventura",
@14 : @"Sonoma",
@15 : @"Sequoia"
};
NSNumber* majorVersion = @(osVersion.majorVersion); NSNumber* majorVersion = @(osVersion.majorVersion);
NSString* versionName = versionNames[majorVersion] ? versionNames[majorVersion] : @"Unknown"; NSString* versionName = versionNames[majorVersion] ? versionNames[majorVersion] : @"Unknown";
NSString* fullVersion = [NSString stringWithFormat:@"macOS %@ %@", versionNumber, versionName]; NSString* fullVersion = [NSString stringWithFormat:@"macOS %@ %@", versionNumber, versionName];
return String([fullVersion UTF8String]);
return fullVersion ? fullVersion : nil;
} }
@end @end
@ -96,25 +120,29 @@ extern "C++" {
const dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); const dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[Bridge fetchCurrentPlayingMetadata:^(std::expected<NSDictionary*, const char*> metadataResult) { [Bridge fetchCurrentPlayingMetadata:^(NSDictionary* __nullable information, NSError* __nullable error) {
if (!metadataResult) { if (error) {
result = Err(DracError(DracErrorCode::InternalError, metadataResult.error())); result = Err(DracError(DracErrorCode::InternalError, [error.localizedDescription UTF8String]));
dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore);
return; return;
} }
const NSDictionary* const metadata = *metadataResult; if (!information) {
if (!metadata) {
result = Err(DracError(DracErrorCode::InternalError, "No metadata")); result = Err(DracError(DracErrorCode::InternalError, "No metadata"));
dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore);
return; return;
} }
const NSString* const title = metadata[@"kMRMediaRemoteNowPlayingInfoTitle"]; const NSString* const title = information[@"kMRMediaRemoteNowPlayingInfoTitle"];
const NSString* const artist = metadata[@"kMRMediaRemoteNowPlayingInfoArtist"]; const NSString* const artist = information[@"kMRMediaRemoteNowPlayingInfoArtist"];
result = MediaInfo( result = MediaInfo(
title ? Option(String([title UTF8String])) : None, artist ? Option(String([artist UTF8String])) : None title
? Option(String([title UTF8String]))
: None,
artist
? Option(String([artist UTF8String]))
: None
); );
dispatch_semaphore_signal(semaphore); dispatch_semaphore_signal(semaphore);
@ -124,7 +152,13 @@ extern "C++" {
return result; return result;
} }
fn GetMacOSVersion() -> Result<String> { return [Bridge macOSVersion]; } fn GetMacOSVersion() -> Result<String> {
NSString* version = [Bridge macOSVersion];
return version
? Result<String>(String([version UTF8String]))
: Err(DracError(DracErrorCode::InternalError, "Failed to get macOS version"));
}
// NOLINTEND(misc-use-internal-linkage) // NOLINTEND(misc-use-internal-linkage)
} }