diff --git a/.gitignore b/.gitignore index 2026f90..21a578a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ -.idea/ -serverstatus.php +# backup files **~ -**.class +**.bak +# php files in main directory (used for specific configurations, usually has database details) +*.php +# maven artifacts +ServerChecker/target +# IDEA and PhpStorm files +.idea/ +**.iml diff --git a/README b/README index 56397c7..c8dc233 100644 --- a/README +++ b/README @@ -37,7 +37,7 @@ you must create the relevant URL rewrite. In lighttpd, it looks like this: "^/serverstatus/([^/]*)\.png$" => "/serverstatus.php?action=image&server=$1", "^/serverstatus/([^/]*)/([^/]*)\.png$" => "/serverstatus.php?action=image&scale=$1&server=$2", ) -5. Compile and set up the (extremely poorly written) ServerChecker.java +5. Compile and set up the ServerChecker java maven project (mvn package) to automatically approve and check the status of servers as a cronjob. 6. Run it, I suggest Lighttpd+FastCGI. @@ -52,7 +52,7 @@ code with everyone to improve it. If you have any questions, contact me at admin@moparisthebest.com. If you use the code, I'd love to know, so drop me a line if you would. -License: (full text in agpl-3.0.txt) +License: (full text in LICENSE) ---------------------- MoparScape.org server status page Copyright (C) 2011 Travis Burtrum (moparisthebest) @@ -77,6 +77,5 @@ tbszip.php : (LGPL) http://www.tinybutstrong.com/dl.php?f=tbszip.zip&s=2 TODO: ---------------------- -1. Re-write ServerChecker.java completely. (partially complete, calls for re-factor of database structure) -2. Embedded youtube support? -3. You suggest it! Or better yet send me a pull request or patch! +1. Embedded youtube support? +2. You suggest it! Or better yet send me a pull request or patch! diff --git a/ServerChecker/pom.xml b/ServerChecker/pom.xml new file mode 100644 index 0000000..e412ee5 --- /dev/null +++ b/ServerChecker/pom.xml @@ -0,0 +1,101 @@ + + + + + 4.0.0 + org.moparscape.serverchecker + ServerChecker + 0.1 + ${project.artifactId} + + ServerChecker checks to see if servers are online. + + + moparscape.org + http://www.moparscape.org + + + + moparisthebest + Travis Burtrum + admin@moparisthebest.com + http://www.moparscape.org/smf/ + + + + scm:git:https://github.com/moparisthebest/Server-Status-Page.git + scm:git:https://github.com/moparisthebest/Server-Status-Page.git + https://github.com/moparisthebest/Server-Status-Page + + + + GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 + http://www.gnu.org/licenses/agpl.html + + + jar + + true + + + + mysql + mysql-connector-java + 5.1.22 + + + + ${project.artifactId} + + + maven-compiler-plugin + 2.5.1 + + 1.6 + 1.6 + false + + + + maven-assembly-plugin + + + + true + org.moparscape.ServerChecker + + + + jar-with-dependencies + + + + + make-my-jar-with-dependencies + package + + single + + + + + + + diff --git a/ServerChecker.java b/ServerChecker/src/main/java/ServerChecker.java similarity index 58% rename from ServerChecker.java rename to ServerChecker/src/main/java/ServerChecker.java index 03d9be0..f3bd825 100755 --- a/ServerChecker.java +++ b/ServerChecker/src/main/java/ServerChecker.java @@ -1,29 +1,27 @@ /* -MoparScape.org server status page -Copyright (C) 2011 Travis Burtrum (moparisthebest) + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program 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 Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; -import java.util.GregorianCalendar; import java.util.Date; import java.util.HashMap; @@ -44,31 +42,32 @@ SELECT s1.* FROM servers s1, servers s2 WHERE s1.id != s2.id AND s1.ipaddress = private static final String sqlOr = " OR id="; - private HashMap iphostname = new HashMap(1000); + private HashMap iphostname = new HashMap(1000); private Connection conn; public ServerChecker() { - System.out.println(new Date()+" - STARTING..."); + System.out.println(new Date() + " - STARTING..."); try { connect(); - // timeFromDate(); + // timeFromDate(); updateServers(); validateNewServers(); // timestamp(); disconnect(); - System.out.println(new Date()+" - FINISHED SUCCESSFULLY!!"); + System.out.println(new Date() + " - FINISHED SUCCESSFULLY!!"); } catch (Exception e) { - System.out.println(new Date()+" - ERROR!!"); + System.out.println(new Date() + " - ERROR!!"); e.printStackTrace(System.out); } } -/* - private void timestamp() throws Exception { - DataOutputStream dos = new DataOutputStream(new FileOutputStream("/opt/lampp/htdocs/moparscape.org/timestamp")); - dos.writeLong(System.currentTimeMillis()/1000); - dos.close(); - } -*/ + + /* + private void timestamp() throws Exception { + DataOutputStream dos = new DataOutputStream(new FileOutputStream("/opt/lampp/htdocs/moparscape.org/timestamp")); + dos.writeLong(System.currentTimeMillis()/1000); + dos.close(); + } + */ private void connect() throws Exception { Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection(databaseUrl, userName, userPass); @@ -78,15 +77,15 @@ SELECT s1.* FROM servers s1, servers s2 WHERE s1.id != s2.id AND s1.ipaddress = conn.close(); } - private void safeExecuteUpdate(Statement stmt, String update){ - try{ - stmt.executeUpdate(update); - }catch(Exception e){ - System.out.println("safeExecuteUpdate error!"); - System.out.println("update: "+update); - System.out.println("Error: "+e.getMessage()); - e.printStackTrace(System.out); - } + private void safeExecuteUpdate(Statement stmt, String update) { + try { + stmt.executeUpdate(update); + } catch (Exception e) { + System.out.println("safeExecuteUpdate error!"); + System.out.println("update: " + update); + System.out.println("Error: " + e.getMessage()); + e.printStackTrace(System.out); + } } private void updateServers() throws Exception { @@ -114,10 +113,10 @@ SELECT s1.* FROM servers s1, servers s2 WHERE s1.id != s2.id AND s1.ipaddress = //System.out.println(online.substring(0, online.length()-sqlOr.length())); //System.out.println(offline.substring(0, offline.length()-sqlOr.length())); - if(online.length() > onLength) - safeExecuteUpdate(stmt, online.substring(0, online.length()-sqlOr.length())); - if(offline.length() > offLength) - safeExecuteUpdate(stmt, offline.substring(0, offline.length()-sqlOr.length())); + if (online.length() > onLength) + safeExecuteUpdate(stmt, online.substring(0, online.length() - sqlOr.length())); + if (offline.length() > offLength) + safeExecuteUpdate(stmt, offline.substring(0, offline.length() - sqlOr.length())); safeExecuteUpdate(stmt, "DELETE FROM `servers` WHERE `uptime` < '40'"); } @@ -132,33 +131,34 @@ SELECT s1.* FROM servers s1, servers s2 WHERE s1.id != s2.id AND s1.ipaddress = // System.out.println("IP:\t" + result.getString("IP")); // System.out.println("Port:\t" + result.getString("Port")); if (validServer(result.getString("ip"), result.getInt("port"))) { - // System.out.println("ONLINE"); - safeExecuteUpdate(stmt2, "INSERT INTO `servers` (`uid`, `uname`, `name`, `ip`, `port`, `version`, `time`, `info`, `ipaddress`, `rs_name`, `rs_pass`) SELECT `uid`, `uname`, `name`, `ip`, `port`, `version`, `time`, `info`, `ipaddress`, `rs_name`, `rs_pass` FROM `toadd` WHERE `id` = "+result.getString("id")); - safeExecuteUpdate(stmt2, "DELETE FROM `toadd` WHERE `id` = "+result.getString("id")); + // System.out.println("ONLINE"); + safeExecuteUpdate(stmt2, "INSERT INTO `servers` (`uid`, `uname`, `name`, `ip`, `port`, `version`, `time`, `info`, `ipaddress`, `rs_name`, `rs_pass`) SELECT `uid`, `uname`, `name`, `ip`, `port`, `version`, `time`, `info`, `ipaddress`, `rs_name`, `rs_pass` FROM `toadd` WHERE `id` = " + result.getString("id")); + safeExecuteUpdate(stmt2, "DELETE FROM `toadd` WHERE `id` = " + result.getString("id")); } } - // delete entries that are past a certain date old - // System.currentTimeMillis()/1000 is unix timestamp - // 86400 is 24 hours in seconds - long oldSeconds = (System.currentTimeMillis()/1000) - 86400; - safeExecuteUpdate(stmt2, "DELETE FROM `toadd` WHERE `time` < "+oldSeconds); + // delete entries that are past a certain date old + // System.currentTimeMillis()/1000 is unix timestamp + // 86400 is 24 hours in seconds + long oldSeconds = (System.currentTimeMillis() / 1000) - 86400; + safeExecuteUpdate(stmt2, "DELETE FROM `toadd` WHERE `time` < " + oldSeconds); } -/* - private void timeFromDate() throws Exception { - Statement stmt = conn.createStatement(); - ResultSet result = stmt.executeQuery("SELECT `id`, `date` from `servers`"); - Statement stmt2 = conn.createStatement(); + /* + private void timeFromDate() throws Exception { + Statement stmt = conn.createStatement(); + ResultSet result = stmt.executeQuery("SELECT `id`, `date` from `servers`"); - while (result.next()) { - String[] date = result.getString("date").split("-"); - safeExecuteUpdate(stmt2, "UPDATE servers SET time="+new GregorianCalendar(Integer.parseInt("20"+date[2]),Integer.parseInt(date[0])-1,Integer.parseInt(date[1])).getTimeInMillis()/1000 +" WHERE id="+result.getString("id")); + Statement stmt2 = conn.createStatement(); + + while (result.next()) { + String[] date = result.getString("date").split("-"); + safeExecuteUpdate(stmt2, "UPDATE servers SET time="+new GregorianCalendar(Integer.parseInt("20"+date[2]),Integer.parseInt(date[0])-1,Integer.parseInt(date[1])).getTimeInMillis()/1000 +" WHERE id="+result.getString("id")); + } } - } -*/ + */ private void deleteServers(String s1, String s2) throws Exception { Statement stmt = conn.createStatement(); - safeExecuteUpdate(stmt, "DELETE FROM `servers` WHERE `ip` = '"+s1+"' OR `ip` = '"+s2+"'"); + safeExecuteUpdate(stmt, "DELETE FROM `servers` WHERE `ip` = '" + s1 + "' OR `ip` = '" + s2 + "'"); } private boolean validServer(String ip, int port) throws Exception { @@ -166,29 +166,30 @@ SELECT s1.* FROM servers s1, servers s2 WHERE s1.id != s2.id AND s1.ipaddress = try { s = new Socket(); s.setSoTimeout(2000); - InetSocketAddress addy = new InetSocketAddress(ip, port); - if(addy.isUnresolved()) - return false; + InetSocketAddress addy = new InetSocketAddress(ip, port); + if (addy.isUnresolved()) + return false; // System.out.println("addy: "+addy.getAddress().getHostAddress()); - String resolvedIP = addy.getAddress().getHostAddress(); - if(iphostname.containsKey(resolvedIP)){ + String resolvedIP = addy.getAddress().getHostAddress(); + if (iphostname.containsKey(resolvedIP)) { // System.out.println("deleteServers("+ip+", "+iphostname.get(resolvedIP)+")"); - // if you delete the server in the database, anyone can delete any server by posting a duplicate - // instead simply don't allow this one in. - //deleteServers(ip, iphostname.get(resolvedIP)); - return false; - } + // if you delete the server in the database, anyone can delete any server by posting a duplicate + // instead simply don't allow this one in. + //deleteServers(ip, iphostname.get(resolvedIP)); + return false; + } // System.out.println("iphostname.put("+resolvedIP+", "+ip+")"); - iphostname.put(resolvedIP, ip); + iphostname.put(resolvedIP, ip); s.connect(addy, 2000); } catch (Exception e) { // e.printStackTrace(); return false; } - try { + try { s.close(); - } catch (Exception e) {} - return true; + } catch (Exception e) { + } + return true; /* try { DataOutputStream out = new DataOutputStream(s.getOutputStream()); DataInputStream in = new DataInputStream(s.getInputStream()); @@ -207,11 +208,12 @@ SELECT s1.* FROM servers s1, servers s2 WHERE s1.id != s2.id AND s1.ipaddress = s.close(); } catch (Exception e) {} return false; -*/ } +*/ + } public static void main(String args[]) { - // System.out.println(new GregorianCalendar(2008,2-1,1).getTimeInMillis()/1000);// 1204329600 - new ServerChecker(); + // System.out.println(new GregorianCalendar(2008,2-1,1).getTimeInMillis()/1000);// 1204329600 + new ServerChecker(); } diff --git a/ServerChecker/src/main/java/org/moparscape/NewProcessor.java b/ServerChecker/src/main/java/org/moparscape/NewProcessor.java new file mode 100755 index 0000000..57e8ca8 --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/NewProcessor.java @@ -0,0 +1,44 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape; + +public class NewProcessor extends OnlineOfflineProcessor { + + public NewProcessor(int millisPerRow, int millisTimeLimit) { + super(millisPerRow, millisTimeLimit, + "INSERT INTO `servers` (`uid`, `uname`, `name`, `ip`, `port`, `version`, `time`, `info`, `ipaddress`, `rs_name`, `rs_pass`) SELECT `uid`, `uname`, `name`, `ip`, `port`, `version`, `time`, `info`, `ipaddress`, `rs_name`, `rs_pass` FROM `toadd` WHERE id IN ", + "DELETE FROM `toadd` WHERE id IN ", + "toadd"); + } + + @Override + public void online(String resolvedIP, Long id, String hostName) { + super.online(resolvedIP, id, hostName); + online.add(id); + offline.add(id); + } + + public void finish() { + // delete entries that are past a certain date old + // System.currentTimeMillis()/1000 is unix timestamp + // 86400 is 24 hours in seconds + finalQuery = String.format("DELETE FROM `toadd` WHERE `time` < '%d'", (System.currentTimeMillis() / 1000) - 86400); + super.finish(); + } +} diff --git a/ServerChecker/src/main/java/org/moparscape/OnlineOfflineProcessor.java b/ServerChecker/src/main/java/org/moparscape/OnlineOfflineProcessor.java new file mode 100755 index 0000000..29299d1 --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/OnlineOfflineProcessor.java @@ -0,0 +1,123 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape; + +import org.moparscape.result.AbstractResultProcessor; +import org.moparscape.result.ResultDelegator; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +import static org.moparscape.ServerChecker.getConnection; +import static org.moparscape.ServerChecker.inStatement; +import static org.moparscape.result.ResultDelegator.tryClose; + +public abstract class OnlineOfflineProcessor extends AbstractResultProcessor { + + protected final List online = new ArrayList(); + protected final List offline = new ArrayList(); + + private final List ipUpdates = new ArrayList(); + + private final String ipUpdateTable, onlineQuery, offlineQuery; + + protected String finalQuery = null; + + protected OnlineOfflineProcessor(int millisPerRow, int millisTimeLimit, String onlineQuery, String offlineQuery, String ipUpdateTable) { + super(millisPerRow, millisTimeLimit); + this.onlineQuery = onlineQuery; + this.offlineQuery = offlineQuery; + this.ipUpdateTable = ipUpdateTable; + } + + public void online(String resolvedIP, Long id, String hostName) { + // if resolvedIP has changed, update it + if (resolvedIP != null) + ipUpdates.add(new IPUpdate(id, resolvedIP)); + } + + public void offline(Long id) { + + } + + public void process(ResultSet result) throws SQLException { + while (result.next()) { + Long id = result.getLong("id"); + + StringBuilder resolvedIP = null; + String hostName = result.getString("ip"); + String oldResolvedIP = result.getString("ipaddress"); + //System.out.printf("%s(%s):%d\n", hostName, oldResolvedIP, result.getInt("port")); + // if it's an actual hostname vs the ip itself + if (!hostName.equals(oldResolvedIP)) + resolvedIP = new StringBuilder(); + if (ServerChecker.validServer(millisPerRow, hostName, result.getInt("port"), resolvedIP, id, oldResolvedIP)) { + String newResolvedIP = null; + // if resolvedIP has changed, update it + if (resolvedIP != null && !oldResolvedIP.equals(resolvedIP.toString())) + newResolvedIP = resolvedIP.toString(); + online(newResolvedIP, id, hostName); + } else { + offline(id); + } + } + } + + public void finish() { + Connection conn = null; + Statement stmt = null; + try { + conn = getConnection(); + conn.setAutoCommit(false); + stmt = conn.prepareStatement(String.format("UPDATE `%s` SET `ipaddress` = ? WHERE `id` = ?", this.ipUpdateTable)); + if (!ipUpdates.isEmpty()) { + PreparedStatement ps = (PreparedStatement) stmt; + for (IPUpdate update : ipUpdates) { + ps.setString(1, update.resolvedIP); + ps.setLong(2, update.id); + ps.execute(); + } + } + if (!online.isEmpty()) + stmt.execute(onlineQuery + inStatement(online)); + if (!offline.isEmpty()) + stmt.execute(offlineQuery + inStatement(offline)); + if (finalQuery != null) + stmt.execute(finalQuery); + conn.commit(); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + tryClose(stmt); + ResultDelegator.tryClose(conn); + } + ipUpdates.clear(); + } + + protected static class IPUpdate { + public final String resolvedIP; + public final Long id; + + protected IPUpdate(Long id, String resolvedIP) { + this.id = id; + this.resolvedIP = resolvedIP; + } + } +} diff --git a/ServerChecker/src/main/java/org/moparscape/SampleProcessor.java b/ServerChecker/src/main/java/org/moparscape/SampleProcessor.java new file mode 100755 index 0000000..1ae05b7 --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/SampleProcessor.java @@ -0,0 +1,48 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape; + +import org.moparscape.result.AbstractResultProcessor; + +import java.sql.ResultSet; +import java.util.Random; + +public class SampleProcessor extends AbstractResultProcessor { + + public int count = 0; + + public SampleProcessor(int millisPerRow, int millisTimeLimit) { + super(millisPerRow, millisTimeLimit); + } + + public void process(ResultSet r) { + int myCount = count++; + System.out.println("in process() count: " + myCount); + try { + Thread.sleep(Math.max(this.millisPerRow / 10, new Random().nextInt((int) this.millisPerRow))); + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println("exiting process() count: " + myCount); + } + + public void finish() { + // empty + } +} diff --git a/ServerChecker/src/main/java/org/moparscape/ServerChecker.java b/ServerChecker/src/main/java/org/moparscape/ServerChecker.java new file mode 100755 index 0000000..70279e3 --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/ServerChecker.java @@ -0,0 +1,207 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape; + +import org.moparscape.result.ResultDelegator; + +import java.io.Closeable; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +public class ServerChecker { + + //private static final Map ipToHostname = Collections.synchronizedMap(new HashMap(1000)); + private static final Map ipToHostname = new HashMap(1000); + + // 8 seconds + public static final int millisPerRow = 8 * 1000; + + // 10 minutes + private static final int millisTimeLimitUpdate = 10 * 60 * 1000; + // 5 minutes + private static final int millisTimeLimitNew = 5 * 60 * 1000; + + private static boolean newServers = false; + + private static String databaseUrl; + + private ServerChecker() { + // make sure nothing instantiates us + } + + private static void startChecks(String databaseUrl) { + ServerChecker.databaseUrl = databaseUrl; + printToLog("STARTING..."); + Connection conn = null; + try { + Class.forName("com.mysql.jdbc.Driver").newInstance(); + conn = getConnection(); + + String fields = "`id`, `ip`, `port`, `ipaddress`"; + ResultDelegator updateServers = new ResultDelegator(conn, fields, "from `servers` where sponsored = '0' ORDER BY `servers`.`id` ASC", new UpdateProcessor(millisPerRow, millisTimeLimitUpdate)); + updateServers.waitFor(); + printToLog("updateServers completed!"); + + newServers = true; + ResultDelegator newServers = new ResultDelegator(conn, fields, "from `toadd` WHERE `verified` = '1' ORDER BY `id` ASC", new NewProcessor(millisPerRow, millisTimeLimitNew)); + newServers.waitFor(); + printToLog("newServers completed!"); + + ResultDelegator.tryClose(conn); + + for (Map.Entry entry : ipToHostname.entrySet()) { + String newIP = entry.getKey(); + String[] servers = entry.getValue().toString().split(";"); + if (servers.length == 1) + continue; + String[][] serverInfo = new String[servers.length][]; + System.out.printf("resolvedIP: '%s'\n", newIP); + for (int x = 0; x < servers.length; ++x) { + serverInfo[x] = servers[x].split(","); + System.out.printf("\t\tid: '%s'\n\t\tnewServer: '%s'\n\t\thostName: '%s'\n\t\tport: '%s'\n\t\tonline: '%s'\n\t\tpreviousIP: '%s'\n\n", serverInfo[x][0], serverInfo[x][1], serverInfo[x][2], serverInfo[x][3], serverInfo[x][4], serverInfo[x][5]); + } + System.out.println("------------------------------------------"); + //System.out.printf("key: '%s' value: '%s'\n", newIP, entry.getValue()); + + } + + printToLog("FINISHED SUCCESSFULLY!!"); + } catch (Throwable e) { + printToLog("ERROR!!"); + e.printStackTrace(); + } finally { + ResultDelegator.tryClose(conn); + } + } + + private static boolean returnClose(boolean ret, String resolvedIP, String hostName, int port, Long id, String oldResolvedIP) { + // populate ipToHostname + if (resolvedIP != null) + synchronized (ipToHostname) { + String entry = String.format("%s,%b,%s,%d,%b,%s", id, newServers, hostName, port, ret, oldResolvedIP); + if (ipToHostname.containsKey(resolvedIP)) { + ipToHostname.get(resolvedIP).append(";").append(entry); + //return false; + } else + ipToHostname.put(resolvedIP, new StringBuilder(entry)); + } + return ret; + } + + static boolean validServer(int timeout, String hostName, int port, StringBuilder resolved, Long id, String oldResolvedIP) { + //System.out.printf("%s:%d\n", ip, port); + Socket s = null; + String resolvedIP = null; + try { + InetSocketAddress addy = new InetSocketAddress(hostName, port); + if (addy.isUnresolved()) + return false; + resolvedIP = addy.getAddress().getHostAddress(); + //System.out.printf("%s(%s):%d\n", ip, resolvedIP, port); + if (resolved != null) + resolved.append(resolvedIP); + + // uncomment for testing without spamming packets + if (true) return returnClose(java.lang.Math.random() < 0.5D, resolvedIP, hostName, port, id, oldResolvedIP); + + s = new Socket(); + s.setSoTimeout(timeout); + s.connect(addy, timeout); + /* + DataOutputStream out = null; + DataInputStream in = null; + try { + out = new DataOutputStream(s.getOutputStream()); + in = new DataInputStream(s.getInputStream()); + out.writeChar(14 << 8); + out.flush(); + in.skip(8); + int response = in.readByte() & 0xff; + return returnClose(response == 0, resolvedIP, hostName, port, id, oldResolvedIP); + } finally { + tryClose(out); + tryClose(in); + } + */ + return returnClose(true, resolvedIP, hostName, port, id, oldResolvedIP); + } catch (Exception e) { + //e.printStackTrace(); + return returnClose(false, resolvedIP, hostName, port, id, oldResolvedIP); + } finally { + tryClose(s); + } + } + + static Connection getConnection() throws SQLException { + return DriverManager.getConnection(databaseUrl); + } + + static String inStatement(Collection list) { + if (list == null || list.isEmpty()) + return "()"; + StringBuilder sb = new StringBuilder("("); + boolean notFirst = false; + for (Object o : list) { + if (notFirst) sb.append(","); + else notFirst = true; + sb.append(o); + } + return sb.append(")").toString(); + } + + public static void main(String[] args) { + if (args.length < 1) { + printToLog("Usage: ServerChecker \"jdbc:mysql://localhost:3306/dbname?user=user&password=pass\" [debug]"); + return; + } + if (args.length > 1) + ResultDelegator.debug = System.out; + startChecks(args[0]); + } + + static void printToLog(String msg) { + System.out.printf("%s - %s\n", new Date(), msg); + } + + public static void tryClose(Socket obj) { + if (obj != null) + try { + obj.close(); + } catch (Throwable e) { + // do nothing + } + } + + public static void tryClose(Closeable obj) { + if (obj != null) + try { + obj.close(); + } catch (Throwable e) { + // do nothing + } + } + +} diff --git a/ServerChecker/src/main/java/org/moparscape/UpdateProcessor.java b/ServerChecker/src/main/java/org/moparscape/UpdateProcessor.java new file mode 100755 index 0000000..1a17486 --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/UpdateProcessor.java @@ -0,0 +1,47 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape; + +public class UpdateProcessor extends OnlineOfflineProcessor { + + public UpdateProcessor(int millisPerRow, int millisTimeLimit) { + super(millisPerRow, millisTimeLimit, + "UPDATE servers SET online=1, totalcount=totalcount+1, oncount=oncount+1, `uptime` = (oncount / totalcount * 100) WHERE sponsored = '0' AND id IN ", + "UPDATE servers SET online=0, totalcount=totalcount+1, `uptime` = (oncount / totalcount * 100) WHERE sponsored = '0' AND id IN ", + "servers"); + } + + @Override + public void online(String resolvedIP, Long id, String hostName) { + super.online(resolvedIP, id, hostName); + online.add(id); + } + + @Override + public void offline(Long id) { + super.offline(id); + offline.add(id); + } + + public void finish() { + finalQuery = "DELETE FROM `servers` WHERE `uptime` < '40'"; + super.finish(); + } + +} diff --git a/ServerChecker/src/main/java/org/moparscape/result/AbstractResultProcessor.java b/ServerChecker/src/main/java/org/moparscape/result/AbstractResultProcessor.java new file mode 100755 index 0000000..efede8e --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/result/AbstractResultProcessor.java @@ -0,0 +1,46 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape.result; + +public abstract class AbstractResultProcessor implements ResultProcessor { + + protected final int millisPerRow; + protected final int millisTimeLimit; + + protected AbstractResultProcessor() { + // 8 seconds + millisPerRow = 8 * 1000; + // 10 minutes + millisTimeLimit = 10 * 60 * 1000; + } + + protected AbstractResultProcessor(int millisPerRow, int millisTimeLimit) { + this.millisPerRow = millisPerRow; + this.millisTimeLimit = millisTimeLimit; + } + + public int getMillisTimeLimit() { + return millisTimeLimit; + } + + public int getMillisPerRow() { + return millisPerRow; + } + +} diff --git a/ServerChecker/src/main/java/org/moparscape/result/ResultDelegator.java b/ServerChecker/src/main/java/org/moparscape/result/ResultDelegator.java new file mode 100755 index 0000000..0762a57 --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/result/ResultDelegator.java @@ -0,0 +1,128 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape.result; + +import java.io.PrintStream; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +public class ResultDelegator { + + public static PrintStream debug = null; + + private static void debug(String s, Object... p) { + if (debug == null) + return; + debug.print("[ResultDelegator]: "); + debug.printf(s, p); + debug.println(); + } + + private volatile long numThreads = 0; + private final ResultProcessor rp; + + public ResultDelegator(Connection conn, String fields, String query, final ResultProcessor rp) throws java.sql.SQLException { + this.rp = rp; + Statement stmt = null; + ResultSet count = null; + try { + stmt = conn.createStatement(); + count = stmt.executeQuery("SELECT COUNT(*) AS count " + query); + long numRows = 0; + if (count.next()) + numRows = count.getLong("count"); + count.close(); + stmt.close(); + debug("%d rows found", numRows); + if (numRows == 0) + return; + numThreads = (numRows * rp.getMillisPerRow()) / rp.getMillisTimeLimit(); + if (numThreads <= 0) + numThreads = 1; + long rowsPerThread = numRows / numThreads; + // if there is a remainder, start one more thread + if ((rowsPerThread * numThreads) < numRows) + ++numThreads; + debug("%d threads needed", numThreads); + debug("%d rows per thread", rowsPerThread); + String queryTemplate = "SELECT %s %s LIMIT %d, " + rowsPerThread; + for (long x = 0, total = numThreads; x < total; ++x) { + String subQueryString = String.format(queryTemplate, fields, query, x * rowsPerThread); + //debug("thread: %d query: %s", x, subQueryString); + final Statement subStmt = conn.createStatement(); + final ResultSet subQuery = subStmt.executeQuery(subQueryString); + new Thread() { + @Override + public void run() { + try { + rp.process(subQuery); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + tryClose(subQuery); + tryClose(subStmt); + } + --numThreads; + } + }.start(); + } + } finally { + tryClose(count); + tryClose(stmt); + } + } + + public static void tryClose(Connection obj) { + if (obj != null) + try { + obj.close(); + } catch (Throwable e) { + // do nothing + } + } + + public static void tryClose(Statement obj) { + if (obj != null) + try { + obj.close(); + } catch (Throwable e) { + // do nothing + } + } + + public static void tryClose(ResultSet obj) { + if (obj != null) + try { + obj.close(); + } catch (Throwable e) { + // do nothing + } + } + + public void waitFor() throws java.sql.SQLException { + while (numThreads > 0) + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + rp.finish(); + } +} diff --git a/ServerChecker/src/main/java/org/moparscape/result/ResultProcessor.java b/ServerChecker/src/main/java/org/moparscape/result/ResultProcessor.java new file mode 100755 index 0000000..2eb5f1d --- /dev/null +++ b/ServerChecker/src/main/java/org/moparscape/result/ResultProcessor.java @@ -0,0 +1,34 @@ +/* + * MoparScape.org server status page + * Copyright (C) 2012 Travis Burtrum (moparisthebest) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.moparscape.result; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public interface ResultProcessor { + + public int getMillisPerRow(); + + public int getMillisTimeLimit(); + + public void process(ResultSet r) throws SQLException; + + public void finish(); + +} diff --git a/database.sql b/database.sql index 3e7e34f..1a516bd 100644 --- a/database.sql +++ b/database.sql @@ -6,11 +6,12 @@ SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; -- Table structure for table `banned` -- +DROP TABLE IF EXISTS `banned`; CREATE TABLE IF NOT EXISTS `banned` ( `id` int(11) unsigned NOT NULL, `uid` mediumint(8) unsigned NOT NULL, `uname` varchar(80) NOT NULL, - `online` tinyint(1) unsigned NOT NULL default '1', + `online` tinyint(1) unsigned NOT NULL DEFAULT '1', `name` tinytext NOT NULL, `pic_url` tinytext NOT NULL, `ip` varchar(30) NOT NULL, @@ -18,15 +19,15 @@ CREATE TABLE IF NOT EXISTS `banned` ( `version` smallint(3) unsigned NOT NULL, `time` int(10) unsigned NOT NULL, `info` text NOT NULL, - `oncount` int(11) unsigned NOT NULL default '1', - `totalcount` int(11) unsigned NOT NULL default '1', - `uptime` tinyint(3) unsigned NOT NULL default '100', + `oncount` int(11) unsigned NOT NULL DEFAULT '1', + `totalcount` int(11) unsigned NOT NULL DEFAULT '1', + `uptime` tinyint(3) unsigned NOT NULL DEFAULT '100', `ipaddress` varchar(15) NOT NULL, - `sponsored` smallint(5) unsigned NOT NULL default '0', + `sponsored` smallint(5) unsigned NOT NULL DEFAULT '0', `rs_name` tinytext NOT NULL, `rs_pass` tinytext NOT NULL, - `vote` int(11) NOT NULL default '0', - PRIMARY KEY (`id`), + `vote` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), KEY `uid` (`uid`), KEY `online` (`online`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -37,11 +38,12 @@ CREATE TABLE IF NOT EXISTS `banned` ( -- Table structure for table `servers` -- +DROP TABLE IF EXISTS `servers`; CREATE TABLE IF NOT EXISTS `servers` ( - `id` int(11) unsigned NOT NULL auto_increment, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `uid` mediumint(8) unsigned NOT NULL, `uname` varchar(80) NOT NULL, - `online` tinyint(1) unsigned NOT NULL default '1', + `online` tinyint(1) unsigned NOT NULL DEFAULT '1', `name` tinytext NOT NULL, `pic_url` tinytext NOT NULL, `ip` varchar(30) NOT NULL, @@ -49,15 +51,19 @@ CREATE TABLE IF NOT EXISTS `servers` ( `version` smallint(3) unsigned NOT NULL, `time` int(10) unsigned NOT NULL, `info` text NOT NULL, - `oncount` int(11) unsigned NOT NULL default '1', - `totalcount` int(11) unsigned NOT NULL default '1', - `uptime` tinyint(3) unsigned NOT NULL default '100', + `oncount` int(11) unsigned NOT NULL DEFAULT '1', + `totalcount` int(11) unsigned NOT NULL DEFAULT '1', + `uptime` tinyint(3) unsigned NOT NULL DEFAULT '100', `ipaddress` varchar(15) NOT NULL, - `sponsored` smallint(5) unsigned NOT NULL default '0', + `sponsored` smallint(5) unsigned NOT NULL DEFAULT '0', `rs_name` tinytext NOT NULL, `rs_pass` tinytext NOT NULL, - `vote` int(11) NOT NULL default '0', - PRIMARY KEY (`id`), + `vote` int(11) NOT NULL DEFAULT '0', + `key` varchar(15) NOT NULL, + `verified` tinyint(1) unsigned NOT NULL DEFAULT '0', + `added` tinyint(1) unsigned NOT NULL DEFAULT '0', + `banned` tinyint(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), KEY `uid` (`uid`), KEY `online` (`online`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -68,11 +74,12 @@ CREATE TABLE IF NOT EXISTS `servers` ( -- Table structure for table `toadd` -- +DROP TABLE IF EXISTS `toadd`; CREATE TABLE IF NOT EXISTS `toadd` ( - `id` int(11) unsigned NOT NULL auto_increment, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `uid` mediumint(8) unsigned NOT NULL, `uname` varchar(80) NOT NULL, - `online` tinyint(1) unsigned NOT NULL default '1', + `online` tinyint(1) unsigned NOT NULL DEFAULT '1', `name` tinytext NOT NULL, `pic_url` tinytext NOT NULL, `ip` varchar(30) NOT NULL, @@ -80,28 +87,35 @@ CREATE TABLE IF NOT EXISTS `toadd` ( `version` smallint(3) unsigned NOT NULL, `time` int(10) unsigned NOT NULL, `info` text NOT NULL, - `oncount` int(11) unsigned NOT NULL default '1', - `totalcount` int(11) unsigned NOT NULL default '1', - `uptime` tinyint(3) unsigned NOT NULL default '100', + `oncount` int(11) unsigned NOT NULL DEFAULT '1', + `totalcount` int(11) unsigned NOT NULL DEFAULT '1', + `uptime` tinyint(3) unsigned NOT NULL DEFAULT '100', `ipaddress` varchar(15) NOT NULL, - `sponsored` smallint(5) unsigned NOT NULL default '0', + `sponsored` smallint(5) unsigned NOT NULL DEFAULT '0', `rs_name` tinytext NOT NULL, `rs_pass` tinytext NOT NULL, `key` varchar(15) NOT NULL, - `verified` tinyint(1) unsigned NOT NULL default '0', - PRIMARY KEY (`id`), + `verified` tinyint(1) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), KEY `uid` (`uid`), KEY `online` (`online`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- -------------------------------------------------------- + +-- +-- Table structure for table `log_voted` +-- + DROP TABLE IF EXISTS `log_voted`; CREATE TABLE IF NOT EXISTS `log_voted` ( - `id` int(11) unsigned NOT NULL auto_increment, + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `uid` mediumint(8) unsigned NOT NULL, `uname` varchar(80) NOT NULL, `server_id` int(11) unsigned NOT NULL, `time` int(10) unsigned NOT NULL, `ip` varchar(15) NOT NULL, - PRIMARY KEY (`id`), + `op` char(1) NOT NULL, + PRIMARY KEY (`id`), KEY `uid` (`uid`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/ss_sources/copy_edit_me.php b/ss_sources/copy_edit_me.php index f268a28..f6e5132 100644 --- a/ss_sources/copy_edit_me.php +++ b/ss_sources/copy_edit_me.php @@ -46,7 +46,7 @@ require_once($g_source_dir . '/forums/smf.php'); # do custom setup for above forum connector global $path_to_smf, $smf_admin_groups, $g_forum_url; $path_to_smf = '/path/to/smf'; -$smf_admin_groups = array(2, 63, 70); +$smf_admin_groups = array(2); # 2 is global moderators, usually $g_forum_url = '/smf/index.php'; # include theme