forked from pixmeo/osirix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWADODownload.m
394 lines (302 loc) · 15.5 KB
/
WADODownload.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/*=========================================================================
Program: OsiriX
Copyright (c) OsiriX Team
All rights reserved.
Distributed under GNU - LGPL
See http://www.osirix-viewer.com/copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
=========================================================================*/
#import "WADODownload.h"
#import "BrowserController.h"
#import "DicomDatabase.h"
#import "NSThread+N2.h"
#include <libkern/OSAtomic.h>
#import "dicomFile.h"
#import "LogManager.h"
#import "N2Debug.h"
#import "NSString+N2.h"
@interface NSURLRequest (DummyInterface)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
@end
@implementation WADODownload
@synthesize _abortAssociation, showErrorMessage, countOfSuccesses, WADOGrandTotal, WADOBaseTotal, baseStatus, receivedData, totalData;
+ (void) errorMessage:(NSArray*) msg
{
NSString *alertSuppress = @"hideListenerError";
if ([[NSUserDefaults standardUserDefaults] boolForKey: alertSuppress] == NO)
NSRunCriticalAlertPanel( [msg objectAtIndex: 0], [msg objectAtIndex: 1], [msg objectAtIndex: 2], nil, nil) ;
else
NSLog( @"*** listener error (not displayed - hideListenerError): %@ %@ %@", [msg objectAtIndex: 0], [msg objectAtIndex: 1], [msg objectAtIndex: 2]);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if( [httpResponse statusCode] >= 300)
{
NSLog( @"***** WADO http status code error: %d", (int) [httpResponse statusCode]);
NSLog( @"***** WADO URL : %@", response.URL);
if( firstWadoErrorDisplayed == NO)
{
firstWadoErrorDisplayed = YES;
if( showErrorMessage)
[WADODownload performSelectorOnMainThread :@selector(errorMessage:) withObject: [NSArray arrayWithObjects: NSLocalizedString(@"WADO Retrieve Failed", nil), [NSString stringWithFormat: @"WADO http status code error: %d", (int) [httpResponse statusCode]], NSLocalizedString(@"Continue", nil), nil] waitUntilDone:NO];
}
[WADODownloadDictionary removeObjectForKey: [NSString stringWithFormat:@"%ld", (long) connection]];
}
else
totalData += [[httpResponse.allHeaderFields valueForKey: @"Content-Length"] longLongValue];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if( connection)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableData *d = [[WADODownloadDictionary objectForKey: [NSString stringWithFormat:@"%ld", (long) connection]] objectForKey: @"data"];
[d appendData: data];
receivedData += data.length;
if( WADOTotal == 1) // Only one file: display progress in bytes
{
if( totalData > 0)
[[NSThread currentThread] setProgress: (double) receivedData / (double) totalData];
if( firstReceivedTime == 0)
firstReceivedTime = [NSDate timeIntervalSinceReferenceDate];
if( [NSDate timeIntervalSinceReferenceDate] - lastStatusUpdate > 1 && [NSDate timeIntervalSinceReferenceDate] - firstReceivedTime > 2)
{
lastStatusUpdate = [NSDate timeIntervalSinceReferenceDate];
[NSThread currentThread].status = [NSString stringWithFormat: @"%@ - %@/s", self.baseStatus, [NSString sizeString: (double) receivedData / ([NSDate timeIntervalSinceReferenceDate] - firstReceivedTime)]];
}
}
[pool release];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
if( connection)
{
[WADODownloadDictionary removeObjectForKey: [NSString stringWithFormat:@"%ld", (long) connection]];
NSLog(@"***** WADO Retrieve error: %@", error);
if( firstWadoErrorDisplayed == NO)
{
firstWadoErrorDisplayed = YES;
if( showErrorMessage)
[WADODownload performSelectorOnMainThread :@selector(errorMessage:) withObject: [NSArray arrayWithObjects: NSLocalizedString(@"WADO Retrieve Failed", nil), [NSString stringWithFormat: @"%@", [error localizedDescription]], NSLocalizedString(@"Continue", nil), nil] waitUntilDone:NO];
}
WADOThreads--;
int error = [[logEntry valueForKey: @"logNumberError"] intValue];
error++;
[logEntry setValue:[NSNumber numberWithInt: error] forKey:@"logNumberError"];
}
else
N2LogStackTrace( @"connection == nil");
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
//We dont want to store the images in the cache! Caches/com.rossetantoine.osirix/Cache.db
return nil;
}
- (id) init
{
self = [super init];
showErrorMessage = YES;
[[NSURLCache sharedURLCache] setDiskCapacity: 0];
[[NSURLCache sharedURLCache] setMemoryCapacity: 0];
#ifdef NONETWORKFUNCTIONS
return nil;
#endif
return self;
}
- (void) dealloc
{
self.baseStatus = nil;
[WADODownloadDictionary release];
WADODownloadDictionary = nil;
[logEntry release];
logEntry = nil;
[super dealloc];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if( connection)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *path = [[DicomDatabase defaultDatabase] incomingDirPath];
NSString *key = [NSString stringWithFormat:@"%ld", (long) connection];
NSMutableData *d = [[WADODownloadDictionary objectForKey: key] objectForKey: @"data"];
NSString *extension = @"dcm";
if( [d length] > 2)
{
countOfSuccesses++;
if( [[NSString stringWithCString: [d bytes] length: 2] isEqualToString: @"PK"])
extension = @"osirixzip";
NSString *filename = [[NSString stringWithFormat:@".WADO-%d-%ld", WADOThreads, (long) self] stringByAppendingPathExtension: extension];
[d writeToFile: [path stringByAppendingPathComponent: filename] atomically: YES];
if( WADOThreads == WADOTotal) // The first file !
{
[[DicomDatabase activeLocalDatabase] initiateImportFilesFromIncomingDirUnlessAlreadyImporting];
@try
{
if (!logEntry && [DicomFile isDICOMFile: [path stringByAppendingPathComponent: filename]])
{
DicomFile *dcmFile = [[DicomFile alloc] init: [path stringByAppendingPathComponent: filename]];
@try
{
logEntry = [[NSMutableDictionary dictionary] retain];
[logEntry setValue: [NSString stringWithFormat: @"%lf", [[NSDate date] timeIntervalSince1970]] forKey:@"logUID"];
[logEntry setValue: [NSDate date] forKey:@"logStartTime"];
[logEntry setValue: @"Receive" forKey:@"logType"];
[logEntry setValue: [[[WADODownloadDictionary objectForKey: key] objectForKey: @"url"] host] forKey:@"logCallingAET"];
if ([dcmFile elementForKey: @"patientName"])
[logEntry setValue: [dcmFile elementForKey: @"patientName"] forKey: @"logPatientName"];
if ([dcmFile elementForKey: @"studyDescription"])
[logEntry setValue:[dcmFile elementForKey: @"studyDescription"] forKey:@"logStudyDescription"];
[logEntry setValue:[NSNumber numberWithInt: WADOTotal] forKey:@"logNumberTotal"];
}
@catch (NSException *e) {
N2LogException( e);
}
[dcmFile release];
}
}
@catch (NSException *exception) {
N2LogException( exception);
}
}
[logEntry setValue:[NSNumber numberWithInt: 1 + WADOTotal - WADOThreads] forKey:@"logNumberReceived"];
[logEntry setValue:[NSDate date] forKey:@"logEndTime"];
[logEntry setValue:@"In Progress" forKey:@"logMessage"];
[[LogManager currentLogManager] addLogLine: logEntry];
if( WADOGrandTotal)
[[NSThread currentThread] setProgress: (float) ((WADOTotal - WADOThreads) + WADOBaseTotal) / (float) WADOGrandTotal];
else if( WADOTotal)
[[NSThread currentThread] setProgress: 1.0 - (float) WADOThreads / (float) WADOTotal];
// To remove the '.'
[[NSFileManager defaultManager] moveItemAtPath: [path stringByAppendingPathComponent: filename] toPath: [path stringByAppendingPathComponent: [filename substringFromIndex: 1]] error: nil];
}
[d setLength: 0]; // Free the memory immediately
[WADODownloadDictionary removeObjectForKey: key];
WADOThreads--;
[pool release];
}
else
N2LogStackTrace( @"connection == nil");
}
- (void) WADODownload: (NSArray*) urlToDownload
{
if( urlToDownload.count == 0)
{
NSLog( @"**** urlToDownload.count == 0 in WADODownload");
return;
}
NSMutableArray *connectionsArray = [NSMutableArray array];
NSAutoreleasePool *pool = [NSAutoreleasePool new];
self.baseStatus = [[NSThread currentThread] status];
@try
{
if( [urlToDownload count])
urlToDownload = [[NSSet setWithArray: urlToDownload] allObjects]; // UNIQUE OBJECTS !
if( [urlToDownload count])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
#ifndef NDEBUG
NSLog( @"------ WADO downloading : %d files", (int) [urlToDownload count]);
#endif
firstWadoErrorDisplayed = NO;
if( showErrorMessage == NO)
firstWadoErrorDisplayed = YES; // dont show errors
[WADODownloadDictionary release];
WADODownloadDictionary = [[NSMutableDictionary dictionary] retain];
int WADOMaximumConcurrentDownloads = [[NSUserDefaults standardUserDefaults] integerForKey: @"WADOMaximumConcurrentDownloads"];
if( WADOMaximumConcurrentDownloads < 1)
WADOMaximumConcurrentDownloads = 1;
float timeout = [[NSUserDefaults standardUserDefaults] floatForKey: @"WADOTimeout"];
if( timeout < 240) timeout = 240;
#ifndef NDEBUG
NSLog( @"------ WADO parameters: timeout:%2.2f [secs] / WADOMaximumConcurrentDownloads:%d [URLRequests]", timeout, WADOMaximumConcurrentDownloads);
#endif
self.countOfSuccesses = 0;
WADOTotal = WADOThreads = [urlToDownload count];
NSTimeInterval retrieveStartingDate = [NSDate timeIntervalSinceReferenceDate];
BOOL aborted = NO;
for( NSURL *url in urlToDownload)
{
while( [WADODownloadDictionary count] > WADOMaximumConcurrentDownloads) //Dont download more than XXX images at the same time
{
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
if( _abortAssociation || [NSThread currentThread].isCancelled || [[NSFileManager defaultManager] fileExistsAtPath: @"/tmp/kill_all_storescu"] || [NSDate timeIntervalSinceReferenceDate] - retrieveStartingDate > timeout)
{
aborted = YES;
break;
}
}
retrieveStartingDate = [NSDate timeIntervalSinceReferenceDate];
@try
{
if( [[url scheme] isEqualToString: @"https"])
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
}
@catch (NSException *e)
{
NSLog( @"***** exception in %s: %@", __PRETTY_FUNCTION__, e);
}
NSURLConnection *downloadConnection = [NSURLConnection connectionWithRequest: [NSURLRequest requestWithURL: url cachePolicy: NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: timeout] delegate: self];
if( downloadConnection)
{
[WADODownloadDictionary setObject: [NSDictionary dictionaryWithObjectsAndKeys: url, @"url", [NSMutableData data], @"data", nil] forKey: [NSString stringWithFormat:@"%ld", (long) downloadConnection]];
[downloadConnection start];
[connectionsArray addObject: downloadConnection];
}
if( downloadConnection == nil)
WADOThreads--;
if( _abortAssociation || [NSThread currentThread].isCancelled || [[NSFileManager defaultManager] fileExistsAtPath: @"/tmp/kill_all_storescu"] || [NSDate timeIntervalSinceReferenceDate] - retrieveStartingDate > timeout)
{
aborted = YES;
break;
}
}
if( aborted == NO)
{
while( WADOThreads > 0)
{
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
if( _abortAssociation || [NSThread currentThread].isCancelled || [[NSFileManager defaultManager] fileExistsAtPath: @"/tmp/kill_all_storescu"] || [NSDate timeIntervalSinceReferenceDate] - retrieveStartingDate > timeout)
{
aborted = YES;
break;
}
}
if( aborted == NO && [[WADODownloadDictionary allKeys] count] > 0)
NSLog( @"**** [[WADODownloadDictionary allKeys] count] > 0");
[[DicomDatabase activeLocalDatabase] initiateImportFilesFromIncomingDirUnlessAlreadyImporting];
}
if( aborted) [logEntry setValue:@"Incomplete" forKey:@"logMessage"];
else [logEntry setValue:@"Complete" forKey:@"logMessage"];
[[LogManager currentLogManager] addLogLine: logEntry];
if( aborted)
{
for( NSURLConnection *connection in connectionsArray)
[connection cancel];
}
[WADODownloadDictionary release];
WADODownloadDictionary = nil;
[logEntry release];
logEntry = nil;
[pool release];
#ifndef NDEBUG
if( aborted)
NSLog( @"------ WADO downloading ABORTED");
else
NSLog( @"------ WADO downloading : %d files - finished (errors: %d / total: %d)", (int) [urlToDownload count], (int) (urlToDownload.count - countOfSuccesses), (int) urlToDownload.count);
#endif
}
}
@catch (NSException *exception) {
N2LogException( exception);
}
@finally {
[pool release];
}
}
@end