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
+ 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