Compare commits

...

15 Commits

Author SHA1 Message Date
Zlatin Balevsky
cda81a89a2 Release 0.1.0 2019-06-07 18:39:39 +01:00
Zlatin Balevsky
483773422c fix remaining tests 2019-06-07 18:23:16 +01:00
Zlatin Balevsky
1e1e6d0bb0 fix test 2019-06-07 18:17:16 +01:00
Zlatin Balevsky
668d6e087d fix test 2019-06-07 18:15:03 +01:00
Zlatin Balevsky
49af412b96 status update and auto-retry 2019-06-07 16:13:35 +01:00
Zlatin Balevsky
d5513021ed Release 0.0.14 for split search 2019-06-07 15:00:16 +01:00
Zlatin Balevsky
c3154cf717 stray println 2019-06-07 14:58:03 +01:00
Zlatin Balevsky
114940c4c1 fix searches with spaces 2019-06-07 14:51:09 +01:00
Zlatin Balevsky
d4336e9b5d outbound nickname 2019-06-07 14:24:45 +01:00
Zlatin Balevsky
2c1d5508ed outbound nickname 2019-06-07 14:21:03 +01:00
Zlatin Balevsky
1cebf6c7bd cli downloader 2019-06-07 14:02:10 +01:00
Zlatin Balevsky
e12924a207 shadow jar for cli 2019-06-07 14:01:28 +01:00
Zlatin Balevsky
f3b11895e4 utility for hashing files 2019-06-07 12:10:18 +01:00
Zlatin Balevsky
1e084820fb log tweak 2019-06-07 11:55:17 +01:00
Zlatin Balevsky
2198b4846d change wording 2019-06-07 11:43:02 +01:00
15 changed files with 231 additions and 13 deletions

View File

@@ -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")
}

View File

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

View 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)
}
}
}

View File

@@ -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.13")
Core core = new Core(props, home, "0.1.0")
core.startServices()
// ... at the end, sleep or execute script

View File

@@ -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")

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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,13 +77,13 @@ public class InfoHash {
}
public String toString() {
String rv = "InfoHash[root:"+Base32.encode(root) + " hashList:";
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(Base32.encode(tmp));
b64HashList.add(Base64.encode(tmp));
}
}
rv += b64HashList.toString();

View File

@@ -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

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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)

View File

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

View File

@@ -50,7 +50,8 @@ class MainFrameController {
searchEvent = new SearchEvent(searchHash : Base64.decode(search), uuid : uuid)
} else {
// this can be improved a lot
def terms = search.toLowerCase().trim().split(Constants.SPLIT_PATTERN)
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,

View File

@@ -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))