package org.pixelgaffer.turnierserver.codr.utilities;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pixelgaffer.turnierserver.codr.AiBase;
import org.pixelgaffer.turnierserver.codr.AiOnline;
import org.pixelgaffer.turnierserver.codr.AiSimple;
import org.pixelgaffer.turnierserver.codr.GameBase.GameMode;
import org.pixelgaffer.turnierserver.codr.GameOnline;
import org.pixelgaffer.turnierserver.codr.Version;
import org.pixelgaffer.turnierserver.codr.utilities.Exceptions.CompileException;
import org.pixelgaffer.turnierserver.codr.utilities.Exceptions.DeletedException;
import org.pixelgaffer.turnierserver.codr.utilities.Exceptions.NewException;
import org.pixelgaffer.turnierserver.codr.utilities.Exceptions.NothingDoneException;
import org.pixelgaffer.turnierserver.codr.utilities.Exceptions.UpdateException;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.image.Image;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
/**
* koordiniert die Verbindung zum Server und führt Up-/Downloads aus
*
* @author Nico TODO: Nico, kommentier das mal alles!!!
*/
public class WebConnector {
public String userName = null;
public boolean isLoggedIn = false;
public boolean isConnected = false;
private final String url;
private DateFormat cookieDateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.UK);
public CookieStore cookies = new BasicCookieStore();
private CloseableHttpClient http = HttpClients.custom().setDefaultCookieStore(cookies).build();
/**
* Erstellt einen neuen Web Connector
*
* @param url
* Die URL der API (z.B. http://www.turnierserver.informatik-olympiade.de/api/ <- Der
* '/' muss da sein)
*/
public WebConnector(final String url) {
this.url = url;
readFromFile();
}
/**
* Lädt die angegebene Bibliothek vom Frontend herunter. <code>name</code>
* enthält name/version.
*/
public boolean getLibrary(String language, String name) {
try {
downloadAndExtractZip(new File(Paths.library(language, name)), "lib/" + language + "/" + name);
} catch (IOException | ZipException e) {
ErrorLog.write("Konnte Bibliothek " + name + " in der Sprache " + language + " nicht herunterladen: " + e.getLocalizedMessage());
return false;
}
return true;
}
/**
* Loggt den Benutzer ein
*
* @param userName
* Der Benutzername
* @param password
* Der Passwort
* @return Gibt an ob das Login erfolgreich war
* @throws IOException
*/
public boolean login(String userName, String password) throws IOException {
this.userName = userName;
boolean result = sendPost("login", "email", userName, "password", password, "remember", "true") != null;
saveToFile();
if (result == false) {
isLoggedIn = false;
this.userName = null;
}
getUserName();
return result;
}
public String getUserName() {
try {
String json = toString(sendPost("loggedin"));
if (json == null) {
throw new IOException();
}
userName = new JSONObject(json).getString("name");
isLoggedIn = true;
return userName;
} catch (IOException e) {
ErrorLog.write("Abfrage des Nutzernamens nicht möglich");
isLoggedIn = false;
userName = null;
return null;
}
}
public String getUrlFromGame(GameOnline game) {
return url.substring(0, url.length() - 4) + "game/" + (game.mode == GameMode.onlineInprogress ? "inprogress/" : "") + game.onlineId + "/mini";
}
public int getUserID() {
try {
String json = toString(sendPost("loggedin"));
if (json == null) {
throw new IOException();
}
return new JSONObject(json).getInt("id");
} catch (IOException e) {
ErrorLog.write("Abfrage der Nutzer ID nicht möglich");
return -1;
}
}
private int getLangID(String langName) {
try {
String json = toString(sendGet("langs"));
if (json == null) {
throw new IOException();
}
JSONArray array = new JSONArray(json);
for (int i = 0; i < array.length(); i++) {
if (array.getJSONObject(i).getString("name").equals(langName)) {
return array.getJSONObject(i).getInt("id");
}
}
ErrorLog.write("Es gibt keine Sprache mit dem Namen " + langName);
return -1;
} catch (IOException e) {
ErrorLog.write("Abfrage der Sprachen nicht möglich");
return -1;
}
}
private int getGametypeID(String gametypeName) {
try {
String json = toString(sendGet("gametypes"));
if (json == null) {
throw new IOException();
}
JSONArray array = new JSONArray(json);
for (int i = 0; i < array.length(); i++) {
if (array.getJSONObject(i).getString("name").equals(gametypeName)) {
return array.getJSONObject(i).getInt("id");
}
}
ErrorLog.write("Es gibt keinen Spieltyp mit dem Namen " + gametypeName);
return -1;
} catch (IOException e) {
ErrorLog.write("Abfrage der Spieltypen nicht möglich");
return -1;
}
}
public boolean register(String username, String firstname, String lastname, String email, String password) throws IOException {
return sendPost("register", "username", username, "email", email, "password", password, "firstname", firstname, "lastname", lastname) != null;
}
/**
* Loggt den Benutzer aus
*
* @return Gibt an ob das Ausloggen erfolgreich war
* @throws IOException
*/
public boolean logout() throws IOException {
boolean result = sendPost("logout") != null;
saveToFile();
userName = null;
return result;
}
/**
* Gibt zurück ob die ESU momentan eingeloggt ist
*
* @return Ob die ESU momentan eingeloggt ist
* @throws IOException
*/
public boolean isLoggedIn() throws IOException {
if (getSession() == null || getRememberToken() == null) {
return false;
}
boolean result;
String json = toString(sendPost("loggedin"));
if (json == null){
result = false;
} else {
result = true;
userName = new JSONObject(json).getString("name");
}
if (!result) {
cookies.getCookies().clear();
}
return result;
}
public GameOnline challenge(AiOnline...ais) throws IOException {
String[] args = new String[ais.length * 2];
for(int i = 0; i < ais.length; i++) {
args[i*2] = "ai[]";
args[i*2 + 1] = Integer.toString(ais[i].id);
}
String result = toString(sendPost("games/start", args));
if(result == null) {
throw new IOException("Fehler bei der Verbindung mit dem Server");
}
JSONObject json = new JSONObject(result);
return new GameOnline(json.getInt("inprogress_id"), ais);
}
public ObservableList<AiOnline> getAis(String game) {
ObservableList<AiOnline> result = FXCollections.observableArrayList();
int id = getGametypeID(game);
String json;
try {
json = toString(sendGet("ais/" + id));
} catch (IOException e) {
return result;
}
if (json == null) {
return result;
}
JSONArray ais = new JSONArray(json);
json = null;
try {
json = toString(sendGet("games/" + id));
} catch (IOException e) {
return result;
}
if (json == null) {
return result;
}
JSONArray games = new JSONArray(json);
for (int i = 0; i < ais.length(); i++) {
result.add(new AiOnline(ais.getJSONObject(i), this, games));
}
return result;
}
public ObservableList<GameOnline> getGames(String game) {
ObservableList<GameOnline> result = FXCollections.observableArrayList();
String json;
try {
json = toString(sendGet("games/" + getGametypeID(game)));
} catch (IOException e) {
return result;
}
if (json == null) {
return result;
}
JSONArray games = new JSONArray(json);
for (int i = 0; i < games.length(); i++) {
result.add(new GameOnline(games.getJSONObject(i), this));
}
return result;
}
/**
* Gibt das Bild einer AI zurück
*
* @param id
* Die id der AI
* @return Das Bild der AI
* @throws IOException
*/
public Image getImage(int id) throws IOException {
try {
return new Image(new ByteArrayInputStream(sendGet("ai/" + id + "/icon")));
} catch (NullPointerException e) {
ErrorLog.write("Konnte das Bild der KI " + id + " nicht empfangen.");
return null;
}
}
public void changeImage(File img, int id) throws IOException {
if (img == null) {
return;
}
HttpPost post = new HttpPost(url + "ai/" + id + "/upload_icon");
ByteArrayEntity entity = new ByteArrayEntity(FileUtils.readFileToByteArray(img));
post.setEntity(entity);
HttpResponse response = http.execute(post);
if (getOutput(response.getEntity().getContent()) == null) {
throw new IOException("Konnte nicht zum Server verbinden");
}
}
public void changeDescription(String description, int id) {
String result;
try {
result = toString(sendPost("ai/" + id + "/update", "description", description));
if (result == null) {
throw new IOException("A problem occured while trying to update the description!");
}
} catch (IOException e) {
ErrorLog.write("Die Beschreibung der KI konnte nicht geändert werden.");
e.printStackTrace();
}
}
public void deleteKI(int id) {
String result;
try {
result = toString(sendGet("ai/" + id + "/delete"));
if (result == null) {
throw new IOException("A problem occured while trying to delete ai!");
}
} catch (IOException e) {
ErrorLog.write("Die AI konnte nicht gelöscht werden.");
e.printStackTrace();
}
}
public void uploadVersion(Version version, int id) throws ZipException, IOException {
HttpPost post = new HttpPost(url + "ai/" + id + "/upload_zip");
File file = new File(System.getProperty("java.io.tmpdir"), version.ai.title + "v" + version.number + System.currentTimeMillis() + ".zip");
ZipFile zip = new ZipFile(file);
ZipParameters params = new ZipParameters();
params.setIncludeRootFolder(false);
zip.createZipFileFromFolder(new File(Paths.versionSrc(version)), params, false, -1);
FileEntity entity = new FileEntity(file);
post.setEntity(entity);
HttpResponse response = http.execute(post);
byte[] output = getOutput(response.getEntity().getContent());
if (output == null) {
throw new IOException("Konnte nicht zum Server verbinden");
}
if (response.getStatusLine().getStatusCode() != 200)
{
if (response.getFirstHeader("Content-Type").getValue().contains("json"))
{
JSONObject json = new JSONObject(new String(output, UTF_8));
String error = json.getString("error");
throw new IllegalStateException(error);
}
else
throw new IllegalStateException("Irgendetwas ist beim Hochladen schief gelaufen.");
}
File image = ((AiSimple) version.ai).getPictureFile();
changeImage(image, id);
}
public int createAi(AiBase ai, String name) {
try {
byte response[] = sendGet("ai/create", "name", name, "desc", ai.description, "lang", getLangID(ai.language) + "", "type", getGametypeID(ai.gametype) + "");
if (response == null)
throw new IOException();
JSONObject json = new JSONObject(new String(response, UTF_8));
json = json.getJSONObject("ai");
return json.getInt("id");
} catch (IOException e) {
ErrorLog.write("Konnte AI nicht erstellen: " + e);
return -1;
}
}
public String compile(int id) throws IOException, CompileException {
String json = toString(sendGet("ai/" + id + "/compile_blocking"));
if (json == null) {
throw new IOException("Fehler bei der Verbindung mit dem Server");
}
JSONObject result = new JSONObject(json);
if (!result.isNull("error")) {
throw new CompileException(result.getString("compilelog"));
}
return result.getString("compilelog");
}
public boolean qualify(int id) throws IOException {
String response = toString(sendGet("ai/" + id + "/qualify_blocking"));
if (response == null) {
throw new IOException("Fehler bei der Verbindung mit dem Server");
}
return Boolean.parseBoolean(response);
}
public void freeze(int id) throws IOException {
String response = toString(sendGet("ai/" + id + "/freeze"));
if (response == null) {
throw new IOException("Fehler bei der Verbindung mit dem Server");
}
}
public void setActive(Version version) throws IOException {
setActive(((AiOnline)version.ai).id, version.number);
}
public void setActive(int id, int version) throws IOException {
String response = toString(sendGet("ai/" + id + "/activate_version/" + version));
if (response == null) {
throw new IOException("Fehler bei der Verbindung mit dem Server");
}
}
public ObservableList<AiOnline> getOwnAis() {
return getUserAis(getUserID());
}
public ObservableList<AiOnline> getUserAis(int user) {
ObservableList<AiOnline> result = FXCollections.observableArrayList();
String json;
try {
json = toString(sendGet("user/" + user));
} catch (IOException e) {
return result;
}
if (json == null) {
return result;
}
JSONArray ais = new JSONObject(json).getJSONArray("ais");
for (int i = 0; i < ais.length(); i++) {
result.add(new AiOnline(ais.getJSONObject(i), this));
}
return result;
}
public ObservableList<AiOnline> getOwnAis(String gametype) {
return getUserAis(getUserID(), gametype);
}
public ObservableList<AiOnline> getUserAis(int user, String gametype) {
ObservableList<AiOnline> ais = FXCollections.observableArrayList();
ais.addAll(getUserAis(user).stream().filter(ai -> ai.gametype.equals(gametype)).collect(Collectors.toList()));
return ais;
}
/**
* Pingt den Server
*
* @return Ob der Server erreichbar ist
*/
public boolean ping() {
try {
String result = toString(sendGet("ping"));
return result != null;
} catch (IOException e) {
return false;
}
}
public ObservableList<String> loadGametypesFromFile() {
ObservableList<String> result = FXCollections.observableArrayList();
try {
for (String line : FileUtils.readLines(new File(Paths.gameTypesFile()))) {
result.add(line.split("->")[0]);
}
} catch (IOException e) {
ErrorLog.write("Konnte Spieltypen nicht aus Datei laden. Dies ist beim ersten Starten zu erwarten: " + e);
return null;
}
return result;
}
public ObservableList<String> loadLangsFromFile() {
ObservableList<String> result = FXCollections.observableArrayList();
try {
result.addAll(FileUtils.readLines(new File(Paths.langsFile())));
} catch (IOException e) {
return null;
}
return result;
}
public void updateLanguages() throws DeletedException, NewException, NothingDoneException, IOException {
ObservableList<String> result = FXCollections.observableArrayList();
String json = null;
try {
json = toString(sendGet("langs"));
} catch (IOException e) {
ErrorLog.write("Die Sprachen konnten nicht heruntergeladen werden: " + e);
}
if (json == null) {
throw new IOException("Keine oder böse Antwort vom Server");
}
File langsFile = new File(Paths.langsFile());
List<String> langsInFile = new ArrayList<String>();
try {
langsInFile = FileUtils.readLines(langsFile);
} catch (IOException e) {
ErrorLog.write("Konnte Sprachen nicht aus Datei lesen. Dies ist beim ersten Start zu erwarten: " + e);
}
boolean newLangs = false;
boolean deleted = false;
JSONArray langs = new JSONArray(json);
for (int i = 0; i < langs.length(); i++) {
String lang = langs.getJSONObject(i).getString("name");
if (!langsInFile.contains(lang)) {
newLangs = true;
}
result.add(lang);
}
langsFile.delete();
try {
langsFile.getParentFile().mkdirs();
langsFile.createNewFile();
for (int i = 0; i < result.size(); i++) {
FileUtils.write(langsFile, result.get(i) + "\n", true);
}
} catch (IOException e) {
ErrorLog.write("Die Sprachen konnten nicht in die Datei geschrieben werden!");
}
for (String lang : langsInFile) {
if (!result.contains(lang)) {
deleted = true;
}
}
if (newLangs) {
throw new NewException(result);
}
if (deleted) {
throw new DeletedException(result);
}
throw new NothingDoneException();
}
public void updateGametypes() throws NewException, UpdateException, NothingDoneException, DeletedException, IOException {
ObservableList<String> result = FXCollections.observableArrayList();
String json = null;
try {
json = toString(sendGet("gametypes"));
} catch (IOException e) {
ErrorLog.write("Die Spieltypen konnten nicht heruntergeladen werden: " + e);
}
if (json == null) {
throw new IOException("Keine oder böse Antwort vom Server");
}
JSONArray gametypes = new JSONArray(json);
List<String> fileLines = new ArrayList<>();
try {
fileLines = FileUtils.readLines(new File(Paths.gameTypesFile()));
} catch (IOException e) {
ErrorLog.write("Die Spieltypen konnten nicht aus der Datei gelesen werden: " + e);
ErrorLog.write("Es werden nun alle Spieltypen geladen!");
}
List<String> gametypesInFile = new ArrayList<>();
List<String> gametypesFromFrontend = new ArrayList<>();
for (String fileLine : fileLines) {
gametypesInFile.add(fileLine.split("->")[0]);
}
boolean updated = false;
boolean somethingNew = false;
String[] lines = new String[gametypes.length()];
for (int i = 0; i < gametypes.length(); i++) {
JSONObject gametype = gametypes.getJSONObject(i);
String apparentLine = gametype.getString("name") + "->" + gametype.getLong("last_modified");
gametypesFromFrontend.add(gametype.getString("name"));
if (!fileLines.contains(apparentLine)) {
if (!loadGamelogic(gametype.getInt("id"), gametype.getString("name")) || !loadDataContainer(gametype.getInt("id"), gametype.getString("name"))) {
ErrorLog.write("Konnte Spiel " + gametype.getString("name") + " nicht aktualisieren!");
continue;
} else {
updated = true;
if (!gametypesInFile.contains(gametype.getString("name"))) {
somethingNew = true;
}
}
}
lines[gametype.getInt("id") - 1] = apparentLine;
}
// Speichern in der Datei
try {
File gametypesFile = new File(Paths.gameTypesFile());
gametypesFile.delete();
gametypesFile.getParentFile().mkdirs();
gametypesFile.createNewFile();
for (String line : lines) {
if (line != null) {
result.add(line.split("->")[0]);
FileUtils.write(gametypesFile, line + System.lineSeparator(), true);
}
}
} catch (IOException e) {
ErrorLog.write("Die Spieltypen konnten nicht in die Datei geschrieben werden!");
}
boolean deleted = false;
for (String gametype : gametypesInFile) {
if (!gametypesFromFrontend.contains(gametype)) {
deleted = true;
try {
FileUtils.deleteDirectory(new File(Paths.downloadGameType(gametype)));
} catch (IOException e) {
ErrorLog.write("Konnte Spieltyp " + gametype + " nicht löschen: " + e);
}
break;
}
}
if (somethingNew) {
throw new NewException(result);
}
if (deleted) {
throw new DeletedException(result);
}
if (updated) {
throw new UpdateException();
}
throw new NothingDoneException();
}
public byte[] getCodrHash() throws IOException {
try {
String result = toString(sendGet("codr_hash"));
JSONObject json = new JSONObject(result);
return Base64.getDecoder().decode(json.getString("md5_b64"));
} catch (IOException e) {
return null;
}
}
public boolean updateCodr() throws IOException {
return loadCodr();
}
private boolean loadCodr() {
byte[] codr;
try {
codr = sendGet("download_codr");
} catch (IOException e) {
ErrorLog.write("Die neue Version von Codr konnte nicht heruntergeladen werden: " + e);
return false;
}
if (codr == null)
return false;
try {
File file = new File(Paths.newCodrVersion());
file.mkdirs();
file.delete();
file.createNewFile();
FileUtils.writeByteArrayToFile(new File(Paths.newCodrVersion()), codr);
} catch (IOException e) {
ErrorLog.write("Die neue Version von Codr konnte nicht gespeichert werden: " + e);
return false;
}
return true;
}
private boolean loadGamelogic(int game, String gameName) {
byte[] logic;
try {
logic = sendGet("gamelogic/" + game);
} catch (IOException e) {
ErrorLog.write("Spiellogik konnte nicht heruntergeladen werden: " + e);
return false;
}
if (logic == null)
return false;
try {
FileUtils.writeByteArrayToFile(new File(Paths.gameLogic(gameName)), logic);
} catch (IOException e) {
ErrorLog.write("Spiellogik konnte nicht gespeichert werden: " + e);
return false;
}
return true;
}
private boolean loadDataContainer(int game, String gameName) {
byte[] libraries;
try {
libraries = sendGet("data_container/" + game);
} catch (IOException e) {
ErrorLog.write("Der Data Container konnten nicht heruntergeladen werden: " + e);
return false;
}
if (libraries == null) {
return false;
}
try {
File tempZip = File.createTempFile("datacontainer", System.currentTimeMillis() + ".zip");
FileUtils.writeByteArrayToFile(tempZip, libraries);
ZipFile zipFile = new ZipFile(tempZip);
tempZip.deleteOnExit();
File zip;
zipFile.extractAll((zip = Files.createTempDirectory("datacontainerUnzipped" + System.currentTimeMillis()).toFile()).getAbsolutePath());
zip.deleteOnExit();
if (new File(zip, "info.pdf").exists())
FileUtils.copyFile(new File(zip, "info.pdf"), new File(Paths.downloadGameType(gameName), "info.pdf"));
for (File file : new File(zip, "AiLibraries").listFiles()) {
if (file.isFile()) {
continue;
}
File target = new File(Paths.ailibrary(gameName, file.getName()));
target.mkdirs();
FileUtils.copyDirectory(file, target);
}
for (File file : new File(zip, "SimplePlayers").listFiles()) {
if (file.isFile()) {
continue;
}
File target = new File(Paths.simplePlayer(gameName, file.getName()) + "/src");
FileUtils.deleteDirectory(new File(Paths.simplePlayer(gameName, file.getName())).getParentFile());
target.mkdirs();
File property = new File(Paths.simplePlayer(gameName, file.getName()) + "/..", "aiProperties.txt");
property.createNewFile();
FileUtils.write(property, "versionAmount=1" + System.lineSeparator() + "gametype=" + gameName + System.lineSeparator() + "description=Das ist der " + file.getName() + "-SimplePlayer"
+ System.lineSeparator() + "language=" + file.getName());
property = new File(property.getParent() + "/v0/versionProperties.txt");
property.createNewFile();
FileUtils.write(property, "uploaded=false" + System.lineSeparator() + "compileOutput=" + System.lineSeparator() + "qualifyOutput=" + System.lineSeparator() + "qualified=false"
+ System.lineSeparator() + "compiled=false" + System.lineSeparator() + "finished=false" + System.lineSeparator() + "executeCommand=");
FileUtils.copyDirectory(file, target);
}
} catch (IOException | ZipException e) {
e.printStackTrace();
ErrorLog.write("Ai Libraries konnte nicht entpackt werden: " + e);
return false;
}
return true;
}
/**
* Gibt den Session Token zurück
*
* @return Den Session Token der Session
*/
private String getSession() {
List<Cookie> cookie = cookies.getCookies().stream().filter((Cookie o) -> o.getName().equals("session")).collect(Collectors.toList());
return cookie.isEmpty() ? null : cookie.get(0).getValue();
}
/**
* Gibt den Remember Token zurück
*
* @return Den Remember Token der Session
*/
private String getRememberToken() {
List<Cookie> cookie = cookies.getCookies().stream().filter((Cookie o) -> o.getName().equals("remember_token")).collect(Collectors.toList());
return cookie.isEmpty() ? null : cookie.get(0).getValue();
}
/**
* Speichert die Session in eine Datei
*/
private void saveToFile() {
File file = new File(Paths.sessionFile());
try {
Properties p = new Properties();
List<Cookie> cookies = this.cookies.getCookies();
p.setProperty("session.cookies", Integer.toString(cookies.size()));
for (int i = 0; i < cookies.size(); i++) {
Cookie c = cookies.get(i);
p.setProperty("session.cookies." + i + ".domain", c.getDomain());
if (c.getExpiryDate() != null)
p.setProperty("session.cookies." + i + ".expiry", cookieDateFormat.format(c.getExpiryDate()));
p.setProperty("session.cookies." + i + ".name", c.getName());
p.setProperty("session.cookies." + i + ".path", c.getPath());
p.setProperty("session.cookies." + i + ".value", c.getValue());
p.setProperty("session.cookies." + i + ".version", Integer.toString(c.getVersion()));
}
p.store(new FileOutputStream(file), "Die Session von Codr");
} catch (IOException e) {
ErrorLog.write("Fehler beim Speichern der Session: " + e.getMessage());
return;
}
}
/**
* Holt die Session aus einer Datei
*/
private void readFromFile() {
File file = new File(Paths.sessionFile());
try {
if (!file.exists()) {
return;
}
Properties p = new Properties();
p.load(new FileInputStream(file));
int cookies = Integer.parseInt(p.getProperty("session.cookies"));
for (int i = 0; i < cookies; i++) {
String name = p.getProperty("session.cookies." + i + ".name");
String value = p.getProperty("session.cookies." + i + ".value");
BasicClientCookie c = new BasicClientCookie(name, value);
c.setDomain(p.getProperty("session.cookies." + i + ".domain"));
if (p.containsKey("session.cookies." + i + ".expiry"))
c.setExpiryDate(cookieDateFormat.parse(p.getProperty("session.cookies." + i + ".expiry")));
else
c.setExpiryDate(null);
c.setPath(p.getProperty("session.cookies." + i + ".path"));
c.setVersion(Integer.parseInt(p.getProperty("session.cookies." + i + ".version")));
this.cookies.addCookie(c);
}
} catch (IOException | ParseException e) {
ErrorLog.write("Fehler beim Laden der Session: " + e.getMessage());
return;
}
}
private File downloadAndExtractZip(File folder, String command) throws IOException, ZipException {
File tempZip = File.createTempFile("codr", System.currentTimeMillis() + ".zip");
downloadFile(tempZip, command);
ZipFile zipFile = new ZipFile(tempZip);
tempZip.deleteOnExit();
File zip;
zipFile.extractAll((zip = Files.createTempDirectory("codrUnzipped" + System.currentTimeMillis()).toFile()).getAbsolutePath());
zip.deleteOnExit();
for (File file : zip.listFiles()) {
if (file.isFile()) {
FileUtils.copyFile(file, new File(folder, file.getName()));
} else {
new File(folder, file.getName()).mkdirs();
FileUtils.copyDirectory(file, new File(folder, file.getName()));
}
}
return folder;
}
private File downloadFile(File file, String command) throws IOException {
byte[] data;
data = sendGet(command);
if (data == null) {
throw new IOException("Couldn't download from " + command + " to " + file);
}
FileUtils.writeByteArrayToFile(file, data);
return file;
}
private byte[] sendPost(String command) throws IOException {
return sendPost(command, new NameValuePair[0]);
}
private byte[] sendPost(String command, String... data) throws IOException {
if (data.length % 2 != 0) {
throw new IllegalArgumentException("Pöse pöse, data muss immer eine Länge % 2 = 0 haben!");
}
NameValuePair[] nvpData = new BasicNameValuePair[data.length / 2];
for (int i = 0; i < nvpData.length; i++) {
if (data[i * 2] != null && data[i * 2 + 1] != null) {
nvpData[i] = new BasicNameValuePair(data[i * 2], data[i * 2 + 1]);
}
}
return sendPost(command, nvpData);
}
/**
* Sendet einen PostRequest
*
* @param command
* Das Kommando (z.B. login für
* http://www.turnierserver.informatik-olympiade.de/api/login)
* @param data
* Die Daten, die per POST übegeben werden sollen
* @return Die Antwort als byte[]
* @throws IOException
*/
private byte[] sendPost(String command, NameValuePair... data) throws IOException {
try {
HttpPost post = new HttpPost(command == null || command.length() == 0 ? url.substring(0, url.length() - 1) : url + command);
if (data.length != 0) {
post.setEntity(new UrlEncodedFormEntity(Arrays.asList(data)));
}
HttpResponse response = http.execute(post);
byte[] responseArray = getOutput(response.getEntity().getContent());
if (response.getStatusLine().getStatusCode() != 200) {
ErrorLog.write("ERROR: Executing post request to " + url + command + " failed! ErrorCode: " + response.getStatusLine().getStatusCode() + ", ErrorMessage: " + toString(responseArray));
isConnected = false;
return null;
}
isConnected = true;
return responseArray;
} catch (IOException e) {
isConnected = false;
throw e;
}
}
private byte[] sendGet(String command) throws IOException {
return sendGet(command, new NameValuePair[0]);
}
private byte[] sendGet(String command, String... data) throws IOException {
if (data.length % 2 != 0) {
throw new IllegalArgumentException("Data muss immer eine Länge % 2 = 0 haben!");
}
NameValuePair[] nvpData = new BasicNameValuePair[data.length / 2];
for (int i = 0; i < nvpData.length; i++) {
nvpData[i] = new BasicNameValuePair(data[i * 2], data[i * 2 + 1]);
}
return sendGet(command, nvpData);
}
/**
* Sendet einen GetRequest
*
* @param command
* Das Kommando (z.B. logout für
* http://www.turnierserver.informatik-olympiade.de/api/logout)
* @param data
* Die Daten, die per GET übegeben werden sollen
* @return Die Antwort als byte[]
* @throws IOException
*/
private byte[] sendGet(String command, NameValuePair... data) throws IOException {
try {
String args = "";
for (NameValuePair pair : data) {
args += args.isEmpty() ? "?" : "&";
args += URLEncoder.encode(pair.getName(), "UTF8") + "=" + URLEncoder.encode(pair.getValue(), "UTF8");
}
HttpGet get = new HttpGet(command == null || command.isEmpty() ? url.substring(0, url.length() - 1) + args : url + command + args);
HttpResponse response = http.execute(get);
byte[] responseArray = getOutput(response.getEntity().getContent());
if (response.getStatusLine().getStatusCode() != 200) {
ErrorLog.write("ERROR: Executing get request to " + url + command + " failed! ErrorCode: " + response.getStatusLine().getStatusCode());// +
// ", ErrorMessage: "
// +
System.out.println(toString(responseArray));
isConnected = false;
return null;
}
isConnected = true;
return responseArray;
} catch (IOException e) {
isConnected = false;
throw e;
}
}
private String toString(byte[] bytes) throws IOException {
if (bytes == null) {
throw new IOException();
}
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
System.exit(1);
return null;
}
}
private byte[] getOutput(InputStream in) throws IOException {
ByteArrayOutputStream responseContent = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) > 0) {
for (int i = 0; i < read; i++) {
responseContent.write(buffer[i]);
}
}
return responseContent.toByteArray();
}
}