mirror of https://github.com/zlatinb/muwire
core side of searchers tracking
parent
c7b0ae34af
commit
f5c07f13c0
|
@ -331,7 +331,7 @@ public class Core {
|
|||
eventBus.register(QueryEvent.class, contentManager)
|
||||
|
||||
log.info("initializing browse manager")
|
||||
BrowseManager browseManager = new BrowseManager(i2pConnector, eventBus)
|
||||
BrowseManager browseManager = new BrowseManager(i2pConnector, eventBus, me)
|
||||
eventBus.register(UIBrowseEvent.class, browseManager)
|
||||
|
||||
}
|
||||
|
|
|
@ -288,18 +288,8 @@ class ConnectionAcceptor {
|
|||
if (!searchManager.hasLocalSearch(resultsUUID))
|
||||
throw new UnexpectedResultsException(resultsUUID.toString())
|
||||
|
||||
|
||||
// parse all headers
|
||||
Map<String,String> headers = new HashMap<>()
|
||||
String header
|
||||
while((header = DataUtil.readTillRN(is)) != "" && headers.size() < Constants.MAX_HEADERS) {
|
||||
int colon = header.indexOf(':')
|
||||
if (colon == -1 || colon == header.length() - 1)
|
||||
throw new IOException("invalid header $header")
|
||||
String key = header.substring(0, colon)
|
||||
String value = header.substring(colon + 1)
|
||||
headers[key] = value.trim()
|
||||
}
|
||||
Map<String,String> headers = DataUtil.readAllHeaders(is);
|
||||
|
||||
if (!headers.containsKey("Sender"))
|
||||
throw new IOException("No Sender header")
|
||||
|
@ -340,8 +330,11 @@ class ConnectionAcceptor {
|
|||
dis.readFully(rowse)
|
||||
if (rowse != "ROWSE\r\n".getBytes(StandardCharsets.US_ASCII))
|
||||
throw new IOException("Invalid BROWSE connection")
|
||||
String header
|
||||
while ((header = DataUtil.readTillRN(dis)) != ""); // ignore headers for now
|
||||
|
||||
Persona browser = null
|
||||
Map<String,String> headers = DataUtil.readAllHeaders(dis);
|
||||
if (headers.containsKey('Persona'))
|
||||
browser = new Persona(new ByteArrayInputStream(Base64.decode(headers['Persona'])))
|
||||
|
||||
OutputStream os = e.getOutputStream()
|
||||
if (!settings.browseFiles) {
|
||||
|
@ -362,7 +355,7 @@ class ConnectionAcceptor {
|
|||
DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(os))
|
||||
JsonOutput jsonOutput = new JsonOutput()
|
||||
sharedFiles.each {
|
||||
it.hit()
|
||||
it.hit(browser, System.currentTimeMillis(), "Browse Host");
|
||||
int certificates = certificateManager.getByInfoHash(it.getInfoHash()).size()
|
||||
def obj = ResultsSender.sharedFileToObj(it, false, certificates)
|
||||
def json = jsonOutput.toJson(obj)
|
||||
|
|
|
@ -198,7 +198,7 @@ class FileManager {
|
|||
found = rootToFiles.get new InfoHash(e.searchHash)
|
||||
found = filter(found, e.oobInfohash)
|
||||
if (found != null && !found.isEmpty()) {
|
||||
found.each { it.hit() }
|
||||
found.each { it.hit(e.persona, e.timestamp, "Hash Search") }
|
||||
re = new ResultsEvent(results: found.asList(), uuid: e.uuid, searchEvent: e)
|
||||
}
|
||||
} else {
|
||||
|
@ -214,7 +214,7 @@ class FileManager {
|
|||
files = filter(sharedFiles, e.oobInfohash)
|
||||
|
||||
if (!sharedFiles.isEmpty()) {
|
||||
sharedFiles.each { it.hit() }
|
||||
sharedFiles.each { it.hit(e.persona, e.timestamp, String.join(" ", e.searchTerms)) }
|
||||
re = new ResultsEvent(results: sharedFiles.asList(), uuid: e.uuid, searchEvent: e)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.stream.Collectors
|
|||
import com.muwire.core.DownloadedFile
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.InfoHash
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.Service
|
||||
import com.muwire.core.SharedFile
|
||||
import com.muwire.core.UILoadedEvent
|
||||
|
@ -129,15 +130,19 @@ class PersisterService extends Service {
|
|||
return new FileLoadedEvent(loadedFile : df)
|
||||
}
|
||||
|
||||
int hits = 0
|
||||
if (json.hits != null)
|
||||
hits = json.hits
|
||||
|
||||
SharedFile sf = new SharedFile(file, ih, pieceSize)
|
||||
sf.setComment(json.comment)
|
||||
sf.hits = hits
|
||||
if (json.downloaders != null)
|
||||
sf.getDownloaders().addAll(json.downloaders)
|
||||
if (json.searchers != null) {
|
||||
json.searchers.each {
|
||||
Persona searcher = new Persona(new ByteArrayInputStream(Base64.decode(it.searcher)))
|
||||
long timestamp = it.timestamp
|
||||
String query = it.query
|
||||
sf.hit(searcher, timestamp, query)
|
||||
}
|
||||
}
|
||||
return new FileLoadedEvent(loadedFile: sf)
|
||||
|
||||
}
|
||||
|
@ -172,6 +177,18 @@ class PersisterService extends Service {
|
|||
json.hits = sf.getHits()
|
||||
json.downloaders = sf.getDownloaders()
|
||||
|
||||
if (!sf.searches.isEmpty()) {
|
||||
Set searchers = new HashSet<>()
|
||||
sf.searches.each {
|
||||
def search = [:]
|
||||
search.searcher = it.searcher.toBase64()
|
||||
search.timestamp = it.timestamp
|
||||
search.query = it.query
|
||||
searchers.add(search)
|
||||
}
|
||||
json.searchers = searchers
|
||||
}
|
||||
|
||||
if (sf instanceof DownloadedFile) {
|
||||
json.sources = sf.sources.stream().map( {d -> d.toBase64()}).collect(Collectors.toList())
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.muwire.core.search
|
|||
|
||||
import com.muwire.core.Constants
|
||||
import com.muwire.core.EventBus
|
||||
import com.muwire.core.Persona
|
||||
import com.muwire.core.connection.Endpoint
|
||||
import com.muwire.core.connection.I2PConnector
|
||||
import com.muwire.core.util.DataUtil
|
||||
|
@ -20,12 +21,14 @@ class BrowseManager {
|
|||
|
||||
private final I2PConnector connector
|
||||
private final EventBus eventBus
|
||||
private final Persona me
|
||||
|
||||
private final Executor browserThread = Executors.newSingleThreadExecutor()
|
||||
|
||||
BrowseManager(I2PConnector connector, EventBus eventBus) {
|
||||
BrowseManager(I2PConnector connector, EventBus eventBus, Persona me) {
|
||||
this.connector = connector
|
||||
this.eventBus = eventBus
|
||||
this.me = me
|
||||
}
|
||||
|
||||
void onUIBrowseEvent(UIBrowseEvent e) {
|
||||
|
@ -35,7 +38,9 @@ class BrowseManager {
|
|||
eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.CONNECTING))
|
||||
endpoint = connector.connect(e.host.destination)
|
||||
OutputStream os = endpoint.getOutputStream()
|
||||
os.write("BROWSE\r\n\r\n".getBytes(StandardCharsets.US_ASCII))
|
||||
os.write("BROWSE\r\n".getBytes(StandardCharsets.US_ASCII))
|
||||
os.write("Persona:${me.toBase64()}\r\n".getBytes(StandardCharsets.US_ASCII))
|
||||
os.write("\r\n".getBytes(StandardCharsets.US_ASCII))
|
||||
|
||||
InputStream is = endpoint.getInputStream()
|
||||
String code = DataUtil.readTillRN(is)
|
||||
|
@ -43,16 +48,7 @@ class BrowseManager {
|
|||
throw new IOException("Invalid code $code")
|
||||
|
||||
// parse all headers
|
||||
Map<String,String> headers = new HashMap<>()
|
||||
String header
|
||||
while((header = DataUtil.readTillRN(is)) != "" && headers.size() < Constants.MAX_HEADERS) {
|
||||
int colon = header.indexOf(':')
|
||||
if (colon == -1 || colon == header.length() - 1)
|
||||
throw new IOException("invalid header $header")
|
||||
String key = header.substring(0, colon)
|
||||
String value = header.substring(colon + 1)
|
||||
headers[key] = value.trim()
|
||||
}
|
||||
Map<String,String> headers = DataUtil.readAllHeaders(is)
|
||||
|
||||
if (!headers.containsKey("Count"))
|
||||
throw new IOException("No count header")
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import com.muwire.core.util.DataUtil;
|
||||
|
@ -26,8 +27,8 @@ public class SharedFile {
|
|||
private final List<String> b64EncodedHashList;
|
||||
|
||||
private volatile String comment;
|
||||
private volatile int hits;
|
||||
private final Set<String> downloaders = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<SearchEntry> searches = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
public SharedFile(File file, InfoHash infoHash, int pieceSize) throws IOException {
|
||||
this.file = file;
|
||||
|
@ -97,11 +98,11 @@ public class SharedFile {
|
|||
}
|
||||
|
||||
public int getHits() {
|
||||
return hits;
|
||||
return searches.size();
|
||||
}
|
||||
|
||||
public void hit() {
|
||||
hits++;
|
||||
public void hit(Persona searcher, long timestamp, String query) {
|
||||
searches.add(new SearchEntry(searcher, timestamp, query));
|
||||
}
|
||||
|
||||
public Set<String> getDownloaders() {
|
||||
|
@ -124,4 +125,29 @@ public class SharedFile {
|
|||
SharedFile other = (SharedFile)o;
|
||||
return file.equals(other.file) && infoHash.equals(other.infoHash);
|
||||
}
|
||||
|
||||
public static class SearchEntry {
|
||||
private final Persona searcher;
|
||||
private final long timestamp;
|
||||
private final String query;
|
||||
|
||||
public SearchEntry(Persona searcher, long timestamp, String query) {
|
||||
this.searcher = searcher;
|
||||
this.timestamp = timestamp;
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return Objects.hash(searcher) ^ Objects.hash(timestamp) ^ query.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof SearchEntry))
|
||||
return false;
|
||||
SearchEntry other = (SearchEntry)o;
|
||||
return Objects.equals(searcher, other.searcher) &&
|
||||
timestamp == other.timestamp &&
|
||||
query.equals(other.query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ import java.lang.reflect.Method;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -99,6 +101,20 @@ public class DataUtil {
|
|||
}
|
||||
return new String(baos.toByteArray(), StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
public static Map<String, String> readAllHeaders(InputStream is) throws IOException {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
String header;
|
||||
while(!(header = readTillRN(is)).equals("") && headers.size() < Constants.MAX_HEADERS) {
|
||||
int colon = header.indexOf(':');
|
||||
if (colon == -1 || colon == header.length() - 1)
|
||||
throw new IOException("Invalid header "+ header);
|
||||
String key = header.substring(0, colon);
|
||||
String value = header.substring(colon + 1);
|
||||
headers.put(key, value.trim());
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
public static String encodeXHave(List<Integer> pieces, int totalPieces) {
|
||||
int bytes = totalPieces / 8;
|
||||
|
|
Loading…
Reference in New Issue