From c3f9663f84df7f9fb01941f238b479dcdd7c2714 Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Tue, 26 Oct 2021 07:59:09 +0100 Subject: [PATCH] plumbing for fetching certificates on demand --- .../muwire/gui/ResultDetailsController.groovy | 2 +- gui/griffon-app/i18n/messages.properties | 1 + .../com/muwire/gui/ResultDetailsModel.groovy | 78 +++++++++++++++++++ .../com/muwire/gui/ResultDetailsView.groovy | 64 ++++++++++++++- 4 files changed, 141 insertions(+), 4 deletions(-) diff --git a/gui/griffon-app/controllers/com/muwire/gui/ResultDetailsController.groovy b/gui/griffon-app/controllers/com/muwire/gui/ResultDetailsController.groovy index 26465288..51d0d347 100644 --- a/gui/griffon-app/controllers/com/muwire/gui/ResultDetailsController.groovy +++ b/gui/griffon-app/controllers/com/muwire/gui/ResultDetailsController.groovy @@ -5,5 +5,5 @@ import griffon.metadata.ArtifactProviderFor @ArtifactProviderFor(GriffonController) class ResultDetailsController { - + } diff --git a/gui/griffon-app/i18n/messages.properties b/gui/griffon-app/i18n/messages.properties index e637df16..06b721fd 100644 --- a/gui/griffon-app/i18n/messages.properties +++ b/gui/griffon-app/i18n/messages.properties @@ -286,6 +286,7 @@ COPY_NAME_TO_CLIPBOARD=Copy name to clipboard YOU_ALREADY_HAVE_FILE=You already have {0} copies of this file RESULTS_CAME_FROM=Results came from the following users SELECT_SENDER=Select a sender to see additional details +SENDER_HAS_CERTIFICATES=This sender claims to have {0} certificate(s) for this file. ## Options pane diff --git a/gui/griffon-app/models/com/muwire/gui/ResultDetailsModel.groovy b/gui/griffon-app/models/com/muwire/gui/ResultDetailsModel.groovy index b66de8cf..918e8e7a 100644 --- a/gui/griffon-app/models/com/muwire/gui/ResultDetailsModel.groovy +++ b/gui/griffon-app/models/com/muwire/gui/ResultDetailsModel.groovy @@ -2,7 +2,14 @@ package com.muwire.gui import com.muwire.core.Core import com.muwire.core.InfoHash +import com.muwire.core.Persona import com.muwire.core.SharedFile +import com.muwire.core.collections.FileCollection +import com.muwire.core.filecert.Certificate +import com.muwire.core.filecert.CertificateFetchEvent +import com.muwire.core.filecert.CertificateFetchStatus +import com.muwire.core.filecert.CertificateFetchedEvent +import com.muwire.core.filecert.UIFetchCertificatesEvent import com.muwire.core.search.UIResultEvent import griffon.core.artifact.GriffonModel import griffon.inject.MVCMember @@ -10,6 +17,7 @@ import griffon.metadata.ArtifactProviderFor import net.i2p.data.Base64 import javax.annotation.Nonnull +import javax.swing.table.DefaultTableModel @ArtifactProviderFor(GriffonModel) class ResultDetailsModel { @@ -25,6 +33,11 @@ class ResultDetailsModel { String key List localFiles + Map certificates + Map> collections + + private boolean registeredForCertificates, registeredForCollections + void mvcGroupInit(Map args) { key = fileName + Base64.encode(infoHash.getRoot()) SharedFile[] locals = core.fileManager.getSharedFiles(infoHash.getRoot()) @@ -32,5 +45,70 @@ class ResultDetailsModel { localFiles = Collections.emptyList() else localFiles = Arrays.asList(locals) + + certificates = new HashMap<>() + collections = new HashMap<>() + } + + void mvcGroupDestroy() { + if (registeredForCertificates) { + core.eventBus.unregister(CertificateFetchEvent.class, this) + core.eventBus.unregister(CertificateFetchedEvent.class, this) + } + } + + void registerForCollections(Persona sender) { + if (registeredForCollections) + return + registeredForCollections = true + // TODO: finish + } + + CertsModel registerForCertificates(Persona persona) { + if (certificates.containsKey(persona)) + return null + if (!registeredForCertificates) { + registeredForCertificates = true + core.eventBus.with { + register(CertificateFetchEvent.class, this) + register(CertificateFetchedEvent.class, this) + } + } + def rv = new CertsModel() + certificates.put(persona, rv) + core.eventBus.publish(new UIFetchCertificatesEvent(host: persona, infoHash: infoHash)) + return rv + } + + void onCertificateFetchEvent(CertificateFetchEvent event) { + if (event.infoHash != infoHash) + return + runInsideUIAsync { + CertsModel model = certificates.get(event.user) + if (model == null) + return + model.status = event.status + if (event.status == CertificateFetchStatus.FETCHING) + model.count = event.count + view.refreshCertificates() + } + } + + void onCertificateFetchedEvent(CertificateFetchedEvent event) { + if (event.infoHash != infoHash) + return + runInsideUIAsync { + CertsModel model = certificates.get(event.user) + if (model == null) + return + model.certificates << event.certificate + view.refreshCertificates() + } + } + + static class CertsModel { + CertificateFetchStatus status + int count + final List certificates = new ArrayList<>() } } diff --git a/gui/griffon-app/views/com/muwire/gui/ResultDetailsView.groovy b/gui/griffon-app/views/com/muwire/gui/ResultDetailsView.groovy index b76b1309..cd984189 100644 --- a/gui/griffon-app/views/com/muwire/gui/ResultDetailsView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/ResultDetailsView.groovy @@ -1,14 +1,18 @@ package com.muwire.gui +import com.muwire.core.filecert.Certificate import com.muwire.core.search.UIResultEvent +import com.muwire.gui.ResultDetailsModel.CertsModel import griffon.core.artifact.GriffonView import griffon.inject.MVCMember import griffon.metadata.ArtifactProviderFor import net.i2p.data.DataHelper import javax.annotation.Nonnull -import javax.swing.JCheckBox +import javax.swing.JButton +import javax.swing.JLabel import javax.swing.JPanel +import javax.swing.JScrollPane import javax.swing.JTabbedPane import javax.swing.JTable import javax.swing.ListSelectionModel @@ -31,6 +35,8 @@ class ResultDetailsView { JPanel senderDetailsPanel JTabbedPane tabs + List certsPanelList = [] + void initUI() { int rowHeight = application.context.get("row-height") p = builder.panel { @@ -120,8 +126,28 @@ class ResultDetailsView { tabs.addTab(trans("COMMENT"),commentPanel) } if (event.certificates > 0) { - def certsPanel = builder.panel { - label(text: "TODO fetch certs") + def certsPanel + if (model.certificates.containsKey(event.sender)) { + certsPanel = new CertsPanel(model.certificates[event.sender]) + certsPanel.setPreferredSize(tabs.getPreferredSize()) + certsPanel.refresh() + } else { + certsPanel = builder.panel { + cardLayout() + panel(constraints: "fetch-certificates") { + label(text: trans("SENDER_HAS_CERTIFICATES", event.certificates)) + JButton fetchButton = button(text : trans("VIEW_CERTIFICATES")) + fetchButton.addActionListener( { + def certsModel = model.registerForCertificates(event.sender) + def newCertsPanel = new CertsPanel(certsModel) + certsPanelList << newCertsPanel + newCertsPanel.setPreferredSize(certsPanel.getPreferredSize()) + certsPanel.add(newCertsPanel, "view-certificates") + certsPanel.getLayout().last(certsPanel) + newCertsPanel.refresh() + }) + } + } } tabs.addTab(trans("CERTIFICATES"), certsPanel) } @@ -150,4 +176,36 @@ class ResultDetailsView { def showSelectSender = { senderDetailsPanel.getLayout().show(senderDetailsPanel, "select-sender") } + + void refreshCertificates() { + certsPanelList.each {it.refresh()} + } + + private class CertsPanel extends JPanel { + private final ResultDetailsModel.CertsModel model + private final JLabel statusLabel + private JTable certsTable + CertsPanel(ResultDetailsModel.CertsModel model) { + this.model = model + setLayout(new BorderLayout()) + statusLabel = new JLabel() + add(statusLabel, BorderLayout.NORTH) + + JScrollPane scrollPane = builder.scrollPane { + certsTable = builder.table { + tableModel(list: model.certificates) { + closureColumn(header: trans("NAME"), read: { Certificate c -> c.name.name }) + } + } + } + + add(scrollPane, BorderLayout.CENTER) + } + + void refresh() { + if (model.status != null) + statusLabel.setText(trans(model.status.name())) + certsTable.model.fireTableDataChanged() + } + } }