1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.xnap.plugin.opennap.net;
22
23 import java.io.IOException;
24
25 import org.xnap.plugin.opennap.util.OpenNapFileHelper;
26 import org.xnap.transfer.Segment;
27
28 /***
29 *
30 */
31 public class OpenNapSegmentManager {
32
33
34
35 /***
36 * The number of bytes two segments need to overlap.
37 */
38 public static final int OVERLAP = 100;
39
40
41
42 private OpenNapSegment root;
43 private Segment[] segments = new Segment[0];
44 private OpenNapDownloadContainer parent;
45 private boolean multiSourceDownloading;
46
47
48
49 public OpenNapSegmentManager
50 (OpenNapDownloadContainer parent,
51 boolean multiSourceDownloading,
52 OpenNapSegmentData[] data)
53 {
54 this.parent = parent;
55 this.multiSourceDownloading = multiSourceDownloading;
56
57 if (data != null && data.length > 0) {
58 if (data[0].start != 0
59 || data[0].file.length() > parent.getFilesize()) {
60
61 return;
62 }
63
64
65 root = new OpenNapSegment(data[0], parent.getFilesize());
66 add(root);
67
68
69 OpenNapSegment previous = root;
70 for (int i = 1; i < data.length; i++) {
71 long minStart = previous.getStart()
72 + previous.getTransferred() - OVERLAP;
73
74 if (data[i].start < minStart
75 || (data[i].start + data[i].file.length()
76 > parent.getFilesize())) {
77
78 return;
79 }
80
81
82 OpenNapSegment next
83 = new OpenNapSegment(data[i], parent.getFilesize());
84 previous.append(next);
85 add(next);
86
87 previous = next;
88 }
89 }
90
91 }
92
93 public OpenNapSegmentManager
94 (OpenNapDownloadContainer parent,
95 boolean multiSourceDownloading)
96 {
97 this(parent, multiSourceDownloading, null);
98 }
99
100
101
102 public long getBytesTransferred()
103 {
104 long bytesTransferred = 0;
105 long previousEnd = 0;
106 for (int i = 0; i < segments.length; i++) {
107 bytesTransferred += segments[i].getTransferred();
108
109 bytesTransferred -= previousEnd - segments[i].getStart();
110 previousEnd += segments[i].getEnd();
111 }
112 return bytesTransferred;
113 }
114
115 public OpenNapSegment getRoot()
116 {
117 return root;
118 }
119
120 /***
121 *
122 */
123 public Segment[] getSegments()
124 {
125 return segments;
126 }
127
128 synchronized OpenNapSegment requestSegment(OpenNapDownload d)
129 {
130 if (root == null) {
131 root = new OpenNapSegment
132 (0, parent.getFilesize(), parent.getFilesize());
133 root.setDownload(d);
134 add(root);
135 return root;
136 }
137
138 if (!multiSourceDownloading) {
139
140 if (root.getDownload() == null) {
141 root.setDownload(d);
142 return root;
143 }
144 else {
145 return null;
146 }
147 }
148
149 OpenNapSegment next = root;
150 OpenNapSegment slowest = null;
151 while (next != null) {
152 if (!next.isFinished()) {
153 if (next.getDownload() == null) {
154 next.setDownload(d);
155 return next;
156 }
157 else {
158 if (slowest == null
159 || (next.getDownload().getAverageRate()
160 < slowest.getDownload().getAverageRate())) {
161 slowest = next;
162 }
163 }
164 }
165 next = next.getNext();
166 }
167
168 if (slowest != null) {
169
170 OpenNapSegment s = slowest.split(OVERLAP);
171
172 if (s == null) {
173
174 next = root;
175 while (s == null && next != null) {
176 if (!next.isFinished() && next.getDownload() == null) {
177 s = next.split(OVERLAP);
178 }
179 next = next.getNext();
180 }
181 }
182
183 if (s != null) {
184 s.setDownload(d);
185 add(s);
186 return s;
187 }
188 }
189
190 return null;
191 }
192
193 synchronized void returnSegment(OpenNapSegment s) throws IOException
194 {
195 s.setDownload(null);
196
197 merge(s, s.getNext());
198 merge(s.getPrevious(), s);
199 }
200
201 private synchronized boolean merge(OpenNapSegment p, OpenNapSegment s)
202 throws IOException
203 {
204 if (p == null
205 || p.getFile() == null
206 || p.getDownload() != null
207 || !p.isFinished()
208 || s == null
209 || s.getFile() == null
210 || s.getDownload() != null) {
211
212 return false;
213 }
214
215 int overlap = (int)(p.getEnd() - s.getStart());
216 OpenNapFileHelper.match(p.getFile(), s.getFile(), overlap);
217 OpenNapFileHelper.append(p.getFile(), s.getFile(), overlap);
218
219 s.getFile().delete();
220
221
222 p.merge(s, overlap);
223 remove(s);
224
225 return true;
226 }
227
228 private synchronized void add(OpenNapSegment segment)
229 {
230 OpenNapSegment[] tmp = new OpenNapSegment[segments.length + 1];
231 System.arraycopy(segments, 0, tmp, 0, segments.length);
232 tmp[tmp.length - 1] = segment;
233 segments = tmp;
234 parent.setSegments(tmp);
235 }
236
237 private synchronized void remove(OpenNapSegment segment)
238 {
239 for (int i = 0; i < segments.length; i++) {
240 if (segments[i] == segment) {
241 OpenNapSegment[] tmp = new OpenNapSegment[segments.length - 1];
242 System.arraycopy(segments, 0, tmp, 0, i);
243 System.arraycopy(segments, i + 1, tmp, i,
244 segments.length - i - 1);
245 segments = tmp;
246 parent.setSegments(tmp);
247 return;
248 }
249 }
250 }
251
252 }