hotpocket/services/apple/Shared (App)/HPRPCClient.m

187 lines
6.5 KiB
Objective-C

//
// HPRPCClient.m
// HotPocket
//
// Created by Tomek Wójcik on 19/09/2025.
//
#import "HPRPCClient.h"
@implementation HPRPCCallResult
#pragma mark - HPRPCCallResult implementation
-(id)init {
if (self = [super init]) {
self.error = nil;
self.result = nil;
}
return self;
}
-(NSString *)description {
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:2];
if (self.error == nil) {
[attributes setValue:@"(null)" forKey:@"error"];
} else {
[attributes setValue:self.error forKey:@"error"];
}
if (self.result == nil) {
[attributes setValue:@"(null)" forKey:@"result"];
} else {
[attributes setValue:self.result forKey:@"result"];
}
return [NSString stringWithFormat:@"<%@: %p; %@>", NSStringFromClass([self class]), self, attributes];
}
@end
@implementation HPRPCClient
#pragma mark - Initialization
-(id)initWithBaseURL:(nullable NSURL *)baseURL accessToken:(nullable NSString *)accessToken {
if (self = [super init]) {
self.baseURL = baseURL;
self.accessToken = accessToken;
self.session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration];
}
return self;
}
#pragma mark - Public interface
-(BOOL)hasCredentials {
return (self.baseURL != nil && self.accessToken != nil);
}
-(BOOL)call:(nullable NSString *)callId method:(NSString *)method params:(NSArray *)params endopoint:(nullable NSString *)endpoint completionHandler:(HPRPCClientCompletionHandler)completionHandler {
if (self.baseURL == nil) {
return NO;
}
if (callId == nil) {
callId = [[NSUUID UUID] UUIDString];
}
if (endpoint == nil) {
endpoint = @"/rpc/";
}
NSBundle *mainBundle = [NSBundle mainBundle];
NSDictionary *payload = @{
@"jsonrpc": @"2.0",
@"id": callId,
@"method": method,
@"params": params,
};
NSError *error;
NSData *jsonPayload = [NSJSONSerialization dataWithJSONObject:payload options:0 error:&error];
if (!jsonPayload) {
NSLog(@"-[HPRPCClient call:method:params:endpoint:] Unable to serialize payload: error=`%@`", error);
HPRPCCallResult *result = [[HPRPCCallResult alloc] init];
result.error = error;
if (self.delegate != nil) {
[self.delegate rpcClientDidReceiveResult:result callId:callId];
}
return NO;
}
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self.baseURL resolvingAgainstBaseURL:NO];
urlComponents.path = endpoint;
urlComponents.queryItems = @[
[NSURLQueryItem queryItemWithName:@"method" value:method],
];
NSURL *callURL = [urlComponents URL];
#ifdef DEBUG
NSLog(@"-[HPRPCClient call:method:params:endpoint:] callURL=`%@`", callURL.absoluteString);
#endif
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:callURL];
request.HTTPMethod = @"POST";
request.HTTPBody = jsonPayload;
[request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request setValue:[[mainBundle infoDictionary] valueForKey:@"HPRPCClientOrigin"] forHTTPHeaderField:@"Origin"];
if (self.accessToken != nil) {
NSString *authorization = [NSString stringWithFormat:@"Bearer %@", self.accessToken];
[request setValue:authorization forHTTPHeaderField:@"Authorization"];
}
NSString *build = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
NSString *userAgent = [NSString stringWithFormat:@"HotPocket/%@", build];
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
HPRPCCallResult *result = [[HPRPCCallResult alloc] init];
if (error != nil) {
result.error = error;
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode != 200) {
result.error = [[NSError alloc] initWithDomain:@"pl.bthlabs.HotPocket.HPRPCClient" code:-32000 userInfo:@{
@"callId": callId,
@"url": httpResponse.URL,
@"statusCode": [NSNumber numberWithInteger:httpResponse.statusCode],
@"response": response,
}];
} else {
NSError *jsonDecodeError;
NSDictionary *callResult = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingTopLevelDictionaryAssumed error:&error];
if (jsonDecodeError != nil) {
result.error = jsonDecodeError;
} else {
NSDictionary *rpcError = [callResult valueForKey:@"error"];
if (rpcError != nil) {
NSNumber *rpcErrorCode = [rpcError valueForKey:@"code"];
if (rpcErrorCode == nil) {
rpcErrorCode = [NSNumber numberWithInt:-32000];
}
result.error = [[NSError alloc] initWithDomain:@"pl.bthlabs.HotPocket.HPRPCClient" code:[rpcErrorCode integerValue] userInfo:rpcError];
} else {
result.result = [callResult valueForKey:@"result"];
}
}
}
}
if (completionHandler) {
completionHandler(callId, result);
}
}];
[task resume];
return YES;
}
-(BOOL)call:(nullable NSString *)callId method:(NSString *)method params:(NSArray *)params endopoint:(nullable NSString *)endpoint {
return [self call:callId method:method params:params endopoint:endpoint completionHandler:^(NSString *callId, HPRPCCallResult *result) {
if (self.delegate != nil) {
[self.delegate rpcClientDidReceiveResult:result callId:callId];
}
}];
}
-(BOOL)call:(nullable NSString *)callId method:(NSString *)method params:(NSArray *)params {
return [self call:callId method:method params:params endopoint:nil];
}
-(BOOL)call:(nullable NSString *)callId method:(NSString *)method params:(NSArray *)params completionHandler:(HPRPCClientCompletionHandler)completionHandler {
return [self call:callId method:method params:params endopoint:nil completionHandler:completionHandler];
}
@end