Last active
August 29, 2015 14:26
-
-
Save darkwave/517ce08482cd3321fba3 to your computer and use it in GitHub Desktop.
Simple Helper for Scratch 2.0 offline editor extensions system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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