// Copyright 2016 Eivind Vegsundvåg // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ninja.eivind.hotsreplayuploader.files.tempwatcher; import javafx.concurrent.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.nio.file.*; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.function.Consumer; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.OVERFLOW; public class BattleLobbyWatcher extends TempWatcher { public static final String REPLAY_SERVER_BATTLELOBBY = "replay.server.battlelobby"; public static final long DELAY = 250L; private static final Logger logger = LoggerFactory.getLogger(BattleLobbyWatcher.class); private final File heroesDirectory; private final FilenameFilter fileNameFilter; private Consumer<File> callback; public BattleLobbyWatcher(File heroesDirectory) { this.heroesDirectory = heroesDirectory; fileNameFilter = (dir, name) -> name.contains("TempWriteReplayP"); } @Override protected Task<Void> createTask() { logger.info("BattleLobbyWatcher starting..."); Path path = heroesDirectory.toPath(); new Thread(getInstantFileChecker()).start(); return new Task<Void>() { @Override protected Void call() throws Exception { logger.info("BattleLobbyWatcher started"); try (WatchService watchService = FileSystems.getDefault().newWatchService()) { path.register(watchService, ENTRY_CREATE); while (true) { WatchKey key = watchService.take(); key.pollEvents().forEach(event -> { WatchEvent.Kind<?> kind = event.kind(); @SuppressWarnings("unchecked") final WatchEvent<Path> pathEvent = (WatchEvent<Path>) event; final Path pathName = pathEvent.context(); logger.info("Received " + kind + " for path " + pathName); if (kind == OVERFLOW) { return; } File file = new File(path.toFile(), pathName.toString()); String fileName = file.getName(); if (fileNameFilter.accept(path.toFile(), fileName)) { File target = new File(file, REPLAY_SERVER_BATTLELOBBY); handleFile(target); } }); if (!key.reset()) { break; } } } catch (IOException e) { logger.error("Watcher threw exception", e); } catch (InterruptedException e) { logger.info("TempReplayWatcher was interrupted. Winding down."); } logger.info("Game exited. Stopping BattleLobbyWatcher"); return null; } }; } private Runnable getInstantFileChecker() { return () -> { try { LocalDateTime end = LocalDateTime.now().plus(10, ChronoUnit.SECONDS); while (LocalDateTime.now().isBefore(end)) { File[] files = heroesDirectory.listFiles(fileNameFilter); for (File file : files != null ? files : new File[0]) { File target = new File(file, REPLAY_SERVER_BATTLELOBBY); if (target.exists()) { handleFile(target); return; } } Thread.sleep(DELAY); } } catch (InterruptedException ignored) { } }; } private void handleFile(File target) { logger.info("Discovered BattleLobby: {}", target); new Thread(() -> { try { Thread.sleep(250L); callback.accept(target); } catch (InterruptedException e) { logger.error("", e); } }).start(); } @Override public int getChildCount() { return 0; } @Override public Consumer<File> getCallback() { return callback; } @Override public void setCallback(Consumer<File> callback) { this.callback = callback; } }