-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIdcDm.java
More file actions
141 lines (119 loc) · 4.61 KB
/
Copy pathIdcDm.java
File metadata and controls
141 lines (119 loc) · 4.61 KB
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
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class IdcDm {
/**
* Enter download program.
*
* @param args command-line arguments:
* URL [MAX-CONCURRENT-CONNECTIONS] [MAX-DOWNLOAD-LIMIT]
* @throws Exception
*/
public static void main(String[] args) throws Exception {
int numberOfWorkers = 1;
Long maxBytesPerSecond = null;
if (args.length < 1 || args.length > 3) {
System.err.printf("usage:\n\tjava IdcDm URL [MAX-CONCURRENT-CONNECTIONS] [MAX-DOWNLOAD-LIMIT]\n");
System.exit(1);
} else if (args.length >= 2) {
numberOfWorkers = Integer.parseInt(args[1]);
if (args.length == 3)
maxBytesPerSecond = Long.parseLong(args[2]);
}
String url = args[0];
System.err.printf("Downloading");
if (numberOfWorkers > 1)
System.err.printf(" using %d connections", numberOfWorkers);
if (maxBytesPerSecond != null)
System.err.printf(" limited to %d Bps", maxBytesPerSecond);
System.err.printf("...\n");
DownloadURL(url, numberOfWorkers, maxBytesPerSecond);
}
/**
* Initiate the file's metadata, and iterate over missing ranges. For each:
* 1. Hand a range to a getter thread and submit it to the dThreads for execution
* 2. All along ensure that internet connection is good
* 3. When download finishes, close all threads and begin shutdown
*
* Finally, print "Download succeeded/failed" and delete the metadata as needed.
*
* @param url URL to download
* @param numberOfWorkers number of concurrent connections
* @param maxBytesPerSecond limit on download bytes-per-second
*/
private static void DownloadURL(String url, int numberOfWorkers, Long maxBytesPerSecond) {
// download threads
ExecutorService dThreads = Executors.newFixedThreadPool(numberOfWorkers+1);
//set up the RateLimiter
ExecutorService rLimiterThread = Executors.newSingleThreadExecutor();
rLimiterThread.submit(new RateLimiter(maxBytesPerSecond));
//-----------------------------------------------//
// open the metadata file and get the content-length
DownloadableMetadata metafile = null;
try {
metafile = new DownloadableMetadata(url);
metafile.openFile();
} catch (IOException e) {
dThreads.shutdownNow();
rLimiterThread.shutdownNow();
System.err.println("Download failed");
System.exit(1);
}
int length = metafile.getSize() / 4096;
// instantiate the Chunk Queue
BlockingQueue<Chunk> outQueue = new ArrayBlockingQueue<Chunk>(length);
// fair semaphore with numberOfWorkers permits
Semaphore numChunks = new Semaphore(0, true);
// write the data to a file
// blocks until the chunkQueue starts getting chunks
Callable<Void> file = new FileWriter(metafile, outQueue, numChunks);
dThreads.submit(file);
while(!metafile.isEmptyRanges()) {
Future<Void> res;
Callable<Void> getter = new HTTPRangeGetter(url, metafile.getMissingRange(),
outQueue, numChunks);
res = dThreads.submit(getter);
try {
res.get();
} catch (InterruptedException | ExecutionException e) {
dThreads.shutdownNow();
rLimiterThread.shutdownNow();
System.err.println("Lost internet connection. Please reconnect and try again.");
System.err.println("Download failed");
File temp = new File("temp." + metafile.getMetadataFileName());
if(temp.exists()) {
temp.delete();
}
System.exit(1);
}
}
dThreads.shutdown();
try {
dThreads.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
dThreads.shutdownNow();
}
rLimiterThread.shutdownNow();
Path metadata = Paths.get(metafile.getMetadataFileName());
File temp = new File("temp." + metafile.getMetadataFileName());
try {
Files.delete(metadata);
temp.delete();
} catch (IOException e) {
System.err.println(e);
System.err.println("Couldn't delete Metadata files. Please do so manually.");
}
System.err.println("Download succeeded");
System.exit(0);
}
}