package com.google.jstestdriver.idea.server;
import com.google.common.collect.Lists;
import com.google.gson.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.Consumer;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
public class JstdServerUtils {
private JstdServerUtils() {}
public static void asyncFetchServerInfo(final String serverUrl, final Consumer<JstdServerFetchResult> consumer) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
JstdServerFetchResult serverFetchResult;
try {
serverFetchResult = syncFetchServerInfo(serverUrl);
} catch (Exception e) {
serverFetchResult = new JstdServerFetchResult(null, "Internal error occurred");
}
consumer.consume(serverFetchResult);
}
});
}
public static JstdServerFetchResult syncFetchServerInfo(final String serverUrl) {
try {
new URL(serverUrl);
} catch (MalformedURLException e) {
return JstdServerFetchResult.fromErrorMessage("Malformed url: " + serverUrl);
}
String url = serverUrl.replaceAll("/$", "") + "/cmd?listBrowsers";
Response response = fetchResponse(url);
if (response.getError() == Response.Error.CONNECTION_FAILED) {
return JstdServerFetchResult.fromErrorMessage("Could not connect to " + serverUrl);
} else if (response.getError() == Response.Error.READ_FAILED) {
return JstdServerFetchResult.fromErrorMessage("Reading error occurred");
} else if (response.getStatus() != 200) {
return JstdServerFetchResult.fromErrorMessage("Incorrect server response status");
}
JsonParser jsonParser = new JsonParser();
final String badResponse = "Malformed server response received";
JsonElement jsonElement;
try {
jsonElement = jsonParser.parse(response.getContent());
} catch (JsonSyntaxException e) {
return JstdServerFetchResult.fromErrorMessage(badResponse);
}
try {
List<JstdBrowserInfo> browserInfos = parseBrowsers(jsonElement.getAsJsonArray());
return JstdServerFetchResult.fromServerInfo(new JstdServerInfo(serverUrl, browserInfos));
} catch (Exception e) {
return JstdServerFetchResult.fromErrorMessage(badResponse);
}
}
private static List<JstdBrowserInfo> parseBrowsers(JsonArray jsonArray) {
List<JstdBrowserInfo> browserInfos = Lists.newArrayList();
for (JsonElement child : jsonArray) {
JsonObject browserJsonObject = child.getAsJsonObject();
JsonPrimitive namePrimitive = browserJsonObject.getAsJsonPrimitive("name");
JsonPrimitive versionPrimitive = browserJsonObject.getAsJsonPrimitive("version");
JsonPrimitive osPrimitive = browserJsonObject.getAsJsonPrimitive("os");
if (namePrimitive.isString() && versionPrimitive.isString() && osPrimitive.isString()) {
browserInfos.add(new JstdBrowserInfo(namePrimitive.getAsString(), versionPrimitive.getAsString(), osPrimitive.getAsString()));
} else {
throw new RuntimeException();
}
}
return browserInfos;
}
private static Response fetchResponse(String url) {
HttpURLConnection connection = null;
try {
final int status;
try {
connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect();
status = connection.getResponseCode();
} catch (Exception e) {
return Response.error(Response.Error.CONNECTION_FAILED);
}
try {
String content = readAsString(connection);
return Response.fromContent(status, content);
} catch (IOException e) {
return Response.error(Response.Error.READ_FAILED);
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
private static String readAsString(URLConnection connection) throws IOException {
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream, "UTF-8");
try {
StringBuilder sb = new StringBuilder();
{
char[] buffer = new char[2048];
while (true) {
int read = reader.read(buffer);
if (read < 0) break;
sb.append(buffer, 0, read);
}
}
return sb.toString();
} finally {
try {
reader.close();
} catch (IOException ignored) {}
}
}
private static class Response {
enum Error {
CONNECTION_FAILED,
READ_FAILED
}
final Error myError;
final int myStatus;
final String myContent;
private Response(Error error, int status, String content) {
myError = error;
myStatus = status;
myContent = content;
}
public Error getError() {
return myError;
}
public int getStatus() {
return myStatus;
}
public String getContent() {
return myContent;
}
static Response error(Error error) {
return new Response(error, 0, null);
}
static Response fromContent(int status, String content) {
return new Response(null, status, content);
}
}
}