diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0c382..f857a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,16 @@ # Changes All notable changes to this project will be documented in `CHANGELOG.md`. ## Added -* `PopupHandler` - stops me from duplicating a bunch of code just for settings. -* [TODOs][todos] to changelog. +* GUI to show all scanned MC servers in database (with sorting, too!) ## Modified -* Thread handling has been modified to be (potentially) faster (again) and use less lines of code. +* Fixed everything again, but now it's slower. Need to work on a better thread system. ## Removed -* Hits feature -* 1 unused import -* (potentially) more comments +Nothing has been removed. ## TODOs -- [ ] Optimise IP generation and inital scanning code. (1) +- [ ] Optimise IP generation and inital scanning code. [1] +- [ x ] ~~Add a GUI for viewing servers in a nice friendly grid.~~ [todos]: https://github.com/StupidRepo/MCScanner/blob/main/CHANGELOG.md#todos \ No newline at end of file diff --git a/src/com/stupidrepo/mcscanner/DatabaseHandler.java b/src/com/stupidrepo/mcscanner/DatabaseHandler.java index 131e31b..33687ff 100644 --- a/src/com/stupidrepo/mcscanner/DatabaseHandler.java +++ b/src/com/stupidrepo/mcscanner/DatabaseHandler.java @@ -6,6 +6,7 @@ import com.mongodb.client.MongoDatabase; import org.bson.Document; +import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; @@ -27,6 +28,19 @@ public DatabaseHandler(String uri) { } } + public ArrayList getServers() { + ArrayList servers = new ArrayList<>(); + try { + for (Document doc : mainCollection.find()) { + servers.add(doc); + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Failed to get servers from database!"); + } + + return servers; + } + public void writeDetailsToDB(String ip, String version, String motd, int maxPlayers) { try { mainCollection diff --git a/src/com/stupidrepo/mcscanner/MCScanner.java b/src/com/stupidrepo/mcscanner/MCScanner.java index e93ec55..a393182 100644 --- a/src/com/stupidrepo/mcscanner/MCScanner.java +++ b/src/com/stupidrepo/mcscanner/MCScanner.java @@ -1,25 +1,26 @@ package com.stupidrepo.mcscanner; import java.awt.BorderLayout; +import java.awt.GridLayout; import java.awt.event.WindowEvent; import java.io.*; -import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.NetworkInterface; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; + +import org.bson.Document; public class MCScanner { - public static void main(String[] var0) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { + public static void main(String[] var0) { AtomicInteger threads = new AtomicInteger(1024); int timeout = 1000; int minimumRange = 1; @@ -28,7 +29,7 @@ public static void main(String[] var0) throws IllegalArgumentException, IllegalA Logger logger = Logger.getLogger("com.stupidrepo.mcscanner"); - float version = 1.14f; + float version = 1.15f; AtomicReference uri = new AtomicReference<>("mongodb://localhost:27017"); @@ -56,9 +57,7 @@ public static void main(String[] var0) throws IllegalArgumentException, IllegalA frame.setLayout(new BorderLayout()); double progressThing = (maxRange - minimumRange + 1) * 256 * 256; - ArrayList < Thread > threadList = new ArrayList < Thread > (); - ArrayList < String > ips = new ArrayList < String > (); JLabel scannedLabel = new JLabel("Scanned: 0/" + progressThing * 256); scannedLabel.setHorizontalAlignment(0); @@ -66,55 +65,68 @@ public static void main(String[] var0) throws IllegalArgumentException, IllegalA frame.add(scannedLabel, "Center"); long scanned = 0; + long hits = 0; - frame.setVisible(true); + JLabel hitsLabel = new JLabel("Hits: 0/0"); + hitsLabel.setHorizontalAlignment(0); + + frame.add(hitsLabel, "South"); + + JButton viewServersButton = new JButton("View Servers"); - // TODO: Optimise this code. (1) + viewServersButton.addActionListener(e -> { + ServerList serverList = new ServerList(databaseHandler); + serverList.showGUI(); + }); - ExecutorService executor = Executors.newFixedThreadPool(threads.get()); + frame.add(viewServersButton, "North"); + frame.setVisible(true); + + // TODO: Make this whole thing more efficient, and less ugly. [1] for (int i = minimumRange; i <= maxRange; ++i) { for (int j = 0; j <= 255; ++j) { for (int k = 0; k <= 255; ++k) { for (int l = 0; l <= 255; ++l) { String ip = i + "." + j + "." + k + "." + l; - ips.add(ip); - } - } - } - } - - for (int i = 0; i < ips.size(); ++i) { - int randomIndex = (int)(Math.random() * ips.size()); - String temp = ips.get(i); - ips.set(i, ips.get(randomIndex)); - ips.set(randomIndex, temp); - } - for(String ip: ips) { - Thread scannerThread = new Thread(new ScannerThread(ip, port, timeout, databaseHandler)); - threadList.add(scannerThread); - executor.execute(scannerThread); - - if (threadList.size() >= threads.get()) { - for (Thread nextThread: threadList) { - try { - nextThread.join(); - ++scanned; - scannedLabel.setText("Scanned: " + scanned + "/" + progressThing*256 + " (" + (scanned / (progressThing*256)) * 100 + "%)"); - } catch (InterruptedException timeout2) { - // eh + ScannerThread scannerThread = new ScannerThread(ip, port, timeout, databaseHandler); + Thread scanThread = new Thread(scannerThread); + threadList.add(scanThread); + scanThread.start(); + + if (threadList.size() >= threads.get()) { + for (Thread nextThread: threadList) { + try { + nextThread.join(); + ++scanned; + if(scannerThread.didHit) { + ++hits; + } + // progressBar.setValue(scanned); + hitsLabel.setText("Hits: " + hits + "/" + scanned); + scannedLabel.setText("Scanned: " + scanned + "/" + progressThing * 256 + " (" + Math.round((scanned / (progressThing * 256)) * 100) / 100 + "%)"); + } catch (InterruptedException timeout2) { + // eh + } + } + threadList.clear(); + } } } - threadList.clear(); } } - try { - executor.shutdown(); - executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - logger.log(Level.SEVERE, "Interrupted while waiting for threads to finish."); + for (Thread nextThreadAgain: threadList) { + try { + nextThreadAgain.join(); + ++scanned; + // progressBar.setValue(scanned); + hitsLabel.setText("Hits: " + hits + "/" + scanned); + scannedLabel.setText("Scanned: " + scanned + "/" + progressThing * 256); + } catch (InterruptedException timeout1) { + // well + } } frame.setVisible(false); @@ -212,4 +224,81 @@ public void run() { // No response/invalid response/timeout/port accidentally left open } } +} + +class ServerList { + private final DatabaseHandler dbHandler; + + public ServerList(DatabaseHandler dbHandler) { + this.dbHandler = dbHandler; + } + + public void showGUI() { + JFrame frame = new JFrame("MCScanner - Servers"); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame.setSize(500, 500); + frame.setLayout(new BorderLayout()); + + JTable table = new JTable(); + table.setModel(new DefaultTableModel( + new Object[][] { + }, + new String[] { + "IP", "MOTD", "Version", "Max Players" + } + )); + table.getColumnModel().getColumn(0).setPreferredWidth(100); + table.getColumnModel().getColumn(1).setPreferredWidth(200); + table.getColumnModel().getColumn(2).setPreferredWidth(50); + table.getColumnModel().getColumn(3).setPreferredWidth(50); + table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); + table.setFillsViewportHeight(true); + table.setRowHeight(20); + table.setRowSelectionAllowed(false); + table.getTableHeader().setReorderingAllowed(false); + table.getTableHeader().setResizingAllowed(false); + + JScrollPane scrollPane = new JScrollPane(table); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + ArrayList < Document > documents = dbHandler.getServers(); + for (Document document: documents) { + String ip = document.getString("ip"); + String motd = document.getString("motd"); + String version = document.getString("version"); + int players = document.getInteger("maxPlayers"); + + ((DefaultTableModel) table.getModel()).addRow(new Object[] { + ip, motd, version, players + }); + } + + // refresh option + JButton refreshButton = new JButton("Refresh"); + + refreshButton.addActionListener(e -> { + ((DefaultTableModel) table.getModel()).setRowCount(0); + + ArrayList < Document > documents1 = dbHandler.getServers(); + for (Document document: documents1) { + String ip = document.getString("ip"); + String motd = document.getString("motd"); + String version = document.getString("version"); + int players = document.getInteger("maxPlayers"); + + ((DefaultTableModel) table.getModel()).addRow(new Object[] { + ip, motd, version, players + }); + } + }); + + TableRowSorter < TableModel > sorter = new TableRowSorter < > (table.getModel()); + table.setRowSorter(sorter); + + // frame.add(table, BorderLayout.CENTER); + frame.add(scrollPane, BorderLayout.CENTER); + frame.add(refreshButton, BorderLayout.SOUTH); + frame.setVisible(true); + } } \ No newline at end of file