Răsfoiți Sursa

Added truly asynchronous support to GCDWebServerStreamedResponse

Pierre-Olivier Latour 11 ani în urmă
părinte
comite
514c09dc39

+ 24 - 1
GCDWebServer/Responses/GCDWebServerStreamedResponse.h

@@ -34,6 +34,19 @@
  */
 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 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;
 
 /**
- *  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;
 
+/**
+ *  This method is the designated initializer for the class.
+ */
+- (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
+
 @end

+ 17 - 3
GCDWebServer/Responses/GCDWebServerStreamedResponse.m

@@ -29,7 +29,7 @@
 
 @interface GCDWebServerStreamedResponse () {
 @private
-  GCDWebServerStreamBlock _block;
+  GCDWebServerAsyncStreamBlock _block;
 }
 @end
 
@@ -39,7 +39,21 @@
   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 {
+  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])) {
     _block = [block copy];
     
@@ -54,8 +68,8 @@
   ARC_DEALLOC(super);
 }
 
-- (NSData*)readData:(NSError**)error {
-  return _block(error);
+- (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
+  _block(block);
 }
 
 - (NSString*)description {

+ 19 - 1
Mac/main.m

@@ -311,7 +311,7 @@ int main(int argc, const char* argv[]) {
         fprintf(stdout, "Running in Streaming Response mode");
         webServer = [[GCDWebServer alloc] init];
         [webServer addHandlerForMethod:@"GET"
-                                  path:@"/"
+                                  path:@"/sync"
                           requestClass:[GCDWebServerRequest class]
                           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;
       }