begin websocket api

This commit is contained in:
lucas lelievre
2022-03-31 16:00:13 +02:00
parent 38b8e65d53
commit 281810dfbb
17 changed files with 188 additions and 8 deletions

View File

@@ -21,9 +21,9 @@ javadoc.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
if (JavaVersion.current().isJava9Compatible()) {
options.release = 8
}
// if (JavaVersion.current().isJava9Compatible()) {
// options.release = 8
// }
}
tasks.withType(Test) {
systemProperty('file.encoding', 'UTF-8')
@@ -42,6 +42,9 @@ allprojects {
dependencies {
implementation project(':slime-java-commons')
implementation project(":slimevr-protocol")
implementation group: 'com.google.flatbuffers', name: 'flatbuffers-java', version: '2.0.3'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'org.apache.commons:commons-math3:3.6.1'

1
log_last.log.1 Normal file
View File

@@ -0,0 +1 @@
2022-03-24 21:58:25 [SEVERE] SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.

0
log_last.log.lck Normal file
View File

1
log_main.log.1 Normal file
View File

@@ -0,0 +1 @@
2022-03-24 21:58:25 [SEVERE] SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.

0
log_main.log.lck Normal file
View File

View File

View File

@@ -0,0 +1 @@
2022-03-24 21:58:25 [SEVERE] SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.

View File

View File

View File

View File

@@ -9,3 +9,7 @@
rootProject.name = 'SlimeVR Server'
include ':slime-java-commons'
include ':slimevr-protocol'
project(':slimevr-protocol').projectDir = new File('slimevr_protocol/protocol/java')

1
slimevr_protocol Submodule

Submodule slimevr_protocol added at 5021544854

View File

@@ -6,6 +6,7 @@ import java.net.ServerSocket;
import javax.swing.JOptionPane;
import dev.slimevr.websocketapi.WebsocketAPI;
import org.apache.commons.lang3.JavaVersion;
import org.apache.commons.lang3.SystemUtils;
@@ -41,6 +42,7 @@ public class Main {
new ServerSocket(6969).close();
new ServerSocket(35903).close();
new ServerSocket(21110).close();
new ServerSocket(21111).close();
} catch (IOException e) {
LogManager.log.severe("SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.");
JOptionPane.showMessageDialog(null, "SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.", "SlimeVR: Ports are busy", JOptionPane.ERROR_MESSAGE);
@@ -51,7 +53,8 @@ public class Main {
vrServer = new VRServer();
vrServer.start();
new Keybinding(vrServer);
new VRServerGUI(vrServer);
new WebsocketAPI(vrServer).start();
// new VRServerGUI(vrServer);
} catch(Throwable e) {
e.printStackTrace();
try {

View File

@@ -17,7 +17,6 @@ import java.util.function.Consumer;
import dev.slimevr.bridge.Bridge;
import dev.slimevr.platform.windows.WindowsNamedPipeBridge;
import dev.slimevr.platform.windows.WindowsSteamVRPipeInputBridge;
import dev.slimevr.bridge.VMCBridge;
import dev.slimevr.bridge.WebSocketVRBridge;
import dev.slimevr.util.ann.VRServerThread;
@@ -75,7 +74,7 @@ public class VRServer extends Thread {
WindowsNamedPipeBridge feederBridge = new WindowsNamedPipeBridge(null, "steamvr_feeder", "SteamVR Feeder Bridge", "\\\\.\\pipe\\SlimeVRInput", new FastList<ShareableTracker>());
tasks.add(() -> feederBridge.startBridge());
bridges.add(feederBridge);
}
// Create WebSocket server
@@ -215,7 +214,7 @@ public class VRServer extends Thread {
public void run() {
trackersServer.start();
while(true) {
//final long start = System.currentTimeMillis();
// final long start = System.currentTimeMillis();
do {
Runnable task = tasks.poll();
if(task == null)
@@ -232,7 +231,7 @@ public class VRServer extends Thread {
humanPoseProcessor.update();
for(int i = 0; i < bridges.size(); ++i)
bridges.get(i).dataWrite();
//final long time = System.currentTimeMillis() - start;
// final long time = System.currentTimeMillis() - start;
try {
Thread.sleep(1); // 1000Hz
} catch(InterruptedException e) {

View File

@@ -6,6 +6,7 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import dev.slimevr.bridge.Bridge;
import org.java_websocket.WebSocket;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;

View File

@@ -0,0 +1,7 @@
package dev.slimevr.websocketapi;
public class APIApplication {
public int applicationType;
}

View File

@@ -0,0 +1,159 @@
package dev.slimevr.websocketapi;
import com.google.flatbuffers.FlatBufferBuilder;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import dev.slimevr.VRServer;
import dev.slimevr.vr.trackers.IMUTracker;
import dev.slimevr.vr.trackers.ReferenceAdjustedTracker;
import dev.slimevr.vr.trackers.Tracker;
import io.eiren.util.ann.ThreadSafe;
import io.eiren.util.logging.LogManager;
import org.java_websocket.WebSocket;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import slimevr_protocol.datatypes.Quat;
import slimevr_protocol.datatypes.Vec3f;
import slimevr_protocol.server.*;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
public class WebsocketAPI extends WebSocketServer {
public VRServer server;
private final HashMap<Integer, APIApplication> applications;
private long lastMillis = 0;
public WebsocketAPI(VRServer server) {
super(new InetSocketAddress(21111), Collections.<Draft>singletonList(new Draft_6455()));
this.server = server;
this.applications = new HashMap<>();
System.out.println("INIT");
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
LogManager.log.info("[WebSocketAPI] New connection from: " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
LogManager.log.info("[WebSocketAPI] Disconnected: " + conn.getRemoteSocketAddress().getAddress().getHostAddress() + ", (" + code + ") " + reason + ". Remote: " + remote);
this.applications.remove(conn.hashCode());
}
@Override
public void onMessage(WebSocket conn, String message) {}
@Override
public void onMessage(WebSocket conn, ByteBuffer message) {
InboundPacket inboundPacket = InboundPacket.getRootAsInboundPacket(message);
APIApplication application = this.applications.get(conn.hashCode());
try {
switch (inboundPacket.packetType()) {
case InboundUnion.HandshakeRequest: {
HandshakeRequest req = (HandshakeRequest) inboundPacket.packet(new HandshakeRequest());
if (req != null) this.onHandshakeRequest(conn, req);
break;
}
default:
LogManager.log.warning("[WebSocketAPI] Received unknown packet type: " + inboundPacket.packetType());
}
} catch (Exception e) {
LogManager.log.severe("[WebSocketAPI] Failed to parse packet: " + inboundPacket.packetType(), e);
}
}
public void onHandshakeRequest(WebSocket con, HandshakeRequest req) {
APIApplication app = new APIApplication();
app.applicationType = req.applicationType();
this.applications.put(con.hashCode(), app);
}
@ThreadSafe
public void updateTrackersList() {
if (System.currentTimeMillis() - lastMillis <= 100) {
return;
}
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
int[] trackersIds = new int[this.server.getTrackersCount()];
for (int index = 0; index < this.server.getTrackersCount(); index++) {
Tracker tracker = this.server.getAllTrackers().get(index);
if(tracker instanceof ReferenceAdjustedTracker)
tracker = ((ReferenceAdjustedTracker<? extends Tracker>) tracker).getTracker();
int trackerName = fbb.createString(tracker.getName());
Vector3f pos3f = new Vector3f();
Quaternion quatRot = new Quaternion();
tracker.getPosition(pos3f);
tracker.getRotation(quatRot);
DeviceStatus.startDeviceStatus(fbb);
DeviceStatus.addName(fbb, trackerName);
DeviceStatus.addPosition(fbb, Vec3f.createVec3f(fbb, pos3f.x, pos3f.y, pos3f.z));
DeviceStatus.addRotation(fbb, Quat.createQuat(fbb, quatRot.getX(), quatRot.getY(), quatRot.getZ(), quatRot.getW()));
if (tracker instanceof IMUTracker) {
IMUTracker imu = (IMUTracker) tracker;
// put back to 0 - 256 so we can fit it in a byte instead of float
DeviceStatus.addBattery(fbb, (int)(imu.getBatteryLevel() * 256));
DeviceStatus.addPing(fbb, imu.ping);
DeviceStatus.addSignal(fbb, imu.signalStrength);
DeviceStatus.addTps(fbb, (int)Math.floor(imu.getTPS()));
}
trackersIds[index] = DeviceStatus.endDeviceStatus(fbb);
}
int trackers = TrackersList.createTrackersVector(fbb, trackersIds);
TrackersList.startTrackersList(fbb);
TrackersList.addTrackers(fbb, trackers);
int list = TrackersList.endTrackersList(fbb);
int outbound = OutboundPacket.createOutboundPacket(fbb, 0, false, OutboundUnion.TrackersList, list);
fbb.finish(outbound);
ByteBuffer buf = fbb.dataBuffer();
this.sendToApps(buf);
lastMillis = System.currentTimeMillis();
}
public void sendToApps(ByteBuffer buf) {
this.getConnections()
.stream()
.filter((conn) -> this.applications.containsKey(conn.hashCode()))
.forEach((conn) -> conn.send(buf));
}
@Override
public void onError(WebSocket conn, Exception ex) {
ex.printStackTrace();
}
@Override
public void onStart() {
LogManager.log.info("[WebSocketAPI] Web Socket API started on port " + getPort());
setConnectionLostTimeout(0);
this.server.addOnTick(this::updateTrackersList);
}
}