New ServerChecker project finally pushed up

This commit is contained in:
Travis Burtrum 2012-12-26 14:43:39 -05:00
parent e0621f931d
commit ae637db6b8
14 changed files with 913 additions and 114 deletions

12
.gitignore vendored
View File

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

9
README
View File

@ -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!

101
ServerChecker/pom.xml Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ MoparScape.org server status page ServerChecker
~ Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.moparscape.serverchecker</groupId>
<artifactId>ServerChecker</artifactId>
<version>0.1</version>
<name>${project.artifactId}</name>
<description>
ServerChecker checks to see if servers are online.
</description>
<organization>
<name>moparscape.org</name>
<url>http://www.moparscape.org</url>
</organization>
<developers>
<developer>
<id>moparisthebest</id>
<name>Travis Burtrum</name>
<email>admin@moparisthebest.com</email>
<url>http://www.moparscape.org/smf/</url>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/moparisthebest/Server-Status-Page.git</connection>
<developerConnection>scm:git:https://github.com/moparisthebest/Server-Status-Page.git</developerConnection>
<url>https://github.com/moparisthebest/Server-Status-Page</url>
</scm>
<licenses>
<license>
<name>GNU AFFERO GENERAL PUBLIC LICENSE, Version 3</name>
<url>http://www.gnu.org/licenses/agpl.html</url>
</license>
</licenses>
<packaging>jar</packaging>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.22</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<debug>false</debug>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.moparscape.ServerChecker</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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 <http://www.gnu.org/licenses/>.
*/
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<String, String> iphostname = new HashMap<String, String>(1000);
private HashMap<String, String> iphostname = new HashMap<String, String>(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();
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<Long> online = new ArrayList<Long>();
protected final List<Long> offline = new ArrayList<Long>();
private final List<IPUpdate> ipUpdates = new ArrayList<IPUpdate>();
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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<String, String> ipToHostname = Collections.synchronizedMap(new HashMap<String, String>(1000));
private static final Map<String, StringBuilder> ipToHostname = new HashMap<String, StringBuilder>(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<String, StringBuilder> 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
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}

View File

@ -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;

View File

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