Compare commits
35 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 | ||
![]() |
9a2531b264 | ||
![]() |
9a8dadff57 | ||
![]() |
4a274010f9 | ||
![]() |
1eb930435b | ||
![]() |
9df28552ad | ||
![]() |
ac0204dffc | ||
![]() |
e5c402a400 | ||
![]() |
7704c73b68 | ||
![]() |
a9aa8dd840 | ||
![]() |
de682a802a | ||
![]() |
5435518212 | ||
![]() |
bd01f983c9 | ||
![]() |
8b63864b90 |
@@ -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
|
### Known bugs and limitations
|
||||||
|
|
||||||
* Any shared files get re-hashed on startup
|
|
||||||
* Sometimes the list of shared files gets lost
|
* Sometimes the list of shared files gets lost
|
||||||
* Many UI features you would expect are not there yet
|
* Many UI features you would expect are not there yet
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
apply plugin : 'application'
|
apply plugin : 'application'
|
||||||
|
|
||||||
mainClassName = 'com.muwire.cli.Cli'
|
mainClassName = 'com.muwire.cli.Cli'
|
||||||
|
applicationDefaultJvmArgs = ['-Djava.util.logging.config.file=logging.properties']
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(":core")
|
compile project(":core")
|
||||||
|
@@ -1,7 +1,12 @@
|
|||||||
package com.muwire.cli
|
package com.muwire.cli
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
|
||||||
import com.muwire.core.Core
|
import com.muwire.core.Core
|
||||||
import com.muwire.core.MuWireSettings
|
import com.muwire.core.MuWireSettings
|
||||||
|
import com.muwire.core.files.AllFilesLoadedEvent
|
||||||
|
import com.muwire.core.files.FileHashedEvent
|
||||||
|
import com.muwire.core.files.FileSharedEvent
|
||||||
|
|
||||||
class Cli {
|
class Cli {
|
||||||
|
|
||||||
@@ -23,20 +28,59 @@ class Cli {
|
|||||||
|
|
||||||
Core core
|
Core core
|
||||||
try {
|
try {
|
||||||
core = new Core(props, home, "0.0.8")
|
core = new Core(props, home, "0.0.11")
|
||||||
} catch (Exception bad) {
|
} catch (Exception bad) {
|
||||||
bad.printStackTrace(System.out)
|
bad.printStackTrace(System.out)
|
||||||
println "Failed to initialize core, exiting"
|
println "Failed to initialize core, exiting"
|
||||||
System.exit(1)
|
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()
|
core.startServices()
|
||||||
|
|
||||||
|
println "waiting for files to load"
|
||||||
|
latch.await()
|
||||||
|
|
||||||
|
|
||||||
// now we begin
|
// now we begin
|
||||||
println "MuWire is ready"
|
println "MuWire is ready"
|
||||||
println "Enter a file containing list of files to share"
|
|
||||||
def reader = new BufferedReader(new InputStreamReader(System.in))
|
def filesList
|
||||||
def filesList = reader.readLine()
|
if (args.length == 0) {
|
||||||
|
println "Enter a file containing list of files to share"
|
||||||
|
def reader = new BufferedReader(new InputStreamReader(System.in))
|
||||||
|
filesList = reader.readLine()
|
||||||
|
} else
|
||||||
|
filesList = args[0]
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
filesList = new File(filesList)
|
||||||
|
filesList.withReader {
|
||||||
|
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)
|
Thread.sleep(Integer.MAX_VALUE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -56,6 +56,8 @@ public class Core {
|
|||||||
final EventBus eventBus
|
final EventBus eventBus
|
||||||
final Persona me
|
final Persona me
|
||||||
final File home
|
final File home
|
||||||
|
final Properties i2pOptions
|
||||||
|
final MuWireSettings muOptions
|
||||||
|
|
||||||
private final TrustService trustService
|
private final TrustService trustService
|
||||||
private final PersisterService persisterService
|
private final PersisterService persisterService
|
||||||
@@ -69,6 +71,7 @@ public class Core {
|
|||||||
|
|
||||||
public Core(MuWireSettings props, File home, String myVersion) {
|
public Core(MuWireSettings props, File home, String myVersion) {
|
||||||
this.home = home
|
this.home = home
|
||||||
|
this.muOptions = props
|
||||||
log.info "Initializing I2P context"
|
log.info "Initializing I2P context"
|
||||||
I2PAppContext.getGlobalContext().logManager()
|
I2PAppContext.getGlobalContext().logManager()
|
||||||
I2PAppContext.getGlobalContext()._logManager = new MuWireLogManager()
|
I2PAppContext.getGlobalContext()._logManager = new MuWireLogManager()
|
||||||
@@ -83,12 +86,23 @@ public class Core {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def sysProps = System.getProperties().clone()
|
i2pOptions = new Properties()
|
||||||
sysProps["inbound.nickname"] = "MuWire"
|
def i2pOptionsFile = new File(home,"i2p.properties")
|
||||||
|
if (i2pOptionsFile.exists()) {
|
||||||
|
i2pOptionsFile.withInputStream { i2pOptions.load(it) }
|
||||||
|
} else {
|
||||||
|
i2pOptions["inbound.nickname"] = "MuWire"
|
||||||
|
i2pOptions["inbound.length"] = "3"
|
||||||
|
i2pOptions["inbound.quantity"] = "2"
|
||||||
|
i2pOptions["outbound.length"] = "3"
|
||||||
|
i2pOptions["outbound.quantity"] = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
// options like tunnel length and quantity
|
||||||
I2PSession i2pSession
|
I2PSession i2pSession
|
||||||
I2PSocketManager socketManager
|
I2PSocketManager socketManager
|
||||||
keyDat.withInputStream {
|
keyDat.withInputStream {
|
||||||
socketManager = new I2PSocketManagerFactory().createManager(it, sysProps)
|
socketManager = new I2PSocketManagerFactory().createManager(it, i2pOptions)
|
||||||
}
|
}
|
||||||
socketManager.getDefaultOptions().setReadTimeout(60000)
|
socketManager.getDefaultOptions().setReadTimeout(60000)
|
||||||
socketManager.getDefaultOptions().setConnectTimeout(30000)
|
socketManager.getDefaultOptions().setConnectTimeout(30000)
|
||||||
@@ -129,7 +143,7 @@ public class Core {
|
|||||||
|
|
||||||
|
|
||||||
log.info "initializing file manager"
|
log.info "initializing file manager"
|
||||||
FileManager fileManager = new FileManager(eventBus)
|
FileManager fileManager = new FileManager(eventBus, props)
|
||||||
eventBus.register(FileHashedEvent.class, fileManager)
|
eventBus.register(FileHashedEvent.class, fileManager)
|
||||||
eventBus.register(FileLoadedEvent.class, fileManager)
|
eventBus.register(FileLoadedEvent.class, fileManager)
|
||||||
eventBus.register(FileDownloadedEvent.class, fileManager)
|
eventBus.register(FileDownloadedEvent.class, fileManager)
|
||||||
@@ -147,7 +161,8 @@ public class Core {
|
|||||||
|
|
||||||
log.info("initializing connection manager")
|
log.info("initializing connection manager")
|
||||||
connectionManager = props.isLeaf() ?
|
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(TrustEvent.class, connectionManager)
|
||||||
eventBus.register(ConnectionEvent.class, connectionManager)
|
eventBus.register(ConnectionEvent.class, connectionManager)
|
||||||
eventBus.register(DisconnectionEvent.class, connectionManager)
|
eventBus.register(DisconnectionEvent.class, connectionManager)
|
||||||
@@ -177,17 +192,17 @@ public class Core {
|
|||||||
log.info("initializing upload manager")
|
log.info("initializing upload manager")
|
||||||
UploadManager uploadManager = new UploadManager(eventBus, fileManager)
|
UploadManager uploadManager = new UploadManager(eventBus, fileManager)
|
||||||
|
|
||||||
|
log.info("initializing connection establisher")
|
||||||
|
connectionEstablisher = new ConnectionEstablisher(eventBus, i2pConnector, props, connectionManager, hostCache)
|
||||||
|
|
||||||
log.info("initializing acceptor")
|
log.info("initializing acceptor")
|
||||||
I2PAcceptor i2pAcceptor = new I2PAcceptor(socketManager)
|
I2PAcceptor i2pAcceptor = new I2PAcceptor(socketManager)
|
||||||
connectionAcceptor = new ConnectionAcceptor(eventBus, connectionManager, props,
|
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")
|
log.info("initializing hasher service")
|
||||||
hasherService = new HasherService(new FileHasher(), eventBus)
|
hasherService = new HasherService(new FileHasher(), eventBus, fileManager)
|
||||||
eventBus.register(FileSharedEvent.class, hasherService)
|
eventBus.register(FileSharedEvent.class, hasherService)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +248,7 @@ public class Core {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core core = new Core(props, home, "0.0.8")
|
Core core = new Core(props, home, "0.0.11")
|
||||||
core.startServices()
|
core.startServices()
|
||||||
|
|
||||||
// ... at the end, sleep or execute script
|
// ... at the end, sleep or execute script
|
||||||
|
@@ -12,6 +12,7 @@ class MuWireSettings {
|
|||||||
File downloadLocation
|
File downloadLocation
|
||||||
String sharedFiles
|
String sharedFiles
|
||||||
CrawlerResponse crawlerResponse
|
CrawlerResponse crawlerResponse
|
||||||
|
boolean shareDownloadedFiles
|
||||||
|
|
||||||
MuWireSettings() {
|
MuWireSettings() {
|
||||||
this(new Properties())
|
this(new Properties())
|
||||||
@@ -27,6 +28,7 @@ class MuWireSettings {
|
|||||||
sharedFiles = props.getProperty("sharedFiles")
|
sharedFiles = props.getProperty("sharedFiles")
|
||||||
downloadRetryInterval = Integer.parseInt(props.getProperty("downloadRetryInterval","15"))
|
downloadRetryInterval = Integer.parseInt(props.getProperty("downloadRetryInterval","15"))
|
||||||
updateCheckInterval = Integer.parseInt(props.getProperty("updateCheckInterval","36"))
|
updateCheckInterval = Integer.parseInt(props.getProperty("updateCheckInterval","36"))
|
||||||
|
shareDownloadedFiles = Boolean.parseBoolean(props.getProperty("shareDownloadedFiles","true"))
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(OutputStream out) throws IOException {
|
void write(OutputStream out) throws IOException {
|
||||||
@@ -38,6 +40,7 @@ class MuWireSettings {
|
|||||||
props.setProperty("downloadLocation", downloadLocation.getAbsolutePath())
|
props.setProperty("downloadLocation", downloadLocation.getAbsolutePath())
|
||||||
props.setProperty("downloadRetryInterval", String.valueOf(downloadRetryInterval))
|
props.setProperty("downloadRetryInterval", String.valueOf(downloadRetryInterval))
|
||||||
props.setProperty("updateCheckInterval", String.valueOf(updateCheckInterval))
|
props.setProperty("updateCheckInterval", String.valueOf(updateCheckInterval))
|
||||||
|
props.setProperty("shareDownloadedFiles", String.valueOf(shareDownloadedFiles))
|
||||||
if (sharedFiles != null)
|
if (sharedFiles != null)
|
||||||
props.setProperty("sharedFiles", sharedFiles)
|
props.setProperty("sharedFiles", sharedFiles)
|
||||||
props.store(out, "")
|
props.store(out, "")
|
||||||
|
@@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.Persona
|
import com.muwire.core.Persona
|
||||||
import com.muwire.core.hostcache.HostCache
|
import com.muwire.core.hostcache.HostCache
|
||||||
import com.muwire.core.hostcache.HostDiscoveredEvent
|
import com.muwire.core.hostcache.HostDiscoveredEvent
|
||||||
@@ -26,7 +27,8 @@ abstract class Connection implements Closeable {
|
|||||||
final boolean incoming
|
final boolean incoming
|
||||||
final HostCache hostCache
|
final HostCache hostCache
|
||||||
final TrustService trustService
|
final TrustService trustService
|
||||||
|
final MuWireSettings settings
|
||||||
|
|
||||||
private final AtomicBoolean running = new AtomicBoolean()
|
private final AtomicBoolean running = new AtomicBoolean()
|
||||||
private final BlockingQueue messages = new LinkedBlockingQueue()
|
private final BlockingQueue messages = new LinkedBlockingQueue()
|
||||||
private final Thread reader, writer
|
private final Thread reader, writer
|
||||||
@@ -35,12 +37,14 @@ abstract class Connection implements Closeable {
|
|||||||
|
|
||||||
long lastPingSentTime, lastPongReceivedTime
|
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.eventBus = eventBus
|
||||||
this.incoming = incoming
|
this.incoming = incoming
|
||||||
this.endpoint = endpoint
|
this.endpoint = endpoint
|
||||||
this.hostCache = hostCache
|
this.hostCache = hostCache
|
||||||
this.trustService = trustService
|
this.trustService = trustService
|
||||||
|
this.settings = settings
|
||||||
|
|
||||||
this.name = endpoint.destination.toBase32().substring(0,8)
|
this.name = endpoint.destination.toBase32().substring(0,8)
|
||||||
|
|
||||||
@@ -155,11 +159,15 @@ abstract class Connection implements Closeable {
|
|||||||
search.keywords = null
|
search.keywords = null
|
||||||
|
|
||||||
Destination replyTo = new Destination(search.replyTo)
|
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"
|
log.info "dropping search from distrusted peer"
|
||||||
return
|
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
|
Persona originator = null
|
||||||
if (search.originator != null) {
|
if (search.originator != null) {
|
||||||
|
@@ -34,13 +34,15 @@ class ConnectionAcceptor {
|
|||||||
final TrustService trustService
|
final TrustService trustService
|
||||||
final SearchManager searchManager
|
final SearchManager searchManager
|
||||||
final UploadManager uploadManager
|
final UploadManager uploadManager
|
||||||
|
final ConnectionEstablisher establisher
|
||||||
|
|
||||||
final ExecutorService acceptorThread
|
final ExecutorService acceptorThread
|
||||||
final ExecutorService handshakerThreads
|
final ExecutorService handshakerThreads
|
||||||
|
|
||||||
ConnectionAcceptor(EventBus eventBus, UltrapeerConnectionManager manager,
|
ConnectionAcceptor(EventBus eventBus, UltrapeerConnectionManager manager,
|
||||||
MuWireSettings settings, I2PAcceptor acceptor, HostCache hostCache,
|
MuWireSettings settings, I2PAcceptor acceptor, HostCache hostCache,
|
||||||
TrustService trustService, SearchManager searchManager, UploadManager uploadManager) {
|
TrustService trustService, SearchManager searchManager, UploadManager uploadManager,
|
||||||
|
ConnectionEstablisher establisher) {
|
||||||
this.eventBus = eventBus
|
this.eventBus = eventBus
|
||||||
this.manager = manager
|
this.manager = manager
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
@@ -49,7 +51,8 @@ class ConnectionAcceptor {
|
|||||||
this.trustService = trustService
|
this.trustService = trustService
|
||||||
this.searchManager = searchManager
|
this.searchManager = searchManager
|
||||||
this.uploadManager = uploadManager
|
this.uploadManager = uploadManager
|
||||||
|
this.establisher = establisher
|
||||||
|
|
||||||
acceptorThread = Executors.newSingleThreadExecutor { r ->
|
acceptorThread = Executors.newSingleThreadExecutor { r ->
|
||||||
def rv = new Thread(r)
|
def rv = new Thread(r)
|
||||||
rv.setDaemon(true)
|
rv.setDaemon(true)
|
||||||
@@ -140,7 +143,9 @@ class ConnectionAcceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleIncoming(Endpoint e, boolean leaf) {
|
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) {
|
if (accept) {
|
||||||
log.info("accepting connection, leaf:$leaf")
|
log.info("accepting connection, leaf:$leaf")
|
||||||
e.outputStream.write("OK".bytes)
|
e.outputStream.write("OK".bytes)
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package com.muwire.core.connection
|
package com.muwire.core.connection
|
||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.Persona
|
import com.muwire.core.Persona
|
||||||
import com.muwire.core.hostcache.HostCache
|
import com.muwire.core.hostcache.HostCache
|
||||||
import com.muwire.core.search.QueryEvent
|
import com.muwire.core.search.QueryEvent
|
||||||
@@ -19,13 +20,15 @@ abstract class ConnectionManager {
|
|||||||
|
|
||||||
protected final HostCache hostCache
|
protected final HostCache hostCache
|
||||||
protected final Persona me
|
protected final Persona me
|
||||||
|
protected final MuWireSettings settings
|
||||||
|
|
||||||
ConnectionManager() {}
|
ConnectionManager() {}
|
||||||
|
|
||||||
ConnectionManager(EventBus eventBus, Persona me, HostCache hostCache) {
|
ConnectionManager(EventBus eventBus, Persona me, HostCache hostCache, MuWireSettings settings) {
|
||||||
this.eventBus = eventBus
|
this.eventBus = eventBus
|
||||||
this.me = me
|
this.me = me
|
||||||
this.hostCache = hostCache
|
this.hostCache = hostCache
|
||||||
|
this.settings = settings
|
||||||
this.timer = new Timer("connections-pinger",true)
|
this.timer = new Timer("connections-pinger",true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import java.io.InputStream
|
|||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.hostcache.HostCache
|
import com.muwire.core.hostcache.HostCache
|
||||||
import com.muwire.core.trust.TrustService
|
import com.muwire.core.trust.TrustService
|
||||||
|
|
||||||
@@ -16,8 +17,9 @@ import net.i2p.data.Destination
|
|||||||
*/
|
*/
|
||||||
class LeafConnection extends Connection {
|
class LeafConnection extends Connection {
|
||||||
|
|
||||||
public LeafConnection(EventBus eventBus, Endpoint endpoint, HostCache hostCache, TrustService trustService) {
|
public LeafConnection(EventBus eventBus, Endpoint endpoint, HostCache hostCache,
|
||||||
super(eventBus, endpoint, true, hostCache, trustService);
|
TrustService trustService, MuWireSettings settings) {
|
||||||
|
super(eventBus, endpoint, true, hostCache, trustService, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -3,6 +3,7 @@ package com.muwire.core.connection
|
|||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.Persona
|
import com.muwire.core.Persona
|
||||||
import com.muwire.core.hostcache.HostCache
|
import com.muwire.core.hostcache.HostCache
|
||||||
import com.muwire.core.search.QueryEvent
|
import com.muwire.core.search.QueryEvent
|
||||||
@@ -17,8 +18,9 @@ class LeafConnectionManager extends ConnectionManager {
|
|||||||
|
|
||||||
final Map<Destination, UltrapeerConnection> connections = new ConcurrentHashMap()
|
final Map<Destination, UltrapeerConnection> connections = new ConcurrentHashMap()
|
||||||
|
|
||||||
public LeafConnectionManager(EventBus eventBus, Persona me, int maxConnections, HostCache hostCache) {
|
public LeafConnectionManager(EventBus eventBus, Persona me, int maxConnections,
|
||||||
super(eventBus, me, hostCache)
|
HostCache hostCache, MuWireSettings settings) {
|
||||||
|
super(eventBus, me, hostCache, settings)
|
||||||
this.maxConnections = maxConnections
|
this.maxConnections = maxConnections
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import java.io.InputStream
|
|||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.hostcache.HostCache
|
import com.muwire.core.hostcache.HostCache
|
||||||
import com.muwire.core.trust.TrustService
|
import com.muwire.core.trust.TrustService
|
||||||
import com.muwire.core.util.DataUtil
|
import com.muwire.core.util.DataUtil
|
||||||
@@ -29,8 +30,9 @@ class PeerConnection extends Connection {
|
|||||||
private final JsonSlurper slurper = new JsonSlurper()
|
private final JsonSlurper slurper = new JsonSlurper()
|
||||||
|
|
||||||
public PeerConnection(EventBus eventBus, Endpoint endpoint,
|
public PeerConnection(EventBus eventBus, Endpoint endpoint,
|
||||||
boolean incoming, HostCache hostCache, TrustService trustService) {
|
boolean incoming, HostCache hostCache, TrustService trustService,
|
||||||
super(eventBus, endpoint, incoming, hostCache, trustService)
|
MuWireSettings settings) {
|
||||||
|
super(eventBus, endpoint, incoming, hostCache, trustService, settings)
|
||||||
this.dis = new DataInputStream(endpoint.inputStream)
|
this.dis = new DataInputStream(endpoint.inputStream)
|
||||||
this.dos = new DataOutputStream(endpoint.outputStream)
|
this.dos = new DataOutputStream(endpoint.outputStream)
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import java.util.Collection
|
|||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.Persona
|
import com.muwire.core.Persona
|
||||||
import com.muwire.core.hostcache.HostCache
|
import com.muwire.core.hostcache.HostCache
|
||||||
import com.muwire.core.search.QueryEvent
|
import com.muwire.core.search.QueryEvent
|
||||||
@@ -17,15 +18,15 @@ class UltrapeerConnectionManager extends ConnectionManager {
|
|||||||
|
|
||||||
final int maxPeers, maxLeafs
|
final int maxPeers, maxLeafs
|
||||||
final TrustService trustService
|
final TrustService trustService
|
||||||
|
|
||||||
final Map<Destination, PeerConnection> peerConnections = new ConcurrentHashMap()
|
final Map<Destination, PeerConnection> peerConnections = new ConcurrentHashMap()
|
||||||
final Map<Destination, LeafConnection> leafConnections = new ConcurrentHashMap()
|
final Map<Destination, LeafConnection> leafConnections = new ConcurrentHashMap()
|
||||||
|
|
||||||
UltrapeerConnectionManager() {}
|
UltrapeerConnectionManager() {}
|
||||||
|
|
||||||
public UltrapeerConnectionManager(EventBus eventBus, Persona me, int maxPeers, int maxLeafs,
|
public UltrapeerConnectionManager(EventBus eventBus, Persona me, int maxPeers, int maxLeafs,
|
||||||
HostCache hostCache, TrustService trustService) {
|
HostCache hostCache, TrustService trustService, MuWireSettings settings) {
|
||||||
super(eventBus, me, hostCache)
|
super(eventBus, me, hostCache, settings)
|
||||||
this.maxPeers = maxPeers
|
this.maxPeers = maxPeers
|
||||||
this.maxLeafs = maxLeafs
|
this.maxLeafs = maxLeafs
|
||||||
this.trustService = trustService
|
this.trustService = trustService
|
||||||
@@ -85,8 +86,8 @@ class UltrapeerConnectionManager extends ConnectionManager {
|
|||||||
return
|
return
|
||||||
|
|
||||||
Connection c = e.leaf ?
|
Connection c = e.leaf ?
|
||||||
new LeafConnection(eventBus, e.endpoint, hostCache, trustService) :
|
new LeafConnection(eventBus, e.endpoint, hostCache, trustService, settings) :
|
||||||
new PeerConnection(eventBus, e.endpoint, e.incoming, hostCache, trustService)
|
new PeerConnection(eventBus, e.endpoint, e.incoming, hostCache, trustService, settings)
|
||||||
def map = e.leaf ? leafConnections : peerConnections
|
def map = e.leaf ? leafConnections : peerConnections
|
||||||
map.put(e.endpoint.destination, c)
|
map.put(e.endpoint.destination, c)
|
||||||
c.start()
|
c.start()
|
||||||
|
@@ -47,7 +47,7 @@ public class DownloadManager {
|
|||||||
destinations.add(it.sender.destination)
|
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,
|
infohash, pieceSize, connector, destinations,
|
||||||
incompletes)
|
incompletes)
|
||||||
executor.execute({downloader.download()} as Runnable)
|
executor.execute({downloader.download()} as Runnable)
|
||||||
|
@@ -31,8 +31,8 @@ class DownloadSession {
|
|||||||
private final long fileLength
|
private final long fileLength
|
||||||
private final MessageDigest digest
|
private final MessageDigest digest
|
||||||
|
|
||||||
private final ArrayDeque<Long> timestamps = new ArrayDeque<>(SAMPLES)
|
private final LinkedList<Long> timestamps = new LinkedList<>()
|
||||||
private final ArrayDeque<Integer> reads = new ArrayDeque<>(SAMPLES)
|
private final LinkedList<Integer> reads = new LinkedList<>()
|
||||||
|
|
||||||
private ByteBuffer mapped
|
private ByteBuffer mapped
|
||||||
|
|
||||||
@@ -183,9 +183,22 @@ class DownloadSession {
|
|||||||
synchronized int speed() {
|
synchronized int speed() {
|
||||||
if (timestamps.size() < SAMPLES)
|
if (timestamps.size() < SAMPLES)
|
||||||
return 0
|
return 0
|
||||||
long interval = timestamps.last - timestamps.first
|
|
||||||
int totalRead = 0
|
int totalRead = 0
|
||||||
reads.each { totalRead += it }
|
int idx = 0
|
||||||
|
final long now = System.currentTimeMillis()
|
||||||
|
|
||||||
|
while(idx < SAMPLES && timestamps.get(idx) < now - 1000)
|
||||||
|
idx++
|
||||||
|
if (idx == SAMPLES)
|
||||||
|
return 0
|
||||||
|
if (idx == SAMPLES - 1)
|
||||||
|
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)
|
(int)(totalRead * 1000.0 / interval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,10 @@ import java.util.concurrent.Executors
|
|||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
import com.muwire.core.Constants
|
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.connection.I2PConnector
|
||||||
|
import com.muwire.core.files.FileDownloadedEvent
|
||||||
|
|
||||||
import groovy.util.logging.Log
|
import groovy.util.logging.Log
|
||||||
import net.i2p.data.Destination
|
import net.i2p.data.Destination
|
||||||
@@ -27,6 +30,7 @@ public class Downloader {
|
|||||||
rv
|
rv
|
||||||
})
|
})
|
||||||
|
|
||||||
|
private final EventBus eventBus
|
||||||
private final DownloadManager downloadManager
|
private final DownloadManager downloadManager
|
||||||
private final Persona me
|
private final Persona me
|
||||||
private final File file
|
private final File file
|
||||||
@@ -42,10 +46,13 @@ public class Downloader {
|
|||||||
|
|
||||||
|
|
||||||
private volatile boolean cancelled
|
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,
|
int pieceSizePow2, I2PConnector connector, Set<Destination> destinations,
|
||||||
File incompletes) {
|
File incompletes) {
|
||||||
|
this.eventBus = eventBus
|
||||||
this.me = me
|
this.me = me
|
||||||
this.downloadManager = downloadManager
|
this.downloadManager = downloadManager
|
||||||
this.file = file
|
this.file = file
|
||||||
@@ -104,7 +111,8 @@ public class Downloader {
|
|||||||
int total = 0
|
int total = 0
|
||||||
if (getCurrentState() == DownloadState.DOWNLOADING) {
|
if (getCurrentState() == DownloadState.DOWNLOADING) {
|
||||||
activeWorkers.values().each {
|
activeWorkers.values().each {
|
||||||
total += it.speed()
|
if (it.currentState == WorkerState.DOWNLOADING)
|
||||||
|
total += it.speed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total
|
total
|
||||||
@@ -155,7 +163,13 @@ public class Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void resume() {
|
public void resume() {
|
||||||
downloadManager.resume(this)
|
activeWorkers.each { destination, worker ->
|
||||||
|
if (worker.currentState == WorkerState.FINISHED) {
|
||||||
|
def newWorker = new DownloadWorker(destination)
|
||||||
|
activeWorkers.put(destination, newWorker)
|
||||||
|
executorService.submit(newWorker)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadWorker implements Runnable {
|
class DownloadWorker implements Runnable {
|
||||||
@@ -188,6 +202,11 @@ public class Downloader {
|
|||||||
log.log(Level.WARNING,"Exception while downloading",bad)
|
log.log(Level.WARNING,"Exception while downloading",bad)
|
||||||
} finally {
|
} finally {
|
||||||
currentState = WorkerState.FINISHED
|
currentState = WorkerState.FINISHED
|
||||||
|
if (downloaded.isComplete() && !eventFired) {
|
||||||
|
piecesFile.delete()
|
||||||
|
eventFired = true
|
||||||
|
eventBus.publish(new FileDownloadedEvent(downloadedFile : new DownloadedFile(file, infoHash, Collections.emptySet())))
|
||||||
|
}
|
||||||
endpoint?.close()
|
endpoint?.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,6 @@
|
|||||||
|
package com.muwire.core.files
|
||||||
|
|
||||||
|
import com.muwire.core.Event
|
||||||
|
|
||||||
|
class AllFilesLoadedEvent extends Event {
|
||||||
|
}
|
@@ -52,11 +52,11 @@ class FileHasher {
|
|||||||
try {
|
try {
|
||||||
MappedByteBuffer buf
|
MappedByteBuffer buf
|
||||||
for (int i = 0; i < numPieces - 1; i++) {
|
for (int i = 0; i < numPieces - 1; i++) {
|
||||||
buf = raf.getChannel().map(MapMode.READ_ONLY, size * i, size)
|
buf = raf.getChannel().map(MapMode.READ_ONLY, ((long)size) * i, size)
|
||||||
digest.update buf
|
digest.update buf
|
||||||
output.write(digest.digest(), 0, 32)
|
output.write(digest.digest(), 0, 32)
|
||||||
}
|
}
|
||||||
def lastPieceLength = length - (numPieces - 1) * size
|
def lastPieceLength = length - (numPieces - 1) * ((long)size)
|
||||||
buf = raf.getChannel().map(MapMode.READ_ONLY, length - lastPieceLength, lastPieceLength)
|
buf = raf.getChannel().map(MapMode.READ_ONLY, length - lastPieceLength, lastPieceLength)
|
||||||
digest.update buf
|
digest.update buf
|
||||||
output.write(digest.digest(), 0, 32)
|
output.write(digest.digest(), 0, 32)
|
||||||
|
@@ -2,6 +2,7 @@ package com.muwire.core.files
|
|||||||
|
|
||||||
import com.muwire.core.EventBus
|
import com.muwire.core.EventBus
|
||||||
import com.muwire.core.InfoHash
|
import com.muwire.core.InfoHash
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
import com.muwire.core.SharedFile
|
import com.muwire.core.SharedFile
|
||||||
import com.muwire.core.search.ResultsEvent
|
import com.muwire.core.search.ResultsEvent
|
||||||
import com.muwire.core.search.SearchEvent
|
import com.muwire.core.search.SearchEvent
|
||||||
@@ -14,18 +15,22 @@ class FileManager {
|
|||||||
|
|
||||||
|
|
||||||
final EventBus eventBus
|
final EventBus eventBus
|
||||||
|
final MuWireSettings settings
|
||||||
final Map<InfoHash, Set<SharedFile>> rootToFiles = Collections.synchronizedMap(new HashMap<>())
|
final Map<InfoHash, Set<SharedFile>> rootToFiles = Collections.synchronizedMap(new HashMap<>())
|
||||||
final Map<File, SharedFile> fileToSharedFile = Collections.synchronizedMap(new HashMap<>())
|
final Map<File, SharedFile> fileToSharedFile = Collections.synchronizedMap(new HashMap<>())
|
||||||
final Map<String, Set<File>> nameToFiles = new HashMap<>()
|
final Map<String, Set<File>> nameToFiles = new HashMap<>()
|
||||||
final SearchIndex index = new SearchIndex()
|
final SearchIndex index = new SearchIndex()
|
||||||
|
|
||||||
FileManager(EventBus eventBus) {
|
FileManager(EventBus eventBus, MuWireSettings settings) {
|
||||||
|
this.settings = settings
|
||||||
this.eventBus = eventBus
|
this.eventBus = eventBus
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFileHashedEvent(FileHashedEvent e) {
|
void onFileHashedEvent(FileHashedEvent e) {
|
||||||
if (e.sharedFile != null)
|
if (settings.shareDownloadedFiles) {
|
||||||
addToIndex(e.sharedFile)
|
if (e.sharedFile != null)
|
||||||
|
addToIndex(e.sharedFile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFileLoadedEvent(FileLoadedEvent e) {
|
void onFileLoadedEvent(FileLoadedEvent e) {
|
||||||
|
@@ -10,11 +10,13 @@ class HasherService {
|
|||||||
|
|
||||||
final FileHasher hasher
|
final FileHasher hasher
|
||||||
final EventBus eventBus
|
final EventBus eventBus
|
||||||
|
final FileManager fileManager
|
||||||
Executor executor
|
Executor executor
|
||||||
|
|
||||||
HasherService(FileHasher hasher, EventBus eventBus) {
|
HasherService(FileHasher hasher, EventBus eventBus, FileManager fileManager) {
|
||||||
this.hasher = hasher
|
this.hasher = hasher
|
||||||
this.eventBus = eventBus
|
this.eventBus = eventBus
|
||||||
|
this.fileManager = fileManager
|
||||||
}
|
}
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
@@ -22,6 +24,8 @@ class HasherService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onFileSharedEvent(FileSharedEvent evt) {
|
void onFileSharedEvent(FileSharedEvent evt) {
|
||||||
|
if (fileManager.fileToSharedFile.containsKey(evt.file))
|
||||||
|
return
|
||||||
executor.execute( { -> process(evt.file) } as Runnable)
|
executor.execute( { -> process(evt.file) } as Runnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
package com.muwire.core.files
|
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.logging.Level
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
@@ -34,7 +37,7 @@ class PersisterService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
timer.schedule({load()} as TimerTask, 1000)
|
timer.schedule({load()} as TimerTask, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
@@ -55,6 +58,7 @@ class PersisterService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
listener.publish(new AllFilesLoadedEvent())
|
||||||
} catch (IllegalArgumentException|NumberFormatException e) {
|
} catch (IllegalArgumentException|NumberFormatException e) {
|
||||||
log.log(Level.WARNING, "couldn't load files",e)
|
log.log(Level.WARNING, "couldn't load files",e)
|
||||||
}
|
}
|
||||||
@@ -107,15 +111,19 @@ class PersisterService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void persistFiles() {
|
private void persistFiles() {
|
||||||
location.delete()
|
|
||||||
def sharedFiles = fileManager.getSharedFiles()
|
def sharedFiles = fileManager.getSharedFiles()
|
||||||
location.withPrintWriter { writer ->
|
|
||||||
|
File tmp = File.createTempFile("muwire-files", "tmp")
|
||||||
|
tmp.deleteOnExit()
|
||||||
|
tmp.withPrintWriter { writer ->
|
||||||
sharedFiles.each { k, v ->
|
sharedFiles.each { k, v ->
|
||||||
def json = toJson(k,v)
|
def json = toJson(k,v)
|
||||||
json = JsonOutput.toJson(json)
|
json = JsonOutput.toJson(json)
|
||||||
writer.println json
|
writer.println json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Files.copy(tmp.toPath(), location.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
tmp.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
private def toJson(File f, SharedFile sf) {
|
private def toJson(File f, SharedFile sf) {
|
||||||
|
@@ -140,7 +140,7 @@ class CacheClient {
|
|||||||
pong.pongs.asList().each {
|
pong.pongs.asList().each {
|
||||||
Destination dest = new Destination(it)
|
Destination dest = new Destination(it)
|
||||||
if (!session.getMyDestination().equals(dest))
|
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() {
|
synchronized boolean hasSucceeded() {
|
||||||
successes > 0
|
successes > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized void clearFailures() {
|
||||||
|
failures = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,8 +46,12 @@ class HostCache extends Service {
|
|||||||
void onHostDiscoveredEvent(HostDiscoveredEvent e) {
|
void onHostDiscoveredEvent(HostDiscoveredEvent e) {
|
||||||
if (myself == e.destination)
|
if (myself == e.destination)
|
||||||
return
|
return
|
||||||
if (hosts.containsKey(e.destination))
|
if (hosts.containsKey(e.destination)) {
|
||||||
return
|
if (!e.fromHostcache)
|
||||||
|
return
|
||||||
|
hosts.get(e.destination).clearFailures()
|
||||||
|
return
|
||||||
|
}
|
||||||
Host host = new Host(e.destination)
|
Host host = new Host(e.destination)
|
||||||
if (allowHost(host)) {
|
if (allowHost(host)) {
|
||||||
hosts.put(e.destination, host)
|
hosts.put(e.destination, host)
|
||||||
|
@@ -7,9 +7,10 @@ import net.i2p.data.Destination
|
|||||||
class HostDiscoveredEvent extends Event {
|
class HostDiscoveredEvent extends Event {
|
||||||
|
|
||||||
Destination destination
|
Destination destination
|
||||||
|
boolean fromHostcache
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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
|
@Override
|
||||||
public boolean shouldDebug() {
|
public boolean shouldDebug() {
|
||||||
level.intValue().intValue() >= Level.FINE.intValue()
|
level.intValue().intValue() <= Level.FINE.intValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldInfo() {
|
public boolean shouldInfo() {
|
||||||
level.intValue().intValue() >= Level.INFO.intValue()
|
level.intValue().intValue() <= Level.INFO.intValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldWarn() {
|
public boolean shouldWarn() {
|
||||||
level.intValue().intValue() >= Level.WARNING.intValue()
|
level.intValue().intValue() <= Level.WARNING.intValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldError() {
|
public boolean shouldError() {
|
||||||
level.intValue().intValue() >= Level.SEVERE.intValue()
|
level.intValue().intValue() <= Level.SEVERE.intValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
group = com.muwire
|
group = com.muwire
|
||||||
version = 0.0.8
|
version = 0.0.11
|
||||||
groovyVersion = 2.4.15
|
groovyVersion = 2.4.15
|
||||||
slf4jVersion = 1.7.25
|
slf4jVersion = 1.7.25
|
||||||
spockVersion = 1.1-groovy-2.4
|
spockVersion = 1.1-groovy-2.4
|
||||||
|
@@ -6,6 +6,8 @@ import griffon.inject.MVCMember
|
|||||||
import griffon.metadata.ArtifactProviderFor
|
import griffon.metadata.ArtifactProviderFor
|
||||||
import javax.annotation.Nonnull
|
import javax.annotation.Nonnull
|
||||||
|
|
||||||
|
import com.muwire.core.Core
|
||||||
|
|
||||||
@ArtifactProviderFor(GriffonController)
|
@ArtifactProviderFor(GriffonController)
|
||||||
class OptionsController {
|
class OptionsController {
|
||||||
@MVCMember @Nonnull
|
@MVCMember @Nonnull
|
||||||
@@ -15,17 +17,51 @@ class OptionsController {
|
|||||||
|
|
||||||
@ControllerAction
|
@ControllerAction
|
||||||
void save() {
|
void save() {
|
||||||
String text = view.retryField.text
|
String text
|
||||||
model.downloadRetryInterval = text
|
Core core = application.context.get("core")
|
||||||
|
|
||||||
|
def i2pProps = core.i2pOptions
|
||||||
|
|
||||||
|
text = view.inboundLengthField.text
|
||||||
|
model.inboundLength = text
|
||||||
|
i2pProps["inbound.length"] = text
|
||||||
|
|
||||||
|
text = view.inboundQuantityField.text
|
||||||
|
model.inboundQuantity = text
|
||||||
|
i2pProps["inbound.quantity"] = text
|
||||||
|
|
||||||
|
text = view.outboundQuantityField.text
|
||||||
|
model.outboundQuantity = text
|
||||||
|
i2pProps["outbound.quantity"] = text
|
||||||
|
|
||||||
|
text = view.outboundLengthField.text
|
||||||
|
model.outboundLength = text
|
||||||
|
i2pProps["outbound.length"] = text
|
||||||
|
|
||||||
|
File i2pSettingsFile = new File(core.home, "i2p.properties")
|
||||||
|
i2pSettingsFile.withOutputStream {
|
||||||
|
i2pProps.store(it,"")
|
||||||
|
}
|
||||||
|
|
||||||
|
text = view.retryField.text
|
||||||
|
model.downloadRetryInterval = text
|
||||||
|
|
||||||
def settings = application.context.get("muwire-settings")
|
def settings = application.context.get("muwire-settings")
|
||||||
settings.downloadRetryInterval = Integer.valueOf(text)
|
settings.downloadRetryInterval = Integer.valueOf(text)
|
||||||
|
|
||||||
text = view.updateField.text
|
text = view.updateField.text
|
||||||
model.updateCheckInterval = text
|
model.updateCheckInterval = text
|
||||||
settings.updateCheckInterval = Integer.valueOf(text)
|
settings.updateCheckInterval = Integer.valueOf(text)
|
||||||
|
|
||||||
File settingsFile = new File(application.context.get("core").home, "MuWire.properties")
|
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 {
|
settingsFile.withOutputStream {
|
||||||
settings.write(it)
|
settings.write(it)
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ import com.muwire.core.connection.ConnectionEvent
|
|||||||
import com.muwire.core.connection.DisconnectionEvent
|
import com.muwire.core.connection.DisconnectionEvent
|
||||||
import com.muwire.core.download.DownloadStartedEvent
|
import com.muwire.core.download.DownloadStartedEvent
|
||||||
import com.muwire.core.download.Downloader
|
import com.muwire.core.download.Downloader
|
||||||
|
import com.muwire.core.files.FileDownloadedEvent
|
||||||
import com.muwire.core.files.FileHashedEvent
|
import com.muwire.core.files.FileHashedEvent
|
||||||
import com.muwire.core.files.FileLoadedEvent
|
import com.muwire.core.files.FileLoadedEvent
|
||||||
import com.muwire.core.files.FileSharedEvent
|
import com.muwire.core.files.FileSharedEvent
|
||||||
@@ -100,6 +101,7 @@ class MainFrameModel {
|
|||||||
core.eventBus.register(TrustEvent.class, this)
|
core.eventBus.register(TrustEvent.class, this)
|
||||||
core.eventBus.register(QueryEvent.class, this)
|
core.eventBus.register(QueryEvent.class, this)
|
||||||
core.eventBus.register(UpdateAvailableEvent.class, this)
|
core.eventBus.register(UpdateAvailableEvent.class, this)
|
||||||
|
core.eventBus.register(FileDownloadedEvent.class, this)
|
||||||
|
|
||||||
timer.schedule({
|
timer.schedule({
|
||||||
int retryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
int retryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
||||||
@@ -110,7 +112,9 @@ class MainFrameModel {
|
|||||||
lastRetryTime = now
|
lastRetryTime = now
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
downloads.each {
|
downloads.each {
|
||||||
if (it.downloader.currentState == Downloader.DownloadState.FAILED)
|
def state = it.downloader.currentState
|
||||||
|
if (state == Downloader.DownloadState.FAILED ||
|
||||||
|
state == Downloader.DownloadState.DOWNLOADING)
|
||||||
it.downloader.resume()
|
it.downloader.resume()
|
||||||
updateTablePreservingSelection("downloads-table")
|
updateTablePreservingSelection("downloads-table")
|
||||||
}
|
}
|
||||||
@@ -259,4 +263,15 @@ class MainFrameModel {
|
|||||||
JOptionPane.showMessageDialog(null, "A new version of MuWire is available from $e.signer. Please update to $e.version")
|
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,5 +1,8 @@
|
|||||||
package com.muwire.gui
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import com.muwire.core.Core
|
||||||
|
import com.muwire.core.MuWireSettings
|
||||||
|
|
||||||
import griffon.core.artifact.GriffonModel
|
import griffon.core.artifact.GriffonModel
|
||||||
import griffon.transform.Observable
|
import griffon.transform.Observable
|
||||||
import griffon.metadata.ArtifactProviderFor
|
import griffon.metadata.ArtifactProviderFor
|
||||||
@@ -8,9 +11,26 @@ import griffon.metadata.ArtifactProviderFor
|
|||||||
class OptionsModel {
|
class OptionsModel {
|
||||||
@Observable String downloadRetryInterval
|
@Observable String downloadRetryInterval
|
||||||
@Observable String updateCheckInterval
|
@Observable String updateCheckInterval
|
||||||
|
@Observable boolean onlyTrusted
|
||||||
|
@Observable boolean shareDownloadedFiles
|
||||||
|
|
||||||
|
// i2p options
|
||||||
|
@Observable String inboundLength
|
||||||
|
@Observable String inboundQuantity
|
||||||
|
@Observable String outboundLength
|
||||||
|
@Observable String outboundQuantity
|
||||||
|
|
||||||
void mvcGroupInit(Map<String, String> args) {
|
void mvcGroupInit(Map<String, String> args) {
|
||||||
downloadRetryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
MuWireSettings settings = application.context.get("muwire-settings")
|
||||||
updateCheckInterval = application.context.get("muwire-settings").updateCheckInterval
|
downloadRetryInterval = settings.downloadRetryInterval
|
||||||
|
updateCheckInterval = settings.updateCheckInterval
|
||||||
|
onlyTrusted = !settings.allowUntrusted()
|
||||||
|
shareDownloadedFiles = settings.shareDownloadedFiles
|
||||||
|
|
||||||
|
Core core = application.context.get("core")
|
||||||
|
inboundLength = core.i2pOptions["inbound.length"]
|
||||||
|
inboundQuantity = core.i2pOptions["inbound.quantity"]
|
||||||
|
outboundLength = core.i2pOptions["outbound.length"]
|
||||||
|
outboundQuantity = core.i2pOptions["outbound.quantity"]
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,10 +9,12 @@ import javax.swing.BorderFactory
|
|||||||
import javax.swing.Box
|
import javax.swing.Box
|
||||||
import javax.swing.BoxLayout
|
import javax.swing.BoxLayout
|
||||||
import javax.swing.JFileChooser
|
import javax.swing.JFileChooser
|
||||||
|
import javax.swing.JLabel
|
||||||
import javax.swing.JSplitPane
|
import javax.swing.JSplitPane
|
||||||
import javax.swing.ListSelectionModel
|
import javax.swing.ListSelectionModel
|
||||||
import javax.swing.SwingConstants
|
import javax.swing.SwingConstants
|
||||||
import javax.swing.border.Border
|
import javax.swing.border.Border
|
||||||
|
import javax.swing.table.DefaultTableCellRenderer
|
||||||
|
|
||||||
import com.muwire.core.Constants
|
import com.muwire.core.Constants
|
||||||
import com.muwire.core.download.Downloader
|
import com.muwire.core.download.Downloader
|
||||||
@@ -269,6 +271,10 @@ class MainFrameView {
|
|||||||
model.retryButtonEnabled = false
|
model.retryButtonEnabled = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def centerRenderer = new DefaultTableCellRenderer()
|
||||||
|
centerRenderer.setHorizontalAlignment(JLabel.CENTER)
|
||||||
|
builder.getVariable("downloads-table").setDefaultRenderer(Integer.class, centerRenderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
def showSearchWindow = {
|
def showSearchWindow = {
|
||||||
|
@@ -5,8 +5,11 @@ import griffon.inject.MVCMember
|
|||||||
import griffon.metadata.ArtifactProviderFor
|
import griffon.metadata.ArtifactProviderFor
|
||||||
|
|
||||||
import javax.swing.JDialog
|
import javax.swing.JDialog
|
||||||
|
import javax.swing.JPanel
|
||||||
|
import javax.swing.JTabbedPane
|
||||||
import javax.swing.SwingConstants
|
import javax.swing.SwingConstants
|
||||||
|
|
||||||
|
import java.awt.BorderLayout
|
||||||
import java.awt.event.WindowAdapter
|
import java.awt.event.WindowAdapter
|
||||||
import java.awt.event.WindowEvent
|
import java.awt.event.WindowEvent
|
||||||
|
|
||||||
@@ -21,8 +24,19 @@ class OptionsView {
|
|||||||
|
|
||||||
def d
|
def d
|
||||||
def p
|
def p
|
||||||
|
def i
|
||||||
def retryField
|
def retryField
|
||||||
def updateField
|
def updateField
|
||||||
|
def allowUntrustedCheckbox
|
||||||
|
def shareDownloadedCheckbox
|
||||||
|
|
||||||
|
def inboundLengthField
|
||||||
|
def inboundQuantityField
|
||||||
|
def outboundLengthField
|
||||||
|
def outboundQuantityField
|
||||||
|
|
||||||
|
def buttonsPanel
|
||||||
|
|
||||||
def mainFrame
|
def mainFrame
|
||||||
|
|
||||||
void initUI() {
|
void initUI() {
|
||||||
@@ -38,14 +52,44 @@ class OptionsView {
|
|||||||
label(text : "Check for updates every", constraints : gbc(gridx : 0, gridy: 1))
|
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))
|
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 : "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()
|
||||||
|
label(text : "Changing these settings requires a restart", constraints : gbc(gridx : 0, gridy : 0, gridwidth: 2))
|
||||||
|
label(text : "Inbound Length", constraints : gbc(gridx:0, gridy:1))
|
||||||
|
inboundLengthField = textField(text : bind {model.inboundLength}, columns : 2, constraints : gbc(gridx:1, gridy:1))
|
||||||
|
label(text : "Inbound Quantity", constraints : gbc(gridx:0, gridy:2))
|
||||||
|
inboundQuantityField = textField(text : bind {model.inboundQuantity}, columns : 2, constraints : gbc(gridx:1, gridy:2))
|
||||||
|
label(text : "Outbound Length", constraints : gbc(gridx:0, gridy:3))
|
||||||
|
outboundLengthField = textField(text : bind {model.outboundLength}, columns : 2, constraints : gbc(gridx:1, gridy:3))
|
||||||
|
label(text : "Outbound Quantity", constraints : gbc(gridx:0, gridy:4))
|
||||||
|
outboundQuantityField = textField(text : bind {model.outboundQuantity}, columns : 2, constraints : gbc(gridx:1, gridy:4))
|
||||||
|
}
|
||||||
|
buttonsPanel = builder.panel {
|
||||||
|
gridBagLayout()
|
||||||
button(text : "Save", constraints : gbc(gridx : 1, gridy: 2), saveAction)
|
button(text : "Save", constraints : gbc(gridx : 1, gridy: 2), saveAction)
|
||||||
button(text : "Cancel", constraints : gbc(gridx : 2, gridy: 2), cancelAction)
|
button(text : "Cancel", constraints : gbc(gridx : 2, gridy: 2), cancelAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mvcGroupInit(Map<String,String> args) {
|
void mvcGroupInit(Map<String,String> args) {
|
||||||
d.getContentPane().add(p)
|
def tabbedPane = new JTabbedPane()
|
||||||
|
tabbedPane.addTab("MuWire Options", p)
|
||||||
|
tabbedPane.addTab("I2P Options", i)
|
||||||
|
|
||||||
|
JPanel panel = new JPanel()
|
||||||
|
panel.setLayout(new BorderLayout())
|
||||||
|
panel.add(tabbedPane, BorderLayout.CENTER)
|
||||||
|
panel.add(buttonsPanel, BorderLayout.SOUTH)
|
||||||
|
|
||||||
|
d.getContentPane().add(panel)
|
||||||
d.pack()
|
d.pack()
|
||||||
d.setLocationRelativeTo(mainFrame)
|
d.setLocationRelativeTo(mainFrame)
|
||||||
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE)
|
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE)
|
||||||
|
@@ -33,7 +33,7 @@ class SearchTabView {
|
|||||||
def pane = scrollPane {
|
def pane = scrollPane {
|
||||||
resultsTable = table(id : "results-table") {
|
resultsTable = table(id : "results-table") {
|
||||||
tableModel(list: model.results) {
|
tableModel(list: model.results) {
|
||||||
closureColumn(header: "Name", preferredWidth: 350, type: String, read : {row -> row.name})
|
closureColumn(header: "Name", preferredWidth: 350, type: String, read : {row -> row.name.replace('<','_')})
|
||||||
closureColumn(header: "Size", preferredWidth: 50, type: String, read : {row -> DataHelper.formatSize2Decimal(row.size, false)+"B"})
|
closureColumn(header: "Size", preferredWidth: 50, type: String, read : {row -> DataHelper.formatSize2Decimal(row.size, false)+"B"})
|
||||||
closureColumn(header: "Sources", preferredWidth: 10, type : Integer, read : { row -> model.hashBucket[row.infohash].size()})
|
closureColumn(header: "Sources", preferredWidth: 10, type : Integer, read : { row -> model.hashBucket[row.infohash].size()})
|
||||||
closureColumn(header: "Sender", preferredWidth: 170, type: String, read : {row -> row.sender.getHumanReadableName()})
|
closureColumn(header: "Sender", preferredWidth: 170, type: String, read : {row -> row.sender.getHumanReadableName()})
|
||||||
@@ -62,7 +62,7 @@ class SearchTabView {
|
|||||||
searchTerms = args["search-terms"]
|
searchTerms = args["search-terms"]
|
||||||
parent = mvcGroup.parentGroup.view.builder.getVariable("result-tabs")
|
parent = mvcGroup.parentGroup.view.builder.getVariable("result-tabs")
|
||||||
parent.addTab(searchTerms, pane)
|
parent.addTab(searchTerms, pane)
|
||||||
int index = parent.indexOfTab(searchTerms)
|
int index = parent.indexOfComponent(pane)
|
||||||
parent.setSelectedIndex(index)
|
parent.setSelectedIndex(index)
|
||||||
|
|
||||||
def tabPanel
|
def tabPanel
|
||||||
|
@@ -1,2 +1,3 @@
|
|||||||
apply plugin : 'application'
|
apply plugin : 'application'
|
||||||
mainClassName = 'com.muwire.hostcache.HostCache'
|
mainClassName = 'com.muwire.hostcache.HostCache'
|
||||||
|
applicationDefaultJvmArgs = ['-Djava.util.logging.config.file=logging.properties']
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
package com.muwire.hostcache
|
package com.muwire.hostcache
|
||||||
|
|
||||||
|
import java.util.logging.Level
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
|
import groovy.util.logging.Log
|
||||||
import net.i2p.data.Destination
|
import net.i2p.data.Destination
|
||||||
|
|
||||||
|
@Log
|
||||||
class Crawler {
|
class Crawler {
|
||||||
|
|
||||||
final def pinger
|
final def pinger
|
||||||
@@ -22,12 +25,14 @@ class Crawler {
|
|||||||
|
|
||||||
synchronized def handleCrawlerPong(pong, Destination source) {
|
synchronized def handleCrawlerPong(pong, Destination source) {
|
||||||
if (!inFlight.containsKey(source)) {
|
if (!inFlight.containsKey(source)) {
|
||||||
|
log.info("response from host that hasn't been crawled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Host host = inFlight.remove(source)
|
Host host = inFlight.remove(source)
|
||||||
|
|
||||||
if (pong.uuid == null || pong.leafSlots == null || pong.peerSlots == null || pong.peers == null) {
|
if (pong.uuid == null || pong.leafSlots == null || pong.peerSlots == null || pong.peers == null) {
|
||||||
hostPool.fail(host)
|
hostPool.fail(host)
|
||||||
|
log.info("invalid crawler pong")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +45,7 @@ class Crawler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!uuid.equals(currentUUID)) {
|
if (!uuid.equals(currentUUID)) {
|
||||||
|
log.info("uuid mismatch")
|
||||||
hostPool.fail(host)
|
hostPool.fail(host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -50,7 +56,9 @@ class Crawler {
|
|||||||
def peers
|
def peers
|
||||||
try {
|
try {
|
||||||
peers = pong.peers.stream().map({b64 -> new Destination(b64)}).collect(Collectors.toSet())
|
peers = pong.peers.stream().map({b64 -> new Destination(b64)}).collect(Collectors.toSet())
|
||||||
|
log.info("received ${peers.size()} peers")
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
log.log(Level.WARNING,"couldn't parse peers", e)
|
||||||
hostPool.fail(host)
|
hostPool.fail(host)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
package com.muwire.hostcache
|
package com.muwire.hostcache
|
||||||
|
|
||||||
|
import java.util.logging.Level
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
import groovy.json.JsonOutput
|
import groovy.json.JsonOutput
|
||||||
import groovy.json.JsonSlurper
|
import groovy.json.JsonSlurper
|
||||||
|
import groovy.util.logging.Log
|
||||||
import net.i2p.client.I2PClientFactory
|
import net.i2p.client.I2PClientFactory
|
||||||
import net.i2p.client.I2PSession
|
import net.i2p.client.I2PSession
|
||||||
import net.i2p.client.I2PSessionMuxedListener
|
import net.i2p.client.I2PSessionMuxedListener
|
||||||
@@ -12,6 +14,7 @@ import net.i2p.client.datagram.I2PDatagramMaker
|
|||||||
import net.i2p.util.SystemVersion
|
import net.i2p.util.SystemVersion
|
||||||
import net.i2p.data.*
|
import net.i2p.data.*
|
||||||
|
|
||||||
|
@Log
|
||||||
public class HostCache {
|
public class HostCache {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@@ -53,7 +56,7 @@ public class HostCache {
|
|||||||
myDest = session.getMyDestination()
|
myDest = session.getMyDestination()
|
||||||
|
|
||||||
// initialize hostpool and crawler
|
// 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)
|
Pinger pinger = new Pinger(session)
|
||||||
Crawler crawler = new Crawler(pinger, hostPool, 5)
|
Crawler crawler = new Crawler(pinger, hostPool, 5)
|
||||||
|
|
||||||
@@ -64,7 +67,7 @@ public class HostCache {
|
|||||||
session.addMuxedSessionListener(new Listener(hostPool: hostPool, toReturn: 2, crawler: crawler),
|
session.addMuxedSessionListener(new Listener(hostPool: hostPool, toReturn: 2, crawler: crawler),
|
||||||
I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY)
|
I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY)
|
||||||
session.connect()
|
session.connect()
|
||||||
println "INFO: connected, going to sleep"
|
log.info("connected, going to sleep")
|
||||||
Thread.sleep(Integer.MAX_VALUE)
|
Thread.sleep(Integer.MAX_VALUE)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -77,16 +80,16 @@ public class HostCache {
|
|||||||
|
|
||||||
void reportAbuse(I2PSession sesison, int severity) {}
|
void reportAbuse(I2PSession sesison, int severity) {}
|
||||||
void disconnected(I2PSession session) {
|
void disconnected(I2PSession session) {
|
||||||
println "ERROR: session disconnected, exiting"
|
log.severe("session disconnected, exiting")
|
||||||
System.exit(1)
|
System.exit(1)
|
||||||
}
|
}
|
||||||
void errorOccurred(I2PSession session, String message, Throwable error) {
|
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,
|
void messageAvailable(I2PSession session, int msgId, long size, int proto,
|
||||||
int fromport, int toport) {
|
int fromport, int toport) {
|
||||||
if (proto != I2PSession.PROTO_DATAGRAM) {
|
if (proto != I2PSession.PROTO_DATAGRAM) {
|
||||||
println "WARN: received unexpected protocol ${proto}"
|
log.warning("received unexpected protocol ${proto}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,19 +98,19 @@ public class HostCache {
|
|||||||
try {
|
try {
|
||||||
dissector.loadI2PDatagram(payload)
|
dissector.loadI2PDatagram(payload)
|
||||||
def sender = dissector.getSender()
|
def sender = dissector.getSender()
|
||||||
println "INFO: Received something from ${sender.toBase32()}"
|
def b32 = sender.toBase32()
|
||||||
|
|
||||||
payload = dissector.getPayload()
|
payload = dissector.getPayload()
|
||||||
payload = json.parse(payload)
|
payload = json.parse(payload)
|
||||||
if (payload.type == null) {
|
if (payload.type == null) {
|
||||||
println "WARN: type field missing"
|
log.warning("type field missing from $b32")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch(payload.type) {
|
switch(payload.type) {
|
||||||
case "Ping" :
|
case "Ping" :
|
||||||
println "Ping"
|
log.info("ping from $b32")
|
||||||
if (payload.leaf == null) {
|
if (payload.leaf == null) {
|
||||||
println "WARN: ping didn't specify if leaf"
|
log.warning("ping didn't specify if leaf from $b32")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
payload.leaf = Boolean.parseBoolean(payload.leaf.toString())
|
payload.leaf = Boolean.parseBoolean(payload.leaf.toString())
|
||||||
@@ -116,14 +119,14 @@ public class HostCache {
|
|||||||
respond(session, sender, payload)
|
respond(session, sender, payload)
|
||||||
break
|
break
|
||||||
case "CrawlerPong":
|
case "CrawlerPong":
|
||||||
println "CrawlerPong"
|
log.info("CrawlerPong from $b32")
|
||||||
crawler.handleCrawlerPong(payload, sender)
|
crawler.handleCrawlerPong(payload, sender)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
println "WARN: Unexpected message type ${payload.type}, dropping"
|
log.warning("Unexpected message type ${payload.type}, dropping from $b32")
|
||||||
}
|
}
|
||||||
} catch (Exception dfe) {
|
} catch (Exception dfe) {
|
||||||
println "WARN: invalid datagram ${dfe}"
|
log.log(Level.WARNING,"invalid datagram", dfe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void messageAvailable(I2PSession session, int msgId, long size) {
|
void messageAvailable(I2PSession session, int msgId, long size) {
|
||||||
|
@@ -2,6 +2,7 @@ package com.muwire.update
|
|||||||
|
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
|
import groovy.json.JsonSlurper
|
||||||
import groovy.util.logging.Log
|
import groovy.util.logging.Log
|
||||||
import net.i2p.client.I2PClientFactory
|
import net.i2p.client.I2PClientFactory
|
||||||
import net.i2p.client.I2PSession
|
import net.i2p.client.I2PSession
|
||||||
@@ -55,7 +56,7 @@ class UpdateServer {
|
|||||||
static class Listener implements I2PSessionMuxedListener {
|
static class Listener implements I2PSessionMuxedListener {
|
||||||
|
|
||||||
private final File json
|
private final File json
|
||||||
|
private final def slurper = new JsonSlurper()
|
||||||
Listener(File json) {
|
Listener(File json) {
|
||||||
this.json = json
|
this.json = json
|
||||||
}
|
}
|
||||||
@@ -76,8 +77,9 @@ class UpdateServer {
|
|||||||
try {
|
try {
|
||||||
dissector.loadI2PDatagram(payload)
|
dissector.loadI2PDatagram(payload)
|
||||||
def sender = dissector.getSender()
|
def sender = dissector.getSender()
|
||||||
log.info("Got an update ping from "+sender.toBase32())
|
payload = slurper.parse(dissector.getPayload())
|
||||||
// I don't think we care about the payload at this point
|
log.info("Got an update ping from "+sender.toBase32() + " reported version "+payload?.myVersion)
|
||||||
|
|
||||||
def maker = new I2PDatagramMaker(session)
|
def maker = new I2PDatagramMaker(session)
|
||||||
def response = maker.makeI2PDatagram(json.bytes)
|
def response = maker.makeI2PDatagram(json.bytes)
|
||||||
session.sendMessage(sender, response, I2PSession.PROTO_DATAGRAM, 0, 2)
|
session.sendMessage(sender, response, I2PSession.PROTO_DATAGRAM, 0, 2)
|
||||||
|
Reference in New Issue
Block a user