Skip to content

Commit

Permalink
Add file hashing notification
Browse files Browse the repository at this point in the history
A small undetermined progress bar is displayed with the currently indexed file in the tooltip. Might change to displaying the file directly though as it's not obvious of what is happening.
  • Loading branch information
zapek committed Feb 20, 2024
1 parent 50202e9 commit 6c3a675
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.xeres.app.service.notification.file.FileNotificationService;
import io.xeres.app.service.notification.forum.ForumNotificationService;
import io.xeres.app.service.notification.status.StatusNotificationService;
import org.springframework.http.MediaType;
Expand All @@ -40,11 +41,13 @@ public class NotificationController
{
private final StatusNotificationService statusNotificationService;
private final ForumNotificationService forumNotificationService;
private final FileNotificationService fileNotificationService;

public NotificationController(StatusNotificationService statusNotificationService, ForumNotificationService forumNotificationService)
public NotificationController(StatusNotificationService statusNotificationService, ForumNotificationService forumNotificationService, FileNotificationService fileNotificationService)
{
this.statusNotificationService = statusNotificationService;
this.forumNotificationService = forumNotificationService;
this.fileNotificationService = fileNotificationService;
}

@GetMapping("/status")
Expand All @@ -62,4 +65,12 @@ public SseEmitter setupForumNotification()
{
return forumNotificationService.addClient();
}

@GetMapping("/file")
@Operation(summary = "Subscribe to file notifications")
@ApiResponse(responseCode = "200", description = "Request completed successfully")
public SseEmitter setupFileNotification()
{
return fileNotificationService.addClient();
}
}
12 changes: 10 additions & 2 deletions app/src/main/java/io/xeres/app/service/file/FileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void checkForSharesToScan()
log.debug("Scanning: {}", share);
share.setLastScanned(now);
shareRepository.save(share);
scanShare(share.getFile());
scanShare(share);
});
}

Expand Down Expand Up @@ -170,10 +170,12 @@ private List<File> getFullPath(File file)
return tree;
}

void scanShare(File directory)
void scanShare(Share share)
{
try
{
fileNotificationService.startScanning(share);
File directory = share.getFile();
var directoryPath = getFilePath(directory);
Files.walkFileTree(directoryPath, new TrackingFileVisitor(fileRepository, directory)
{
Expand Down Expand Up @@ -247,6 +249,10 @@ public FileVisitResult visitFileFailed(Path file, IOException exc)
{
throw new RuntimeException(e);
}
finally
{
fileNotificationService.stopScanning();
}
}

private Path getFilePath(File file)
Expand Down Expand Up @@ -314,6 +320,7 @@ Sha1Sum calculateFileHash(Path path)
log.debug("Calculating file hash of file {}", path);
try (var fc = FileChannel.open(path, StandardOpenOption.READ)) // ExtendedOpenOption.DIRECT is useless for memory mapped files
{
fileNotificationService.setScanningFile(path);
var md = new Sha1MessageDigest();

var size = fc.size();
Expand All @@ -339,6 +346,7 @@ Sha1Sum calculateFileHash(Path path)
catch (IOException e)
{
log.warn("Error while trying to compute hash of file " + path, e);
fileNotificationService.setScanningFile(null);
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,42 @@

package io.xeres.app.service.notification.file;

import io.xeres.app.database.model.share.Share;
import io.xeres.app.service.notification.NotificationService;
import io.xeres.common.rest.notification.Notification;
import io.xeres.common.rest.notification.file.FileNotification;
import org.springframework.stereotype.Service;

import java.nio.file.Path;

@Service
public class FileNotificationService extends NotificationService
{
private String shareName;
private String scannedFile;

@Override
protected Notification createNotification()
{
return null; // XXX
return new FileNotification(shareName, scannedFile);
}

public void startScanning(Share share)
{
this.shareName = share.getName();
sendNotification();
}

public void setScanningFile(Path scannedFile)
{
this.scannedFile = scannedFile != null ? scannedFile.toString() : null;
sendNotification();
}

public void stopScanning()
{
this.shareName = null;
this.scannedFile = null;
sendNotification();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.xeres.common.rest.notification.file;

import io.xeres.common.rest.notification.Notification;

public record FileNotification(String shareName, String scannedFile) implements Notification
{
}
11 changes: 11 additions & 0 deletions ui/src/main/java/io/xeres/ui/client/NotificationClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package io.xeres.ui.client;

import io.xeres.common.rest.notification.file.FileNotification;
import io.xeres.common.rest.notification.forum.ForumNotification;
import io.xeres.common.rest.notification.status.StatusNotification;
import io.xeres.ui.JavaFxApplication;
Expand Down Expand Up @@ -70,4 +71,14 @@ public Flux<ServerSentEvent<ForumNotification>> getForumNotifications()
{
});
}

public Flux<ServerSentEvent<FileNotification>> getFileNotifications()
{
return webClient.get()
.uri("/file")
.retrieve()
.bodyToFlux(new ParameterizedTypeReference<>()
{
});
}
}
55 changes: 39 additions & 16 deletions ui/src/main/java/io/xeres/ui/controller/MainWindowController.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@
import io.xeres.ui.support.window.WindowManager;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.stage.FileChooser;
Expand Down Expand Up @@ -150,19 +147,22 @@ public class MainWindowController implements WindowController
private Button showQrCodeButton;

@FXML
public Button addFriendButton;
private Button addFriendButton;

@FXML
public Button webHelpButton;
private Button webHelpButton;

@FXML
public Label numberOfConnections;
private Label numberOfConnections;

@FXML
public LedControl natStatus;
private LedControl natStatus;

@FXML
public LedControl dhtStatus;
private LedControl dhtStatus;

@FXML
private ProgressIndicator hashingStatus;

private final ChatViewController chatViewController;

Expand All @@ -177,7 +177,8 @@ public class MainWindowController implements WindowController

private int currentUsers;
private int totalUsers;
private Disposable notificationDisposable;
private Disposable statusNotificationDisposable;
private Disposable fileNotificationDisposable;

public MainWindowController(ChatViewController chatViewController, LocationClient locationClient, TrayService trayService, WindowManager windowManager, Environment environment, IdentityClient identityClient, ConfigClient configClient, NotificationClient notificationClient, ResourceBundle bundle)
{
Expand Down Expand Up @@ -265,7 +266,7 @@ public void initialize()
Platform.exit();
});

setupStatusNotifications();
setupNotifications();

trayService.addSystemTray();

Expand Down Expand Up @@ -307,14 +308,13 @@ private void openUrl(String url)
JavaFxApplication.openUrl(url);
}

private void setupStatusNotifications()
private void setupNotifications()
{
// Apparently the LED is not happy if we don't turn it on first here.
natStatus.setState(true);
dhtStatus.setState(true);

notificationDisposable = notificationClient.getStatusNotifications()
.doOnComplete(() -> log.debug("Notification connection closed"))
statusNotificationDisposable = notificationClient.getStatusNotifications()
.doOnError(UiUtils::showAlertError)
.doOnNext(sse -> Platform.runLater(() -> {
if (sse.data() != null)
Expand All @@ -325,6 +325,24 @@ private void setupStatusNotifications()
}
}))
.subscribe();

fileNotificationDisposable = notificationClient.getFileNotifications()
.doOnError(UiUtils::showAlertError)
.doOnNext(sse -> Platform.runLater(() -> {
if (sse.data() != null)
{
hashingStatus.setVisible(sse.data().shareName() != null);
if (sse.data().scannedFile() != null)
{
TooltipUtils.install(hashingStatus, sse.data().shareName() + ": hashing " + sse.data().scannedFile() + "...");
}
else
{
TooltipUtils.install(hashingStatus, null);
}
}
}))
.subscribe();
}

private void setUserCount(Integer newCurrentUsers, Integer newTotalUsers)
Expand Down Expand Up @@ -400,9 +418,14 @@ private void setDhtInfo(DhtInfo newDhtInfo)
@EventListener
public void onApplicationEvent(ContextClosedEvent ignored)
{
if (notificationDisposable != null && !notificationDisposable.isDisposed())
if (statusNotificationDisposable != null && !statusNotificationDisposable.isDisposed())
{
statusNotificationDisposable.dispose();
}

if (fileNotificationDisposable != null && !fileNotificationDisposable.isDisposed())
{
notificationDisposable.dispose();
fileNotificationDisposable.dispose();
}
}
}
3 changes: 3 additions & 0 deletions ui/src/main/resources/view/main.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
~ along with Xeres. If not, see <http://www.gnu.org/licenses/>.
-->

<?import atlantafx.base.controls.Spacer?>
<?import io.xeres.ui.custom.led.LedControl?>
<?import io.xeres.ui.custom.ReadOnlyTextField?>
<?import javafx.geometry.*?>
Expand Down Expand Up @@ -244,5 +245,7 @@
</HBox.margin>
</Label>
<LedControl fx:id="dhtStatus" prefHeight="16.0" prefWidth="16.0"/>
<Spacer HBox.hgrow="ALWAYS"/>
<ProgressIndicator fx:id="hashingStatus" visible="false" prefWidth="16.0" prefHeight="16.0"/>
</HBox>
</VBox>

0 comments on commit 6c3a675

Please sign in to comment.