1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.plugin.overnet.net;
21
22 import java.awt.event.ActionEvent;
23 import java.io.File;
24 import java.util.Arrays;
25 import javax.swing.AbstractAction;
26 import javax.swing.Action;
27 import javax.swing.Icon;
28 import javax.swing.JOptionPane;
29
30 import org.apache.log4j.Logger;
31 import org.xnap.XNap;
32 import org.xnap.gui.Dialogs;
33 import org.xnap.gui.XNapFrame;
34 import org.xnap.gui.action.SubmenuAction;
35 import org.xnap.gui.util.*;
36 import org.xnap.peer.Peer;
37 import org.xnap.plugin.Plugin;
38 import org.xnap.plugin.overnet.OvernetPlugin;
39 import org.xnap.plugin.overnet.net.msg.MessageHandler;
40 import org.xnap.plugin.overnet.net.msg.OvernetMessage;
41 import org.xnap.plugin.overnet.net.msg.client.CancelDownloadMessage;
42 import org.xnap.plugin.overnet.net.msg.client.GetGapsMessage;
43 import org.xnap.plugin.overnet.net.msg.client.PauseDownloadMessage;
44 import org.xnap.plugin.overnet.net.msg.client.ResumeDownloadMessage;
45 import org.xnap.plugin.overnet.net.msg.client.SetDownloadPriorityMessage;
46 import org.xnap.plugin.overnet.net.msg.core.GapsMessage;
47 import org.xnap.plugin.overnet.net.msg.core.MessageListener;
48 import org.xnap.plugin.overnet.net.msg.core.NewDownloadMessage;
49 import org.xnap.plugin.overnet.net.msg.core.RemoveDownloadMessage;
50 import org.xnap.plugin.overnet.net.msg.core.UpdateDownloadMessage;
51 import org.xnap.plugin.overnet.util.OvernetPreferences;
52 import org.xnap.transfer.AbstractDownload;
53 import org.xnap.transfer.Segment;
54 import org.xnap.transfer.action.AbstractDeleteAction;
55 import org.xnap.transfer.action.AbstractResumeAction;
56 import org.xnap.transfer.action.AbstractStopAction;
57 import org.xnap.util.Scheduler;
58 import org.xnap.util.XNapTask;
59
60 public class OvernetDownload extends AbstractDownload
61 implements MessageListener
62 {
63
64
65 private static final int STATUS_LOOKING = 2;
66 private static final int STATUS_DOWNLOADING = 3;
67 private static final int STATUS_COMPLETING = 9;
68 private static final int STATUS_COMPLETE = 10;
69 private static final int STATUS_COMPLETE_CORRUPTED = 11;
70
71 private static final String[] STATUS_STRINGS = new String[] {
72 XNap.tr("Hashing") + "...",
73 XNap.tr("Queued"),
74 XNap.tr("Looking" ),
75 XNap.tr("Downloading") + "...",
76 XNap.tr("Paused"),
77 XNap.tr("Insufficient Disk Space."),
78 XNap.tr("No Sources"),
79 XNap.tr("Hashing") + "...",
80 XNap.tr("Error Loading."),
81 XNap.tr("Completing") + "...",
82 XNap.tr("Complete"),
83 XNap.tr("Complete, but corrupted."),
84 XNap.tr("Transferring") + "...",
85 XNap.tr("Resuming") + "...",
86 XNap.tr("Pausing") + "...",
87 };
88
89
90
91 private String filename;
92 private long filesize;
93 private int status = -1;
94 private int bytesTransferred;
95 private int totalBytesTransferred;
96 private int startSize = -1;
97 private long currentRate = -1;
98 private byte[] hash;
99 private boolean removed = false;
100 private XNapTask updateTask;
101 private OvernetSegment[] segments;
102 private byte priority;
103 private static OvernetDownload hordeDl = null;
104
105 private boolean available = false;
106 private int sources = 0;
107
108 private static Logger logger = Logger.getLogger(OvernetDownload.class);
109
110
111
112 public OvernetDownload(NewDownloadMessage nm)
113 {
114 filename = nm.filename;
115 filesize = nm.filesize;
116 hash = nm.hash;
117 priority = nm.priority;
118
119 if (priority == NewDownloadMessage.PRIORITY_HIGHEST) {
120 hordeDl = this;
121 }
122
123 MessageHandler handler = OvernetPlugin.getMessageHandler();
124 handler.subscribe(RemoveDownloadMessage.TYPE, this);
125 if (!OvernetPreferences.getInstance().getNewDownloadID()) {
126 handler.subscribe(GapsMessage.TYPE, this);
127 }
128 updateTask = new UpdateGapsListTask();
129 Scheduler.run(0, 10 * 1000, updateTask);
130 transferStarted();
131 }
132
133
134
135 public long getTotalBytesTransferred()
136 {
137 return totalBytesTransferred;
138 }
139
140 public long getBytesTransferred()
141 {
142 return bytesTransferred;
143 }
144
145 public Action[] getActions()
146 {
147 return new Action[] { new ResumeAction(), new PauseAction(),
148 new DeleteAction(), new PriorityMenuAction(),
149 };
150 }
151
152 public long getFilesize()
153 {
154 return filesize;
155 }
156
157 public String getFilename()
158 {
159 return filename;
160 }
161
162 public File getFile()
163 {
164 return null;
165 }
166
167 public String getStatus()
168 {
169 if (removed && status != STATUS_COMPLETE
170 && status != STATUS_COMPLETING) {
171 return XNap.tr("Deleted");
172 }
173 if (status >=0 && status < STATUS_STRINGS.length) {
174 return STATUS_STRINGS[status];
175 }
176 return XNap.tr("Status unknown");
177 }
178
179 public Icon getIcon()
180 {
181 return OvernetPlugin.ICON_16;
182 }
183
184 public Peer getPeer()
185 {
186 return null;
187 }
188
189 public Plugin getPlugin()
190 {
191 return OvernetPlugin.getInstance();
192 }
193
194 public boolean isDone()
195 {
196 return removed || status == STATUS_COMPLETE;
197 }
198
199 public boolean isRunning()
200 {
201 return status == STATUS_DOWNLOADING;
202 }
203
204 public boolean isFailed()
205 {
206 return status == STATUS_COMPLETE_CORRUPTED;
207 }
208
209 public long getCurrentRate()
210 {
211 return currentRate;
212 }
213
214 private String getPrio()
215 {
216 switch (priority) {
217 case NewDownloadMessage.PRIORITY_LOW:
218 return XNap.tr("Low");
219 case NewDownloadMessage.PRIORITY_HIGH:
220 return XNap.tr("High");
221 case NewDownloadMessage.PRIORITY_HIGHEST:
222 return XNap.tr("Highest");
223 case NewDownloadMessage.PRIORITY_NORMAL:
224 default:
225 return XNap.tr("Normal");
226 }
227 }
228
229 public String getDescription()
230 {
231 return "<html><table>"
232 + GUIHelper.tableRow(XNap.tr("Filename"), getFilename())
233 + GUIHelper.tableRow(XNap.tr("Priority"), getPrio())
234 + GUIHelper.tableRow(XNap.tr("Completely Available"), available ?
235 XNap.tr("Yes") : XNap.tr("No"))
236 + GUIHelper.tableRow(XNap.tr("Sources"), sources + "")
237 + "</table></table>";
238 }
239
240 public void update(UpdateDownloadMessage um)
241 {
242 currentRate = (int)(1024 * um.speed);
243 available = um.availability == 100;
244 sources = um.sources;
245
246 updateStatus((int)um.status);
247
248 totalBytesTransferred = um.transferred;
249
250 if (startSize == -1) {
251 startSize = um.transferred;
252 }
253 else {
254 bytesTransferred = totalBytesTransferred - startSize;
255 }
256 }
257
258 private void updateStatus(int newStatus)
259 {
260 if (newStatus == STATUS_LOOKING && currentRate > 0) {
261 newStatus = STATUS_DOWNLOADING;
262 }
263 if (newStatus != status) {
264 status = newStatus;
265 stateChanged();
266 }
267 if (status == STATUS_COMPLETE) {
268 transferStopped();
269 }
270 }
271
272 public void transferStopped()
273 {
274 logger.debug("overnet transfer stopped cleanup");
275
276
277 MessageHandler handler = OvernetPlugin.getMessageHandler();
278 handler.unsubscribe(RemoveDownloadMessage.TYPE, this);
279 if (!OvernetPreferences.getInstance().getNewDownloadID()) {
280 handler.unsubscribe(GapsMessage.TYPE, this);
281 }
282 updateTask.cancel();
283
284 super.transferStopped();
285 }
286
287 public void messageReceived(OvernetMessage msg)
288 {
289 if (msg instanceof RemoveDownloadMessage) {
290 RemoveDownloadMessage rm = (RemoveDownloadMessage)msg;
291 if (Arrays.equals(hash, rm.hash)) {
292 removed = true;
293 transferStopped();
294 }
295 }
296 else if (msg instanceof GapsMessage) {
297 GapsMessage gm = (GapsMessage)msg;
298 if (Arrays.equals(hash, gm.hash)) {
299 updateGaps(gm);
300 }
301 }
302 }
303
304 public void updateGaps(GapsMessage gm)
305 {
306 for (int i = 0; i < gm.segments.length; i++) {
307 gm.segments[i].setTotal(getFilesize());
308 }
309 segments = gm.segments;
310 }
311
312 public Segment[] getSegments()
313 {
314 return segments;
315 }
316
317 private class UpdateGapsListTask extends XNapTask
318 {
319 public void run()
320 {
321 OvernetCore.send(new GetGapsMessage(hash));
322 }
323 }
324
325 private class ResumeAction extends AbstractResumeAction
326 {
327 public void actionPerformed(ActionEvent e)
328 {
329 OvernetCore.send(new ResumeDownloadMessage(hash));
330 }
331 }
332
333 private class PauseAction extends AbstractStopAction
334 {
335 public void actionPerformed(ActionEvent e)
336 {
337 OvernetCore.send(new PauseDownloadMessage(hash));
338 }
339 }
340
341 private class DeleteAction extends AbstractDeleteAction
342 {
343 public DeleteAction()
344 {
345 putValue(Action.NAME, XNap.tr("Delete Transfer"));
346 putValue(Action.SHORT_DESCRIPTION,
347 XNap.tr("Deletes the selected transfers and deletes their files."));
348 putValue(IconHelper.XNAP_ICON, "editdelete.png");
349 }
350
351 public void actionPerformed(ActionEvent e)
352 {
353 if (Dialogs.showConfirmDialog
354 (XNapFrame.getInstance().getTransferPanel(),
355 "DeleteDownloads",
356 XNap.tr("Delete Download"),
357 XNap.tr("Do you really want to delete\n{0}?", filename),
358 JOptionPane.YES_NO_OPTION,
359 OvernetPreferences.getInstance()) == JOptionPane.YES_OPTION) {
360 OvernetCore.send(new CancelDownloadMessage(hash));
361 }
362 }
363 }
364
365 private class SetDownloadPriorityAction extends AbstractAction
366 {
367 private byte priority;
368
369 public SetDownloadPriorityAction(byte priority, String name)
370 {
371 this.priority = priority;
372 putValue(Action.NAME, name);
373 }
374
375 public void actionPerformed(ActionEvent e)
376 {
377 OvernetDownload.this.priority = priority;
378 if (priority == NewDownloadMessage.PRIORITY_HIGHEST) {
379 if (hordeDl != null && hordeDl != OvernetDownload.this) {
380 logger.debug("hordeDl != null");
381 hordeDl.priority = NewDownloadMessage.PRIORITY_HIGH;
382 hordeDl = OvernetDownload.this;
383 }
384 }
385 OvernetCore.send(new SetDownloadPriorityMessage(hash, priority));
386 }
387 }
388
389 private class PriorityMenuAction extends SubmenuAction
390 {
391 public PriorityMenuAction()
392 {
393 super(new Action[] {
394 new SetDownloadPriorityAction(NewDownloadMessage.PRIORITY_LOW,
395 XNap.tr("Low")),
396 new SetDownloadPriorityAction(NewDownloadMessage.PRIORITY_NORMAL,
397 XNap.tr("Normal")),
398 new SetDownloadPriorityAction(NewDownloadMessage.PRIORITY_HIGH,
399 XNap.tr("High")),
400 new SetDownloadPriorityAction(NewDownloadMessage.PRIORITY_HIGHEST,
401 XNap.tr("Highest")),
402 });
403 putValue(Action.NAME, XNap.tr("Set Priority"));
404 }
405 }
406 }