Added basic WebSocket functionality (no decoding yet)
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
package com.example.fitbot.processing;
|
||||
|
||||
public class MotionProcessor {
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package com.example.fitbot.processing;
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
public class MotionData {
|
||||
|
@@ -1,4 +1,6 @@
|
||||
package com.example.fitbot.processing;
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
import com.example.fitbot.util.server.WebSocket;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -17,9 +19,14 @@ public class MotionInputStream extends InputStream {
|
||||
*/
|
||||
public static MotionInputStream startListening()
|
||||
{
|
||||
// Create server
|
||||
|
||||
// Create socket server
|
||||
WebSocket socket = WebSocket.createServer(80);
|
||||
|
||||
// Check if the socket
|
||||
if ( socket != null )
|
||||
{
|
||||
socket.startListening();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -0,0 +1,4 @@
|
||||
package com.example.fitbot.util.processing;
|
||||
|
||||
public class MotionProcessor {
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package com.example.fitbot.util.server;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Interface for handling WebSocket events.
|
||||
*/
|
||||
public interface IWebSocketHandler {
|
||||
|
||||
// Function for handling the connection of the WebSocket.
|
||||
default void onConnected(Socket socket) {}
|
||||
default void onDisconnected(Socket socket) {}
|
||||
default void onMessageReceived(String message) {}
|
||||
default void onError(Socket socket, String error) {}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
package com.example.fitbot.util.server;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class WebSocket {
|
||||
|
||||
private ServerSocket serverSocket;
|
||||
private WebSocketConnectionHandler connectionHandler;
|
||||
private final Set<Socket> clients = Collections.synchronizedSet(new HashSet<>());
|
||||
protected IWebSocketHandler eventHandler = new IWebSocketHandler() {}; // NO-OP event handler.
|
||||
|
||||
/**
|
||||
* Constructor for creating a new WebSocket server.
|
||||
*/
|
||||
private WebSocket() {}
|
||||
|
||||
/**
|
||||
* Function for creating a new WebSocket server given the provided port.
|
||||
* @param port The port to configure the server to.
|
||||
* @return A WebSocket connection, or null if something went wrong.
|
||||
*/
|
||||
public static @Nullable WebSocket createServer(int port) {
|
||||
try {
|
||||
WebSocket socket = new WebSocket();
|
||||
socket.serverSocket = new ServerSocket(port);
|
||||
return socket;
|
||||
} catch (IOException error)
|
||||
{
|
||||
String cause = error.getMessage() == null ? "Unknown reason" : error.getMessage();
|
||||
Log.e("WebSocket -- Creating new WebSocket server", cause);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for listening for incoming connections.
|
||||
*/
|
||||
public void startListening() {
|
||||
this.connectionHandler = new WebSocketConnectionHandler(this);
|
||||
this.connectionHandler.listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for getting the ServerSocket connection
|
||||
* @return The ServerSocket connection.
|
||||
*/
|
||||
public ServerSocket getSocket() {
|
||||
return this.serverSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for checking whether this WebSocket connection is connected.
|
||||
* @return The connection status of the WebSocket.
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
return !this.serverSocket.isClosed();
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
package com.example.fitbot.util.server;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class WebSocketConnectionHandler implements Runnable {
|
||||
|
||||
private final WebSocket theSocket;
|
||||
private Thread thread;
|
||||
|
||||
/**
|
||||
* Constructor for WebSocketConnectionHandler.
|
||||
* This class handles all new incoming Socket connections.
|
||||
* @param webSocket The socket to check for new connections.
|
||||
*/
|
||||
protected WebSocketConnectionHandler(WebSocket webSocket) {
|
||||
this.theSocket = webSocket;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@Override
|
||||
public void run() {
|
||||
while (theSocket.isConnected()) {
|
||||
try {
|
||||
Socket newSocket = this.theSocket.getSocket().accept();
|
||||
this.theSocket.eventHandler.onConnected(newSocket);
|
||||
|
||||
Scanner scanner = new Scanner(newSocket.getInputStream(), "UTF-8");
|
||||
String data = scanner.useDelimiter("\\r\\n\\r\\n").next();
|
||||
Matcher header = Pattern.compile("^GET").matcher(data);
|
||||
|
||||
// Check if the header contains the GET keyword
|
||||
// If this is the case, upgrade the HTTP connection to WebSocket.
|
||||
if (header.find()) {
|
||||
Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
|
||||
match.find();
|
||||
|
||||
String SECAccept = Base64.getEncoder().encodeToString(
|
||||
MessageDigest.getInstance("SHA-1").digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
byte[] response = (
|
||||
"HTTP/1.1 101 Switching Protocols\r\n" +
|
||||
"Connection: Upgrade\r\n" +
|
||||
"Upgrade: websocket\r\n" +
|
||||
"Sec-WebSocket-Accept: " +
|
||||
SECAccept + "\r\n\r\n").getBytes(StandardCharsets.UTF_8);
|
||||
newSocket.getOutputStream().write(response, 0, response.length);
|
||||
|
||||
// TODO: Read data from socket and provide in onMessageReceived.
|
||||
|
||||
}
|
||||
|
||||
} catch (IOException | NoSuchAlgorithmException error) {
|
||||
String reason = error.getMessage() == null ? "Unknown reason" : error.getMessage();
|
||||
Log.e("WebSocketConnectionHandler", "Error listening to Socket connections: " + reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for checking whether the connection handler is actively listening.
|
||||
* @return Whether or not it's listening.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return this.thread.isAlive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for listening to all new incoming socket connections.
|
||||
*/
|
||||
public void listen() {
|
||||
this.thread = new Thread(this);
|
||||
this.thread.start();
|
||||
Log.i("WebSocketConnectionHandler", "Listening started.");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user