Compare commits

...

8 Commits

Author SHA1 Message Date
Zlatin Balevsky
32b7867e44 Release 0.1.2 for search index test 2019-06-08 13:09:28 +01:00
Zlatin Balevsky
5b313276f4 fix tests broken by piece size change 2019-06-08 13:08:20 +01:00
Zlatin Balevsky
abba4cc6fa fix a bug where multi-term search modifies the index 2019-06-08 12:55:47 +01:00
Zlatin Balevsky
15b4804968 update wire protocol with originator and oobHashlist fields 2019-06-08 12:40:38 +01:00
Zlatin Balevsky
942a01a501 forgot to commit 2019-06-08 09:33:16 +01:00
Zlatin Balevsky
502a8d91da print only the root 2019-06-08 09:30:01 +01:00
Zlatin Balevsky
5414e8679b update readme 2019-06-08 09:07:13 +01:00
Zlatin Balevsky
14e42dd7c2 correct element 2019-06-08 08:46:28 +01:00
12 changed files with 40 additions and 19 deletions

View File

@@ -31,6 +31,5 @@ The first time you run MuWire it will ask you to select a nickname. This nickna
### Known bugs and limitations ### Known bugs and limitations
* Many UI features you would expect are not there yet * Many UI features you would expect are not there yet
* On windows the preferences are stored in %HOME%\.MuWire instead of the user profile directory
* Downloads in progress do not get remembered between restarts * Downloads in progress do not get remembered between restarts

View File

@@ -34,7 +34,7 @@ class Cli {
Core core Core core
try { try {
core = new Core(props, home, "0.1.1") core = new Core(props, home, "0.1.2")
} 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"

View File

@@ -53,7 +53,7 @@ class CliDownloader {
Core core Core core
try { try {
core = new Core(props, home, "0.1.1") core = new Core(props, home, "0.1.2")
} 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"

View File

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

View File

@@ -1,6 +1,9 @@
package com.muwire.core.files package com.muwire.core.files
import com.muwire.core.InfoHash import com.muwire.core.InfoHash
import net.i2p.data.Base64
import java.nio.MappedByteBuffer import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel import java.nio.channels.FileChannel
import java.nio.channels.FileChannel.MapMode import java.nio.channels.FileChannel.MapMode
@@ -79,6 +82,6 @@ class FileHasher {
file = file.getAbsoluteFile() file = file.getAbsoluteFile()
def hasher = new FileHasher() def hasher = new FileHasher()
def infohash = hasher.hashFile(file) def infohash = hasher.hashFile(file)
println infohash println Base64.encode(infohash.getRoot())
} }
} }

View File

@@ -42,7 +42,7 @@ class SearchIndex {
terms.each { terms.each {
Set<String> forWord = keywords.getOrDefault(it,[]) Set<String> forWord = keywords.getOrDefault(it,[])
if (rv == null) { if (rv == null) {
rv = forWord rv = new HashSet<>(forWord)
} else { } else {
rv.retainAll(forWord) rv.retainAll(forWord)
} }

View File

@@ -24,9 +24,9 @@ class FileHasherTest extends GroovyTestCase {
@Test @Test
void testPieceSize() { void testPieceSize() {
assert 18 == FileHasher.getPieceSize(1000000) assert 17 == FileHasher.getPieceSize(1000000)
assert 20 == FileHasher.getPieceSize(100000000) assert 17 == FileHasher.getPieceSize(100000000)
assert 30 == FileHasher.getPieceSize(FileHasher.MAX_SIZE) assert 27 == FileHasher.getPieceSize(FileHasher.MAX_SIZE)
shouldFail IllegalArgumentException, { shouldFail IllegalArgumentException, {
FileHasher.getPieceSize(Long.MAX_VALUE) FileHasher.getPieceSize(Long.MAX_VALUE)
} }
@@ -48,7 +48,7 @@ class FileHasherTest extends GroovyTestCase {
fos.write b fos.write b
fos.close() fos.close()
def ih = hasher.hashFile tmp def ih = hasher.hashFile tmp
assert ih.getHashList().length == 32 assert ih.getHashList().length == 64
} }
@Test @Test
@@ -58,7 +58,7 @@ class FileHasherTest extends GroovyTestCase {
fos.write b fos.write b
fos.close() fos.close()
def ih = hasher.hashFile tmp def ih = hasher.hashFile tmp
assert ih.getHashList().length == 64 assert ih.getHashList().length == 96
} }
@Test @Test
@@ -68,7 +68,7 @@ class FileHasherTest extends GroovyTestCase {
fos.write b fos.write b
fos.close() fos.close()
def ih = hasher.hashFile tmp def ih = hasher.hashFile tmp
assert ih.getHashList().length == 64 assert ih.getHashList().length == 128
} }
@Test @Test
@@ -78,6 +78,6 @@ class FileHasherTest extends GroovyTestCase {
fos.write b fos.write b
fos.close() fos.close()
def ih = hasher.hashFile tmp def ih = hasher.hashFile tmp
assert ih.getHashList().length == 32 * 3 assert ih.getHashList().length == 160
} }
} }

View File

@@ -99,7 +99,7 @@ class PersisterServiceLoadingTest {
FileHasher fh = new FileHasher() FileHasher fh = new FileHasher()
InfoHash ih1 = fh.hashFile(sharedFile1) InfoHash ih1 = fh.hashFile(sharedFile1)
assert ih1.getHashList().length == 2 * 32 assert ih1.getHashList().length == 96
def json = [:] def json = [:]
json.file = getSharedFileJsonName(sharedFile1) json.file = getSharedFileJsonName(sharedFile1)
@@ -111,7 +111,9 @@ class PersisterServiceLoadingTest {
String hash1 = Base64.encode(tmp) String hash1 = Base64.encode(tmp)
System.arraycopy(ih1.getHashList(), 32, tmp, 0, 32) System.arraycopy(ih1.getHashList(), 32, tmp, 0, 32)
String hash2 = Base64.encode(tmp) String hash2 = Base64.encode(tmp)
json.hashList = [hash1, hash2] System.arraycopy(ih1.getHashList(), 64, tmp, 0, 32)
String hash3 = Base64.encode(tmp)
json.hashList = [hash1, hash2, hash3]
json = JsonOutput.toJson(json) json = JsonOutput.toJson(json)

View File

@@ -30,7 +30,18 @@ class SearchIndexTest {
assert found.size() == 2 assert found.size() == 2
assert found.contains("a b.c") assert found.contains("a b.c")
assert found.contains("c d.e") assert found.contains("c d.e")
} }
@Test
public void testDrillDownDoesNotModifyIndex() {
initIndex(["a b.c", "c d.e"])
index.search(["c","e"])
def found = index.search(["c"])
assert found.size() == 2
assert found.contains("a b.c")
assert found.contains("c d.e")
}
@Test @Test
void testDrillDown() { void testDrillDown() {

View File

@@ -131,12 +131,18 @@ Sent by a leaf or ultrapeer when performing a search. Contains the reply-to per
firstHop: false, firstHop: false,
keywords : ["keyword1","keyword2"...] keywords : ["keyword1","keyword2"...]
infohash: "asdfasdf...", infohash: "asdfasdf...",
replyTo : "asdfasf...b64" replyTo : "asdfasf...b64",
originator : "asfasdf...",
"oobHashlist" : true
} }
``` ```
A search can contain either the query entered by the user in the UI or the infohash if the user is looking for a specific file. If both are present, the infohash takes precedence and the keyword query is ignored. A search can contain either the query entered by the user in the UI or the infohash if the user is looking for a specific file. If both are present, the infohash takes precedence and the keyword query is ignored.
The "originator" field contains the Base64-encoded persona of the originator of the query. It is used for display purposes only. The I2P destination in that persona must match the one in the "replyTo" field.
The oobHashlist flag indicates support for out-of-band hashlist delivery, which is not yet implemented. Nevertheless, this flag gets propagated through the network for future-proofing.
### Ultrapeer to leaf ### Ultrapeer to leaf
The "Search" message is also sent from an ultrapeer to a leaf. The "Search" message is also sent from an ultrapeer to a leaf.

View File

@@ -1,5 +1,5 @@
group = com.muwire group = com.muwire
version = 0.1.0 version = 0.1.2
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

View File

@@ -31,8 +31,8 @@ class SearchTabView {
builder.with { builder.with {
def resultsTable def resultsTable
def pane = scrollPane { def pane = scrollPane {
resultsTable = table(id : "results-table") { resultsTable = table(id : "results-table", autoCreateRowSorter : true) {
tableModel(list: model.results, autoCreateRowSorter : true) { tableModel(list: model.results) {
closureColumn(header: "Name", preferredWidth: 350, type: String, read : {row -> row.name.replace('<','_')}) 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()})