Compare commits
32 Commits
muwire-0.0
...
muwire-0.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cda81a89a2 | ||
![]() |
483773422c | ||
![]() |
1e1e6d0bb0 | ||
![]() |
668d6e087d | ||
![]() |
49af412b96 | ||
![]() |
d5513021ed | ||
![]() |
c3154cf717 | ||
![]() |
114940c4c1 | ||
![]() |
d4336e9b5d | ||
![]() |
2c1d5508ed | ||
![]() |
1cebf6c7bd | ||
![]() |
e12924a207 | ||
![]() |
f3b11895e4 | ||
![]() |
1e084820fb | ||
![]() |
2198b4846d | ||
![]() |
a5d442d320 | ||
![]() |
3f9ee887d6 | ||
![]() |
4a9e6d3b6b | ||
![]() |
80f2cc5f99 | ||
![]() |
12283dba9d | ||
![]() |
5c959bc8b7 | ||
![]() |
f3712fe7af | ||
![]() |
3e49b0ec66 | ||
![]() |
f90beb8e3d | ||
![]() |
fbad7b6c7e | ||
![]() |
ec2d89c18c | ||
![]() |
c27fc0a515 | ||
![]() |
14681c2060 | ||
![]() |
1aeb230ea8 | ||
![]() |
d1dfc73f5a | ||
![]() |
0cebe4119c | ||
![]() |
9f21120ec8 |
@@ -32,7 +32,6 @@ At the moment there are very few nodes on the network, so you will see very few
|
||||
|
||||
### Known bugs and limitations
|
||||
|
||||
* Sometimes the list of shared files gets lost
|
||||
* Many UI features you would expect are not there yet
|
||||
|
||||
|
||||
|
@@ -1,8 +1,22 @@
|
||||
apply plugin : 'application'
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin : 'application'
|
||||
mainClassName = 'com.muwire.cli.Cli'
|
||||
apply plugin : 'com.github.johnrengelman.shadow'
|
||||
|
||||
applicationDefaultJvmArgs = ['-Djava.util.logging.config.file=logging.properties']
|
||||
|
||||
dependencies {
|
||||
compile project(":core")
|
||||
}
|
||||
|
||||
|
@@ -4,9 +4,15 @@ import java.util.concurrent.CountDownLatch
|
||||
|
||||
import com.muwire.core.Core
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.connection.ConnectionAttemptStatus
|
||||
import com.muwire.core.connection.ConnectionEvent
|
||||
import com.muwire.core.connection.DisconnectionEvent
|
||||
import com.muwire.core.files.AllFilesLoadedEvent
|
||||
import com.muwire.core.files.FileHashedEvent
|
||||
import com.muwire.core.files.FileLoadedEvent
|
||||
import com.muwire.core.files.FileSharedEvent
|
||||
import com.muwire.core.upload.UploadEvent
|
||||
import com.muwire.core.upload.UploadFinishedEvent
|
||||
|
||||
class Cli {
|
||||
|
||||
@@ -28,28 +34,15 @@ class Cli {
|
||||
|
||||
Core core
|
||||
try {
|
||||
core = new Core(props, home, "0.0.11")
|
||||
core = new Core(props, home, "0.1.0")
|
||||
} catch (Exception bad) {
|
||||
bad.printStackTrace(System.out)
|
||||
println "Failed to initialize core, exiting"
|
||||
System.exit(1)
|
||||
}
|
||||
|
||||
def latch = new CountDownLatch(1)
|
||||
def fileLoader = new Object() {
|
||||
public void onAllFilesLoadedEvent(AllFilesLoadedEvent e) {
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
core.eventBus.register(AllFilesLoadedEvent.class, fileLoader)
|
||||
core.startServices()
|
||||
|
||||
println "waiting for files to load"
|
||||
latch.await()
|
||||
|
||||
|
||||
// now we begin
|
||||
println "MuWire is ready"
|
||||
|
||||
def filesList
|
||||
if (args.length == 0) {
|
||||
@@ -62,14 +55,39 @@ class Cli {
|
||||
Thread.sleep(1000)
|
||||
println "loading shared files from $filesList"
|
||||
|
||||
core.eventBus.register(FileHashedEvent.class, new Object() {
|
||||
void onFileHashedEvent(FileHashedEvent e) {
|
||||
if (e.error != null)
|
||||
println "ERROR $e.error"
|
||||
else
|
||||
println "Shared file : $e.sharedFile.file"
|
||||
// listener for shared files
|
||||
def sharedListener = new SharedListener()
|
||||
core.eventBus.register(FileHashedEvent.class, sharedListener)
|
||||
core.eventBus.register(FileLoadedEvent.class, sharedListener)
|
||||
|
||||
// for connections
|
||||
def connectionsListener = new ConnectionListener()
|
||||
core.eventBus.register(ConnectionEvent.class, connectionsListener)
|
||||
core.eventBus.register(DisconnectionEvent.class, connectionsListener)
|
||||
|
||||
// for uploads
|
||||
def uploadsListener = new UploadsListener()
|
||||
core.eventBus.register(UploadEvent.class, uploadsListener)
|
||||
core.eventBus.register(UploadFinishedEvent.class, uploadsListener)
|
||||
|
||||
Timer timer = new Timer("status-printer", true)
|
||||
timer.schedule({
|
||||
println "Connections $connectionsListener.connections Uploads $uploadsListener.uploads Shared $sharedListener.shared"
|
||||
} as TimerTask, 60000, 60000)
|
||||
|
||||
def latch = new CountDownLatch(1)
|
||||
def fileLoader = new Object() {
|
||||
public void onAllFilesLoadedEvent(AllFilesLoadedEvent e) {
|
||||
latch.countDown()
|
||||
}
|
||||
})
|
||||
}
|
||||
core.eventBus.register(AllFilesLoadedEvent.class, fileLoader)
|
||||
core.startServices()
|
||||
|
||||
println "waiting for files to load"
|
||||
latch.await()
|
||||
// now we begin
|
||||
println "MuWire is ready"
|
||||
|
||||
filesList = new File(filesList)
|
||||
filesList.withReader {
|
||||
@@ -83,4 +101,42 @@ class Cli {
|
||||
})
|
||||
Thread.sleep(Integer.MAX_VALUE)
|
||||
}
|
||||
|
||||
static class ConnectionListener {
|
||||
volatile int connections
|
||||
public void onConnectionEvent(ConnectionEvent e) {
|
||||
if (e.status == ConnectionAttemptStatus.SUCCESSFUL)
|
||||
connections++
|
||||
}
|
||||
public void onDisconnectionEvent(DisconnectionEvent e) {
|
||||
connections--
|
||||
}
|
||||
}
|
||||
|
||||
static class UploadsListener {
|
||||
volatile int uploads
|
||||
public void onUploadEvent(UploadEvent e) {
|
||||
uploads++
|
||||
println "Starting upload of ${e.uploader.file.getName()} to ${e.uploader.request.downloader.getHumanReadableName()}"
|
||||
}
|
||||
public void onUploadFinishedEvent(UploadFinishedEvent e) {
|
||||
uploads--
|
||||
println "Finished upload of ${e.uploader.file.getName()} to ${e.uploader.request.downloader.getHumanReadableName()}"
|
||||
}
|
||||
}
|
||||
|
||||
static class SharedListener {
|
||||
volatile int shared
|
||||
void onFileHashedEvent(FileHashedEvent e) {
|
||||
if (e.error != null)
|
||||
println "ERROR $e.error"
|
||||
else {
|
||||
println "Shared file : $e.sharedFile.file"
|
||||
shared++
|
||||
}
|
||||
}
|
||||
void onFileLoadedEvent(FileLoadedEvent e) {
|
||||
shared++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
166
cli/src/main/groovy/com/muwire/cli/CliDownloader.groovy
Normal file
166
cli/src/main/groovy/com/muwire/cli/CliDownloader.groovy
Normal file
@@ -0,0 +1,166 @@
|
||||
package com.muwire.cli
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
import com.muwire.core.Core
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.connection.ConnectionAttemptStatus
|
||||
import com.muwire.core.connection.ConnectionEvent
|
||||
import com.muwire.core.download.DownloadStartedEvent
|
||||
import com.muwire.core.download.Downloader
|
||||
import com.muwire.core.download.UIDownloadEvent
|
||||
import com.muwire.core.search.QueryEvent
|
||||
import com.muwire.core.search.SearchEvent
|
||||
import com.muwire.core.search.UIResultEvent
|
||||
|
||||
import net.i2p.data.Base64
|
||||
|
||||
class CliDownloader {
|
||||
|
||||
private static final List<Downloader> downloaders = Collections.synchronizedList(new ArrayList<>())
|
||||
private static final Map<UUID,ResultsHolder> resultsListeners = new ConcurrentHashMap<>()
|
||||
|
||||
public static void main(String []args) {
|
||||
def home = System.getProperty("user.home") + File.separator + ".MuWire"
|
||||
home = new File(home)
|
||||
if (!home.exists())
|
||||
home.mkdirs()
|
||||
|
||||
def propsFile = new File(home,"MuWire.properties")
|
||||
if (!propsFile.exists()) {
|
||||
println "create props file ${propsFile.getAbsoluteFile()} before launching MuWire"
|
||||
System.exit(1)
|
||||
}
|
||||
|
||||
def props = new Properties()
|
||||
propsFile.withInputStream { props.load(it) }
|
||||
props = new MuWireSettings(props)
|
||||
|
||||
def filesList
|
||||
int connections
|
||||
int resultWait
|
||||
if (args.length != 3) {
|
||||
println "Enter a file containing list of hashes of files to download, " +
|
||||
"how many connections you want before searching" +
|
||||
"and how long to wait for results to arrive"
|
||||
System.exit(1)
|
||||
} else {
|
||||
filesList = args[0]
|
||||
connections = Integer.parseInt(args[1])
|
||||
resultWait = Integer.parseInt(args[2])
|
||||
}
|
||||
|
||||
Core core
|
||||
try {
|
||||
core = new Core(props, home, "0.1.0")
|
||||
} catch (Exception bad) {
|
||||
bad.printStackTrace(System.out)
|
||||
println "Failed to initialize core, exiting"
|
||||
System.exit(1)
|
||||
}
|
||||
|
||||
|
||||
def latch = new CountDownLatch(connections)
|
||||
def connectionListener = new ConnectionWaiter(latch : latch)
|
||||
core.eventBus.register(ConnectionEvent.class, connectionListener)
|
||||
|
||||
core.startServices()
|
||||
println "starting to wait until there are $connections connections"
|
||||
latch.await()
|
||||
|
||||
println "connected, searching for files"
|
||||
|
||||
def file = new File(filesList)
|
||||
file.eachLine {
|
||||
String[] split = it.split(",")
|
||||
UUID uuid = UUID.randomUUID()
|
||||
core.eventBus.register(UIResultEvent.class, new ResultsListener(fileName : split[1]))
|
||||
def hash = Base64.decode(split[0])
|
||||
def searchEvent = new SearchEvent(searchHash : hash, uuid : uuid)
|
||||
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop:true,
|
||||
replyTo: core.me.destination, receivedOn : core.me.destination, originator: core.me))
|
||||
}
|
||||
|
||||
println "waiting for results to arrive"
|
||||
Thread.sleep(resultWait * 1000)
|
||||
|
||||
core.eventBus.register(DownloadStartedEvent.class, new DownloadListener())
|
||||
resultsListeners.each { uuid, resultsListener ->
|
||||
println "starting download of $resultsListener.fileName from ${resultsListener.getResults().size()} hosts"
|
||||
File target = new File(resultsListener.fileName)
|
||||
|
||||
core.eventBus.publish(new UIDownloadEvent(target : target, result : resultsListener.getResults()))
|
||||
}
|
||||
|
||||
Thread.sleep(1000)
|
||||
|
||||
Timer timer = new Timer("stats-printer")
|
||||
timer.schedule({
|
||||
println "==== STATUS UPDATE ==="
|
||||
downloaders.each {
|
||||
int donePieces = it.donePieces()
|
||||
int totalPieces = it.nPieces
|
||||
int sources = it.activeWorkers.size()
|
||||
def root = Base64.encode(it.infoHash.getRoot())
|
||||
def state = it.getCurrentState()
|
||||
println "file $it.file hash: $root progress: $donePieces/$totalPieces sources: $sources status: $state}"
|
||||
it.resume()
|
||||
}
|
||||
println "==== END ==="
|
||||
} as TimerTask, 60000, 60000)
|
||||
|
||||
println "waiting for downloads to finish"
|
||||
while(true) {
|
||||
boolean allFinished = true
|
||||
for (Downloader d : downloaders) {
|
||||
allFinished &= d.getCurrentState() == Downloader.DownloadState.FINISHED
|
||||
}
|
||||
if (allFinished)
|
||||
break
|
||||
Thread.sleep(1000)
|
||||
}
|
||||
|
||||
println "all downloads finished"
|
||||
}
|
||||
|
||||
static class ResultsHolder {
|
||||
final List<UIResultEvent> results = Collections.synchronizedList(new ArrayList<>())
|
||||
String fileName
|
||||
void add(UIResultEvent e) {
|
||||
results.add(e)
|
||||
}
|
||||
List getResults() {
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
static class ResultsListener {
|
||||
UUID uuid
|
||||
String fileName
|
||||
public onUIResultEvent(UIResultEvent e) {
|
||||
println "got a result for $fileName from ${e.sender.getHumanReadableName()}"
|
||||
ResultsHolder listener = resultsListeners.get(e.uuid)
|
||||
if (listener == null) {
|
||||
listener = new ResultsHolder(fileName : fileName)
|
||||
resultsListeners.put(e.uuid, listener)
|
||||
}
|
||||
listener.add(e)
|
||||
}
|
||||
}
|
||||
|
||||
static class ConnectionWaiter {
|
||||
CountDownLatch latch
|
||||
public void onConnectionEvent(ConnectionEvent e) {
|
||||
if (e.status == ConnectionAttemptStatus.SUCCESSFUL)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class DownloadListener {
|
||||
public void onDownloadStartedEvent(DownloadStartedEvent e) {
|
||||
downloaders.add(e.downloader)
|
||||
}
|
||||
}
|
||||
}
|
@@ -92,6 +92,7 @@ public class Core {
|
||||
i2pOptionsFile.withInputStream { i2pOptions.load(it) }
|
||||
} else {
|
||||
i2pOptions["inbound.nickname"] = "MuWire"
|
||||
i2pOptions["outbound.nickname"] = "MuWire"
|
||||
i2pOptions["inbound.length"] = "3"
|
||||
i2pOptions["inbound.quantity"] = "2"
|
||||
i2pOptions["outbound.length"] = "3"
|
||||
@@ -248,7 +249,7 @@ public class Core {
|
||||
}
|
||||
}
|
||||
|
||||
Core core = new Core(props, home, "0.0.11")
|
||||
Core core = new Core(props, home, "0.1.0")
|
||||
core.startServices()
|
||||
|
||||
// ... at the end, sleep or execute script
|
||||
|
@@ -3,6 +3,7 @@ package com.muwire.core
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.logging.Level
|
||||
|
||||
import com.muwire.core.files.FileSharedEvent
|
||||
|
||||
@@ -23,14 +24,18 @@ class EventBus {
|
||||
}
|
||||
|
||||
private void publishInternal(Event e) {
|
||||
log.fine "publishing event $e of type ${e.getClass().getSimpleName()}"
|
||||
log.fine "publishing event $e of type ${e.getClass().getSimpleName()} event $e"
|
||||
def currentHandlers
|
||||
final def clazz = e.getClass()
|
||||
synchronized(this) {
|
||||
currentHandlers = handlers.getOrDefault(clazz, [])
|
||||
}
|
||||
currentHandlers.each {
|
||||
it."on${clazz.getSimpleName()}"(e)
|
||||
try {
|
||||
it."on${clazz.getSimpleName()}"(e)
|
||||
} catch (Exception bad) {
|
||||
log.log(Level.SEVERE, "exception dispatching event",bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -127,6 +127,8 @@ abstract class Connection implements Closeable {
|
||||
query.uuid = e.searchEvent.getUuid()
|
||||
query.firstHop = e.firstHop
|
||||
query.keywords = e.searchEvent.getSearchTerms()
|
||||
if (e.searchEvent.searchHash != null)
|
||||
query.infohash = Base64.encode(e.searchEvent.searchHash)
|
||||
query.replyTo = e.replyTo.toBase64()
|
||||
if (e.originator != null)
|
||||
query.originator = e.originator.toBase64()
|
||||
@@ -155,8 +157,11 @@ abstract class Connection implements Closeable {
|
||||
|
||||
protected void handleSearch(def search) {
|
||||
UUID uuid = UUID.fromString(search.uuid)
|
||||
if (search.infohash != null)
|
||||
byte [] infohash = null
|
||||
if (search.infohash != null) {
|
||||
search.keywords = null
|
||||
infohash = Base64.decode(search.infohash)
|
||||
}
|
||||
|
||||
Destination replyTo = new Destination(search.replyTo)
|
||||
TrustLevel trustLevel = trustService.getLevel(replyTo)
|
||||
@@ -180,7 +185,7 @@ abstract class Connection implements Closeable {
|
||||
|
||||
|
||||
SearchEvent searchEvent = new SearchEvent(searchTerms : search.keywords,
|
||||
searchHash : search.infohash,
|
||||
searchHash : infohash,
|
||||
uuid : uuid)
|
||||
QueryEvent event = new QueryEvent ( searchEvent : searchEvent,
|
||||
replyTo : replyTo,
|
||||
|
@@ -144,7 +144,7 @@ class ConnectionAcceptor {
|
||||
|
||||
private void handleIncoming(Endpoint e, boolean leaf) {
|
||||
boolean accept = !manager.isConnected(e.destination) &&
|
||||
!establisher.inProgress.contains(e.destination) &&
|
||||
!establisher.isInProgress(e.destination) &&
|
||||
(leaf ? manager.hasLeafSlots() : manager.hasPeerSlots())
|
||||
if (accept) {
|
||||
log.info("accepting connection, leaf:$leaf")
|
||||
|
@@ -35,6 +35,8 @@ class ConnectionEstablisher {
|
||||
|
||||
final Set inProgress = new ConcurrentHashSet()
|
||||
|
||||
ConnectionEstablisher(){}
|
||||
|
||||
ConnectionEstablisher(EventBus eventBus, I2PConnector i2pConnector, MuWireSettings settings,
|
||||
ConnectionManager connectionManager, HostCache hostCache) {
|
||||
this.eventBus = eventBus
|
||||
@@ -176,4 +178,8 @@ class ConnectionEstablisher {
|
||||
e.close()
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInProgress(Destination d) {
|
||||
inProgress.contains(d)
|
||||
}
|
||||
}
|
||||
|
@@ -67,4 +67,18 @@ class FileHasher {
|
||||
byte [] hashList = output.toByteArray()
|
||||
InfoHash.fromHashList(hashList)
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 1) {
|
||||
println "This utility computes an infohash of a file"
|
||||
println "Pass absolute path to a file as an argument"
|
||||
System.exit(1)
|
||||
}
|
||||
|
||||
def file = new File(args[0])
|
||||
file = file.getAbsoluteFile()
|
||||
def hasher = new FileHasher()
|
||||
def infohash = hasher.hashFile(file)
|
||||
println infohash
|
||||
}
|
||||
}
|
||||
|
@@ -13,4 +13,8 @@ class QueryEvent extends Event {
|
||||
Persona originator
|
||||
Destination receivedOn
|
||||
|
||||
String toString() {
|
||||
"searchEvent: $searchEvent firstHop:$firstHop, replyTo:${replyTo.toBase32()}" +
|
||||
"originator: ${originator.getHumanReadableName()} receivedOn: ${receivedOn.toBase32()}"
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,18 @@
|
||||
package com.muwire.core.search
|
||||
|
||||
import com.muwire.core.Event
|
||||
import com.muwire.core.InfoHash
|
||||
|
||||
class SearchEvent extends Event {
|
||||
|
||||
List<String> searchTerms
|
||||
byte [] searchHash
|
||||
UUID uuid
|
||||
|
||||
String toString() {
|
||||
def infoHash = null
|
||||
if (searchHash != null)
|
||||
infoHash = new InfoHash(searchHash)
|
||||
"searchTerms: $searchTerms searchHash:$infoHash, uuid:$uuid"
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,10 @@
|
||||
package com.muwire.core.update
|
||||
|
||||
import com.muwire.core.Event
|
||||
import com.muwire.core.InfoHash
|
||||
|
||||
class UpdateAvailableEvent extends Event {
|
||||
String version
|
||||
String signer
|
||||
String infoHash
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ class UpdateClient {
|
||||
|
||||
void start() {
|
||||
session.addMuxedSessionListener(new Listener(), I2PSession.PROTO_DATAGRAM, 2)
|
||||
timer.schedule({checkUpdate()} as TimerTask, 30000, 60 * 60 * 1000)
|
||||
timer.schedule({checkUpdate()} as TimerTask, 60000, 60 * 60 * 1000)
|
||||
}
|
||||
|
||||
void stop() {
|
||||
@@ -107,7 +107,7 @@ class UpdateClient {
|
||||
}
|
||||
|
||||
log.info("new version $payload.version available, publishing event")
|
||||
eventBus.publish(new UpdateAvailableEvent(version : payload.version, signer : payload.signer))
|
||||
eventBus.publish(new UpdateAvailableEvent(version : payload.version, signer : payload.signer, infoHash : payload.infoHash))
|
||||
|
||||
} catch (Exception e) {
|
||||
log.log(Level.WARNING,"Invalid datagram",e)
|
||||
|
@@ -7,6 +7,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.Base64;
|
||||
|
||||
public class InfoHash {
|
||||
|
||||
@@ -76,14 +77,16 @@ public class InfoHash {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String rv = "InfoHash[root:"+Base32.encode(root) + " hashList:";
|
||||
List<String> b32HashList = new ArrayList<>(hashList.length / SIZE);
|
||||
byte [] tmp = new byte[SIZE];
|
||||
for (int i = 0; i < hashList.length / SIZE; i++) {
|
||||
System.arraycopy(hashList, SIZE * i, tmp, 0, SIZE);
|
||||
b32HashList.add(Base32.encode(tmp));
|
||||
String rv = "InfoHash[root:"+Base64.encode(root) + " hashList:";
|
||||
List<String> b64HashList = new ArrayList<>();
|
||||
if (hashList != null) {
|
||||
byte [] tmp = new byte[SIZE];
|
||||
for (int i = 0; i < hashList.length / SIZE; i++) {
|
||||
System.arraycopy(hashList, SIZE * i, tmp, 0, SIZE);
|
||||
b64HashList.add(Base64.encode(tmp));
|
||||
}
|
||||
}
|
||||
rv += b32HashList.toString();
|
||||
rv += b64HashList.toString();
|
||||
rv += "]";
|
||||
return rv;
|
||||
}
|
||||
|
@@ -43,6 +43,9 @@ class ConnectionAcceptorTest {
|
||||
|
||||
def uploadManagerMock
|
||||
UploadManager uploadManager
|
||||
|
||||
def connectionEstablisherMock
|
||||
ConnectionEstablisher connectionEstablisher
|
||||
|
||||
ConnectionAcceptor acceptor
|
||||
List<ConnectionEvent> connectionEvents
|
||||
@@ -57,6 +60,7 @@ class ConnectionAcceptorTest {
|
||||
trustServiceMock = new MockFor(TrustService.class)
|
||||
searchManagerMock = new MockFor(SearchManager.class)
|
||||
uploadManagerMock = new MockFor(UploadManager.class)
|
||||
connectionEstablisherMock = new MockFor(ConnectionEstablisher.class)
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -68,6 +72,7 @@ class ConnectionAcceptorTest {
|
||||
trustServiceMock.verify trustService
|
||||
searchManagerMock.verify searchManager
|
||||
uploadManagerMock.verify uploadManager
|
||||
connectionEstablisherMock.verify connectionEstablisher
|
||||
Thread.sleep(100)
|
||||
}
|
||||
|
||||
@@ -87,8 +92,10 @@ class ConnectionAcceptorTest {
|
||||
trustService = trustServiceMock.proxyInstance()
|
||||
searchManager = searchManagerMock.proxyInstance()
|
||||
uploadManager = uploadManagerMock.proxyInstance()
|
||||
connectionEstablisher = connectionEstablisherMock.proxyInstance()
|
||||
|
||||
acceptor = new ConnectionAcceptor(eventBus, connectionManager, settings, i2pAcceptor, hostCache, trustService, searchManager, uploadManager)
|
||||
acceptor = new ConnectionAcceptor(eventBus, connectionManager, settings, i2pAcceptor,
|
||||
hostCache, trustService, searchManager, uploadManager, connectionEstablisher)
|
||||
acceptor.start()
|
||||
Thread.sleep(100)
|
||||
}
|
||||
@@ -108,6 +115,7 @@ class ConnectionAcceptorTest {
|
||||
new Endpoint(destinations.dest1, is, os, null)
|
||||
}
|
||||
i2pAcceptorMock.demand.accept { Thread.sleep(Integer.MAX_VALUE) }
|
||||
connectionEstablisherMock.demand.isInProgress(destinations.dest1) { false }
|
||||
connectionManagerMock.demand.isConnected { dest ->
|
||||
assert dest == destinations.dest1
|
||||
false
|
||||
@@ -150,6 +158,7 @@ class ConnectionAcceptorTest {
|
||||
new Endpoint(destinations.dest1, is, os, null)
|
||||
}
|
||||
i2pAcceptorMock.demand.accept { Thread.sleep(Integer.MAX_VALUE) }
|
||||
connectionEstablisherMock.demand.isInProgress(destinations.dest1) { false }
|
||||
connectionManagerMock.demand.isConnected { dest ->
|
||||
assert dest == destinations.dest1
|
||||
false
|
||||
@@ -264,6 +273,7 @@ class ConnectionAcceptorTest {
|
||||
new Endpoint(destinations.dest1, is, os, null)
|
||||
}
|
||||
i2pAcceptorMock.demand.accept { Thread.sleep(Integer.MAX_VALUE) }
|
||||
connectionEstablisherMock.demand.isInProgress(destinations.dest1) { false }
|
||||
connectionManagerMock.demand.isConnected { dest ->
|
||||
assert dest == destinations.dest1
|
||||
false
|
||||
@@ -310,6 +320,7 @@ class ConnectionAcceptorTest {
|
||||
new Endpoint(destinations.dest1, is, os, null)
|
||||
}
|
||||
i2pAcceptorMock.demand.accept { Thread.sleep(Integer.MAX_VALUE) }
|
||||
connectionEstablisherMock.demand.isInProgress(destinations.dest1) { false }
|
||||
connectionManagerMock.demand.isConnected { dest ->
|
||||
assert dest == destinations.dest1
|
||||
false
|
||||
@@ -356,6 +367,7 @@ class ConnectionAcceptorTest {
|
||||
new Endpoint(destinations.dest1, is, os, null)
|
||||
}
|
||||
i2pAcceptorMock.demand.accept { Thread.sleep(Integer.MAX_VALUE) }
|
||||
connectionEstablisherMock.demand.isInProgress(destinations.dest1) { false }
|
||||
connectionManagerMock.demand.isConnected { dest ->
|
||||
assert dest == destinations.dest1
|
||||
false
|
||||
|
@@ -5,6 +5,7 @@ import org.junit.Test
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.InfoHash
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.SharedFile
|
||||
import com.muwire.core.search.ResultsEvent
|
||||
import com.muwire.core.search.SearchEvent
|
||||
@@ -26,7 +27,7 @@ class FileManagerTest {
|
||||
void before() {
|
||||
eventBus = new EventBus()
|
||||
eventBus.register(ResultsEvent.class, listener)
|
||||
manager = new FileManager(eventBus)
|
||||
manager = new FileManager(eventBus, new MuWireSettings())
|
||||
results = null
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
|
||||
class HasherServiceTest {
|
||||
|
||||
@@ -24,7 +25,7 @@ class HasherServiceTest {
|
||||
void before() {
|
||||
eventBus = new EventBus()
|
||||
hasher = new FileHasher()
|
||||
service = new HasherService(hasher, eventBus)
|
||||
service = new HasherService(hasher, eventBus, new FileManager(eventBus, new MuWireSettings()))
|
||||
eventBus.register(FileHashedEvent.class, listener)
|
||||
service.start()
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import com.muwire.core.Destinations
|
||||
import com.muwire.core.DownloadedFile
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.InfoHash
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.SharedFile
|
||||
import com.muwire.core.util.DataUtil
|
||||
|
||||
@@ -31,7 +32,7 @@ class PersisterServiceSavingTest {
|
||||
f = new File("build.gradle")
|
||||
f = f.getCanonicalFile()
|
||||
ih = fh.hashFile(f)
|
||||
fileSource = new FileManager(eventBus) {
|
||||
fileSource = new FileManager(eventBus, new MuWireSettings()) {
|
||||
Map<File, SharedFile> getSharedFiles() {
|
||||
Map<File, SharedFile> rv = new HashMap<>()
|
||||
rv.put(f, sf)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
group = com.muwire
|
||||
version = 0.0.11
|
||||
version = 0.1.0
|
||||
groovyVersion = 2.4.15
|
||||
slf4jVersion = 1.7.25
|
||||
spockVersion = 1.1-groovy-2.4
|
||||
|
@@ -7,6 +7,8 @@ import griffon.core.mvc.MVCGroup
|
||||
import griffon.core.mvc.MVCGroupConfiguration
|
||||
import griffon.inject.MVCMember
|
||||
import griffon.metadata.ArtifactProviderFor
|
||||
import net.i2p.data.Base64
|
||||
|
||||
import javax.annotation.Nonnull
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -42,15 +44,37 @@ class MainFrameController {
|
||||
params["uuid"] = uuid.toString()
|
||||
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
|
||||
model.results[uuid.toString()] = group
|
||||
|
||||
// this can be improved a lot
|
||||
def terms = search.toLowerCase().trim().split(Constants.SPLIT_PATTERN)
|
||||
def searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid)
|
||||
|
||||
def searchEvent
|
||||
if (model.hashSearch) {
|
||||
searchEvent = new SearchEvent(searchHash : Base64.decode(search), uuid : uuid)
|
||||
} else {
|
||||
// this can be improved a lot
|
||||
def replaced = search.toLowerCase().trim().replaceAll(Constants.SPLIT_PATTERN, " ")
|
||||
def terms = replaced.split(" ")
|
||||
searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid)
|
||||
}
|
||||
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
|
||||
replyTo: core.me.destination, receivedOn: core.me.destination,
|
||||
originator : core.me))
|
||||
}
|
||||
|
||||
void search(String infoHash, String tabTitle) {
|
||||
def cardsPanel = builder.getVariable("cards-panel")
|
||||
cardsPanel.getLayout().show(cardsPanel, "search window")
|
||||
def uuid = UUID.randomUUID()
|
||||
Map<String, Object> params = new HashMap<>()
|
||||
params["search-terms"] = tabTitle
|
||||
params["uuid"] = uuid.toString()
|
||||
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
|
||||
model.results[uuid.toString()] = group
|
||||
|
||||
def searchEvent = new SearchEvent(searchHash : Base64.decode(infoHash), uuid:uuid)
|
||||
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
|
||||
replyTo: core.me.destination, receivedOn: core.me.destination,
|
||||
originator : core.me))
|
||||
}
|
||||
|
||||
private def selectedResult() {
|
||||
def selected = builder.getVariable("result-tabs").getSelectedComponent()
|
||||
def group = selected.getClientProperty("mvc-group")
|
||||
@@ -137,6 +161,16 @@ class MainFrameController {
|
||||
markTrust("trusted-table", TrustLevel.NEUTRAL, model.trusted)
|
||||
}
|
||||
|
||||
@ControllerAction
|
||||
void keywordSearch() {
|
||||
model.hashSearch = false
|
||||
}
|
||||
|
||||
@ControllerAction
|
||||
void hashSearch() {
|
||||
model.hashSearch = true
|
||||
}
|
||||
|
||||
void mvcGroupInit(Map<String, String> args) {
|
||||
application.addPropertyChangeListener("core", {e->
|
||||
core = e.getNewValue()
|
||||
|
@@ -29,6 +29,7 @@ import com.muwire.core.upload.UploadFinishedEvent
|
||||
|
||||
import griffon.core.GriffonApplication
|
||||
import griffon.core.artifact.GriffonModel
|
||||
import griffon.core.env.Metadata
|
||||
import griffon.core.mvc.MVCGroup
|
||||
import griffon.inject.MVCMember
|
||||
import griffon.transform.FXObservable
|
||||
@@ -38,8 +39,11 @@ import griffon.metadata.ArtifactProviderFor
|
||||
|
||||
@ArtifactProviderFor(GriffonModel)
|
||||
class MainFrameModel {
|
||||
@Inject Metadata metadata
|
||||
@MVCMember @Nonnull
|
||||
FactoryBuilderSupport builder
|
||||
@MVCMember @Nonnull
|
||||
MainFrameController controller
|
||||
@Inject @Nonnull GriffonApplication application
|
||||
@Observable boolean coreInitialized = false
|
||||
|
||||
@@ -52,6 +56,8 @@ class MainFrameModel {
|
||||
def trusted = []
|
||||
def distrusted = []
|
||||
|
||||
boolean hashSearch
|
||||
|
||||
@Observable int connections
|
||||
@Observable String me
|
||||
@Observable boolean searchButtonsEnabled
|
||||
@@ -260,7 +266,13 @@ class MainFrameModel {
|
||||
|
||||
void onUpdateAvailableEvent(UpdateAvailableEvent e) {
|
||||
runInsideUIAsync {
|
||||
JOptionPane.showMessageDialog(null, "A new version of MuWire is available from $e.signer. Please update to $e.version")
|
||||
|
||||
int option = JOptionPane.showConfirmDialog(null,
|
||||
"MuWire $e.version is available from $e.signer. You have "+ metadata["application.version"]+" Update?",
|
||||
"New MuWire version availble", JOptionPane.OK_CANCEL_OPTION)
|
||||
if (option == JOptionPane.CANCEL_OPTION)
|
||||
return
|
||||
controller.search(e.infoHash,"MuWire update")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -76,6 +76,12 @@ class MainFrameView {
|
||||
|
||||
}
|
||||
panel( constraints: BorderLayout.EAST) {
|
||||
panel {
|
||||
buttonGroup(id : "searchButtonGroup")
|
||||
radioButton(text : "Keywords", selected : true, buttonGroup : searchButtonGroup, keywordSearchAction)
|
||||
radioButton(text : "Hash", selected : false, buttonGroup : searchButtonGroup, hashSearchAction)
|
||||
|
||||
}
|
||||
button(text: "Search", searchAction)
|
||||
}
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ class OptionsView {
|
||||
updateField = textField(text : bind {model.updateCheckInterval }, columns : 2, constraints : gbc(gridx : 1, gridy: 1))
|
||||
label(text : "hours", constraints : gbc(gridx: 2, gridy : 1))
|
||||
|
||||
label(text : "Only allow trusted connections", constraints : gbc(gridx: 0, gridy : 2))
|
||||
label(text : "Allow only trusted connections", constraints : gbc(gridx: 0, gridy : 2))
|
||||
allowUntrustedCheckbox = checkBox(selected : bind {model.onlyTrusted}, constraints : gbc(gridx: 1, gridy : 2))
|
||||
|
||||
label(text : "Share downloaded files", constraints : gbc(gridx : 0, gridy:3))
|
||||
|
Reference in New Issue
Block a user