package admin;
import http.server.*;
import http.gen.HTTPReq;
import http.gen.HTTPResp;
import gen.*;
import java.io.*;
import java.util.Date;
import java.util.TimeZone;
import java.text.DateFormat;
import logging.Logger;
import edu.neu.ccs.demeterf.demfgen.lib.List;
import edu.neu.ccs.demeterf.demfgen.lib.Map;
/** Player/Competition Registration Server. Waits for registration requests, and
* responds accordingly.
*
The registration protocol is as follows:
*
* - The Palyer sends a {@link gen.PlayerSpec PlayerSpec} as the body of
* a POST to the RegServer, including a URL argument.
* - The full URL request will be:
*
* RegServer.PATH_ENTRY+"?"+RegServer.PASS_URL_ARG+"="+PASSWORD
*
* where PASSWORD is the Player/Team password as registered with
* the Teaching Staff (to be described separately).
*
* - If registration succeeds, an HTTP Response with code 200 (OK) will be
* sent back, with a short description "Player '...' has been Registered".
-
*
*
*/
@Server(RegServer.PORT)
public class RegServer{
/** Path the RegServer Listens On */
public static final String PATH_ENTRY = "/register";
/** Admins Listening (incoming) Port */
public static final int PORT = 7000;
/** Hashed Passwords File */
private static final String PASS_FILE = "files/passwords.pwd";
/** Password Argument Name */
public static final String PASS_URL_ARG = "password";
/** Date Format for parsing Dates */
public static final DateFormat DateFmt =
DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT);
/** Set the current Time Zone for Date Parsing */
static{
DateFmt.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
//DateFmt.setTimeZone(TimeZone.getTimeZone("EST"));
}
/** Password List */
private Map passwds;
/** Currently registered Players */
private List players = List.create();
/** Logger for the Registration Process */
private Logger log;
/** Create a RegServer with the given Passwords. Players/Teams will submit a
* Passsword, which we will 'encrypt' and store to verify the registration
* for competitions. */
private RegServer(Map ps, Logger l){ passwds = ps; log = l; }
/** Create a RegServer with the given Passwords. Players/Teams will submit a
* Passsword, which we will 'encrypt' and store to verify the registration
* for competitions. */
public static RegServer create(Map ps, Logger l){
l.notify(PrintHeapToString.PrintHeapToStringM(ps));
return new RegServer(ps,l);
}
/** Create a RegServer with the given Logger. Passwords will be loaded from
* the usual File. */
public static RegServer create(Logger l) throws ParseException,IOException{
PasswordFile file = PasswordFile.parse(new FileInputStream(PASS_FILE));
return create(file.getPasswordMap(),l);
}
/** Main URL handler for the RegServer */
@Path(PATH_ENTRY)
public HTTPResp registerResp(HTTPReq req){
log.event("Registration Request");
synchronized(players){
try{
PlayerSpec spec = PlayerSpec.parse(req.getBody());
if(!passwds.containsKey(spec.getName()))
return HTTPResp.error(log.error("Unknown Team Name '"+spec.getName()+"'"));
if(players.contains(spec.sameNamePred()))
return HTTPResp.error(log.error("Player '"+spec.getName()+"' Already Registered"));
Map args = req.urlArgs();
if(!args.containsKey(PASS_URL_ARG))
return HTTPResp.error(log.error("No Password Given"));
if(verify(passwds.get(spec.getName()),args.get(PASS_URL_ARG))){
players = players.push(spec);
return HTTPResp.textResponse(log.event("Player '"+spec.getName()+"' has been Registered"));
}
return HTTPResp.error(log.error("Password Does not Match Player '"+spec.getName()+"'"));
}catch(ParseException pe){
return HTTPResp.error(log.error("Error Parsing Registration (gen.PlayerSpec)"));
}
}
}
/** Encrypt a given Password (consistently) */
public static String encrypt(String s){
// PlainText for now
return s;
}
/** Encrypt and Verify the given Password agains the known 'Hash' */
private static boolean verify(String known, String unknownPlain){
return known.equals(encrypt(unknownPlain));
}
@Path()
public HTTPResp defaultResp(HTTPReq req){
return HTTPResp.error("Unhandled Server Path '"+req.trimmedUrl()+"'");
}
/** How long to wait before re-checking the competition strat */
private static final int TIMEOUT = 20;
/** Run the registration server, until the competition starts. */
public List runRegistration(String startDate) throws IOException,java.text.ParseException{
return runRegistration(DateFmt.parse(startDate));
}
/** Run the registration server, until the competition starts. */
public List runRegistration(Date start) throws IOException{
ServerThread server = Factory.create(this);
log.event("Registration Opened");
log.notify("Competition will start at: "+DateFmt.format(start));
while(start.compareTo(new Date()) > 0){
try{
Thread.sleep(1000*TIMEOUT);
}catch(InterruptedException ie){}
}
server.shutdown();
log.event("Registration Closed");
return players;
}
/** Main Test for the Server. */
public static void main(String[] args) throws Exception{
RegServer server = RegServer.create(Logger.text(System.err));
System.err.println(server.runRegistration("7/2/2009 12:50 pm").toString());
System.err.println("\n\n ******* DONE : "+DateFmt.format(new Date())+" ************");
}
}