Compare commits

..

9 Commits

Author SHA1 Message Date
Zlatin Balevsky
36a6e2769f Release 0.2.3 2019-06-16 19:05:12 +01:00
Zlatin Balevsky
69eeb7d77a fix 2019-06-16 18:58:52 +01:00
Zlatin Balevsky
551982b72a batch results sent to the GUI to prevent freeze 2019-06-16 18:51:07 +01:00
Zlatin Balevsky
8d808f0b8f Release 0.2.2 2019-06-16 13:30:11 +01:00
Zlatin Balevsky
7833a83c87 mark hash queries for V2 results 2019-06-16 13:17:32 +01:00
Zlatin Balevsky
3160c1a8f3 fix for silent uploader exceptions 2019-06-16 13:01:14 +01:00
Zlatin Balevsky
e295aa67d5 proper log statement 2019-06-16 10:59:11 +01:00
Zlatin Balevsky
a9f5625dc3 fix popup menu on failed downloads 2019-06-16 10:50:21 +01:00
Zlatin Balevsky
cc0af5b9ed add context menu to downloads table 2019-06-16 10:29:28 +01:00
14 changed files with 158 additions and 14 deletions

View File

@@ -34,7 +34,7 @@ class Cli {
Core core
try {
core = new Core(props, home, "0.2.1")
core = new Core(props, home, "0.2.3")
} catch (Exception bad) {
bad.printStackTrace(System.out)
println "Failed to initialize core, exiting"

View File

@@ -53,7 +53,7 @@ class CliDownloader {
Core core
try {
core = new Core(props, home, "0.2.1")
core = new Core(props, home, "0.2.3")
} catch (Exception bad) {
bad.printStackTrace(System.out)
println "Failed to initialize core, exiting"

View File

@@ -268,7 +268,7 @@ public class Core {
}
}
Core core = new Core(props, home, "0.2.1")
Core core = new Core(props, home, "0.2.3")
core.startServices()
// ... at the end, sleep or execute script

View File

@@ -17,6 +17,8 @@ import com.muwire.core.upload.UploadManager
import com.muwire.core.search.InvalidSearchResultException
import com.muwire.core.search.ResultsParser
import com.muwire.core.search.SearchManager
import com.muwire.core.search.UIResultBatchEvent
import com.muwire.core.search.UIResultEvent
import com.muwire.core.search.UnexpectedResultsException
import groovy.json.JsonOutput
@@ -225,13 +227,15 @@ class ConnectionAcceptor {
if (sender.destination != e.getDestination())
throw new IOException("Sender destination mismatch expected $e.getDestination(), got $sender.destination")
int nResults = dis.readUnsignedShort()
UIResultEvent[] results = new UIResultEvent[nResults]
for (int i = 0; i < nResults; i++) {
int jsonSize = dis.readUnsignedShort()
byte [] payload = new byte[jsonSize]
dis.readFully(payload)
def json = slurper.parse(payload)
eventBus.publish(ResultsParser.parse(sender, resultsUUID, json))
results[i] = ResultsParser.parse(sender, resultsUUID, json)
}
eventBus.publish(new UIResultBatchEvent(uuid: resultsUUID, results: results))
} catch (IOException | UnexpectedResultsException | InvalidSearchResultException bad) {
log.log(Level.WARNING, "failed to process POST", bad)
} finally {

View File

@@ -1,6 +1,7 @@
package com.muwire.core.connection
import java.util.concurrent.atomic.AtomicBoolean
import java.util.logging.Level
import groovy.util.logging.Log
import net.i2p.data.Destination
@@ -24,7 +25,7 @@ class Endpoint implements Closeable {
@Override
public void close() {
if (!closed.compareAndSet(false, true)) {
log.warning("Close loop detected for ${destination.toBase32()}", new Exception())
log.log(Level.WARNING,"Close loop detected for ${destination.toBase32()}", new Exception())
return
}
if (inputStream != null) {

View File

@@ -0,0 +1,8 @@
package com.muwire.core.search
import com.muwire.core.Event
class UIResultBatchEvent extends Event {
UUID uuid
UIResultEvent[] results
}

View File

@@ -51,4 +51,23 @@ class ContentUploader extends Uploader {
}
}
@Override
public String getName() {
return file.getName();
}
@Override
public synchronized int getProgress() {
if (mapped == null)
return 0
int position = mapped.position()
int total = request.getRange().end - request.getRange().start
(int)(position * 100.0 / total)
}
@Override
public String getDownloader() {
request.downloader.getHumanReadableName()
}
}

View File

@@ -6,6 +6,8 @@ import java.nio.charset.StandardCharsets
import com.muwire.core.InfoHash
import com.muwire.core.connection.Endpoint
import net.i2p.data.Base64
class HashListUploader extends Uploader {
private final InfoHash infoHash
private final HashListRequest request
@@ -14,6 +16,7 @@ class HashListUploader extends Uploader {
super(endpoint)
this.infoHash = infoHash
mapped = ByteBuffer.wrap(infoHash.getHashList())
this.request = request
}
void respond() {
@@ -32,4 +35,21 @@ class HashListUploader extends Uploader {
}
endpoint.getOutputStream().flush()
}
@Override
public String getName() {
return "Hash list for " + Base64.encode(infoHash.getRoot());
}
@Override
public synchronized int getProgress() {
(int)(mapped.position() * 100.0 / mapped.capacity())
}
@Override
public String getDownloader() {
request.downloader.getHumanReadableName()
}
}

View File

@@ -23,4 +23,13 @@ abstract class Uploader {
return -1
mapped.position()
}
abstract String getName();
/**
* @return an integer between 0 and 100
*/
abstract int getProgress();
abstract String getDownloader();
}

View File

@@ -1,5 +1,5 @@
group = com.muwire
version = 0.2.1
version = 0.2.3
groovyVersion = 2.4.15
slf4jVersion = 1.7.25
spockVersion = 1.1-groovy-2.4

View File

@@ -62,7 +62,7 @@ class MainFrameController {
def searchEvent
if (hashSearch) {
searchEvent = new SearchEvent(searchHash : root, uuid : uuid)
searchEvent = new SearchEvent(searchHash : root, uuid : uuid, oobInfohash: true)
} else {
// this can be improved a lot
def replaced = search.toLowerCase().trim().replaceAll(Constants.SPLIT_PATTERN, " ")

View File

@@ -20,6 +20,7 @@ import com.muwire.core.files.FileHashedEvent
import com.muwire.core.files.FileLoadedEvent
import com.muwire.core.files.FileSharedEvent
import com.muwire.core.search.QueryEvent
import com.muwire.core.search.UIResultBatchEvent
import com.muwire.core.search.UIResultEvent
import com.muwire.core.trust.TrustEvent
import com.muwire.core.trust.TrustService
@@ -115,6 +116,7 @@ class MainFrameModel {
core = e.getNewValue()
me = core.me.getHumanReadableName()
core.eventBus.register(UIResultEvent.class, this)
core.eventBus.register(UIResultBatchEvent.class, this)
core.eventBus.register(DownloadStartedEvent.class, this)
core.eventBus.register(ConnectionEvent.class, this)
core.eventBus.register(DisconnectionEvent.class, this)
@@ -161,6 +163,11 @@ class MainFrameModel {
resultsGroup?.model.handleResult(e)
}
void onUIResultBatchEvent(UIResultBatchEvent e) {
MVCGroup resultsGroup = results.get(e.uuid)
resultsGroup?.model.handleResultBatch(e.results)
}
void onDownloadStartedEvent(DownloadStartedEvent e) {
runInsideUIAsync {
downloads << e

View File

@@ -52,4 +52,22 @@ class SearchTabModel {
table.model.fireTableDataChanged()
}
}
void handleResultBatch(UIResultEvent[] batch) {
runInsideUIAsync {
batch.each {
if (uiSettings.excludeLocalResult && it.sender == core.me)
return
def bucket = hashBucket.get(it.infohash)
if (bucket == null) {
bucket = []
hashBucket[it.infohash] = bucket
}
bucket << it
results << it
}
JTable table = builder.getVariable("results-table")
table.model.fireTableDataChanged()
}
}
}

View File

@@ -160,16 +160,13 @@ class MainFrameView {
scrollPane (constraints : BorderLayout.CENTER) {
table(id : "uploads-table") {
tableModel(list : model.uploads) {
closureColumn(header : "Name", type : String, read : {row -> row.file.getName() })
closureColumn(header : "Name", type : String, read : {row -> row.getName() })
closureColumn(header : "Progress", type : String, read : { row ->
int position = row.getPosition()
def range = row.request.getRange()
int total = range.end - range.start
int percent = (int)((position * 100.0) / total)
int percent = row.getProgress()
"$percent%"
})
closureColumn(header : "Downloader", type : String, read : { row ->
row.request.downloader?.getHumanReadableName()
row.getDownloader()
})
}
}
@@ -306,6 +303,19 @@ class MainFrameView {
downloadsTable.rowSorter.addRowSorterListener({evt -> lastDownloadSortEvent = evt})
downloadsTable.rowSorter.setSortsOnUpdates(true)
downloadsTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger())
showDownloadsMenu(e)
}
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger())
showDownloadsMenu(e)
}
})
// shared files table
def sharedFilesTable = builder.getVariable("shared-files-table")
sharedFilesTable.columnModel.getColumn(1).setCellRenderer(new SizeRenderer())
@@ -353,7 +363,7 @@ class MainFrameView {
}
def showPopupMenu(JPopupMenu menu, MouseEvent event) {
private static void showPopupMenu(JPopupMenu menu, MouseEvent event) {
menu.show(event.getComponent(), event.getX(), event.getY())
}
@@ -386,6 +396,54 @@ class MainFrameView {
selected
}
def showDownloadsMenu(MouseEvent e) {
int selected = selectedDownloaderRow()
if (selected < 0)
return
boolean cancelEnabled = false
boolean retryEnabled = false
Downloader downloader = model.downloads[selected].downloader
switch(downloader.currentState) {
case Downloader.DownloadState.DOWNLOADING:
case Downloader.DownloadState.HASHLIST:
case Downloader.DownloadState.CONNECTING:
cancelEnabled = true
retryEnabled = false
break
case Downloader.DownloadState.FAILED:
cancelEnabled = true
retryEnabled = true
break
default :
cancelEnabled = false
retryEnabled = false
}
JPopupMenu menu = new JPopupMenu()
JMenuItem copyHashToClipboard = new JMenuItem("Copy hash to clipboard")
copyHashToClipboard.addActionListener({
String hash = Base64.encode(downloader.infoHash.getRoot())
StringSelection selection = new StringSelection(hash)
def clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
clipboard.setContents(selection, null)
})
menu.add(copyHashToClipboard)
if (cancelEnabled) {
JMenuItem cancel = new JMenuItem("Cancel")
cancel.addActionListener({mvcGroup.controller.cancel()})
menu.add(cancel)
}
if (retryEnabled) {
JMenuItem retry = new JMenuItem("Retry")
retry.addActionListener({mvcGroup.controller.resume()})
menu.add(retry)
}
showPopupMenu(menu, e)
}
def showSearchWindow = {
def cardsPanel = builder.getVariable("cards-panel")
cardsPanel.getLayout().show(cardsPanel, "search window")