Skip to content

Instantly share code, notes, and snippets.

@darkwave
Last active August 29, 2015 14:26
Show Gist options
  • Save darkwave/517ce08482cd3321fba3 to your computer and use it in GitHub Desktop.
Save darkwave/517ce08482cd3321fba3 to your computer and use it in GitHub Desktop.
Simple Helper for Scratch 2.0 offline editor extensions system
/*
* This file is part of ScratchHelper Library by Massimo Avvisati
*
* Licensed under GPL v3
*
*/
package com.mondonerd.scratch;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.ConnectionClosedException;
import org.apache.http.HttpConnectionFactory;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpServerConnection;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.DefaultBHttpServerConnection;
import org.apache.http.impl.DefaultBHttpServerConnectionFactory;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpProcessorBuilder;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.HttpService;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;
import org.apache.http.protocol.UriHttpRequestHandlerMapper;
import processing.core.PApplet;
public class Helper {
static PApplet sketch;
static Method commandWithString = null;
static Method commandWithBoolean = null;
static Method commandWithNumber = null;
static Method commandWithoutParam = null;
public Helper(PApplet sketch, int port) throws IOException {
this.sketch = sketch;
try {
commandWithString = sketch.getClass().getMethod("onScratch",
new Class[] { String.class, String.class });
} catch (Exception e) {
// no such method, or an error.. which is fine, just ignore
System.out.println("Please implement " + e.getMessage());
}
try {
commandWithBoolean = sketch.getClass().getMethod("onScratch",
new Class[] { String.class, boolean.class });
} catch (Exception e) {
// no such method, or an error.. which is fine, just ignore
System.out.println("Please implement " + e.getMessage());
}
try {
commandWithNumber = sketch.getClass().getMethod("onScratch",
new Class[] { String.class, float.class });
} catch (Exception e) {
// no such method, or an error.. which is fine, just ignore
System.out.println("Please implement " + e.getMessage());
}
try {
commandWithoutParam = sketch.getClass().getMethod("onScratch",
new Class[] { String.class });
} catch (Exception e) {
// no such method, or an error.. which is fine, just ignore
System.out.println("Please implement " + e.getMessage());
}
// Set up the HTTP protocol processor
HttpProcessor httpproc = HttpProcessorBuilder.create()
.add(new ResponseDate())
.add(new ResponseServer("Scratch Helper/1.1"))
.add(new ResponseContent()).add(new ResponseConnControl())
.build();
// Set up request handlers
UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper();
reqistry.register("*", new HttpScratchHandler());
// Set up the HTTP service
HttpService httpService = new HttpService(httpproc, reqistry);
Thread t = new RequestListenerThread(port, httpService);
t.setDaemon(false);
t.start();
}
static HashMap<String, String> sensors = new HashMap<String, String>();
// static final HashMap<String, String> temporarySensors = new
// HashMap<String, String>();
public void publish(String sensorName, String value) {
sensors.put(sensorName, value);
// System.out.println(sensorName + ": " + value);
}
static void forwardOperation(String operation, String value) {
}
static class HttpScratchHandler implements HttpRequestHandler {
public void handle(final HttpRequest request,
final HttpResponse response, final HttpContext context) {
Map<String, String> map = Collections.synchronizedMap(sensors);
String target = request.getRequestLine().getUri();
// System.out.println("now what!? " + target + map.size());
response.setStatusCode(HttpStatus.SC_OK);
String result = "";
if (target.contains("/poll")) {
Iterator<Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> pair = it.next();
result = result + pair.getKey() + " = " + pair.getValue()
+ "\n";
// it.remove(); // avoids a ConcurrentModificationException
}
} else {
// System.out.println(target);
// System.out.println(command);
String operation = "";
float fValue = 0.0f;
boolean bValue = false;
String sValue = null;
boolean isNumber = false;
String possibleValue = null;
int possibleValuePosition = target.indexOf('/', 1);
boolean hasValue = possibleValuePosition >= 0;
if (hasValue) {
operation = target.substring(0, possibleValuePosition);
possibleValue = target.substring(possibleValuePosition + 1);
try {
fValue = Float.parseFloat(possibleValue);
isNumber = true;
//System.out.println("is a number");
} catch (NumberFormatException nfex) {
}
if (isNumber == false) {
if (possibleValue.equalsIgnoreCase("true")
|| possibleValue.equalsIgnoreCase("false")) {
bValue = Boolean.parseBoolean(possibleValue);
//System.out.println("is a boolean");
} else {
sValue = possibleValue;
//System.out.println("is a string");
}
}
}
if (hasValue == false && commandWithoutParam != null)
try {
commandWithoutParam.invoke(Helper.sketch, target);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
else if (isNumber && commandWithNumber != null)
try {
commandWithNumber.invoke(Helper.sketch, operation, fValue);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
else if (sValue != null && commandWithString != null)
try {
commandWithString.invoke(Helper.sketch, operation, sValue);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
else if (commandWithBoolean != null)
try {
commandWithBoolean
.invoke(Helper.sketch, operation, bValue);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
StringEntity entity = new StringEntity(
// "mouseX " + Math.random() + "\nmouseY 20\n",
result, ContentType.create("text/html", "UTF-8"));
response.setEntity(entity);
// System.out.println(result);
// TODO
}
}
static class RequestListenerThread extends Thread {
private final HttpConnectionFactory<DefaultBHttpServerConnection> connFactory;
private final ServerSocket serversocket;
private final HttpService httpService;
public RequestListenerThread(final int port,
final HttpService httpService) throws IOException {
this.connFactory = DefaultBHttpServerConnectionFactory.INSTANCE;
this.serversocket = new ServerSocket(port);
this.httpService = httpService;
}
@Override
public void run() {
System.out.println("Listening on port "
+ this.serversocket.getLocalPort());
while (!Thread.interrupted()) {
try {
// Set up HTTP connection
Socket socket = this.serversocket.accept();
System.out.println("Incoming connection from "
+ socket.getInetAddress());
HttpServerConnection conn = this.connFactory
.createConnection(socket);
// Start worker thread
Thread t = new WorkerThread(this.httpService, conn);
t.setDaemon(true);
t.start();
} catch (InterruptedIOException ex) {
break;
} catch (IOException e) {
System.err
.println("I/O error initialising connection thread: "
+ e.getMessage());
break;
}
}
}
}
static class WorkerThread extends Thread {
private final HttpService httpservice;
private final HttpServerConnection conn;
public WorkerThread(final HttpService httpservice,
final HttpServerConnection conn) {
super();
this.httpservice = httpservice;
this.conn = conn;
}
@Override
public void run() {
System.out.println("New connection thread");
HttpContext context = new BasicHttpContext(null);
try {
while (!Thread.interrupted() && this.conn.isOpen()) {
// this is important: consecutive messages are handled by
// this function
// inside the same http context
this.httpservice.handleRequest(this.conn, context);
}
} catch (ConnectionClosedException ex) {
System.err.println("Client closed connection");
} catch (IOException ex) {
System.err.println("I/O error: " + ex.getMessage());
} catch (HttpException ex) {
System.err.println("Unrecoverable HTTP protocol violation: "
+ ex.getMessage());
} finally {
try {
this.conn.shutdown();
} catch (IOException ignore) {
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment