/* * Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Tobias Fleig (tobifleig gmail com) * * All rights reserved. * * This file is part of LanXchange. * * LanXchange is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * LanXchange is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with LanXchange. If not, see <http://www.gnu.org/licenses/>. */ package de.tobifleig.lxc; import de.tobifleig.lxc.data.FileListChangeSet; import de.tobifleig.lxc.data.FileManager; import de.tobifleig.lxc.data.LXCFile; import de.tobifleig.lxc.log.LXCLogBackend; import de.tobifleig.lxc.log.LXCLogger; import de.tobifleig.lxc.net.LXCInstance; import de.tobifleig.lxc.net.NetworkManager; import de.tobifleig.lxc.net.NetworkManagerListener; import de.tobifleig.lxc.net.TransFileList; import de.tobifleig.lxc.plaf.GuiInterface; import de.tobifleig.lxc.plaf.GuiListener; import de.tobifleig.lxc.plaf.Platform; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * The main class of LanXchange. * Contains the main-method. * * @author Tobias Fleig <tobifleig googlemail com> */ public class LXC { /** * The internal version id. * For automatic updates. */ public static final int versionId = 170; /** * The external version id. */ public static final String versionString = "v1.50"; /** * Logger for core components */ private final LXCLogger logger; /** * The Platform we are running on. */ private final Platform platform; /** * Our GUI. */ private final GuiInterface gui; /** * The networkmanager. */ private final NetworkManager network; /** * The filemanager. */ private final FileManager files; /** * The default target for downloads. */ private File defaultDownloadTarget; /** * Use default target or ask. */ private boolean askForDownloadTargetSupported; /** * Create a new instance of LXC with the given command-line options. * Should be called by the main-method only. * * @param platform the platform LXC is running on * @param args command-line args */ public LXC(Platform platform, final String[] args) { logger = LXCLogBackend.getLogger("core"); this.platform = platform; logger.info("This is LanXchange " + versionString + " (" + versionId + ") - Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Tobias Fleig - License GPLv3 or later"); platform.readConfiguration(args); if (platform.hasAutoUpdates()) { platform.checkAndPerformUpdates(args); } gui = platform.getGui(args); // set up listeners initListeners(); gui.init(); askForDownloadTargetSupported = platform.askForDownloadTargetSupported(); if (platform.getDefaultDownloadTarget() != null) { defaultDownloadTarget = new File(platform.getDefaultDownloadTarget()); } // create components files = new FileManager(); // init networking network = new NetworkManager(new NetworkManagerListener() { @Override public void listReceived(TransFileList list, LXCInstance sender) { FileListChangeSet changes = files.computeFileList(list, sender); if (!changes.getRemovedFiles().isEmpty()) { // no way of picking multiple files in larger set, must serialize for (FileListChangeSet.FileModification modification : changes.getRemovedFiles()) { gui.notifyFileChange(GuiInterface.UPDATE_ORIGIN_REMOTE, GuiInterface.UPDATE_OPERATION_REMOVE, modification.index, 1, Collections.singletonList(modification.file)); } } if (!changes.getAddedFiles().isEmpty()) { // manual list copy. need Java 8 in this module soon... List<LXCFile> addedLXCFiles = new ArrayList<LXCFile>(); for (FileListChangeSet.FileModification addition : changes.getAddedFiles()) { addedLXCFiles.add(addition.file); } gui.notifyFileChange(GuiInterface.UPDATE_ORIGIN_REMOTE, GuiInterface.UPDATE_OPERATION_ADD, changes.getAddedFiles().get(0).index, changes.getAddedFiles().size(), addedLXCFiles); } } @Override public void refreshGui() { gui.update(); } @Override public void notifyJobAdded(LXCFile file, int jobIndex) { gui.notifyJobChange(GuiInterface.UPDATE_OPERATION_ADD, file, jobIndex); } @Override public void notifyRemoveJob(LXCFile file, int jobIndex) { gui.notifyJobChange(GuiInterface.UPDATE_OPERATION_REMOVE, file, jobIndex); } @Override public void instanceRemoved(LXCInstance removedInstance) { FileListChangeSet removals = files.instanceRemoved(removedInstance); if (!removals.getRemovedFiles().isEmpty()) { // no way of picking multiple files in larger set, must serialize for (FileListChangeSet.FileModification modification : removals.getRemovedFiles()) { gui.notifyFileChange(GuiInterface.UPDATE_ORIGIN_REMOTE, GuiInterface.UPDATE_OPERATION_REMOVE, modification.index, 1, Collections.singletonList(modification.file)); } } } @Override public void downloadComplete(LXCFile file, File targetFolder) { LXC.this.platform.downloadComplete(file, targetFolder); } @Override public void downloadFailedFileMissing() { gui.showError("At least one file could not be downloaded because it is no longer offered."); } @Override public void downloadFailedFileOk(String problemFilePath) { gui.showError("Download error, unable to create/write file:\n\"" + problemFilePath + "\"\nPossible reasons include missing write permissions and insufficient free space."); } @Override public void uploadFailedFileMissing(LXCFile file) { if (file.getFiles().size() == 1) { gui.showError("Uploading \"" + file.getShownName() + "\" failed, LXC cannot locate this file anymore (did you move/delete it?)\n To avoid future errors, this file is no longer offered."); } else { gui.showError("Uploading \"" + file.getShownName() + "\" failed, at least one file cannot be located anymore (did you move/delete it?)\n To avoid future errors, these files are no longer offered."); } } }, files, platform); // start networking if (!network.checkSingletonAndStart()) { // It is not possible to run multiple instances at the same time. // Warn user and exit. gui.showError("LXC is already running!"); System.exit(1); } logger.info("My instance-id is " + LXCInstance.local.id); // startup completed, display gui gui.display(); quickShare(args); } /** * quick share for PC version (will be replaced by full cli interface some day) * @param args the command line args, will look for "-share=file1,file2,file3" */ private void quickShare(String[] args) { String quickShare = ""; boolean quickShareRequested = false; for (String s : args) { if (s.startsWith("-share=")) { quickShare = s.substring(7); quickShareRequested = true; break; } } if (!quickShareRequested) { return; } if (quickShare.isEmpty()) { logger.info("Quickshare: No files found, sharing nothing"); return; } String[] files = quickShare.split(","); final List<File> actualFiles = new ArrayList<File>(); for (String path : files) { File file = new File(path); if (file.exists()) { actualFiles.add(file); } else { logger.warn("Quickshare: Cannot find file \"" + path + "\""); } } if (actualFiles.isEmpty()) { logger.info("Quickshare: No files found, sharing nothing"); } Thread thread = new Thread(new Runnable() { @Override public void run() { LXCFile tempFile = new LXCFile(LXCFile.convertToVirtual(actualFiles), actualFiles.get(0).getName()); // share int newIndex = LXC.this.files.addLocal(tempFile); if (newIndex != -1) { network.broadcastList(); gui.notifyFileChange(GuiInterface.UPDATE_ORIGIN_LOCAL, GuiInterface.UPDATE_OPERATION_ADD, newIndex, 1, Collections.singletonList(tempFile)); } } }, "lxc_helper_sizecalcer"); thread.setPriority(Thread.NORM_PRIORITY - 1); thread.start(); } /** * Init listeners for all components. */ private void initListeners() { gui.setGuiListener(new GuiListener() { @Override public void offerFile(LXCFile newFile) { int newIndex = files.addLocal(newFile); if (newIndex != -1) { network.broadcastList(); gui.notifyFileChange(GuiInterface.UPDATE_ORIGIN_LOCAL, GuiInterface.UPDATE_OPERATION_ADD, newIndex, 1, Collections.singletonList(newFile)); } } @Override public boolean shutdown(boolean force, boolean askUserOnTransfer, boolean block) { if (!force && files.transferRunning()) { // always abort when askUser is false if (!askUserOnTransfer || !gui.confirmCloseWithTransfersRunning()) { return false; } } if (block) { // synchronous LXC.this.shutdown(); } else { // asynchronous new Thread(new Runnable() { @Override public void run() { LXC.this.shutdown(); } }, "t_shutdown_helper").start(); } return true; } @Override public void resetFile(LXCFile file) { files.resetAvailableFile(file); } @Override public void removeFile(LXCFile oldFile) { files.removeLocal(oldFile); network.broadcastList(); } @Override public void downloadFile(LXCFile file, boolean chooseTarget) { File targetFolder = defaultDownloadTarget; if (askForDownloadTargetSupported && chooseTarget || defaultDownloadTarget == null) { // let user choose a (different) target targetFolder = gui.getFileTarget(file); if (targetFolder == null) { // abort file.setLocked(false); return; } } if (!network.connectAndDownload(file, targetFolder)) { gui.showError("Download failed, host unreachable."); } } @Override public void downloadFile(LXCFile file, File targetDir) { if (!network.connectAndDownload(file, targetDir)) { gui.showError("Download failed, host unreachable."); } } @Override public void reloadConfiguration() { askForDownloadTargetSupported = platform.askForDownloadTargetSupported(); if (platform.getDefaultDownloadTarget() != null) { defaultDownloadTarget = new File(platform.getDefaultDownloadTarget()); } else { defaultDownloadTarget = null; } } @Override public String generateUniqueFileName(String base, String extension) { return files.generateUniqueFileName(base, extension); } @Override public List<LXCFile> getFileList() { return files.getList(); } }); } /** * Stops LanXchange. */ private void shutdown() { network.stop(); // write configuration platform.writeConfiguration(); // done, exit logger.info("LXC done. Thank you."); } }