mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
begin websocket api
This commit is contained in:
@@ -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
1
log_last.log.1
Normal 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
0
log_last.log.lck
Normal file
1
log_main.log.1
Normal file
1
log_main.log.1
Normal 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
0
log_main.log.lck
Normal file
0
logs/log_2021-12-05.log.lck
Normal file
0
logs/log_2021-12-05.log.lck
Normal file
1
logs/log_2022-03-24.log.1
Normal file
1
logs/log_2022-03-24.log.1
Normal 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
logs/log_2022-03-24.log.lck
Normal file
0
logs/log_2022-03-24.log.lck
Normal file
0
logs/log_2022-03-30.log.lck
Normal file
0
logs/log_2022-03-30.log.lck
Normal file
0
logs/log_2022-03-31.log.lck
Normal file
0
logs/log_2022-03-31.log.lck
Normal 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
1
slimevr_protocol
Submodule
Submodule slimevr_protocol added at 5021544854
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.slimevr.websocketapi;
|
||||
|
||||
public class APIApplication {
|
||||
|
||||
public int applicationType;
|
||||
|
||||
}
|
||||
159
src/main/java/dev/slimevr/websocketapi/WebsocketAPI.java
Normal file
159
src/main/java/dev/slimevr/websocketapi/WebsocketAPI.java
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user