From d60d57ee435a3f6efbe6d7e06c096dd641c4137a Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Sun, 8 Mar 2020 17:04:11 +0000 Subject: [PATCH] wip on server side feed handling --- .../core/connection/ConnectionAcceptor.groovy | 51 +++++++++++++++++++ .../muwire/core/filefeeds/FeedItems.groovy | 28 ++++++++++ .../com/muwire/core/files/FileManager.groovy | 12 +++++ 3 files changed, 91 insertions(+) create mode 100644 core/src/main/groovy/com/muwire/core/filefeeds/FeedItems.groovy diff --git a/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy b/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy index b1fcbaf3..16c67c1c 100644 --- a/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy +++ b/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy @@ -15,9 +15,11 @@ import com.muwire.core.EventBus import com.muwire.core.InfoHash import com.muwire.core.MuWireSettings import com.muwire.core.Persona +import com.muwire.core.SharedFile import com.muwire.core.chat.ChatServer import com.muwire.core.filecert.Certificate import com.muwire.core.filecert.CertificateManager +import com.muwire.core.filefeeds.FeedItems import com.muwire.core.files.FileManager import com.muwire.core.hostcache.HostCache import com.muwire.core.trust.TrustLevel @@ -161,6 +163,9 @@ class ConnectionAcceptor { case (byte)'I': processIRC(e) break + case (byte)'F': + processFEED(e) + break default: throw new Exception("Invalid read $read") } @@ -524,5 +529,51 @@ class ConnectionAcceptor { throw new Exception("Invalid IRC connection") chatServer.handle(e) } + + private void processFEED(Endpoint e) { + try { + byte[] EED = new byte[5]; + DataInputStream dis = new DataInputStream(e.getInputStream()) + dis.readFully(EED); + if (EED != "EED\r\n".getBytes(StandardCharsets.US_ASCII)) + throw new Exception("Invalid FEED connection") + + + Map headers = DataUtil.readAllHeaders(dis) + if (!headers.containsKey("Persona")) + throw new Exception("Persona header missing") + Persona requestor = new Persona(new ByteArrayInputStream(Base64.decode(headers['Persona']))) + if (requestor.destination != e.destination) + throw new Exception("Requestor persona mismatch") + + // TODO: check settings if feed is permitted at all + + long timestamp = 0 + if (headers.containsKey("Timestamp")) { + timestamp = Long.parseLong(headers['Timestamp']) + } + + List published = fileManager.getPublishedSince(timestamp) + + OutputStream os = e.getOutputStream() + os.write("200 OK\r\n".getBytes(StandardCharsets.US_ASCII)) + os.write("Count: ${published.size()}\r\n".getBytes(StandardCharsets.US_ASCII)); + os.write("\r\n".getBytes(StandardCharsets.US_ASCII)) + + DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(os)) + JsonOutput jsonOutput = new JsonOutput() + published.each { + int certificates = certificateManager.getByInfoHash(new InfoHash(it.getRoot())).size() + def obj = FeedItems.sharedFileToObj(it, certificates) + def json = jsonOutput.toJson(obj) + dos.writeShort((short)json.length()) + dos.write(json.getBytes(StandardCharsets.US_ASCII)) + } + dos.flush() + dos.close() + } finally { + e.close() + } + } } diff --git a/core/src/main/groovy/com/muwire/core/filefeeds/FeedItems.groovy b/core/src/main/groovy/com/muwire/core/filefeeds/FeedItems.groovy new file mode 100644 index 00000000..c2519aa6 --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/filefeeds/FeedItems.groovy @@ -0,0 +1,28 @@ +package com.muwire.core.filefeeds + +import com.muwire.core.SharedFile +import com.muwire.core.util.DataUtil + +import net.i2p.data.Base64 + +class FeedItems { + + public static def sharedFileToObj(SharedFile sf, int certificates) { + def json = [:] + json.type = "FeedItem" + json.version = 1 + json.name = Base64.encode(DataUtil.encodei18nString(sf.getFile().getName())) + json.infoHash = Base64.encode(sf.getRoot()) + json.size = sf.getCachedLength() + json.pieceSize = sf.getPieceSize() + + if (sf.getComment() != null) + json.comment = sf.getComment() + + json.certificates = certificates + + json.timestamp = sf.getPublishedTimestamp() + + json + } +} diff --git a/core/src/main/groovy/com/muwire/core/files/FileManager.groovy b/core/src/main/groovy/com/muwire/core/files/FileManager.groovy index 16864be7..a130d336 100644 --- a/core/src/main/groovy/com/muwire/core/files/FileManager.groovy +++ b/core/src/main/groovy/com/muwire/core/files/FileManager.groovy @@ -1,5 +1,8 @@ package com.muwire.core.files +import java.util.stream.Collectors +import java.util.stream.Stream + import com.muwire.core.EventBus import com.muwire.core.InfoHash import com.muwire.core.MuWireSettings @@ -254,4 +257,13 @@ class FileManager { settings.negativeFileTree.clear() settings.negativeFileTree.addAll(negativeTree.fileToNode.keySet().collect { it.getAbsolutePath() }) } + + public List getPublishedSince(long timestamp) { + synchronized(fileToSharedFile) { + fileToSharedFile.values().stream(). + filter({sf -> sf.isPublished()}). + filter({sf -> sf.getPublishedTimestamp() >= timestamp}). + collect(Collectors.toList()) + } + } }