package org.hwbot.bench.service;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import org.apache.commons.codec.binary.Hex;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.hwbot.bench.Benchmark;
import org.hwbot.bench.BenchmarkConfiguration;
import org.hwbot.bench.PrimeBenchmark;
import org.hwbot.bench.model.Hardware;
import org.hwbot.bench.model.Response;
import org.hwbot.bench.prime.HardwareService;
import org.hwbot.bench.prime.Log;
import org.hwbot.bench.prime.ProgressBar;
import org.hwbot.bench.remote.BasicResponseStatusHandler;
import org.hwbot.bench.security.EncryptionModule;
import org.hwbot.bench.ui.BenchUI;
import org.hwbot.bench.ui.Output;
import org.hwbot.bench.ui.console.BenchConsole;
import org.hwbot.bench.ui.console.SystemConsole;
import org.hwbot.bench.ui.console.SystemProgressBar;
import org.hwbot.bench.ui.swing.BenchSwingUI;
import org.hwbot.bench.ui.swing.JProgressBarProgressBar;
import org.hwbot.bench.util.DataServiceXml;
public class BenchService implements Runnable {
public Number score;
protected static String version;
static {
version = BenchService.class.getPackage().getImplementationVersion() != null ? BenchService.class.getClass().getPackage().getImplementationVersion()
: "dev";
}
protected BenchUI benchUI;
protected ProgressBar progressBar;
protected Output output;
private String server = System.getProperty("server", "http://192.168.0.248:9090/");
public static boolean headless;
protected static EncryptionModule encryptionModule;
private Benchmark benchmark;
private ScheduledFuture<?> processorFrequencyMonitorScheduler;
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
private String checksum, checksumbase;
private char[] checksumChars;
private Hardware hardware;
public BenchService() {
try {
ServiceLoader<EncryptionModule> encryptionLoader = ServiceLoader.load(EncryptionModule.class);
for (EncryptionModule encryptionModule : encryptionLoader) {
// BenchService.encryptionModule = encryptionModule;
}
} catch (Exception e) {
// no encryption
Log.error("No encryption module found.");
// e.printStackTrace();
}
}
public void initialize(boolean ui, String outputFile) throws IOException {
// Class.forName(className)
HardwareService hardwareService = HardwareServiceFactory.getInstance();
hardware = hardwareService.gatherHardwareInfo();
int availableProcessors = Runtime.getRuntime().availableProcessors();
BenchService.headless = !ui;
if (ui) {
Log.info("Using UI mode.");
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
try {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception e1) {
}
}
JFrame frame = new JFrame("HWBOT Prime " + version);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BenchSwingUI benchUI = new BenchSwingUI(this, getTitle(), getSubtitle());
// Get the size of the screen
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
// Determine the new location of the window
int w = frame.getSize().width;
int h = frame.getSize().height;
int x = (dim.width - w) / 2;
int y = (dim.height - h) / 2;
// Move the window
frame.setLocation(x, y);
frame.setContentPane(benchUI);
frame.pack();
frame.setVisible(true);
JProgressBar progressbar = benchUI.getjProgressBar1();
progressbar.setMaximum(100);
// output = new JTextAreaConsole(benchUI.getConsole());
benchUI.getProcessor().setText(hardware.getProcessor().getName());
benchUI.getFrequency().setText(getProcessorFrequency(hardware.getProcessor().getCoreClock()));
benchUI.getThreads().setText(String.valueOf(availableProcessors));
benchUI.getMemory().setText(hardware.getMemory().getTotalSizeMB() + "MB");
output = new SystemConsole();
frame.pack();
progressBar = new JProgressBarProgressBar(progressbar);
this.benchUI = benchUI;
} else {
BenchConsole benchUI = new BenchConsole(this, outputFile);
output = new SystemConsole();
progressBar = new SystemProgressBar(100);
this.benchUI = benchUI;
Float processorTemperature = hardwareService.getProcessorTemperature();
output.write("--------- HWBOT Prime " + version + " ----------\n");
output.write("Processor detected:\n" + hardware.getProcessor().getName());
output.write("Estimating speed... ", false);
output.write(((availableProcessors > 1) ? availableProcessors + "x " : "") + getProcessorFrequency(hardware.getProcessor().getCoreClock()) + "MHz"
+ (processorTemperature != null ? " @ " + processorTemperature + " C" : ""));
if (hardware.getMemory().getTotalSizeMB() > 0) {
output.write(hardware.getMemory().getTotalSizeMB() + "MB memory");
}
}
benchUI.waitForCommands();
}
public String getSubtitle() {
return "Multithreaded Prime Bench - ARM/x86 - Win/Mac/Linux";
}
public String getTitle() {
return "HWBOT Prime Benchmark";
}
public static String getProcessorFrequency(Float processorSpeed) {
String freq;
if (processorSpeed == null) {
freq = "n/a";
} else {
NumberFormat instance = NumberFormat.getInstance(Locale.ENGLISH);
instance.setMaximumFractionDigits(2);
freq = instance.format(processorSpeed);
}
return freq;
}
public enum BenchPhase {
ready, warmup, inprogress, finished
}
private ExecutorService exec;
private BenchPhase currentPhase = BenchPhase.ready;
public void benchmark() {
exec = Executors.newFixedThreadPool(2, new ThreadFactory() {
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setPriority(Thread.MAX_PRIORITY);
thread.setName("benchmark");
thread.setDaemon(false);
return thread;
}
});
if (scheduledThreadPoolExecutor != null) {
scheduledThreadPoolExecutor.shutdownNow();
processorFrequencyMonitorScheduler.cancel(true);
}
benchmark = instantiateBenchmark();
new Thread(this).start();
}
@Override
public void run() {
Future<Number> submit = exec.submit(benchmark);
this.currentPhase = BenchPhase.inprogress;
// wait for outout
try {
score = submit.get();
checksum = toSHA1((checksumbase + score).getBytes("UTF8"));
checksumChars = checksum.toCharArray();
this.currentPhase = BenchPhase.finished;
benchUI.notifyBenchmarkFinished(benchmark);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public Benchmark instantiateBenchmark() {
BenchmarkConfiguration configuration = new BenchmarkConfiguration();
configuration.setValue(PrimeBenchmark.TIME_SPAN, TimeUnit.SECONDS.toMillis(10));
configuration.setValue(PrimeBenchmark.SILENT, false);
return new PrimeBenchmark(configuration, Runtime.getRuntime().availableProcessors(), this.progressBar);
}
public void submit() {
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 20;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection * 1000);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutConnection * 1000);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
try {
// Create a response handler
byte[] bytes = getDataFile();
BasicResponseStatusHandler responseHandler = new BasicResponseStatusHandler();
String uri = server + "/submit/api?client=" + URLEncoder.encode(benchmark.getClient(), "ISO-8859-1") + "&clientVersion=" + getClientVersion();
Log.info("URI: " + uri);
HttpPost req = new HttpPost(uri);
req.addHeader("Accept", "application/xml");
MultipartEntity mpEntity = new MultipartEntity();
mpEntity.addPart("data", new ByteArrayBody(bytes, "data"));
req.setEntity(mpEntity);
Response response = DataServiceXml.parseResponse(httpclient.execute(req, responseHandler));
if ("success".equals(response.getStatus())) {
String url = response.getUrl();
try {
Desktop.getDesktop().browse(new URI(url));
} catch (Exception e) {
output.write("Failed to open your browser, please open " + url + " to view your submission.");
}
} else if ("error".equals(response.getStatus())) {
this.benchUI.notifyError(response.getMessage());
} else {
output.write("Failed to submit score. Status was: " + response);
output.write(response.getMessage());
}
} catch (HttpHostConnectException e) {
e.printStackTrace();
output.write("Failed to connect to HWBOT server! Are you connected to the internet?");
} catch (Exception e) {
e.printStackTrace();
output.write("Error communicating with online service. If this issue persists, please contact HWBOT crew.");
} finally {
httpclient.getConnectionManager().shutdown();
}
}
public byte[] getDataFile() throws UnsupportedEncodingException {
byte[] bytes = null;
// processor speed ignored, not reliable enough...
verifyMemoryUnaltered();
String xml = DataServiceXml.createXml(benchmark.getClient(), version, hardware, this.formatScore(benchmark.getScore()), !headless,
BenchService.encryptionModule);
if (encryptionModule != null) {
bytes = BenchService.encryptionModule.encrypt(xml.getBytes("utf8"), null);
} else {
bytes = xml.getBytes("utf8");
}
return bytes;
}
private void verifyMemoryUnaltered() {
return;
// try {
// checksum = processor + availableProcessors + score;
// checksum = toSHA1(checksum.getBytes("UTF8"));
// if (!ArrayUtils.isEquals(checksumChars, checksum.toCharArray())) {
// throw new SecurityException("Memory has been altered. Bad hacker! Shoo!");
// }
// } catch (UnsupportedEncodingException e) {
// throw new RuntimeException();
// }
}
public static String toSHA1(byte[] string) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException();
}
return Hex.encodeHexString(md.digest(string));
}
protected String getClientVersion() {
return version;
}
public String formatScore(Number score) {
return String.format(Locale.ENGLISH, "%.2f", score);
}
public void saveToFile(File file) {
if (file.isDirectory()) {
file = new File(file, "HWBOT Prime - " + new SimpleDateFormat("dd-MM-yyyy HH'h'mm'm'") + ".hwbot");
}
byte[] dataFile;
try {
dataFile = getDataFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(dataFile);
fileOutputStream.close();
} catch (Exception e) {
Log.error("Failed to save the file: " + file.getAbsolutePath() + ". Reason: " + e.getMessage());
}
}
public ProgressBar getProgressBar() {
return progressBar;
}
public void setProgressBar(ProgressBar progressBar) {
this.progressBar = progressBar;
}
public BenchPhase getCurrentPhase() {
return this.currentPhase;
}
}