Compare commits
13 Commits
muwire-0.0
...
muwire-0.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e69a5eac18 | ||
![]() |
6e0f1778b7 | ||
![]() |
abbb741d73 | ||
![]() |
07dfc0a1d1 | ||
![]() |
00c12cfd49 | ||
![]() |
1ee389ff91 | ||
![]() |
3642736cfe | ||
![]() |
b6f7f51476 | ||
![]() |
4c21f2d5ae | ||
![]() |
9e0d52d548 | ||
![]() |
fad01603de | ||
![]() |
da007795fb | ||
![]() |
881d755dd3 |
@@ -34,7 +34,7 @@ class MuWireSettings {
|
|||||||
props.setProperty("crawlerResponse", crawlerResponse.toString())
|
props.setProperty("crawlerResponse", crawlerResponse.toString())
|
||||||
props.setProperty("nickname", nickname)
|
props.setProperty("nickname", nickname)
|
||||||
props.setProperty("downloadLocation", downloadLocation.getAbsolutePath())
|
props.setProperty("downloadLocation", downloadLocation.getAbsolutePath())
|
||||||
props.setProperty("downloadRetryInterval", "15")
|
props.setProperty("downloadRetryInterval", String.valueOf(downloadRetryInterval))
|
||||||
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.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
|
||||||
import com.muwire.core.search.QueryEvent
|
import com.muwire.core.search.QueryEvent
|
||||||
@@ -14,6 +15,7 @@ import com.muwire.core.trust.TrustLevel
|
|||||||
import com.muwire.core.trust.TrustService
|
import com.muwire.core.trust.TrustService
|
||||||
|
|
||||||
import groovy.util.logging.Log
|
import groovy.util.logging.Log
|
||||||
|
import net.i2p.data.Base64
|
||||||
import net.i2p.data.Destination
|
import net.i2p.data.Destination
|
||||||
|
|
||||||
@Log
|
@Log
|
||||||
@@ -120,9 +122,10 @@ abstract class Connection implements Closeable {
|
|||||||
query.version = 1
|
query.version = 1
|
||||||
query.uuid = e.searchEvent.getUuid()
|
query.uuid = e.searchEvent.getUuid()
|
||||||
query.firstHop = e.firstHop
|
query.firstHop = e.firstHop
|
||||||
// TODO: first hop figure out
|
|
||||||
query.keywords = e.searchEvent.getSearchTerms()
|
query.keywords = e.searchEvent.getSearchTerms()
|
||||||
query.replyTo = e.getReceivedOn().toBase64()
|
query.replyTo = e.replyTo.toBase64()
|
||||||
|
if (e.originator != null)
|
||||||
|
query.originator = e.originator.toBase64()
|
||||||
messages.put(query)
|
messages.put(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,11 +161,22 @@ abstract class Connection implements Closeable {
|
|||||||
}
|
}
|
||||||
// TODO: add option to respond only to trusted peers
|
// TODO: add option to respond only to trusted peers
|
||||||
|
|
||||||
|
Persona originator = null
|
||||||
|
if (search.originator != null) {
|
||||||
|
originator = new Persona(new ByteArrayInputStream(Base64.decode(search.originator)))
|
||||||
|
if (originator.destination != replyTo) {
|
||||||
|
log.info("originator doesn't match destination")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SearchEvent searchEvent = new SearchEvent(searchTerms : search.keywords,
|
SearchEvent searchEvent = new SearchEvent(searchTerms : search.keywords,
|
||||||
searchHash : search.infohash,
|
searchHash : search.infohash,
|
||||||
uuid : uuid)
|
uuid : uuid)
|
||||||
QueryEvent event = new QueryEvent ( searchEvent : searchEvent,
|
QueryEvent event = new QueryEvent ( searchEvent : searchEvent,
|
||||||
replyTo : replyTo,
|
replyTo : replyTo,
|
||||||
|
originator : originator,
|
||||||
receivedOn : endpoint.destination,
|
receivedOn : endpoint.destination,
|
||||||
firstHop : search.firstHop )
|
firstHop : search.firstHop )
|
||||||
eventBus.publish(event)
|
eventBus.publish(event)
|
||||||
|
@@ -20,6 +20,8 @@ import java.security.NoSuchAlgorithmException
|
|||||||
@Log
|
@Log
|
||||||
class DownloadSession {
|
class DownloadSession {
|
||||||
|
|
||||||
|
private static int SAMPLES = 10
|
||||||
|
|
||||||
private final String meB64
|
private final String meB64
|
||||||
private final Pieces pieces
|
private final Pieces pieces
|
||||||
private final InfoHash infoHash
|
private final InfoHash infoHash
|
||||||
@@ -29,6 +31,9 @@ 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 ArrayDeque<Integer> reads = new ArrayDeque<>(SAMPLES)
|
||||||
|
|
||||||
private ByteBuffer mapped
|
private ByteBuffer mapped
|
||||||
|
|
||||||
DownloadSession(String meB64, Pieces pieces, InfoHash infoHash, Endpoint endpoint, File file,
|
DownloadSession(String meB64, Pieces pieces, InfoHash infoHash, Endpoint endpoint, File file,
|
||||||
@@ -122,6 +127,13 @@ class DownloadSession {
|
|||||||
throw new IOException()
|
throw new IOException()
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
mapped.put(tmp, 0, read)
|
mapped.put(tmp, 0, read)
|
||||||
|
|
||||||
|
if (timestamps.size() == SAMPLES) {
|
||||||
|
timestamps.removeFirst()
|
||||||
|
reads.removeFirst()
|
||||||
|
}
|
||||||
|
timestamps.addLast(System.currentTimeMillis())
|
||||||
|
reads.addLast(read)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,4 +156,13 @@ class DownloadSession {
|
|||||||
return 0
|
return 0
|
||||||
mapped.position()
|
mapped.position()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized int speed() {
|
||||||
|
if (timestamps.size() < SAMPLES)
|
||||||
|
return 0
|
||||||
|
long interval = timestamps.last - timestamps.first
|
||||||
|
int totalRead = 0
|
||||||
|
reads.each { totalRead += it }
|
||||||
|
(int)(totalRead * 1000.0 / interval)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -109,6 +109,12 @@ public class Downloader {
|
|||||||
currentSession.positionInPiece()
|
currentSession.positionInPiece()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int speed() {
|
||||||
|
if (currentSession == null)
|
||||||
|
return 0
|
||||||
|
currentSession.speed()
|
||||||
|
}
|
||||||
|
|
||||||
public DownloadState getCurrentState() {
|
public DownloadState getCurrentState() {
|
||||||
currentState
|
currentState
|
||||||
}
|
}
|
||||||
@@ -119,6 +125,7 @@ public class Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void resume() {
|
public void resume() {
|
||||||
|
currentState = DownloadState.CONNECTING
|
||||||
downloadManager.resume(this)
|
downloadManager.resume(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,7 @@ class HostCache extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onConnectionEvent(ConnectionEvent e) {
|
void onConnectionEvent(ConnectionEvent e) {
|
||||||
if (e.incoming || e.leaf)
|
if (e.leaf)
|
||||||
return
|
return
|
||||||
Destination dest = e.endpoint.destination
|
Destination dest = e.endpoint.destination
|
||||||
Host host = hosts.get(dest)
|
Host host = hosts.get(dest)
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package com.muwire.core.search
|
package com.muwire.core.search
|
||||||
|
|
||||||
import com.muwire.core.Event
|
import com.muwire.core.Event
|
||||||
|
import com.muwire.core.Persona
|
||||||
|
|
||||||
import net.i2p.data.Destination
|
import net.i2p.data.Destination
|
||||||
|
|
||||||
@@ -9,6 +10,7 @@ class QueryEvent extends Event {
|
|||||||
SearchEvent searchEvent
|
SearchEvent searchEvent
|
||||||
boolean firstHop
|
boolean firstHop
|
||||||
Destination replyTo
|
Destination replyTo
|
||||||
|
Persona originator
|
||||||
Destination receivedOn
|
Destination receivedOn
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,11 @@ public class UploadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request request = Request.parse(new InfoHash(infoHashRoot), e.getInputStream())
|
Request request = Request.parse(new InfoHash(infoHashRoot), e.getInputStream())
|
||||||
|
if (request.downloader != null && request.downloader.destination != e.destination) {
|
||||||
|
log.info("Downloader persona doesn't match their destination")
|
||||||
|
e.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
Uploader uploader = new Uploader(sharedFiles.iterator().next().file, request, e)
|
Uploader uploader = new Uploader(sharedFiles.iterator().next().file, request, e)
|
||||||
eventBus.publish(new UploadEvent(uploader : uploader))
|
eventBus.publish(new UploadEvent(uploader : uploader))
|
||||||
try {
|
try {
|
||||||
|
11
core/src/test/groovy/com/muwire/core/Personas.groovy
Normal file
11
core/src/test/groovy/com/muwire/core/Personas.groovy
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package com.muwire.core
|
||||||
|
|
||||||
|
import net.i2p.data.Base64
|
||||||
|
|
||||||
|
class Personas {
|
||||||
|
private final String encoded1 = "AQADemFiO~pgSoEo8wQfwncYMvBQWkvPY9I7DYUllHp289UE~zBaLdbl~wbliktAUsW-S70f3UeYgHq34~c7zVuUQjgHZ506iG9hX8B9S3a9gQ3CSG0GuDpeNyiXmZkpHp5m8vT9PZ1zMWzxvzZY~fP9yKFKgO4yrso5I9~DGOPeyJZJ4BFsTJDERv41aZqjFLYUBDmeHGgg9RjYy~93h-nQMVYj9JSO3AgowW-ix49rtiKYIXHMa2PxWHUXkUHWJZtIZntNIDEFeMnPdzLxjAl8so2G6pDcTMZPLLwyb73Ee5ZVfxUynPqyp~fIGVP8Rl4rlaGFli2~ATGBz3XY54aObC~0p7us2JnWaTC~oQT5DVDM7gaOO885o-m8BB8b0duzMBelbdnMZFQJ5jIHVKxkC6Niw4fxTOoXTyOqQmVhtK-9xcwxMuN5DF9IewkR5bhpq5rgnfBP5zvyBaAHMq-d3TCOjTsZ-d3liB98xX5p8G5zmS7gfKArQtM5~CcK~AlX-lGLBQAEAAcAAN5MW1Tq983szfZgY1l8tQFqy8I9tdMf7vc1Ktj~TCIvXYw6AYMbMGy3S67FSPLZVmfHEMQKj2KLAdaRKQkHPAY"
|
||||||
|
private final String encoded2 = "AQAHemxhdGluYiN~3G-hPoBfJ04mhcC52lC6TYSwWxH-WNWno9Y35JS-WrXlnPsodZtwy96ttEaiKTg-hkRqMsaYKpWar1FwayR6qlo0pZCo5pQOLfR7GIM3~wde0JIBEp8BUpgzF1-QXLhuRG1t7tBbenW2tSgp5jQH61RI-c9flyUlOvf6nrhQMZ3aoviZ4aZW23Fx-ajYQBDk7PIxuyn8qYNwWy3kWOhGan05c54NnumS3XCzQWFDDPlADmco1WROeY9qrwwtmLM8lzDCEtJQXJlk~K5yLbyB63hmAeTK7J4iS6f9nnWv7TbB5r-Z3kC6D9TLYrQbu3h4AAxrqso45P8yHQtKUA4QJicS-6NJoBOnlCCU887wx2k9YSxxwNydlIxb1mZsX65Ke4uY0HDFokZHTzUcxvfLB6G~5JkSPDCyZz~2fREgW2-VXu7gokEdEugkuZRrsiQzyfAOOkv53ti5MzTbMOXinBskSb1vZyN2-XcZNaDJvEqUNj~qpfhe-ov2F7FuwQUABAAHAAAfqq-MneIqWBQY92-sy9Z0s~iQsq6lUFa~sYMdY-5o-94fF8a140dm-emF3rO8vuidUIPNaS-37Rl05mAKUCcB"
|
||||||
|
|
||||||
|
Persona persona1 = new Persona(new ByteArrayInputStream(Base64.decode(encoded1)))
|
||||||
|
Persona persona2 = new Persona(new ByteArrayInputStream(Base64.decode(encoded2)))
|
||||||
|
}
|
@@ -5,14 +5,17 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import com.muwire.core.Destinations
|
import com.muwire.core.Destinations
|
||||||
|
import com.muwire.core.Persona
|
||||||
|
import com.muwire.core.Personas
|
||||||
|
|
||||||
|
import net.i2p.data.Base64
|
||||||
import net.i2p.data.Destination
|
import net.i2p.data.Destination
|
||||||
|
|
||||||
class TrustServiceTest {
|
class TrustServiceTest {
|
||||||
|
|
||||||
TrustService service
|
TrustService service
|
||||||
File persistGood, persistBad
|
File persistGood, persistBad
|
||||||
Destinations dests = new Destinations()
|
Personas personas = new Personas()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
void before() {
|
void before() {
|
||||||
@@ -33,51 +36,50 @@ class TrustServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testEmpty() {
|
void testEmpty() {
|
||||||
assert TrustLevel.NEUTRAL == service.getLevel(dests.dest1)
|
assert TrustLevel.NEUTRAL == service.getLevel(personas.persona1.destination)
|
||||||
assert TrustLevel.NEUTRAL == service.getLevel(dests.dest2)
|
assert TrustLevel.NEUTRAL == service.getLevel(personas.persona2.destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testOnEvent() {
|
void testOnEvent() {
|
||||||
service.onTrustEvent new TrustEvent(level: TrustLevel.TRUSTED, destination: dests.dest1)
|
service.onTrustEvent new TrustEvent(level: TrustLevel.TRUSTED, persona: personas.persona1)
|
||||||
service.onTrustEvent new TrustEvent(level: TrustLevel.DISTRUSTED, destination: dests.dest2)
|
service.onTrustEvent new TrustEvent(level: TrustLevel.DISTRUSTED, persona: personas.persona2)
|
||||||
|
|
||||||
assert TrustLevel.TRUSTED == service.getLevel(dests.dest1)
|
assert TrustLevel.TRUSTED == service.getLevel(personas.persona1.destination)
|
||||||
assert TrustLevel.DISTRUSTED == service.getLevel(dests.dest2)
|
assert TrustLevel.DISTRUSTED == service.getLevel(personas.persona2.destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPersist() {
|
void testPersist() {
|
||||||
service.onTrustEvent new TrustEvent(level: TrustLevel.TRUSTED, destination: dests.dest1)
|
service.onTrustEvent new TrustEvent(level: TrustLevel.TRUSTED, persona: personas.persona1)
|
||||||
service.onTrustEvent new TrustEvent(level: TrustLevel.DISTRUSTED, destination: dests.dest2)
|
service.onTrustEvent new TrustEvent(level: TrustLevel.DISTRUSTED, persona: personas.persona2)
|
||||||
|
|
||||||
Thread.sleep(250)
|
Thread.sleep(250)
|
||||||
def trusted = new HashSet<>()
|
def trusted = new HashSet<>()
|
||||||
persistGood.eachLine {
|
persistGood.eachLine {
|
||||||
trusted.add(new Destination(it))
|
trusted.add(new Persona(new ByteArrayInputStream(Base64.decode(it))))
|
||||||
}
|
}
|
||||||
def distrusted = new HashSet<>()
|
def distrusted = new HashSet<>()
|
||||||
persistBad.eachLine {
|
persistBad.eachLine {
|
||||||
distrusted.add(new Destination(it))
|
distrusted.add(new Persona(new ByteArrayInputStream(Base64.decode(it))))
|
||||||
}
|
}
|
||||||
|
|
||||||
assert trusted.size() == 1
|
assert trusted.size() == 1
|
||||||
assert trusted.contains(dests.dest1)
|
assert trusted.contains(personas.persona1)
|
||||||
assert distrusted.size() == 1
|
assert distrusted.size() == 1
|
||||||
assert distrusted.contains(dests.dest2)
|
assert distrusted.contains(personas.persona2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testLoad() {
|
void testLoad() {
|
||||||
service.stop()
|
service.stop()
|
||||||
persistGood.append("${dests.dest1.toBase64()}\n")
|
persistGood.append("${personas.persona1.toBase64()}\n")
|
||||||
persistBad.append("${dests.dest2.toBase64()}\n")
|
persistBad.append("${personas.persona2.toBase64()}\n")
|
||||||
service = new TrustService(persistGood, persistBad, 100)
|
service = new TrustService(persistGood, persistBad, 100)
|
||||||
service.start()
|
service.start()
|
||||||
Thread.sleep(10)
|
Thread.sleep(50)
|
||||||
|
|
||||||
assert TrustLevel.TRUSTED == service.getLevel(dests.dest1)
|
|
||||||
assert TrustLevel.DISTRUSTED == service.getLevel(dests.dest2)
|
|
||||||
|
|
||||||
|
assert TrustLevel.TRUSTED == service.getLevel(personas.persona1.destination)
|
||||||
|
assert TrustLevel.DISTRUSTED == service.getLevel(personas.persona2.destination)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
group = com.muwire
|
group = com.muwire
|
||||||
version = 0.0.5
|
version = 0.0.6
|
||||||
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
|
||||||
|
@@ -21,4 +21,9 @@ mvcGroups {
|
|||||||
view = 'com.muwire.gui.SearchTabView'
|
view = 'com.muwire.gui.SearchTabView'
|
||||||
controller = 'com.muwire.gui.SearchTabController'
|
controller = 'com.muwire.gui.SearchTabController'
|
||||||
}
|
}
|
||||||
|
'Options' {
|
||||||
|
model = 'com.muwire.gui.OptionsModel'
|
||||||
|
view = 'com.muwire.gui.OptionsView'
|
||||||
|
controller = 'com.muwire.gui.OptionsController'
|
||||||
|
}
|
||||||
}
|
}
|
@@ -47,7 +47,8 @@ class MainFrameController {
|
|||||||
def terms = search.toLowerCase().trim().split(Constants.SPLIT_PATTERN)
|
def terms = search.toLowerCase().trim().split(Constants.SPLIT_PATTERN)
|
||||||
def searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid)
|
def searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid)
|
||||||
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
|
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
|
||||||
replyTo: core.me.destination, receivedOn: core.me.destination))
|
replyTo: core.me.destination, receivedOn: core.me.destination,
|
||||||
|
originator : core.me))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def selectedResult() {
|
private def selectedResult() {
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import griffon.core.artifact.GriffonController
|
||||||
|
import griffon.core.controller.ControllerAction
|
||||||
|
import griffon.inject.MVCMember
|
||||||
|
import griffon.metadata.ArtifactProviderFor
|
||||||
|
import javax.annotation.Nonnull
|
||||||
|
|
||||||
|
@ArtifactProviderFor(GriffonController)
|
||||||
|
class OptionsController {
|
||||||
|
@MVCMember @Nonnull
|
||||||
|
OptionsModel model
|
||||||
|
@MVCMember @Nonnull
|
||||||
|
OptionsView view
|
||||||
|
|
||||||
|
@ControllerAction
|
||||||
|
void save() {
|
||||||
|
String text = view.retryField.text
|
||||||
|
model.downloadRetryInterval = text
|
||||||
|
|
||||||
|
def settings = application.context.get("muwire-settings")
|
||||||
|
settings.downloadRetryInterval = Integer.valueOf(text)
|
||||||
|
|
||||||
|
File settingsFile = new File(application.context.get("core").home, "MuWire.properties")
|
||||||
|
settingsFile.withOutputStream {
|
||||||
|
settings.write(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
@ControllerAction
|
||||||
|
void cancel() {
|
||||||
|
view.d.setVisible(false)
|
||||||
|
mvcGroup.destroy()
|
||||||
|
}
|
||||||
|
}
|
@@ -8,6 +8,7 @@ import javax.swing.JTable
|
|||||||
|
|
||||||
import com.muwire.core.Core
|
import com.muwire.core.Core
|
||||||
import com.muwire.core.InfoHash
|
import com.muwire.core.InfoHash
|
||||||
|
import com.muwire.core.Persona
|
||||||
import com.muwire.core.connection.ConnectionAttemptStatus
|
import com.muwire.core.connection.ConnectionAttemptStatus
|
||||||
import com.muwire.core.connection.ConnectionEvent
|
import com.muwire.core.connection.ConnectionEvent
|
||||||
import com.muwire.core.connection.DisconnectionEvent
|
import com.muwire.core.connection.DisconnectionEvent
|
||||||
@@ -58,6 +59,8 @@ class MainFrameModel {
|
|||||||
|
|
||||||
volatile Core core
|
volatile Core core
|
||||||
|
|
||||||
|
private long lastRetryTime = System.currentTimeMillis()
|
||||||
|
|
||||||
void updateTablePreservingSelection(String tableName) {
|
void updateTablePreservingSelection(String tableName) {
|
||||||
def downloadTable = builder.getVariable(tableName)
|
def downloadTable = builder.getVariable(tableName)
|
||||||
int selectedRow = downloadTable.getSelectedRow()
|
int selectedRow = downloadTable.getSelectedRow()
|
||||||
@@ -95,18 +98,24 @@ 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)
|
||||||
|
|
||||||
|
timer.schedule({
|
||||||
int retryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
int retryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
||||||
if (retryInterval > 0) {
|
if (retryInterval > 0) {
|
||||||
retryInterval *= 60000
|
retryInterval *= 60000
|
||||||
timer.schedule({
|
long now = System.currentTimeMillis()
|
||||||
|
if (now - lastRetryTime > retryInterval) {
|
||||||
|
lastRetryTime = now
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
downloads.each {
|
downloads.each {
|
||||||
if (it.downloader.currentState == Downloader.DownloadState.FAILED)
|
if (it.downloader.currentState == Downloader.DownloadState.FAILED)
|
||||||
it.downloader.resume()
|
it.downloader.resume()
|
||||||
|
updateTablePreservingSelection("downloads-table")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, retryInterval, retryInterval)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}, 60000, 60000)
|
||||||
|
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
trusted.addAll(core.trustService.good.values())
|
trusted.addAll(core.trustService.good.values())
|
||||||
@@ -228,11 +237,17 @@ class MainFrameModel {
|
|||||||
if (search.trim().size() == 0)
|
if (search.trim().size() == 0)
|
||||||
return
|
return
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
searches.addFirst(search)
|
searches.addFirst(new IncomingSearch(search : search, replyTo : e.replyTo, originator : e.originator))
|
||||||
while(searches.size() > 200)
|
while(searches.size() > 200)
|
||||||
searches.removeLast()
|
searches.removeLast()
|
||||||
JTable table = builder.getVariable("searches-table")
|
JTable table = builder.getVariable("searches-table")
|
||||||
table.model.fireTableDataChanged()
|
table.model.fireTableDataChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class IncomingSearch {
|
||||||
|
String search
|
||||||
|
Destination replyTo
|
||||||
|
Persona originator
|
||||||
|
}
|
||||||
}
|
}
|
14
gui/griffon-app/models/com/muwire/gui/OptionsModel.groovy
Normal file
14
gui/griffon-app/models/com/muwire/gui/OptionsModel.groovy
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import griffon.core.artifact.GriffonModel
|
||||||
|
import griffon.transform.Observable
|
||||||
|
import griffon.metadata.ArtifactProviderFor
|
||||||
|
|
||||||
|
@ArtifactProviderFor(GriffonModel)
|
||||||
|
class OptionsModel {
|
||||||
|
@Observable String downloadRetryInterval
|
||||||
|
|
||||||
|
void mvcGroupInit(Map<String, String> args) {
|
||||||
|
downloadRetryInterval = application.context.get("muwire-settings").downloadRetryInterval
|
||||||
|
}
|
||||||
|
}
|
@@ -21,6 +21,7 @@ class SearchTabModel {
|
|||||||
Core core
|
Core core
|
||||||
String uuid
|
String uuid
|
||||||
def results = []
|
def results = []
|
||||||
|
def hashCount = [:]
|
||||||
|
|
||||||
|
|
||||||
void mvcGroupInit(Map<String, String> args) {
|
void mvcGroupInit(Map<String, String> args) {
|
||||||
@@ -34,6 +35,12 @@ class SearchTabModel {
|
|||||||
|
|
||||||
void handleResult(UIResultEvent e) {
|
void handleResult(UIResultEvent e) {
|
||||||
runInsideUIAsync {
|
runInsideUIAsync {
|
||||||
|
Integer count = hashCount.get(e.infohash)
|
||||||
|
if (count == null)
|
||||||
|
count = 0
|
||||||
|
count++
|
||||||
|
hashCount[e.infohash] = count
|
||||||
|
|
||||||
results << e
|
results << e
|
||||||
JTable table = builder.getVariable("results-table")
|
JTable table = builder.getVariable("results-table")
|
||||||
table.model.fireTableDataChanged()
|
table.model.fireTableDataChanged()
|
||||||
|
@@ -44,6 +44,11 @@ class MainFrameView {
|
|||||||
imageIcon('/griffon-icon-16x16.png').image],
|
imageIcon('/griffon-icon-16x16.png').image],
|
||||||
pack : false,
|
pack : false,
|
||||||
visible : bind { model.coreInitialized }) {
|
visible : bind { model.coreInitialized }) {
|
||||||
|
menuBar {
|
||||||
|
menu (text : "Options") {
|
||||||
|
menuItem("Configuration", actionPerformed : {mvcGroup.createMVCGroup("Options")})
|
||||||
|
}
|
||||||
|
}
|
||||||
borderLayout()
|
borderLayout()
|
||||||
panel (border: etchedBorder(), constraints : BorderLayout.NORTH) {
|
panel (border: etchedBorder(), constraints : BorderLayout.NORTH) {
|
||||||
borderLayout()
|
borderLayout()
|
||||||
@@ -104,6 +109,7 @@ class MainFrameView {
|
|||||||
int pieceSize = row.downloader.pieceSize // TODO: fix for last piece
|
int pieceSize = row.downloader.pieceSize // TODO: fix for last piece
|
||||||
"$position/$pieceSize bytes"
|
"$position/$pieceSize bytes"
|
||||||
})
|
})
|
||||||
|
closureColumn(header: "Speed (bytes/second)", type:Integer, read :{row -> row.downloader.speed()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,7 +183,14 @@ class MainFrameView {
|
|||||||
scrollPane(constraints : BorderLayout.CENTER) {
|
scrollPane(constraints : BorderLayout.CENTER) {
|
||||||
table(id : "searches-table") {
|
table(id : "searches-table") {
|
||||||
tableModel(list : model.searches) {
|
tableModel(list : model.searches) {
|
||||||
closureColumn(header : "Keywords", type : String, read : { it })
|
closureColumn(header : "Keywords", type : String, read : { it.search })
|
||||||
|
closureColumn(header : "From", type : String, read : {
|
||||||
|
if (it.originator != null) {
|
||||||
|
return it.originator.getHumanReadableName()
|
||||||
|
} else {
|
||||||
|
return it.replyTo.toBase32()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
gui/griffon-app/views/com/muwire/gui/OptionsView.groovy
Normal file
54
gui/griffon-app/views/com/muwire/gui/OptionsView.groovy
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import griffon.core.artifact.GriffonView
|
||||||
|
import griffon.inject.MVCMember
|
||||||
|
import griffon.metadata.ArtifactProviderFor
|
||||||
|
|
||||||
|
import javax.swing.JDialog
|
||||||
|
import javax.swing.SwingConstants
|
||||||
|
|
||||||
|
import java.awt.event.WindowAdapter
|
||||||
|
import java.awt.event.WindowEvent
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull
|
||||||
|
|
||||||
|
@ArtifactProviderFor(GriffonView)
|
||||||
|
class OptionsView {
|
||||||
|
@MVCMember @Nonnull
|
||||||
|
FactoryBuilderSupport builder
|
||||||
|
@MVCMember @Nonnull
|
||||||
|
OptionsModel model
|
||||||
|
|
||||||
|
def d
|
||||||
|
def p
|
||||||
|
def retryField
|
||||||
|
def mainFrame
|
||||||
|
|
||||||
|
void initUI() {
|
||||||
|
mainFrame = application.windowManager.findWindow("main-frame")
|
||||||
|
d = new JDialog(mainFrame, "Options", true)
|
||||||
|
d.setResizable(false)
|
||||||
|
p = builder.panel {
|
||||||
|
gridBagLayout()
|
||||||
|
label(text : "Retry failed downloads every", constraints : gbc(gridx: 0, gridy: 0))
|
||||||
|
retryField = textField(text : bind { model.downloadRetryInterval }, columns : 2, constraints : gbc(gridx: 1, gridy: 0))
|
||||||
|
label(text : "minutes", constraints : gbc(gridx : 2, gridy: 0))
|
||||||
|
|
||||||
|
button(text : "Save", constraints : gbc(gridx : 1, gridy: 1), saveAction)
|
||||||
|
button(text : "Cancel", constraints : gbc(gridx : 2, gridy: 1), cancelAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mvcGroupInit(Map<String,String> args) {
|
||||||
|
d.getContentPane().add(p)
|
||||||
|
d.pack()
|
||||||
|
d.setLocationRelativeTo(mainFrame)
|
||||||
|
d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE)
|
||||||
|
d.addWindowListener(new WindowAdapter() {
|
||||||
|
public void windowClosed(WindowEvent e) {
|
||||||
|
mvcGroup.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
d.show()
|
||||||
|
}
|
||||||
|
}
|
@@ -31,6 +31,7 @@ class SearchTabView {
|
|||||||
tableModel(list: model.results) {
|
tableModel(list: model.results) {
|
||||||
closureColumn(header: "Name", type: String, read : {row -> row.name})
|
closureColumn(header: "Name", type: String, read : {row -> row.name})
|
||||||
closureColumn(header: "Size", preferredWidth: 150, type: Long, read : {row -> row.size})
|
closureColumn(header: "Size", preferredWidth: 150, type: Long, read : {row -> row.size})
|
||||||
|
closureColumn(header: "Sources", type : Integer, read : { row -> model.hashCount[row.infohash]})
|
||||||
closureColumn(header: "Sender", type: String, read : {row -> row.sender.getHumanReadableName()})
|
closureColumn(header: "Sender", type: String, read : {row -> row.sender.getHumanReadableName()})
|
||||||
closureColumn(header: "Trust", type: String, read : {row ->
|
closureColumn(header: "Trust", type: String, read : {row ->
|
||||||
model.core.trustService.getLevel(row.sender.destination)
|
model.core.trustService.getLevel(row.sender.destination)
|
||||||
|
@@ -0,0 +1,25 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import griffon.core.test.GriffonFestRule
|
||||||
|
import org.fest.swing.fixture.FrameFixture
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail
|
||||||
|
|
||||||
|
class OptionsIntegrationTest {
|
||||||
|
static {
|
||||||
|
System.setProperty('griffon.swing.edt.violations.check', 'true')
|
||||||
|
System.setProperty('griffon.swing.edt.hang.monitor', 'true')
|
||||||
|
}
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final GriffonFestRule fest = new GriffonFestRule()
|
||||||
|
|
||||||
|
private FrameFixture window
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void smokeTest() {
|
||||||
|
fail('Not implemented yet!')
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
package com.muwire.gui
|
||||||
|
|
||||||
|
import griffon.core.test.GriffonUnitRule
|
||||||
|
import griffon.core.test.TestFor
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail
|
||||||
|
|
||||||
|
@TestFor(OptionsController)
|
||||||
|
class OptionsControllerTest {
|
||||||
|
private OptionsController controller
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final GriffonUnitRule griffon = new GriffonUnitRule()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void smokeTest() {
|
||||||
|
fail('Not yet implemented!')
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user