Last active
August 29, 2015 14:05
-
-
Save darkwave/ddec4c1bef9013521621 to your computer and use it in GitHub Desktop.
Scratch Helper using Processing prototype
This file contains 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
import java.io.File; | |
import java.io.IOException; | |
import java.io.InterruptedIOException; | |
import java.net.ServerSocket; | |
import java.net.Socket; | |
import java.net.URL; | |
import java.net.URLDecoder; | |
import java.nio.charset.Charset; | |
import java.security.KeyStore; | |
import java.util.Locale; | |
import org.apache.http.ConnectionClosedException; | |
import org.apache.http.HttpConnectionFactory; | |
import org.apache.http.HttpEntity; | |
import org.apache.http.HttpEntityEnclosingRequest; | |
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.MethodNotSupportedException; | |
import org.apache.http.entity.ContentType; | |
import org.apache.http.entity.FileEntity; | |
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 org.apache.http.util.EntityUtils; | |
import processing.core.*; | |
import javax.net.ssl.KeyManager; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLServerSocketFactory; | |
/** | |
* Basic, yet fully functional and spec compliant, HTTP/1.1 file server. | |
*/ | |
import java.lang.reflect.*; | |
public class ElementalHttpServer { | |
static PApplet parent; | |
static Method displayMethod; | |
ElementalHttpServer(PApplet _parent) { | |
parent = _parent; | |
try { | |
displayMethod = parent.getClass().getMethod("onScratch", | |
new Class[] { | |
float.class, float.class, float.class | |
} | |
); | |
} | |
catch (Exception e) { | |
// no such method, or an error.. which is fine, just ignore | |
System.out.println("please implement " + e.getMessage()); | |
} | |
} | |
public static void main(String... args) throws Exception { | |
if (args.length < 1) { | |
System.err.println("Please specify document root directory"); | |
System.exit(1); | |
} | |
// Document root directory | |
String docRoot = args[0]; | |
int port = 8080; | |
if (args.length >= 2) { | |
port = Integer.parseInt(args[1]); | |
} | |
// Set up the HTTP protocol processor | |
HttpProcessor httpproc = HttpProcessorBuilder.create() | |
.add(new ResponseDate()) | |
.add(new ResponseServer("Test/1.1")) | |
.add(new ResponseContent()) | |
.add(new ResponseConnControl()).build(); | |
// Set up request handlers | |
UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper(); | |
reqistry.register("*", new HttpFileHandler(docRoot)); | |
// Set up the HTTP service | |
HttpService httpService = new HttpService(httpproc, reqistry); | |
SSLServerSocketFactory sf = null; | |
if (port == 8443) { | |
// Initialize SSL context | |
ClassLoader cl = ElementalHttpServer.class.getClassLoader(); | |
URL url = cl.getResource("my.keystore"); | |
if (url == null) { | |
System.out.println("Keystore not found"); | |
System.exit(1); | |
} | |
KeyStore keystore = KeyStore.getInstance("jks"); | |
keystore.load(url.openStream(), "secret".toCharArray()); | |
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance( | |
KeyManagerFactory.getDefaultAlgorithm()); | |
kmfactory.init(keystore, "secret".toCharArray()); | |
KeyManager[] keymanagers = kmfactory.getKeyManagers(); | |
SSLContext sslcontext = SSLContext.getInstance("TLS"); | |
sslcontext.init(keymanagers, null, null); | |
sf = sslcontext.getServerSocketFactory(); | |
} | |
Thread t = new RequestListenerThread(port, httpService, sf); | |
t.setDaemon(false); | |
t.start(); | |
} | |
static class HttpFileHandler implements HttpRequestHandler { | |
private final String docRoot; | |
public HttpFileHandler(final String docRoot) { | |
super(); | |
this.docRoot = docRoot; | |
} | |
float x, y, dir; | |
public void handle( | |
final HttpRequest request, | |
final HttpResponse response, | |
final HttpContext context) throws HttpException, IOException { | |
String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH); | |
if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { | |
throw new MethodNotSupportedException(method + " method not supported"); | |
} | |
String target = request.getRequestLine().getUri(); | |
if (target.indexOf("setX/")>= 0) | |
x = Float.parseFloat(target.substring(target.lastIndexOf('/') + 1)); | |
if (target.indexOf("setY/")>= 0) | |
y = Float.parseFloat(target.substring(target.lastIndexOf('/') + 1)); | |
if (target.indexOf("setDirection/")>= 0) | |
dir = Float.parseFloat(target.substring(target.lastIndexOf('/') + 1)); | |
try { | |
displayMethod.invoke(parent, dir, x, y); | |
} | |
catch (Exception e) { | |
System.out.println("Disabling displayMethod() because of an error."); | |
// e.printStackTrace(); | |
displayMethod = null; | |
} | |
/* | |
if (request instanceof HttpEntityEnclosingRequest) { | |
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); | |
byte[] entityContent = EntityUtils.toByteArray(entity); | |
System.out.println("Incoming entity content (bytes): " + entityContent.length); | |
} | |
final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8")); | |
if (!file.exists()) { | |
response.setStatusCode(HttpStatus.SC_OK); | |
StringEntity entity = new StringEntity( | |
"volume " + parent.mouseX, | |
ContentType.create("text/html", "UTF-8")); | |
response.setEntity(entity); | |
System.out.println("File " + file.getPath() + " not found!"); | |
} else if (!file.canRead() || file.isDirectory()) { | |
response.setStatusCode(HttpStatus.SC_FORBIDDEN); | |
StringEntity entity = new StringEntity( | |
"volume " + parent.mouseX, | |
ContentType.create("text/html", "UTF-8")); | |
response.setEntity(entity); | |
//System.out.println("Cannot read file " + file.getPath()); | |
} else { | |
response.setStatusCode(HttpStatus.SC_OK); | |
FileEntity body = new FileEntity(file, ContentType.create("text/html", (Charset) null)); | |
response.setEntity(body); | |
System.out.println("Serving file " + file.getPath()); | |
} | |
*/ | |
} | |
} | |
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, | |
final SSLServerSocketFactory sf) throws IOException { | |
this.connFactory = DefaultBHttpServerConnectionFactory.INSTANCE; | |
this.serversocket = sf != null ? sf.createServerSocket(port) : 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.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) { | |
} | |
} | |
} | |
} | |
} |
This file contains 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
{ "extensionName": "Scratch3D", | |
"extensionPort": 12345, | |
"blockSpecs": [ | |
[" ", "change background", "randomBackground"], | |
[" ", "set direction to %n", "setDirection", 5], | |
[" ", "set x to %n", "setX", 5], | |
[" ", "set y to %n", "setY", 5], | |
["r", "mouseX", "mouseX"], | |
["r", "mouseY", "mouseY"], | |
] | |
} |
This file contains 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
import remixlab.proscene.*; | |
Scene scene; | |
ElementalHttpServer server; | |
void setup() { | |
size(640, 480, P3D); | |
noStroke(); | |
scene = new Scene(this); | |
server = new ElementalHttpServer(this); | |
try { | |
server.main(sketchPath, "12345"); | |
} | |
catch (Exception ex) { | |
println(ex); | |
} | |
} | |
public float x, y, direction; | |
void draw() { | |
background(0); | |
lights(); | |
pushMatrix(); | |
translate(x, y); | |
rotateZ(radians(direction)); | |
box(30); | |
popMatrix(); | |
} | |
void onScratch(float scratchDirection, float scratchX, float scratchY) { | |
if (abs(scratchX - x) > 1) | |
x += (scratchX - x) * 0.1; | |
if (abs(scratchY - y) > 1) | |
y += (-scratchY -y) * 0.1; | |
direction = scratchDirection; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment