mirror of
https://github.com/samsonjs/samhuri.net-ios.git
synced 2026-03-25 09:25:47 +00:00
154 lines
7 KiB
Objective-C
154 lines
7 KiB
Objective-C
#import <CoreFoundation/CFString.h>
|
|
#import <CoreFoundation/CFURL.h>
|
|
#import <Foundation/NSJSONSerialization.h>
|
|
#import <Foundation/NSThread.h>
|
|
#import <Foundation/NSURLError.h>
|
|
#import <Foundation/NSURL.h>
|
|
#import <Foundation/NSURLResponse.h>
|
|
#import "NSURLConnection+PromiseKit.h"
|
|
#import <OMGHTTPURLRQ/OMGHTTPURLRQ.h>
|
|
#import <OMGHTTPURLRQ/OMGUserAgent.h>
|
|
#import "PromiseKit/Promise.h"
|
|
|
|
NSString const*const PMKURLErrorFailingURLResponse = PMKURLErrorFailingURLResponseKey;
|
|
NSString const*const PMKURLErrorFailingData = PMKURLErrorFailingDataKey;
|
|
|
|
|
|
@implementation NSURLConnection (PromiseKit)
|
|
|
|
+ (PMKPromise *)GET:(id)urlFormat, ... {
|
|
if ([urlFormat isKindOfClass:[NSString class]]) {
|
|
va_list arguments;
|
|
va_start(arguments, urlFormat);
|
|
urlFormat = [[NSString alloc] initWithFormat:urlFormat arguments:arguments];
|
|
va_end(arguments);
|
|
} else if ([urlFormat isKindOfClass:[NSURL class]]) {
|
|
NSMutableURLRequest *rq = [[NSMutableURLRequest alloc] initWithURL:urlFormat];
|
|
[rq setValue:OMGUserAgent() forHTTPHeaderField:@"User-Agent"];
|
|
return [self promise:rq];
|
|
} else {
|
|
urlFormat = [urlFormat description];
|
|
}
|
|
return [self promise:[OMGHTTPURLRQ GET:urlFormat:nil]];
|
|
}
|
|
|
|
+ (PMKPromise *)GET:(NSString *)url query:(NSDictionary *)params {
|
|
return [self promise:[OMGHTTPURLRQ GET:url:params]];
|
|
}
|
|
|
|
+ (PMKPromise *)POST:(NSString *)url formURLEncodedParameters:(NSDictionary *)params {
|
|
return [self promise:[OMGHTTPURLRQ POST:url:params]];
|
|
}
|
|
|
|
+ (PMKPromise *)POST:(NSString *)urlString JSON:(NSDictionary *)params {
|
|
return [self promise:[OMGHTTPURLRQ POST:urlString JSON:params]];
|
|
}
|
|
|
|
+ (PMKPromise *)PUT:(NSString *)url formURLEncodedParameters:(NSDictionary *)params {
|
|
return [self promise:[OMGHTTPURLRQ PUT:url:params]];
|
|
}
|
|
|
|
+ (PMKPromise *)DELETE:(NSString *)url formURLEncodedParameters:(NSDictionary *)params {
|
|
return [self promise:[OMGHTTPURLRQ DELETE:url:params]];
|
|
}
|
|
|
|
+ (PMKPromise *)promise:(NSURLRequest *)rq {
|
|
return [PMKPromise new:^(PMKPromiseFulfiller fluff, PMKPromiseRejecter rejunk){
|
|
[NSURLConnection sendAsynchronousRequest:rq queue:PMKOperationQueue() completionHandler:^(id rsp, id data, NSError *urlError) {
|
|
|
|
assert(![NSThread isMainThread]);
|
|
|
|
PMKPromiseFulfiller fulfiller = ^(id responseObject){
|
|
fluff(PMKManifold(responseObject, rsp, data));
|
|
};
|
|
PMKPromiseRejecter rejecter = ^(NSError *error){
|
|
id userInfo = error.userInfo.mutableCopy ?: [NSMutableDictionary new];
|
|
if (data) userInfo[PMKURLErrorFailingDataKey] = data;
|
|
if (rsp) userInfo[PMKURLErrorFailingURLResponseKey] = rsp;
|
|
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
|
|
rejunk(error);
|
|
};
|
|
|
|
NSStringEncoding (^stringEncoding)() = ^NSStringEncoding{
|
|
id encodingName = [rsp textEncodingName];
|
|
if (encodingName) {
|
|
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName);
|
|
if (encoding != kCFStringEncodingInvalidId)
|
|
return CFStringConvertEncodingToNSStringEncoding(encoding);
|
|
}
|
|
return NSUTF8StringEncoding;
|
|
};
|
|
|
|
if (urlError) {
|
|
rejecter(urlError);
|
|
} else if (![rsp isKindOfClass:[NSHTTPURLResponse class]]) {
|
|
fulfiller(data);
|
|
} else if ([rsp statusCode] < 200 || [rsp statusCode] >= 300) {
|
|
id info = @{
|
|
NSLocalizedDescriptionKey: @"The server returned a bad HTTP response code",
|
|
NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString,
|
|
NSURLErrorFailingURLErrorKey: rq.URL
|
|
};
|
|
id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:info];
|
|
rejecter(err);
|
|
} else if (PMKHTTPURLResponseIsJSON(rsp)) {
|
|
// work around ever-so-common Rails workaround: https://github.com/rails/rails/issues/1742
|
|
if ([rsp expectedContentLength] == 1 && [data isEqualToData:[NSData dataWithBytes:" " length:1]])
|
|
return fulfiller(nil);
|
|
|
|
NSError *err = nil;
|
|
id json = [NSJSONSerialization JSONObjectWithData:data options:PMKJSONDeserializationOptions error:&err];
|
|
if (!err) {
|
|
fulfiller(json);
|
|
} else {
|
|
id userInfo = err.userInfo.mutableCopy;
|
|
if (data) {
|
|
NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding()];
|
|
if (string)
|
|
userInfo[PMKURLErrorFailingStringKey] = string;
|
|
}
|
|
long long length = [rsp expectedContentLength];
|
|
id bytes = length <= 0 ? @"" : [NSString stringWithFormat:@"%lld bytes", length];
|
|
id fmt = @"The server claimed a%@ JSON response, but decoding failed with: %@";
|
|
userInfo[NSLocalizedDescriptionKey] = [NSString stringWithFormat:fmt, bytes, userInfo[NSLocalizedDescriptionKey]];
|
|
err = [NSError errorWithDomain:err.domain code:err.code userInfo:userInfo];
|
|
rejecter(err);
|
|
}
|
|
#ifdef UIKIT_EXTERN
|
|
} else if (PMKHTTPURLResponseIsImage(rsp)) {
|
|
UIImage *image = [[UIImage alloc] initWithData:data];
|
|
image = [[UIImage alloc] initWithCGImage:[image CGImage] scale:image.scale orientation:image.imageOrientation];
|
|
if (image)
|
|
fulfiller(image);
|
|
else {
|
|
id info = @{
|
|
NSLocalizedDescriptionKey: @"The server returned invalid image data",
|
|
NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString,
|
|
NSURLErrorFailingURLErrorKey: rq.URL
|
|
};
|
|
id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:info];
|
|
rejecter(err);
|
|
}
|
|
#endif
|
|
} else if (PMKHTTPURLResponseIsText(rsp)) {
|
|
id str = [[NSString alloc] initWithData:data encoding:stringEncoding()];
|
|
if (str)
|
|
fulfiller(str);
|
|
else {
|
|
id info = @{
|
|
NSLocalizedDescriptionKey: @"The server returned invalid string data",
|
|
NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString,
|
|
NSURLErrorFailingURLErrorKey: rq.URL
|
|
};
|
|
id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:info];
|
|
rejecter(err);
|
|
}
|
|
} else
|
|
fulfiller(data);
|
|
}];
|
|
}];
|
|
|
|
#undef fulfiller
|
|
}
|
|
|
|
@end
|