Compare commits
22 Commits
muwire-0.0
...
muwire-0.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7eea8be67d | ||
![]() |
f114302bdb | ||
![]() |
05b9b37488 | ||
![]() |
52f317a5b7 | ||
![]() |
fb8227a1f3 | ||
![]() |
5677d9f46a | ||
![]() |
c5192e3845 | ||
![]() |
43c2a55cb8 | ||
![]() |
94f6de6bea | ||
![]() |
6782849a12 | ||
![]() |
c07d351c5d | ||
![]() |
dc2f675dd3 | ||
![]() |
a8e795ec51 | ||
![]() |
33c5b3b18e | ||
![]() |
581fce4643 | ||
![]() |
7fe78a0719 | ||
![]() |
cdb6e22522 | ||
![]() |
2edeb046be | ||
![]() |
4021f3c244 | ||
![]() |
9008fac24d | ||
![]() |
e2f92c5c5e | ||
![]() |
7b33a16fd8 |
@@ -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
|
||||
|
||||
* Any shared files get re-hashed on startup
|
||||
* Sometimes the list of shared files gets lost
|
||||
* Many UI features you would expect are not there yet
|
||||
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package com.muwire.cli
|
||||
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
import com.muwire.core.Core
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.files.AllFilesLoadedEvent
|
||||
import com.muwire.core.files.FileHashedEvent
|
||||
import com.muwire.core.files.FileSharedEvent
|
||||
|
||||
@@ -25,15 +28,26 @@ class Cli {
|
||||
|
||||
Core core
|
||||
try {
|
||||
core = new Core(props, home, "0.0.9")
|
||||
core = new Core(props, home, "0.0.11")
|
||||
} 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"
|
||||
|
||||
@@ -62,7 +76,11 @@ class Cli {
|
||||
def toShare = it.readLine()
|
||||
core.eventBus.publish(new FileSharedEvent(file : new File(toShare)))
|
||||
}
|
||||
|
||||
Runtime.getRuntime().addShutdownHook({
|
||||
println "shutting down.."
|
||||
core.shutdown()
|
||||
println "shutdown."
|
||||
})
|
||||
Thread.sleep(Integer.MAX_VALUE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -57,6 +57,7 @@ public class Core {
|
||||
final Persona me
|
||||
final File home
|
||||
final Properties i2pOptions
|
||||
final MuWireSettings muOptions
|
||||
|
||||
private final TrustService trustService
|
||||
private final PersisterService persisterService
|
||||
@@ -70,6 +71,7 @@ public class Core {
|
||||
|
||||
public Core(MuWireSettings props, File home, String myVersion) {
|
||||
this.home = home
|
||||
this.muOptions = props
|
||||
log.info "Initializing I2P context"
|
||||
I2PAppContext.getGlobalContext().logManager()
|
||||
I2PAppContext.getGlobalContext()._logManager = new MuWireLogManager()
|
||||
@@ -141,7 +143,7 @@ public class Core {
|
||||
|
||||
|
||||
log.info "initializing file manager"
|
||||
FileManager fileManager = new FileManager(eventBus)
|
||||
FileManager fileManager = new FileManager(eventBus, props)
|
||||
eventBus.register(FileHashedEvent.class, fileManager)
|
||||
eventBus.register(FileLoadedEvent.class, fileManager)
|
||||
eventBus.register(FileDownloadedEvent.class, fileManager)
|
||||
@@ -159,7 +161,8 @@ public class Core {
|
||||
|
||||
log.info("initializing connection manager")
|
||||
connectionManager = props.isLeaf() ?
|
||||
new LeafConnectionManager(eventBus, me, 3, hostCache) : new UltrapeerConnectionManager(eventBus, me, 512, 512, hostCache, trustService)
|
||||
new LeafConnectionManager(eventBus, me, 3, hostCache, props) :
|
||||
new UltrapeerConnectionManager(eventBus, me, 512, 512, hostCache, trustService, props)
|
||||
eventBus.register(TrustEvent.class, connectionManager)
|
||||
eventBus.register(ConnectionEvent.class, connectionManager)
|
||||
eventBus.register(DisconnectionEvent.class, connectionManager)
|
||||
@@ -189,15 +192,15 @@ public class Core {
|
||||
log.info("initializing upload manager")
|
||||
UploadManager uploadManager = new UploadManager(eventBus, fileManager)
|
||||
|
||||
log.info("initializing connection establisher")
|
||||
connectionEstablisher = new ConnectionEstablisher(eventBus, i2pConnector, props, connectionManager, hostCache)
|
||||
|
||||
log.info("initializing acceptor")
|
||||
I2PAcceptor i2pAcceptor = new I2PAcceptor(socketManager)
|
||||
connectionAcceptor = new ConnectionAcceptor(eventBus, connectionManager, props,
|
||||
i2pAcceptor, hostCache, trustService, searchManager, uploadManager)
|
||||
i2pAcceptor, hostCache, trustService, searchManager, uploadManager, connectionEstablisher)
|
||||
|
||||
|
||||
connectionEstablisher = new ConnectionEstablisher(eventBus, i2pConnector, props, connectionManager, hostCache)
|
||||
|
||||
log.info("initializing hasher service")
|
||||
hasherService = new HasherService(new FileHasher(), eventBus, fileManager)
|
||||
eventBus.register(FileSharedEvent.class, hasherService)
|
||||
@@ -245,7 +248,7 @@ public class Core {
|
||||
}
|
||||
}
|
||||
|
||||
Core core = new Core(props, home, "0.0.9")
|
||||
Core core = new Core(props, home, "0.0.11")
|
||||
core.startServices()
|
||||
|
||||
// ... at the end, sleep or execute script
|
||||
|
@@ -12,6 +12,7 @@ class MuWireSettings {
|
||||
File downloadLocation
|
||||
String sharedFiles
|
||||
CrawlerResponse crawlerResponse
|
||||
boolean shareDownloadedFiles
|
||||
|
||||
MuWireSettings() {
|
||||
this(new Properties())
|
||||
@@ -27,6 +28,7 @@ class MuWireSettings {
|
||||
sharedFiles = props.getProperty("sharedFiles")
|
||||
downloadRetryInterval = Integer.parseInt(props.getProperty("downloadRetryInterval","15"))
|
||||
updateCheckInterval = Integer.parseInt(props.getProperty("updateCheckInterval","36"))
|
||||
shareDownloadedFiles = Boolean.parseBoolean(props.getProperty("shareDownloadedFiles","true"))
|
||||
}
|
||||
|
||||
void write(OutputStream out) throws IOException {
|
||||
@@ -38,6 +40,7 @@ class MuWireSettings {
|
||||
props.setProperty("downloadLocation", downloadLocation.getAbsolutePath())
|
||||
props.setProperty("downloadRetryInterval", String.valueOf(downloadRetryInterval))
|
||||
props.setProperty("updateCheckInterval", String.valueOf(updateCheckInterval))
|
||||
props.setProperty("shareDownloadedFiles", String.valueOf(shareDownloadedFiles))
|
||||
if (sharedFiles != null)
|
||||
props.setProperty("sharedFiles", sharedFiles)
|
||||
props.store(out, "")
|
||||
|
@@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.logging.Level
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.hostcache.HostCache
|
||||
import com.muwire.core.hostcache.HostDiscoveredEvent
|
||||
@@ -26,7 +27,8 @@ abstract class Connection implements Closeable {
|
||||
final boolean incoming
|
||||
final HostCache hostCache
|
||||
final TrustService trustService
|
||||
|
||||
final MuWireSettings settings
|
||||
|
||||
private final AtomicBoolean running = new AtomicBoolean()
|
||||
private final BlockingQueue messages = new LinkedBlockingQueue()
|
||||
private final Thread reader, writer
|
||||
@@ -35,12 +37,14 @@ abstract class Connection implements Closeable {
|
||||
|
||||
long lastPingSentTime, lastPongReceivedTime
|
||||
|
||||
Connection(EventBus eventBus, Endpoint endpoint, boolean incoming, HostCache hostCache, TrustService trustService) {
|
||||
Connection(EventBus eventBus, Endpoint endpoint, boolean incoming,
|
||||
HostCache hostCache, TrustService trustService, MuWireSettings settings) {
|
||||
this.eventBus = eventBus
|
||||
this.incoming = incoming
|
||||
this.endpoint = endpoint
|
||||
this.hostCache = hostCache
|
||||
this.trustService = trustService
|
||||
this.settings = settings
|
||||
|
||||
this.name = endpoint.destination.toBase32().substring(0,8)
|
||||
|
||||
@@ -155,11 +159,15 @@ abstract class Connection implements Closeable {
|
||||
search.keywords = null
|
||||
|
||||
Destination replyTo = new Destination(search.replyTo)
|
||||
if (trustService.getLevel(replyTo) == TrustLevel.DISTRUSTED) {
|
||||
TrustLevel trustLevel = trustService.getLevel(replyTo)
|
||||
if (trustLevel == TrustLevel.DISTRUSTED) {
|
||||
log.info "dropping search from distrusted peer"
|
||||
return
|
||||
}
|
||||
// TODO: add option to respond only to trusted peers
|
||||
if (trustLevel == TrustLevel.NEUTRAL && !settings.allowUntrusted()) {
|
||||
log.info("dropping search from neutral peer")
|
||||
return
|
||||
}
|
||||
|
||||
Persona originator = null
|
||||
if (search.originator != null) {
|
||||
|
@@ -34,13 +34,15 @@ class ConnectionAcceptor {
|
||||
final TrustService trustService
|
||||
final SearchManager searchManager
|
||||
final UploadManager uploadManager
|
||||
final ConnectionEstablisher establisher
|
||||
|
||||
final ExecutorService acceptorThread
|
||||
final ExecutorService handshakerThreads
|
||||
|
||||
ConnectionAcceptor(EventBus eventBus, UltrapeerConnectionManager manager,
|
||||
MuWireSettings settings, I2PAcceptor acceptor, HostCache hostCache,
|
||||
TrustService trustService, SearchManager searchManager, UploadManager uploadManager) {
|
||||
TrustService trustService, SearchManager searchManager, UploadManager uploadManager,
|
||||
ConnectionEstablisher establisher) {
|
||||
this.eventBus = eventBus
|
||||
this.manager = manager
|
||||
this.settings = settings
|
||||
@@ -49,7 +51,8 @@ class ConnectionAcceptor {
|
||||
this.trustService = trustService
|
||||
this.searchManager = searchManager
|
||||
this.uploadManager = uploadManager
|
||||
|
||||
this.establisher = establisher
|
||||
|
||||
acceptorThread = Executors.newSingleThreadExecutor { r ->
|
||||
def rv = new Thread(r)
|
||||
rv.setDaemon(true)
|
||||
@@ -140,7 +143,9 @@ class ConnectionAcceptor {
|
||||
}
|
||||
|
||||
private void handleIncoming(Endpoint e, boolean leaf) {
|
||||
boolean accept = !manager.isConnected(e.destination) && (leaf ? manager.hasLeafSlots() : manager.hasPeerSlots())
|
||||
boolean accept = !manager.isConnected(e.destination) &&
|
||||
!establisher.inProgress.contains(e.destination) &&
|
||||
(leaf ? manager.hasLeafSlots() : manager.hasPeerSlots())
|
||||
if (accept) {
|
||||
log.info("accepting connection, leaf:$leaf")
|
||||
e.outputStream.write("OK".bytes)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package com.muwire.core.connection
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.hostcache.HostCache
|
||||
import com.muwire.core.search.QueryEvent
|
||||
@@ -19,13 +20,15 @@ abstract class ConnectionManager {
|
||||
|
||||
protected final HostCache hostCache
|
||||
protected final Persona me
|
||||
protected final MuWireSettings settings
|
||||
|
||||
ConnectionManager() {}
|
||||
|
||||
ConnectionManager(EventBus eventBus, Persona me, HostCache hostCache) {
|
||||
ConnectionManager(EventBus eventBus, Persona me, HostCache hostCache, MuWireSettings settings) {
|
||||
this.eventBus = eventBus
|
||||
this.me = me
|
||||
this.hostCache = hostCache
|
||||
this.settings = settings
|
||||
this.timer = new Timer("connections-pinger",true)
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.hostcache.HostCache
|
||||
import com.muwire.core.trust.TrustService
|
||||
|
||||
@@ -16,8 +17,9 @@ import net.i2p.data.Destination
|
||||
*/
|
||||
class LeafConnection extends Connection {
|
||||
|
||||
public LeafConnection(EventBus eventBus, Endpoint endpoint, HostCache hostCache, TrustService trustService) {
|
||||
super(eventBus, endpoint, true, hostCache, trustService);
|
||||
public LeafConnection(EventBus eventBus, Endpoint endpoint, HostCache hostCache,
|
||||
TrustService trustService, MuWireSettings settings) {
|
||||
super(eventBus, endpoint, true, hostCache, trustService, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -3,6 +3,7 @@ package com.muwire.core.connection
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.hostcache.HostCache
|
||||
import com.muwire.core.search.QueryEvent
|
||||
@@ -17,8 +18,9 @@ class LeafConnectionManager extends ConnectionManager {
|
||||
|
||||
final Map<Destination, UltrapeerConnection> connections = new ConcurrentHashMap()
|
||||
|
||||
public LeafConnectionManager(EventBus eventBus, Persona me, int maxConnections, HostCache hostCache) {
|
||||
super(eventBus, me, hostCache)
|
||||
public LeafConnectionManager(EventBus eventBus, Persona me, int maxConnections,
|
||||
HostCache hostCache, MuWireSettings settings) {
|
||||
super(eventBus, me, hostCache, settings)
|
||||
this.maxConnections = maxConnections
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.hostcache.HostCache
|
||||
import com.muwire.core.trust.TrustService
|
||||
import com.muwire.core.util.DataUtil
|
||||
@@ -29,8 +30,9 @@ class PeerConnection extends Connection {
|
||||
private final JsonSlurper slurper = new JsonSlurper()
|
||||
|
||||
public PeerConnection(EventBus eventBus, Endpoint endpoint,
|
||||
boolean incoming, HostCache hostCache, TrustService trustService) {
|
||||
super(eventBus, endpoint, incoming, hostCache, trustService)
|
||||
boolean incoming, HostCache hostCache, TrustService trustService,
|
||||
MuWireSettings settings) {
|
||||
super(eventBus, endpoint, incoming, hostCache, trustService, settings)
|
||||
this.dis = new DataInputStream(endpoint.inputStream)
|
||||
this.dos = new DataOutputStream(endpoint.outputStream)
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import java.util.Collection
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.MuWireSettings
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.hostcache.HostCache
|
||||
import com.muwire.core.search.QueryEvent
|
||||
@@ -17,15 +18,15 @@ class UltrapeerConnectionManager extends ConnectionManager {
|
||||
|
||||
final int maxPeers, maxLeafs
|
||||
final TrustService trustService
|
||||
|
||||
|
||||
final Map<Destination, PeerConnection> peerConnections = new ConcurrentHashMap()
|
||||
final Map<Destination, LeafConnection> leafConnections = new ConcurrentHashMap()
|
||||
|
||||
UltrapeerConnectionManager() {}
|
||||
|
||||
public UltrapeerConnectionManager(EventBus eventBus, Persona me, int maxPeers, int maxLeafs,
|
||||
HostCache hostCache, TrustService trustService) {
|
||||
super(eventBus, me, hostCache)
|
||||
HostCache hostCache, TrustService trustService, MuWireSettings settings) {
|
||||
super(eventBus, me, hostCache, settings)
|
||||
this.maxPeers = maxPeers
|
||||
this.maxLeafs = maxLeafs
|
||||
this.trustService = trustService
|
||||
@@ -85,8 +86,8 @@ class UltrapeerConnectionManager extends ConnectionManager {
|
||||
return
|
||||
|
||||
Connection c = e.leaf ?
|
||||
new LeafConnection(eventBus, e.endpoint, hostCache, trustService) :
|
||||
new PeerConnection(eventBus, e.endpoint, e.incoming, hostCache, trustService)
|
||||
new LeafConnection(eventBus, e.endpoint, hostCache, trustService, settings) :
|
||||
new PeerConnection(eventBus, e.endpoint, e.incoming, hostCache, trustService, settings)
|
||||
def map = e.leaf ? leafConnections : peerConnections
|
||||
map.put(e.endpoint.destination, c)
|
||||
c.start()
|
||||
|
@@ -47,7 +47,7 @@ public class DownloadManager {
|
||||
destinations.add(it.sender.destination)
|
||||
}
|
||||
|
||||
def downloader = new Downloader(this, me, e.target, size,
|
||||
def downloader = new Downloader(eventBus, this, me, e.target, size,
|
||||
infohash, pieceSize, connector, destinations,
|
||||
incompletes)
|
||||
executor.execute({downloader.download()} as Runnable)
|
||||
|
@@ -195,7 +195,8 @@ class DownloadSession {
|
||||
return reads[idx]
|
||||
|
||||
long interval = timestamps.last - timestamps[idx]
|
||||
|
||||
if (interval == 0)
|
||||
interval = 1
|
||||
for (int i = idx; i < SAMPLES; i++)
|
||||
totalRead += reads[idx]
|
||||
(int)(totalRead * 1000.0 / interval)
|
||||
|
@@ -10,7 +10,10 @@ import java.util.concurrent.Executors
|
||||
import java.util.logging.Level
|
||||
|
||||
import com.muwire.core.Constants
|
||||
import com.muwire.core.DownloadedFile
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.connection.I2PConnector
|
||||
import com.muwire.core.files.FileDownloadedEvent
|
||||
|
||||
import groovy.util.logging.Log
|
||||
import net.i2p.data.Destination
|
||||
@@ -27,6 +30,7 @@ public class Downloader {
|
||||
rv
|
||||
})
|
||||
|
||||
private final EventBus eventBus
|
||||
private final DownloadManager downloadManager
|
||||
private final Persona me
|
||||
private final File file
|
||||
@@ -42,10 +46,13 @@ public class Downloader {
|
||||
|
||||
|
||||
private volatile boolean cancelled
|
||||
private volatile boolean eventFired
|
||||
|
||||
public Downloader(DownloadManager downloadManager, Persona me, File file, long length, InfoHash infoHash,
|
||||
public Downloader(EventBus eventBus, DownloadManager downloadManager,
|
||||
Persona me, File file, long length, InfoHash infoHash,
|
||||
int pieceSizePow2, I2PConnector connector, Set<Destination> destinations,
|
||||
File incompletes) {
|
||||
this.eventBus = eventBus
|
||||
this.me = me
|
||||
this.downloadManager = downloadManager
|
||||
this.file = file
|
||||
@@ -195,6 +202,11 @@ public class Downloader {
|
||||
log.log(Level.WARNING,"Exception while downloading",bad)
|
||||
} finally {
|
||||
currentState = WorkerState.FINISHED
|
||||
if (downloaded.isComplete() && !eventFired) {
|
||||
piecesFile.delete()
|
||||
eventFired = true
|
||||
eventBus.publish(new FileDownloadedEvent(downloadedFile : new DownloadedFile(file, infoHash, Collections.emptySet())))
|
||||
}
|
||||
endpoint?.close()
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
package com.muwire.core.files
|
||||
|
||||
import com.muwire.core.Event
|
||||
|
||||
class AllFilesLoadedEvent extends Event {
|
||||
}
|
@@ -2,6 +2,7 @@ package com.muwire.core.files
|
||||
|
||||
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
|
||||
@@ -14,18 +15,22 @@ class FileManager {
|
||||
|
||||
|
||||
final EventBus eventBus
|
||||
final MuWireSettings settings
|
||||
final Map<InfoHash, Set<SharedFile>> rootToFiles = Collections.synchronizedMap(new HashMap<>())
|
||||
final Map<File, SharedFile> fileToSharedFile = Collections.synchronizedMap(new HashMap<>())
|
||||
final Map<String, Set<File>> nameToFiles = new HashMap<>()
|
||||
final SearchIndex index = new SearchIndex()
|
||||
|
||||
FileManager(EventBus eventBus) {
|
||||
FileManager(EventBus eventBus, MuWireSettings settings) {
|
||||
this.settings = settings
|
||||
this.eventBus = eventBus
|
||||
}
|
||||
|
||||
void onFileHashedEvent(FileHashedEvent e) {
|
||||
if (e.sharedFile != null)
|
||||
addToIndex(e.sharedFile)
|
||||
if (settings.shareDownloadedFiles) {
|
||||
if (e.sharedFile != null)
|
||||
addToIndex(e.sharedFile)
|
||||
}
|
||||
}
|
||||
|
||||
void onFileLoadedEvent(FileLoadedEvent e) {
|
||||
|
@@ -1,5 +1,8 @@
|
||||
package com.muwire.core.files
|
||||
|
||||
import java.nio.file.CopyOption
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.logging.Level
|
||||
import java.util.stream.Collectors
|
||||
|
||||
@@ -55,6 +58,7 @@ class PersisterService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
listener.publish(new AllFilesLoadedEvent())
|
||||
} catch (IllegalArgumentException|NumberFormatException e) {
|
||||
log.log(Level.WARNING, "couldn't load files",e)
|
||||
}
|
||||
@@ -107,15 +111,19 @@ class PersisterService extends Service {
|
||||
}
|
||||
|
||||
private void persistFiles() {
|
||||
location.delete()
|
||||
def sharedFiles = fileManager.getSharedFiles()
|
||||
location.withPrintWriter { writer ->
|
||||
|
||||
File tmp = File.createTempFile("muwire-files", "tmp")
|
||||
tmp.deleteOnExit()
|
||||
tmp.withPrintWriter { writer ->
|
||||
sharedFiles.each { k, v ->
|
||||
def json = toJson(k,v)
|
||||
json = JsonOutput.toJson(json)
|
||||
writer.println json
|
||||
}
|
||||
}
|
||||
Files.copy(tmp.toPath(), location.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
tmp.delete()
|
||||
}
|
||||
|
||||
private def toJson(File f, SharedFile sf) {
|
||||
|
@@ -140,7 +140,7 @@ class CacheClient {
|
||||
pong.pongs.asList().each {
|
||||
Destination dest = new Destination(it)
|
||||
if (!session.getMyDestination().equals(dest))
|
||||
eventBus.publish(new HostDiscoveredEvent(destination: dest))
|
||||
eventBus.publish(new HostDiscoveredEvent(destination: dest, fromHostcache : true))
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -30,4 +30,8 @@ class Host {
|
||||
synchronized boolean hasSucceeded() {
|
||||
successes > 0
|
||||
}
|
||||
|
||||
synchronized void clearFailures() {
|
||||
failures = 0
|
||||
}
|
||||
}
|
||||
|
@@ -46,8 +46,12 @@ class HostCache extends Service {
|
||||
void onHostDiscoveredEvent(HostDiscoveredEvent e) {
|
||||
if (myself == e.destination)
|
||||
return
|
||||
if (hosts.containsKey(e.destination))
|
||||
return
|
||||
if (hosts.containsKey(e.destination)) {
|
||||
if (!e.fromHostcache)
|
||||
return
|
||||
hosts.get(e.destination).clearFailures()
|
||||
return
|
||||
}
|
||||
Host host = new Host(e.destination)
|
||||
if (allowHost(host)) {
|
||||
hosts.put(e.destination, host)
|
||||
|
@@ -7,9 +7,10 @@ import net.i2p.data.Destination
|
||||
class HostDiscoveredEvent extends Event {
|
||||
|
||||
Destination destination
|
||||
|
||||
boolean fromHostcache
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
"HostDiscoveredEvent ${super.toString()} destination:${destination.toBase32()}"
|
||||
"HostDiscoveredEvent ${super.toString()} destination:${destination.toBase32()} from hostcache $fromHostcache"
|
||||
}
|
||||
}
|
||||
|
@@ -55,21 +55,21 @@ class JULLog extends Log {
|
||||
|
||||
@Override
|
||||
public boolean shouldDebug() {
|
||||
level.intValue().intValue() >= Level.FINE.intValue()
|
||||
level.intValue().intValue() <= Level.FINE.intValue()
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldInfo() {
|
||||
level.intValue().intValue() >= Level.INFO.intValue()
|
||||
level.intValue().intValue() <= Level.INFO.intValue()
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldWarn() {
|
||||
level.intValue().intValue() >= Level.WARNING.intValue()
|
||||
level.intValue().intValue() <= Level.WARNING.intValue()
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldError() {
|
||||
level.intValue().intValue() >= Level.SEVERE.intValue()
|
||||
level.intValue().intValue() <= Level.SEVERE.intValue()
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
group = com.muwire
|
||||
version = 0.0.9
|
||||
version = 0.0.11
|
||||
groovyVersion = 2.4.15
|
||||
slf4jVersion = 1.7.25
|
||||
spockVersion = 1.1-groovy-2.4
|
||||
|
@@ -52,7 +52,15 @@ class OptionsController {
|
||||
text = view.updateField.text
|
||||
model.updateCheckInterval = text
|
||||
settings.updateCheckInterval = Integer.valueOf(text)
|
||||
|
||||
|
||||
boolean onlyTrusted = view.allowUntrustedCheckbox.model.isSelected()
|
||||
model.onlyTrusted = onlyTrusted
|
||||
settings.setAllowUntrusted(!onlyTrusted)
|
||||
|
||||
boolean shareDownloaded = view.shareDownloadedCheckbox.model.isSelected()
|
||||
model.shareDownloadedFiles = shareDownloaded
|
||||
settings.shareDownloadedFiles = shareDownloaded
|
||||
|
||||
File settingsFile = new File(core.home, "MuWire.properties")
|
||||
settingsFile.withOutputStream {
|
||||
settings.write(it)
|
||||
|
@@ -15,6 +15,7 @@ import com.muwire.core.connection.ConnectionEvent
|
||||
import com.muwire.core.connection.DisconnectionEvent
|
||||
import com.muwire.core.download.DownloadStartedEvent
|
||||
import com.muwire.core.download.Downloader
|
||||
import com.muwire.core.files.FileDownloadedEvent
|
||||
import com.muwire.core.files.FileHashedEvent
|
||||
import com.muwire.core.files.FileLoadedEvent
|
||||
import com.muwire.core.files.FileSharedEvent
|
||||
@@ -100,6 +101,7 @@ class MainFrameModel {
|
||||
core.eventBus.register(TrustEvent.class, this)
|
||||
core.eventBus.register(QueryEvent.class, this)
|
||||
core.eventBus.register(UpdateAvailableEvent.class, this)
|
||||
core.eventBus.register(FileDownloadedEvent.class, this)
|
||||
|
||||
timer.schedule({
|
||||
int retryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
||||
@@ -261,4 +263,15 @@ class MainFrameModel {
|
||||
JOptionPane.showMessageDialog(null, "A new version of MuWire is available from $e.signer. Please update to $e.version")
|
||||
}
|
||||
}
|
||||
|
||||
void onFileDownloadedEvent(FileDownloadedEvent e) {
|
||||
if (!core.muOptions.shareDownloadedFiles)
|
||||
return
|
||||
infoHashes.add(e.downloadedFile.infoHash)
|
||||
runInsideUIAsync {
|
||||
shared << e.downloadedFile
|
||||
JTable table = builder.getVariable("shared-files-table")
|
||||
table.model.fireTableDataChanged()
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package com.muwire.gui
|
||||
|
||||
import com.muwire.core.Core
|
||||
import com.muwire.core.MuWireSettings
|
||||
|
||||
import griffon.core.artifact.GriffonModel
|
||||
import griffon.transform.Observable
|
||||
@@ -10,6 +11,8 @@ import griffon.metadata.ArtifactProviderFor
|
||||
class OptionsModel {
|
||||
@Observable String downloadRetryInterval
|
||||
@Observable String updateCheckInterval
|
||||
@Observable boolean onlyTrusted
|
||||
@Observable boolean shareDownloadedFiles
|
||||
|
||||
// i2p options
|
||||
@Observable String inboundLength
|
||||
@@ -18,8 +21,11 @@ class OptionsModel {
|
||||
@Observable String outboundQuantity
|
||||
|
||||
void mvcGroupInit(Map<String, String> args) {
|
||||
downloadRetryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
||||
updateCheckInterval = application.context.get("muwire-settings").updateCheckInterval
|
||||
MuWireSettings settings = application.context.get("muwire-settings")
|
||||
downloadRetryInterval = settings.downloadRetryInterval
|
||||
updateCheckInterval = settings.updateCheckInterval
|
||||
onlyTrusted = !settings.allowUntrusted()
|
||||
shareDownloadedFiles = settings.shareDownloadedFiles
|
||||
|
||||
Core core = application.context.get("core")
|
||||
inboundLength = core.i2pOptions["inbound.length"]
|
||||
|
@@ -27,6 +27,8 @@ class OptionsView {
|
||||
def i
|
||||
def retryField
|
||||
def updateField
|
||||
def allowUntrustedCheckbox
|
||||
def shareDownloadedCheckbox
|
||||
|
||||
def inboundLengthField
|
||||
def inboundQuantityField
|
||||
@@ -50,7 +52,13 @@ class OptionsView {
|
||||
label(text : "Check for updates every", constraints : gbc(gridx : 0, gridy: 1))
|
||||
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))
|
||||
allowUntrustedCheckbox = checkBox(selected : bind {model.onlyTrusted}, constraints : gbc(gridx: 1, gridy : 2))
|
||||
|
||||
label(text : "Share downloaded files", constraints : gbc(gridx : 0, gridy:3))
|
||||
shareDownloadedCheckbox = checkBox(selected : bind {model.shareDownloadedFiles}, constraints : gbc(gridx :1, gridy:3))
|
||||
|
||||
}
|
||||
i = builder.panel {
|
||||
gridBagLayout()
|
||||
|
@@ -1,2 +1,3 @@
|
||||
apply plugin : 'application'
|
||||
mainClassName = 'com.muwire.hostcache.HostCache'
|
||||
applicationDefaultJvmArgs = ['-Djava.util.logging.config.file=logging.properties']
|
||||
|
@@ -1,9 +1,12 @@
|
||||
package com.muwire.hostcache
|
||||
|
||||
import java.util.logging.Level
|
||||
import java.util.stream.Collectors
|
||||
|
||||
import groovy.util.logging.Log
|
||||
import net.i2p.data.Destination
|
||||
|
||||
@Log
|
||||
class Crawler {
|
||||
|
||||
final def pinger
|
||||
@@ -22,12 +25,14 @@ class Crawler {
|
||||
|
||||
synchronized def handleCrawlerPong(pong, Destination source) {
|
||||
if (!inFlight.containsKey(source)) {
|
||||
log.info("response from host that hasn't been crawled")
|
||||
return
|
||||
}
|
||||
Host host = inFlight.remove(source)
|
||||
|
||||
if (pong.uuid == null || pong.leafSlots == null || pong.peerSlots == null || pong.peers == null) {
|
||||
hostPool.fail(host)
|
||||
log.info("invalid crawler pong")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -40,6 +45,7 @@ class Crawler {
|
||||
}
|
||||
|
||||
if (!uuid.equals(currentUUID)) {
|
||||
log.info("uuid mismatch")
|
||||
hostPool.fail(host)
|
||||
return
|
||||
}
|
||||
@@ -50,7 +56,9 @@ class Crawler {
|
||||
def peers
|
||||
try {
|
||||
peers = pong.peers.stream().map({b64 -> new Destination(b64)}).collect(Collectors.toSet())
|
||||
log.info("received ${peers.size()} peers")
|
||||
} catch (Exception e) {
|
||||
log.log(Level.WARNING,"couldn't parse peers", e)
|
||||
hostPool.fail(host)
|
||||
return
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package com.muwire.hostcache
|
||||
|
||||
import java.util.logging.Level
|
||||
import java.util.stream.Collectors
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.util.logging.Log
|
||||
import net.i2p.client.I2PClientFactory
|
||||
import net.i2p.client.I2PSession
|
||||
import net.i2p.client.I2PSessionMuxedListener
|
||||
@@ -12,6 +14,7 @@ import net.i2p.client.datagram.I2PDatagramMaker
|
||||
import net.i2p.util.SystemVersion
|
||||
import net.i2p.data.*
|
||||
|
||||
@Log
|
||||
public class HostCache {
|
||||
|
||||
public static void main(String[] args) {
|
||||
@@ -53,7 +56,7 @@ public class HostCache {
|
||||
myDest = session.getMyDestination()
|
||||
|
||||
// initialize hostpool and crawler
|
||||
HostPool hostPool = new HostPool(3, 60 * 1000 * 1000)
|
||||
HostPool hostPool = new HostPool(3, 60 * 60 * 1000)
|
||||
Pinger pinger = new Pinger(session)
|
||||
Crawler crawler = new Crawler(pinger, hostPool, 5)
|
||||
|
||||
@@ -64,7 +67,7 @@ public class HostCache {
|
||||
session.addMuxedSessionListener(new Listener(hostPool: hostPool, toReturn: 2, crawler: crawler),
|
||||
I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY)
|
||||
session.connect()
|
||||
println "INFO: connected, going to sleep"
|
||||
log.info("connected, going to sleep")
|
||||
Thread.sleep(Integer.MAX_VALUE)
|
||||
|
||||
}
|
||||
@@ -77,16 +80,16 @@ public class HostCache {
|
||||
|
||||
void reportAbuse(I2PSession sesison, int severity) {}
|
||||
void disconnected(I2PSession session) {
|
||||
println "ERROR: session disconnected, exiting"
|
||||
log.severe("session disconnected, exiting")
|
||||
System.exit(1)
|
||||
}
|
||||
void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
println "ERROR: ${message} ${error}"
|
||||
log.warning("${message} ${error}")
|
||||
}
|
||||
void messageAvailable(I2PSession session, int msgId, long size, int proto,
|
||||
int fromport, int toport) {
|
||||
if (proto != I2PSession.PROTO_DATAGRAM) {
|
||||
println "WARN: received unexpected protocol ${proto}"
|
||||
log.warning("received unexpected protocol ${proto}")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -95,19 +98,19 @@ public class HostCache {
|
||||
try {
|
||||
dissector.loadI2PDatagram(payload)
|
||||
def sender = dissector.getSender()
|
||||
println "INFO: Received something from ${sender.toBase32()}"
|
||||
def b32 = sender.toBase32()
|
||||
|
||||
payload = dissector.getPayload()
|
||||
payload = json.parse(payload)
|
||||
if (payload.type == null) {
|
||||
println "WARN: type field missing"
|
||||
log.warning("type field missing from $b32")
|
||||
return
|
||||
}
|
||||
switch(payload.type) {
|
||||
case "Ping" :
|
||||
println "Ping"
|
||||
case "Ping" :
|
||||
log.info("ping from $b32")
|
||||
if (payload.leaf == null) {
|
||||
println "WARN: ping didn't specify if leaf"
|
||||
log.warning("ping didn't specify if leaf from $b32")
|
||||
return
|
||||
}
|
||||
payload.leaf = Boolean.parseBoolean(payload.leaf.toString())
|
||||
@@ -116,14 +119,14 @@ public class HostCache {
|
||||
respond(session, sender, payload)
|
||||
break
|
||||
case "CrawlerPong":
|
||||
println "CrawlerPong"
|
||||
log.info("CrawlerPong from $b32")
|
||||
crawler.handleCrawlerPong(payload, sender)
|
||||
break
|
||||
default:
|
||||
println "WARN: Unexpected message type ${payload.type}, dropping"
|
||||
log.warning("Unexpected message type ${payload.type}, dropping from $b32")
|
||||
}
|
||||
} catch (Exception dfe) {
|
||||
println "WARN: invalid datagram ${dfe}"
|
||||
log.log(Level.WARNING,"invalid datagram", dfe)
|
||||
}
|
||||
}
|
||||
void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
|
@@ -2,6 +2,7 @@ package com.muwire.update
|
||||
|
||||
import java.util.logging.Level
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.util.logging.Log
|
||||
import net.i2p.client.I2PClientFactory
|
||||
import net.i2p.client.I2PSession
|
||||
@@ -55,7 +56,7 @@ class UpdateServer {
|
||||
static class Listener implements I2PSessionMuxedListener {
|
||||
|
||||
private final File json
|
||||
|
||||
private final def slurper = new JsonSlurper()
|
||||
Listener(File json) {
|
||||
this.json = json
|
||||
}
|
||||
@@ -76,8 +77,9 @@ class UpdateServer {
|
||||
try {
|
||||
dissector.loadI2PDatagram(payload)
|
||||
def sender = dissector.getSender()
|
||||
log.info("Got an update ping from "+sender.toBase32())
|
||||
// I don't think we care about the payload at this point
|
||||
payload = slurper.parse(dissector.getPayload())
|
||||
log.info("Got an update ping from "+sender.toBase32() + " reported version "+payload?.myVersion)
|
||||
|
||||
def maker = new I2PDatagramMaker(session)
|
||||
def response = maker.makeI2PDatagram(json.bytes)
|
||||
session.sendMessage(sender, response, I2PSession.PROTO_DATAGRAM, 0, 2)
|
||||
|
Reference in New Issue
Block a user