Kaynağa Gözat

Add ios task cancel implementation, add test case for task cancel #39

Ben Hsieh 8 yıl önce
ebeveyn
işleme
05ade3a0d8

+ 1
- 0
src/index.js Dosyayı Görüntüle

@@ -160,6 +160,7 @@ function fetch(...args:any):Promise {
160 160
     return promise
161 161
   }
162 162
   promise.cancel = (fn) => {
163
+    fn = fn || function(){}
163 164
     RNFetchBlob.cancelRequest(taskId, fn)
164 165
   }
165 166
 

+ 6
- 0
src/ios/RNFetchBlob/RNFetchBlob.m Dosyayı Görüntüle

@@ -347,6 +347,12 @@ RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
347 347
                ]);
348 348
 }
349 349
 
350
+RCT_EXPORT_METHOD(cancelRequest:(NSString *)taskId callback:(RCTResponseSenderBlock)callback) {
351
+    [RNFetchBlobNetwork cancelRequest:taskId];
352
+    callback(@[[NSNull null], taskId]);
353
+    
354
+}
355
+
350 356
 #pragma mark RNFetchBlob private methods
351 357
 
352 358
 

+ 1
- 0
src/ios/RNFetchBlobNetwork.h Dosyayı Görüntüle

@@ -35,6 +35,7 @@ typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse
35 35
 - (void) sendRequest;
36 36
 
37 37
 + (NSMutableDictionary  * _Nullable ) normalizeHeaders:(NSDictionary * _Nullable)headers;
38
++ (void) cancelRequest:(NSString *)taskId;
38 39
 - (void) sendRequest:(NSDictionary  * _Nullable )options contentLength:(long)contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId withRequest:(NSURLRequest * _Nullable)req callback:(_Nullable RCTResponseSenderBlock) callback;
39 40
 
40 41
 

+ 14
- 2
src/ios/RNFetchBlobNetwork.m Dosyayı Görüntüle

@@ -21,6 +21,8 @@
21 21
 //
22 22
 ////////////////////////////////////////
23 23
 
24
+NSMutableDictionary * taskTable;
25
+
24 26
 @interface RNFetchBlobNetwork ()
25 27
 {
26 28
     BOOL * respFile;
@@ -53,6 +55,9 @@ NSOperationQueue *taskQueue;
53 55
     if(taskQueue == nil) {
54 56
         taskQueue = [[NSOperationQueue alloc] init];
55 57
     }
58
+    if(taskTable == nil) {
59
+        taskTable = [[NSMutableDictionary alloc] init];
60
+    }
56 61
     return self;
57 62
 }
58 63
 
@@ -109,7 +114,7 @@ NSOperationQueue *taskQueue;
109 114
         respFile = NO;
110 115
     }
111 116
     NSURLSessionDataTask * task = [session dataTaskWithRequest:req];
112
-    
117
+    [taskTable setValue:task forKey:taskId];
113 118
     [task resume];
114 119
     
115 120
     // network status indicator
@@ -189,7 +194,7 @@ NSOperationQueue *taskQueue;
189 194
 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite
190 195
 {
191 196
     [self.bridge.eventDispatcher
192
-     sendDeviceEventWithName:@"RNFetchBlobProgress"
197
+     sendDeviceEventWithName:@"RNFetchBlobProgress-upload"
193 198
      body:@{
194 199
             @"taskId": taskId,
195 200
             @"written": [NSString stringWithFormat:@"%d", totalBytesWritten],
@@ -198,6 +203,13 @@ NSOperationQueue *taskQueue;
198 203
      ];
199 204
 }
200 205
 
206
++ (void) cancelRequest:(NSString *)taskId
207
+{
208
+    NSURLSessionDataTask * task = (NSURLSessionDataTask *)[taskTable objectForKey:taskId];
209
+    if(task != nil && task.state == NSURLSessionTaskStateRunning)
210
+        [task cancel];
211
+}
212
+
201 213
 //- (void) application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
202 214
 //    
203 215
 //}

+ 85
- 28
test/test-0.7.0.js Dosyayı Görüntüle

@@ -26,9 +26,10 @@ const { TEST_SERVER_URL, TEST_SERVER_URL_SSL, DROPBOX_TOKEN, styles } = prop()
26 26
 const  dirs = RNFetchBlob.fs.dirs
27 27
 
28 28
 let prefix = ((Platform.OS === 'android') ? 'file://' : '')
29
+let bigfile = null
29 30
 
30 31
 describe('Upload and download large file', (report, done) => {
31
-  let filename = '22mb-dummy-' + Date.now()
32
+  let filename = Platform.OS+'-0.7.0-22mb-dummy-' + Date.now()
32 33
   let begin = -1
33 34
   let begin2 = -1
34 35
   let deb = Date.now()
@@ -49,35 +50,91 @@ describe('Upload and download large file', (report, done) => {
49 50
     </Info>)
50 51
   })
51 52
   .then((res) => {
52
-    try {
53
+    bigfile = res.path()
54
+    done()
55
+  })
56
+  // .then((res) => {
57
+  //   bigfile = res.path()
58
+  //   try {
59
+  //   deb = Date.now()
60
+  //   let promise =  RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
61
+  //     Authorization : `Bearer ${DROPBOX_TOKEN}`,
62
+  //     'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+filename+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
63
+  //     'Content-Type' : 'application/octet-stream',
64
+  //   }, RNFetchBlob.wrap(res.path()))
65
+  //   promise.uploadProgress((now, total) => {
66
+  //     if(Date.now() - deb < 1000)
67
+  //       return
68
+  //     deb = Date.now()
69
+  //     if(begin2 === -1)
70
+  //       begin2 = Date.now()
71
+  //     let speed = Math.floor(now / (Date.now() - begin2))
72
+  //     report(<Info uid="100"  key="progress">
73
+  //       <Text>
74
+  //         {`upload ${now} / ${total} bytes (${speed} kb/s)`}
75
+  //         {` ${Math.floor((total-now)/speed/1000)} seconds left`}
76
+  //       </Text>
77
+  //     </Info>)
78
+  //   })
79
+  //   return promise
80
+  // } catch(err) { console.log(err) }
81
+  // })
82
+  // .then((res) => {
83
+  //   report(<Assert
84
+  //     key="upload should success without crashing app"
85
+  //     expect={filename}
86
+  //     actual={res.json().name}/>)
87
+  //   done()
88
+  // })
89
+})
90
+
91
+describe('cancel task should work properly', (report, done) => {
92
+  let filename = Platform.OS+'-0.7.0-cancel-test-22mb-dummy-' + Date.now()
93
+  let bytesWitten = 0
94
+  let deb = Date.now()
95
+  let begin = -1
96
+  let promise =  RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
97
+    Authorization : `Bearer ${DROPBOX_TOKEN}`,
98
+    'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+filename+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
99
+    'Content-Type' : 'application/octet-stream',
100
+  }, RNFetchBlob.wrap(bigfile))
101
+  promise.uploadProgress((now, total) => {
102
+    bytesWitten = now
103
+    if(Date.now() - deb < 1000)
104
+      return
53 105
     deb = Date.now()
54
-    let promise =  RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
55
-      Authorization : `Bearer ${DROPBOX_TOKEN}`,
56
-      'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+filename+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
57
-      'Content-Type' : 'application/octet-stream',
58
-    }, RNFetchBlob.wrap(res.path()))
59
-    promise.uploadProgress((now, total) => {
60
-      if(Date.now() - deb < 1000)
61
-        return
62
-      deb = Date.now()
63
-      if(begin2 === -1)
64
-        begin2 = Date.now()
65
-      let speed = Math.floor(now / (Date.now() - begin2))
66
-      report(<Info uid="100"  key="progress">
67
-        <Text>
68
-          {`upload ${now} / ${total} bytes (${speed} kb/s)`}
69
-          {` ${Math.floor((total-now)/speed/1000)} seconds left`}
70
-        </Text>
71
-      </Info>)
72
-    })
73
-    return promise
74
-  } catch(err) { console.log(err) }
106
+    if(begin === -1)
107
+      begin = Date.now()
108
+    let speed = Math.floor(now / (Date.now() - begin))
109
+    report(<Info uid="100"  key="progress">
110
+      <Text>
111
+        {`upload ${now} / ${total} bytes (${speed} kb/s)`}
112
+        {` ${Math.floor((total-now)/speed/1000)} seconds left`}
113
+      </Text>
114
+    </Info>)
75 115
   })
76
-  .then((res) => {
77
-    report(<Assert
78
-      key="upload should success without crashing app"
79
-      expect={filename}
80
-      actual={res.json().name}/>)
116
+  let checkpoint1 = 0
117
+  Timer.setTimeout(() => {
118
+    promise.cancel()
119
+  }, 5000)
120
+  Timer.setTimeout(() => {
121
+    checkpoint1 = bytesWitten
122
+  }, 6000)
123
+  Timer.setTimeout(() => {
124
+    report(<Assert key="data should not write to stream after task is canceled"
125
+      expect={checkpoint1}
126
+      actual={bytesWitten}/>)
81 127
     done()
128
+  }, 10000)
129
+  promise.then((res) => {
130
+    report(
131
+      <Assert key="task not canceled"
132
+        expected={false}
133
+        actual={true}/>)
134
+  })
135
+  promise.catch((resp) => {
136
+    report(<Assert key="task cancelled rejection should be catachable"
137
+      expect={true}
138
+      actual={true}/>)
82 139
   })
83 140
 })

+ 8
- 8
test/test-init.js Dosyayı Görüntüle

@@ -58,12 +58,12 @@ describe('GET image from server', (report, done) => {
58 58
 })
59 59
 
60 60
 
61
-require('./test-0.1.x-0.4.x')
62
-require('./test-0.5.1')
63
-require('./test-0.5.2')
64
-require('./test-0.6.0')
65
-require('./test-0.6.2')
66
-require('./test-0.6.3')
61
+// require('./test-0.1.x-0.4.x')
62
+// require('./test-0.5.1')
63
+// require('./test-0.5.2')
64
+// require('./test-0.6.0')
65
+// require('./test-0.6.2')
66
+// require('./test-0.6.3')
67 67
 require('./test-0.7.0')
68
-require('./test-fs')
69
-require('./test-android')
68
+// require('./test-fs')
69
+// require('./test-android')