A fairly simple yet secure way of doing callbacks for the Rune-Server top list. It shouldn't be too hard to adapt to other top lists with call backs.
Setting Up
In CallbackListener change CALLBACK_PORT to a suitable unused port number. Or you could just leave it as 9001. This is used in your callback URL.
In CallbackListener change key to any random secure string you want. This is used in your callback URL below.
On the top list change your callback URL to:
http://yoursite.com:#CALLBACK_PORT#/callback#KEY#
where #CALLBACK_PORT# and #KEY# are the ones you set them to.
In Vote change SERVER_ID to your server's ID on the top list.
Change line 52 of Vote to link the player to the vote URL, or you could insert the incentive into a database and show it on your website.
Change line 65 of Vote to give the item any rewards.
Somewhere in the code where your server starts up add this:
Code:
CallbackListener callbackListener = new CallbackListener();
Thread callbackThread = new Thread(callbackListener);
callbackThread.start();
Then when you want to send them the vote URL run this code:
Code:
Vote.doVote(client);
where client is the client voting.
I'm not going to spoon feed it to anyone. If you can't get it figured out it's your problem not mine.
Code for CallbackListener:
Code:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class CallbackListener implements Runnable {
private ServerSocket callbackSocket;
/*
* Starts a very basic HTTP server listening on the port below for the call backs.
*/
private int CALLBACK_PORT = 9001;
@Override
public void run() {
while (true) {
try {
//Accept connection.
Socket socket = callbackSocket.accept();
CallbackHandler handler = new CallbackHandler(socket);
Thread handlerThread = new Thread(handler);
handlerThread.start();
} catch (IOException e) {
//Failed to accept connection.
e.printStackTrace();
}
}
}
public CallbackListener() throws IOException {
this.callbackSocket = new ServerSocket(CALLBACK_PORT);
}
}
Code for CallbackHandler:
Code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CallbackHandler implements Runnable {
private Socket socket;
public CallbackHandler(Socket socket) {
this.socket = socket;
}
/*
* SECRET KEY
* Change this to some random sequence of letters
* I would recommend only using 8 to 64 lower case alphanumeric characters
*
* CHANGE THIS TO SOMETHING RANDOM AND SECURE BEFORE USE!
*/
String key = "abcdefgh";
Pattern callbackPattern = Pattern.compile("callback" + key + "\\?postback=(\\S*)");
String callbackResponse = "HTTP/1.1 200 OK\nContent-Type: text/plain; charset=utf-8\nContent-Length: 2\n\nok";
@Override
public void run() {
while (true) {
try {
try {
socket.setSoTimeout(10000); //To prevent denial of service by leaving connections open.
OutputStream out = socket.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = in.readLine();
Matcher matcher = callbackPattern.matcher(request);
if (matcher.find()) {
//Handle a correctly formatted request.
Vote.handleCallback(matcher.group(1));
}
out.write(callbackResponse.getBytes("utf-8"));
socket.close();
} catch (SocketException e) {
//Connection timed out.
socket.close();
}
} catch (IOException e) {
//Failed to accept connection.
e.printStackTrace();
}
}
}
}
Code for Vote:
Code:
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;
public class Vote {
private String key;
private Client client;
/*
* Change this to your server ID on the top list.
*/
private static int SERVER_ID = 0;
private static SecureRandom random = new SecureRandom();
private static ArrayList<Vote> votes = new ArrayList<Vote>();
public Vote(String key, Client client) {
this.key = key;
this.client = client;
}
public static void doVote(Client client) {
String key = new BigInteger(128, random).toString(32);
Vote vote = new Vote(key, client);
//Check if this person already has a vote key assigned to them.
boolean hasDuplicateKey = true;
while (hasDuplicateKey) {
hasDuplicateKey = false;
for (Vote tvote : votes) {
if (tvote.getClient() == client) {
//Handle client collision.
vote = tvote;
key = vote.getKey();
break;
} else if (tvote.getKey().equals(vote.getKey())) {
//Handle key collision.
key = new BigInteger(128, random).toString(32);
hasDuplicateKey = true;
} else {
//Nothing unusual happened, no key or client collision.
}
}
}
/*
* Change this to send the users to the URL somehow.
*/
System.out.println("http://www.rune-server.org/toplist.php?do=vote&sid=" + Integer.toString(SERVER_ID) + "&incentive=" + key);
votes.add(vote);
}
public static void handleCallback(String key) {
Iterator<Vote> votesIterator = votes.iterator();
while (votesIterator.hasNext()) {
Vote vote = (Vote) votesIterator.next();
if (vote.getKey().equals(key)) {
/*
* Key is valid, give them (vote.getClient()) the reward here!
*/
System.out.println("Valid callback for " + vote.getClient());
votesIterator.remove();
break;
}
}
}
public String getKey() {
return key;
}
public Client getClient() {
return client;
}
}