Added truly asynchronous support to GCDWebServerStreamedResponse

This commit is contained in:
Pierre-Olivier Latour
2014-10-14 12:40:51 -07:00
parent c4bf7b11e2
commit 514c09dc39
3 changed files with 60 additions and 5 deletions
@@ -34,6 +34,19 @@
*/ */
typedef NSData* (^GCDWebServerStreamBlock)(NSError** error); typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
/**
* The GCDWebServerAsyncStreamBlock works like the GCDWebServerStreamBlock
* except the streamed data can be returned at a later time allowing for
* truly asynchronous generation of the data.
*
* The block must return empty NSData when done or nil on error and set the
* "error" argument which is guaranteed to be non-NULL.
*
* The block must eventually call "completionBlock" passing the streamed data
* if any and the error if applicable.
*/
typedef void (^GCDWebServerAsyncStreamBlock)(GCDWebServerBodyReaderCompletionBlock completionBlock);
/** /**
* The GCDWebServerStreamedResponse subclass of GCDWebServerResponse streams * The GCDWebServerStreamedResponse subclass of GCDWebServerResponse streams
* the body of the HTTP response using a GCD block. * the body of the HTTP response using a GCD block.
@@ -46,8 +59,18 @@ typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
+ (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block; + (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block;
/** /**
* This method is the designated initializer for the class. * Creates a response with async streamed data and a given content type.
*/
+ (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
/**
* Initializes a response with streamed data and a given content type.
*/ */
- (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block; - (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block;
/**
* This method is the designated initializer for the class.
*/
- (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
@end @end
@@ -29,7 +29,7 @@
@interface GCDWebServerStreamedResponse () { @interface GCDWebServerStreamedResponse () {
@private @private
GCDWebServerStreamBlock _block; GCDWebServerAsyncStreamBlock _block;
} }
@end @end
@@ -39,7 +39,21 @@
return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type streamBlock:block]); return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type streamBlock:block]);
} }
+ (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
return ARC_AUTORELEASE([[[self class] alloc] initWithContentType:type asyncStreamBlock:block]);
}
- (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block { - (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
return [self initWithContentType:type asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
NSError* error = nil;
NSData* data = block(&error);
completionBlock(data, error);
}];
}
- (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
if ((self = [super init])) { if ((self = [super init])) {
_block = [block copy]; _block = [block copy];
@@ -54,8 +68,8 @@
ARC_DEALLOC(super); ARC_DEALLOC(super);
} }
- (NSData*)readData:(NSError**)error { - (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
return _block(error); _block(block);
} }
- (NSString*)description { - (NSString*)description {
+19 -1
View File
@@ -311,7 +311,7 @@ int main(int argc, const char* argv[]) {
fprintf(stdout, "Running in Streaming Response mode"); fprintf(stdout, "Running in Streaming Response mode");
webServer = [[GCDWebServer alloc] init]; webServer = [[GCDWebServer alloc] init];
[webServer addHandlerForMethod:@"GET" [webServer addHandlerForMethod:@"GET"
path:@"/" path:@"/sync"
requestClass:[GCDWebServerRequest class] requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) { processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
@@ -327,6 +327,24 @@ int main(int argc, const char* argv[]) {
}]; }];
}];
[webServer addHandlerForMethod:@"GET"
path:@"/async"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
__block int countDown = 10;
return [GCDWebServerStreamedResponse responseWithContentType:@"text/plain" asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSData* data = countDown ? [[NSString stringWithFormat:@"%i\n", countDown--] dataUsingEncoding:NSUTF8StringEncoding] : [NSData data];
completionBlock(data, nil);
});
}];
}]; }];
break; break;
} }