Compare commits

..

22 Commits

Author SHA1 Message Date
Zlatin Balevsky
a5d442d320 Release 0.0.13 for keyword search fix 2019-06-07 06:37:23 +01:00
Zlatin Balevsky
3f9ee887d6 prevent NPE in toString 2019-06-07 06:31:29 +01:00
Zlatin Balevsky
4a9e6d3b6b prevent npe in keyword searches 2019-06-07 06:14:40 +01:00
Zlatin Balevsky
80f2cc5f99 logging and toString() 2019-06-07 06:07:02 +01:00
Zlatin Balevsky
12283dba9d Release 0.0.12 for search by hash 2019-06-06 22:22:43 +01:00
Zlatin Balevsky
5c959bc8b7 name update search tab 2019-06-06 22:07:20 +01:00
Zlatin Balevsky
f3712fe7af delay initial update check a minute 2019-06-06 21:52:35 +01:00
Zlatin Balevsky
3e49b0ec66 infohash may be null 2019-06-06 21:40:44 +01:00
Zlatin Balevsky
f90beb8e3d encode infohash 2019-06-06 21:31:00 +01:00
Zlatin Balevsky
fbad7b6c7e searchHash 2019-06-06 21:27:07 +01:00
Zlatin Balevsky
ec2d89c18c serialize infohash 2019-06-06 21:21:40 +01:00
Zlatin Balevsky
c27fc0a515 update from infohash 2019-06-06 21:08:58 +01:00
Zlatin Balevsky
14681c2060 search by hash ui 2019-06-06 20:30:15 +01:00
Zlatin Balevsky
1aeb230ea8 catch exceptions in event dispatch thread 2019-06-06 19:31:10 +01:00
Zlatin Balevsky
d1dfc73f5a decode infohash 2019-06-06 19:28:29 +01:00
Zlatin Balevsky
0cebe4119c update list of limitations 2019-06-06 14:19:43 +01:00
Zlatin Balevsky
9f21120ec8 print periodic stats 2019-06-06 13:59:05 +01:00
Zlatin Balevsky
7eea8be67d Release 0.0.11 for file loading bug 2019-06-06 09:22:16 +01:00
Zlatin Balevsky
f114302bdb hopefully fix the shared file loss 2019-06-06 09:19:00 +01:00
Zlatin Balevsky
05b9b37488 emit an event when all files are loaded 2019-06-06 09:10:09 +01:00
Zlatin Balevsky
52f317a5b7 prevent division by zero 2019-06-06 07:09:54 +01:00
Zlatin Balevsky
fb8227a1f3 prevent division by zero 2019-06-06 07:09:05 +01:00
17 changed files with 196 additions and 35 deletions

View File

@@ -32,7 +32,6 @@ At the moment there are very few nodes on the network, so you will see very few
### Known bugs and limitations
* Sometimes the list of shared files gets lost
* Many UI features you would expect are not there yet

View File

@@ -1,9 +1,18 @@
package com.muwire.cli
import java.util.concurrent.CountDownLatch
import com.muwire.core.Core
import com.muwire.core.MuWireSettings
import com.muwire.core.connection.ConnectionAttemptStatus
import com.muwire.core.connection.ConnectionEvent
import com.muwire.core.connection.DisconnectionEvent
import com.muwire.core.files.AllFilesLoadedEvent
import com.muwire.core.files.FileHashedEvent
import com.muwire.core.files.FileLoadedEvent
import com.muwire.core.files.FileSharedEvent
import com.muwire.core.upload.UploadEvent
import com.muwire.core.upload.UploadFinishedEvent
class Cli {
@@ -25,17 +34,15 @@ class Cli {
Core core
try {
core = new Core(props, home, "0.0.10")
core = new Core(props, home, "0.0.13")
} catch (Exception bad) {
bad.printStackTrace(System.out)
println "Failed to initialize core, exiting"
System.exit(1)
}
core.startServices()
// now we begin
println "MuWire is ready"
def filesList
if (args.length == 0) {
@@ -48,14 +55,39 @@ class Cli {
Thread.sleep(1000)
println "loading shared files from $filesList"
core.eventBus.register(FileHashedEvent.class, new Object() {
void onFileHashedEvent(FileHashedEvent e) {
if (e.error != null)
println "ERROR $e.error"
else
println "Shared file : $e.sharedFile.file"
// listener for shared files
def sharedListener = new SharedListener()
core.eventBus.register(FileHashedEvent.class, sharedListener)
core.eventBus.register(FileLoadedEvent.class, sharedListener)
// for connections
def connectionsListener = new ConnectionListener()
core.eventBus.register(ConnectionEvent.class, connectionsListener)
core.eventBus.register(DisconnectionEvent.class, connectionsListener)
// for uploads
def uploadsListener = new UploadsListener()
core.eventBus.register(UploadEvent.class, uploadsListener)
core.eventBus.register(UploadFinishedEvent.class, uploadsListener)
Timer timer = new Timer("status-printer", true)
timer.schedule({
println "Connections $connectionsListener.connections Uploads $uploadsListener.uploads Shared $sharedListener.shared"
} as TimerTask, 60000, 60000)
def latch = new CountDownLatch(1)
def fileLoader = new Object() {
public void onAllFilesLoadedEvent(AllFilesLoadedEvent e) {
latch.countDown()
}
})
}
core.eventBus.register(AllFilesLoadedEvent.class, fileLoader)
core.startServices()
println "waiting for files to load"
latch.await()
// now we begin
println "MuWire is ready"
filesList = new File(filesList)
filesList.withReader {
@@ -69,4 +101,42 @@ class Cli {
})
Thread.sleep(Integer.MAX_VALUE)
}
static class ConnectionListener {
volatile int connections
public void onConnectionEvent(ConnectionEvent e) {
if (e.status == ConnectionAttemptStatus.SUCCESSFUL)
connections++
}
public void onDisconnectionEvent(DisconnectionEvent e) {
connections--
}
}
static class UploadsListener {
volatile int uploads
public void onUploadEvent(UploadEvent e) {
uploads++
println "Starting upload of ${e.uploader.file.getName()} to ${e.uploader.request.downloader.getHumanReadableName()}"
}
public void onUploadFinishedEvent(UploadFinishedEvent e) {
uploads--
println "Finished upload of ${e.uploader.file.getName()} to ${e.uploader.request.downloader.getHumanReadableName()}"
}
}
static class SharedListener {
volatile int shared
void onFileHashedEvent(FileHashedEvent e) {
if (e.error != null)
println "ERROR $e.error"
else {
println "Shared file : $e.sharedFile.file"
shared++
}
}
void onFileLoadedEvent(FileLoadedEvent e) {
shared++
}
}
}

View File

@@ -248,7 +248,7 @@ public class Core {
}
}
Core core = new Core(props, home, "0.0.10")
Core core = new Core(props, home, "0.0.13")
core.startServices()
// ... at the end, sleep or execute script

View File

@@ -3,6 +3,7 @@ package com.muwire.core
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import java.util.logging.Level
import com.muwire.core.files.FileSharedEvent
@@ -23,14 +24,18 @@ class EventBus {
}
private void publishInternal(Event e) {
log.fine "publishing event $e of type ${e.getClass().getSimpleName()}"
log.fine "publishing event $e of type ${e.getClass().getSimpleName()} event $e"
def currentHandlers
final def clazz = e.getClass()
synchronized(this) {
currentHandlers = handlers.getOrDefault(clazz, [])
}
currentHandlers.each {
try {
it."on${clazz.getSimpleName()}"(e)
} catch (Exception bad) {
log.log(Level.SEVERE, "exception dispatching event",bad)
}
}
}

View File

@@ -127,6 +127,8 @@ abstract class Connection implements Closeable {
query.uuid = e.searchEvent.getUuid()
query.firstHop = e.firstHop
query.keywords = e.searchEvent.getSearchTerms()
if (e.searchEvent.searchHash != null)
query.infohash = Base64.encode(e.searchEvent.searchHash)
query.replyTo = e.replyTo.toBase64()
if (e.originator != null)
query.originator = e.originator.toBase64()
@@ -155,8 +157,11 @@ abstract class Connection implements Closeable {
protected void handleSearch(def search) {
UUID uuid = UUID.fromString(search.uuid)
if (search.infohash != null)
byte [] infohash = null
if (search.infohash != null) {
search.keywords = null
infohash = Base64.decode(search.infohash)
}
Destination replyTo = new Destination(search.replyTo)
TrustLevel trustLevel = trustService.getLevel(replyTo)
@@ -180,7 +185,7 @@ abstract class Connection implements Closeable {
SearchEvent searchEvent = new SearchEvent(searchTerms : search.keywords,
searchHash : search.infohash,
searchHash : infohash,
uuid : uuid)
QueryEvent event = new QueryEvent ( searchEvent : searchEvent,
replyTo : replyTo,

View File

@@ -195,7 +195,8 @@ class DownloadSession {
return reads[idx]
long interval = timestamps.last - timestamps[idx]
if (interval == 0)
interval = 1
for (int i = idx; i < SAMPLES; i++)
totalRead += reads[idx]
(int)(totalRead * 1000.0 / interval)

View File

@@ -0,0 +1,6 @@
package com.muwire.core.files
import com.muwire.core.Event
class AllFilesLoadedEvent extends Event {
}

View File

@@ -1,5 +1,8 @@
package com.muwire.core.files
import java.nio.file.CopyOption
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.logging.Level
import java.util.stream.Collectors
@@ -55,6 +58,7 @@ class PersisterService extends Service {
}
}
}
listener.publish(new AllFilesLoadedEvent())
} catch (IllegalArgumentException|NumberFormatException e) {
log.log(Level.WARNING, "couldn't load files",e)
}
@@ -107,15 +111,19 @@ class PersisterService extends Service {
}
private void persistFiles() {
location.delete()
def sharedFiles = fileManager.getSharedFiles()
location.withPrintWriter { writer ->
File tmp = File.createTempFile("muwire-files", "tmp")
tmp.deleteOnExit()
tmp.withPrintWriter { writer ->
sharedFiles.each { k, v ->
def json = toJson(k,v)
json = JsonOutput.toJson(json)
writer.println json
}
}
Files.copy(tmp.toPath(), location.toPath(), StandardCopyOption.REPLACE_EXISTING)
tmp.delete()
}
private def toJson(File f, SharedFile sf) {

View File

@@ -13,4 +13,8 @@ class QueryEvent extends Event {
Persona originator
Destination receivedOn
String toString() {
"searchEvent: $searchEvent firstHop:$firstHop, replyTo:${replyTo.toBase32()}" +
"originator: ${originator.getHumanReadableName()} receivedOn: ${receivedOn.toBase32()}"
}
}

View File

@@ -1,10 +1,18 @@
package com.muwire.core.search
import com.muwire.core.Event
import com.muwire.core.InfoHash
class SearchEvent extends Event {
List<String> searchTerms
byte [] searchHash
UUID uuid
String toString() {
def infoHash = null
if (searchHash != null)
infoHash = new InfoHash(searchHash)
"searchTerms: $searchTerms searchHash:$infoHash, uuid:$uuid"
}
}

View File

@@ -1,8 +1,10 @@
package com.muwire.core.update
import com.muwire.core.Event
import com.muwire.core.InfoHash
class UpdateAvailableEvent extends Event {
String version
String signer
String infoHash
}

View File

@@ -36,7 +36,7 @@ class UpdateClient {
void start() {
session.addMuxedSessionListener(new Listener(), I2PSession.PROTO_DATAGRAM, 2)
timer.schedule({checkUpdate()} as TimerTask, 30000, 60 * 60 * 1000)
timer.schedule({checkUpdate()} as TimerTask, 60000, 60 * 60 * 1000)
}
void stop() {
@@ -107,7 +107,7 @@ class UpdateClient {
}
log.info("new version $payload.version available, publishing event")
eventBus.publish(new UpdateAvailableEvent(version : payload.version, signer : payload.signer))
eventBus.publish(new UpdateAvailableEvent(version : payload.version, signer : payload.signer, infoHash : payload.infoHash))
} catch (Exception e) {
log.log(Level.WARNING,"Invalid datagram",e)

View File

@@ -77,13 +77,15 @@ public class InfoHash {
public String toString() {
String rv = "InfoHash[root:"+Base32.encode(root) + " hashList:";
List<String> b32HashList = new ArrayList<>(hashList.length / SIZE);
List<String> b64HashList = new ArrayList<>();
if (hashList != null) {
byte [] tmp = new byte[SIZE];
for (int i = 0; i < hashList.length / SIZE; i++) {
System.arraycopy(hashList, SIZE * i, tmp, 0, SIZE);
b32HashList.add(Base32.encode(tmp));
b64HashList.add(Base32.encode(tmp));
}
rv += b32HashList.toString();
}
rv += b64HashList.toString();
rv += "]";
return rv;
}

View File

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

View File

@@ -7,6 +7,8 @@ import griffon.core.mvc.MVCGroup
import griffon.core.mvc.MVCGroupConfiguration
import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor
import net.i2p.data.Base64
import javax.annotation.Nonnull
import javax.inject.Inject
@@ -43,9 +45,30 @@ class MainFrameController {
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
model.results[uuid.toString()] = group
def searchEvent
if (model.hashSearch) {
searchEvent = new SearchEvent(searchHash : Base64.decode(search), uuid : uuid)
} else {
// this can be improved a lot
def terms = search.toLowerCase().trim().split(Constants.SPLIT_PATTERN)
def searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid)
searchEvent = new SearchEvent(searchTerms : terms, uuid : uuid)
}
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
replyTo: core.me.destination, receivedOn: core.me.destination,
originator : core.me))
}
void search(String infoHash, String tabTitle) {
def cardsPanel = builder.getVariable("cards-panel")
cardsPanel.getLayout().show(cardsPanel, "search window")
def uuid = UUID.randomUUID()
Map<String, Object> params = new HashMap<>()
params["search-terms"] = tabTitle
params["uuid"] = uuid.toString()
def group = mvcGroup.createMVCGroup("SearchTab", uuid.toString(), params)
model.results[uuid.toString()] = group
def searchEvent = new SearchEvent(searchHash : Base64.decode(infoHash), uuid:uuid)
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : true,
replyTo: core.me.destination, receivedOn: core.me.destination,
originator : core.me))
@@ -137,6 +160,16 @@ class MainFrameController {
markTrust("trusted-table", TrustLevel.NEUTRAL, model.trusted)
}
@ControllerAction
void keywordSearch() {
model.hashSearch = false
}
@ControllerAction
void hashSearch() {
model.hashSearch = true
}
void mvcGroupInit(Map<String, String> args) {
application.addPropertyChangeListener("core", {e->
core = e.getNewValue()

View File

@@ -29,6 +29,7 @@ import com.muwire.core.upload.UploadFinishedEvent
import griffon.core.GriffonApplication
import griffon.core.artifact.GriffonModel
import griffon.core.env.Metadata
import griffon.core.mvc.MVCGroup
import griffon.inject.MVCMember
import griffon.transform.FXObservable
@@ -38,8 +39,11 @@ import griffon.metadata.ArtifactProviderFor
@ArtifactProviderFor(GriffonModel)
class MainFrameModel {
@Inject Metadata metadata
@MVCMember @Nonnull
FactoryBuilderSupport builder
@MVCMember @Nonnull
MainFrameController controller
@Inject @Nonnull GriffonApplication application
@Observable boolean coreInitialized = false
@@ -52,6 +56,8 @@ class MainFrameModel {
def trusted = []
def distrusted = []
boolean hashSearch
@Observable int connections
@Observable String me
@Observable boolean searchButtonsEnabled
@@ -260,7 +266,13 @@ class MainFrameModel {
void onUpdateAvailableEvent(UpdateAvailableEvent e) {
runInsideUIAsync {
JOptionPane.showMessageDialog(null, "A new version of MuWire is available from $e.signer. Please update to $e.version")
int option = JOptionPane.showConfirmDialog(null,
"MuWire $e.version is available from $e.signer. You have "+ metadata["application.version"]+" Update?",
"New MuWire version availble", JOptionPane.OK_CANCEL_OPTION)
if (option == JOptionPane.CANCEL_OPTION)
return
controller.search(e.infoHash,"MuWire update")
}
}

View File

@@ -76,6 +76,12 @@ class MainFrameView {
}
panel( constraints: BorderLayout.EAST) {
panel {
buttonGroup(id : "searchButtonGroup")
radioButton(text : "Keywords", selected : true, buttonGroup : searchButtonGroup, keywordSearchAction)
radioButton(text : "Hash", selected : false, buttonGroup : searchButtonGroup, hashSearchAction)
}
button(text: "Search", searchAction)
}
}