From ffe530dc94e0cb3cb8f3d7a012474324bd93d1a6 Mon Sep 17 00:00:00 2001 From: ImUrX Date: Thu, 15 Jun 2023 15:37:21 -0300 Subject: [PATCH] move bridges to desktop --- .../src/main/java/dev/slimevr/android/Main.kt | 2 +- server/build.gradle.kts | 64 ++++++++++++ server/core/build.gradle.kts | 60 +---------- .../src/main/java/dev/slimevr/VRServer.kt | 99 ++++--------------- .../hardware/magentometer/Magneto.java | 14 --- server/desktop/build.gradle.kts | 15 +-- .../src/main/java/dev/slimevr/desktop/Main.kt | 95 +++++++++++++++++- .../platform/linux/UnixSocketBridge.java | 18 +++- .../windows/WindowsNamedPipeBridge.java | 2 +- .../windows/WindowsNamedPipeVRBridge.java | 2 +- .../platform/windows/WindowsPipe.java | 2 +- server/{core => }/spotless.xml | 0 12 files changed, 207 insertions(+), 166 deletions(-) create mode 100644 server/build.gradle.kts delete mode 100644 server/core/src/main/java/dev/slimevr/hardware/magentometer/Magneto.java rename server/{core/src/main/java/dev/slimevr => desktop/src/main/java/dev/slimevr/desktop}/platform/linux/UnixSocketBridge.java (89%) rename server/{core/src/main/java/dev/slimevr => desktop/src/main/java/dev/slimevr/desktop}/platform/windows/WindowsNamedPipeBridge.java (99%) rename server/{core/src/main/java/dev/slimevr => desktop/src/main/java/dev/slimevr/desktop}/platform/windows/WindowsNamedPipeVRBridge.java (99%) rename server/{core/src/main/java/dev/slimevr => desktop/src/main/java/dev/slimevr/desktop}/platform/windows/WindowsPipe.java (92%) rename server/{core => }/spotless.xml (100%) diff --git a/server/android/src/main/java/dev/slimevr/android/Main.kt b/server/android/src/main/java/dev/slimevr/android/Main.kt index 61716f4c8..d73265049 100644 --- a/server/android/src/main/java/dev/slimevr/android/Main.kt +++ b/server/android/src/main/java/dev/slimevr/android/Main.kt @@ -45,7 +45,7 @@ fun main(activity: AppCompatActivity) { e1.printStackTrace() } try { - vrServer = VRServer(File(activity.filesDir, "vrconfig.yml").absolutePath) + vrServer = VRServer(configPath = File(activity.filesDir, "vrconfig.yml").absolutePath) vrServer.start() Keybinding(vrServer) vrServer.join() diff --git a/server/build.gradle.kts b/server/build.gradle.kts new file mode 100644 index 000000000..cb94b49ad --- /dev/null +++ b/server/build.gradle.kts @@ -0,0 +1,64 @@ +plugins { + id("com.diffplug.spotless") +} + +repositories { + mavenCentral() +} + +configure { + // optional: limit format enforcement to just the files changed by this feature branch + // ratchetFrom "origin/main" + + format("misc") { + // define the files to apply `misc` to + target("*.gradle", "*.md", ".gitignore") + + // define the steps to apply to those files + trimTrailingWhitespace() + endWithNewline() + indentWithTabs() + } + // format "yaml", { + // target "*.yml", "*.yaml", + + // trimTrailingWhitespace() + // endWithNewline() + // indentWithSpaces(2) // YAML cannot contain tabs: https://yaml.org/faq.html + // } + + // .editorconfig doesn't work so, manual override + // https://github.com/diffplug/spotless/issues/142 + val editorConfig = + mapOf( + "indent_size" to 4, + "indent_style" to "tab", +// "max_line_length" to 88, + "ktlint_experimental" to "enabled", + "ij_kotlin_packages_to_use_import_on_demand" to + "java.util.*,kotlin.math.*,dev.slimevr.autobone.errors.*,io.github.axisangles.ktmath.*,kotlinx.atomicfu.*", + "ij_kotlin_allow_trailing_comma" to true + ) + val ktlintVersion = "0.47.1" + kotlinGradle { + target("**/*.gradle.kts") // default target for kotlinGradle + ktlint(ktlintVersion) + .setUseExperimental(true) + .editorConfigOverride(editorConfig) + } + kotlin { + target("**/*.kt") + targetExclude("**/build/**/**.kt") + ktlint(ktlintVersion) + .setUseExperimental(true) + .editorConfigOverride(editorConfig) + } + java { + target("**/*.java") + targetExclude("**/BuildConfig.java") + + removeUnusedImports() + // Use eclipse JDT formatter + eclipse().configFile("spotless.xml") + } +} diff --git a/server/core/build.gradle.kts b/server/core/build.gradle.kts index 684bb0fee..130b80970 100644 --- a/server/core/build.gradle.kts +++ b/server/core/build.gradle.kts @@ -12,7 +12,6 @@ plugins { kotlin("jvm") kotlin("plugin.serialization") `java-library` - id("com.diffplug.spotless") } // FIXME: Please replace these to Java 11 as that's what they actually are @@ -74,11 +73,9 @@ dependencies { implementation("org.apache.commons:commons-lang3:3.12.0") implementation("org.apache.commons:commons-collections4:4.4") - implementation("net.java.dev.jna:jna:5.+") - implementation("net.java.dev.jna:jna-platform:5.+") implementation("com.illposed.osc:javaosc-core:0.8") implementation("com.fazecast:jSerialComm:2.+") - implementation("com.google.protobuf:protobuf-java:3.21.12") + api("com.google.protobuf:protobuf-java:3.21.12") implementation("org.java-websocket:Java-WebSocket:1.+") implementation("com.melloware:jintellitype:1.+") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") @@ -103,58 +100,3 @@ fun String.runCommand(currentWorkingDir: File = file("./")): String { } return String(byteOut.toByteArray()).trim() } - -configure { - // optional: limit format enforcement to just the files changed by this feature branch - // ratchetFrom "origin/main" - - format("misc") { - // define the files to apply `misc` to - target("*.gradle", "*.md", ".gitignore") - - // define the steps to apply to those files - trimTrailingWhitespace() - endWithNewline() - indentWithTabs() - } - // format "yaml", { - // target "*.yml", "*.yaml", - - // trimTrailingWhitespace() - // endWithNewline() - // indentWithSpaces(2) // YAML cannot contain tabs: https://yaml.org/faq.html - // } - - // .editorconfig doesn't work so, manual override - // https://github.com/diffplug/spotless/issues/142 - val editorConfig = - mapOf( - "indent_size" to 4, - "indent_style" to "tab", -// "max_line_length" to 88, - "ktlint_experimental" to "enabled", - "ij_kotlin_packages_to_use_import_on_demand" to - "java.util.*,kotlin.math.*,dev.slimevr.autobone.errors.*,io.github.axisangles.ktmath.*,kotlinx.atomicfu.*", - "ij_kotlin_allow_trailing_comma" to true - ) - val ktlintVersion = "0.47.1" - kotlinGradle { - target("*.gradle.kts") // default target for kotlinGradle - ktlint(ktlintVersion) - .setUseExperimental(true) - .editorConfigOverride(editorConfig) - } - kotlin { - targetExclude("build/**/**.kt") - ktlint(ktlintVersion) - .setUseExperimental(true) - .editorConfigOverride(editorConfig) - } - java { - targetExclude("**/BuildConfig.java") - - removeUnusedImports() - // Use eclipse JDT formatter - eclipse().configFile("spotless.xml") - } -} diff --git a/server/core/src/main/java/dev/slimevr/VRServer.kt b/server/core/src/main/java/dev/slimevr/VRServer.kt index 0611ab401..1c50a952a 100644 --- a/server/core/src/main/java/dev/slimevr/VRServer.kt +++ b/server/core/src/main/java/dev/slimevr/VRServer.kt @@ -9,8 +9,6 @@ import dev.slimevr.osc.OSCRouter import dev.slimevr.osc.VMCHandler import dev.slimevr.osc.VRCOSCHandler import dev.slimevr.platform.SteamVRBridge -import dev.slimevr.platform.linux.UnixSocketBridge -import dev.slimevr.platform.windows.WindowsNamedPipeBridge import dev.slimevr.posestreamer.BVHRecorder import dev.slimevr.protocol.ProtocolAPI import dev.slimevr.reset.ResetHandler @@ -26,19 +24,27 @@ import dev.slimevr.tracking.trackers.TrackerPosition import dev.slimevr.tracking.trackers.udp.TrackersUDPServer import dev.slimevr.util.ann.VRServerThread import dev.slimevr.websocketapi.WebSocketVRBridge -import io.eiren.util.OperatingSystem import io.eiren.util.ann.ThreadSafe import io.eiren.util.ann.ThreadSecure import io.eiren.util.collections.FastList import io.eiren.util.logging.LogManager import solarxr_protocol.datatypes.TrackerIdT -import java.nio.file.Paths import java.util.* import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.atomic.AtomicInteger import java.util.function.Consumer -class VRServer @JvmOverloads constructor(configPath: String? = "vrconfig.yml") : Thread("VRServer") { +typealias SteamBridgeProvider = ( + server: VRServer, + hmdTracker: Tracker, + computedTrackers: List, +) -> SteamVRBridge? + +class VRServer constructor( + driverBridgeProvider: SteamBridgeProvider = { _: VRServer, _: Tracker, _: List -> null }, + feederBridgeProvider: (VRServer) -> SteamVRBridge? = { _: VRServer -> null }, + configPath: String, +) : Thread("VRServer") { @JvmField val configManager: ConfigManager @@ -107,12 +113,9 @@ class VRServer @JvmOverloads constructor(configPath: String? = "vrconfig.yml") : "HMD", TrackerPosition.HEAD, null, - true, - true, - false, - false, - false, - true + hasPosition = true, + hasRotation = true, + isComputed = true ) humanPoseManager = HumanPoseManager(this) val computedTrackers = humanPoseManager.computedTrackers @@ -124,81 +127,19 @@ class VRServer @JvmOverloads constructor(configPath: String? = "vrconfig.yml") : trackerPort, "Sensors UDP server" ) { tracker: Tracker -> registerTracker(tracker) } - val driverBridge: SteamVRBridge? - if (OperatingSystem.getCurrentPlatform() == OperatingSystem.WINDOWS) { - // Create named pipe bridge for SteamVR driver - driverBridge = WindowsNamedPipeBridge( - this, - hmdTracker, - "steamvr", - "SteamVR Driver Bridge", - "\\\\.\\pipe\\SlimeVRDriver", - computedTrackers - ) + // Start bridges for SteamVR and Feeder + val driverBridge = driverBridgeProvider(this, hmdTracker, computedTrackers) + if (driverBridge != null) { tasks.add(Runnable { driverBridge.startBridge() }) bridges.add(driverBridge) - - // Create named pipe bridge for SteamVR input - // TODO: how do we want to handle HMD input from the feeder app? - val feederBridge = WindowsNamedPipeBridge( - this, - null, - "steamvr_feeder", - "SteamVR Feeder Bridge", - "\\\\.\\pipe\\SlimeVRInput", - FastList() - ) + } + val feederBridge = feederBridgeProvider(this) + if (feederBridge != null) { tasks.add(Runnable { feederBridge.startBridge() }) bridges.add(feederBridge) - } else if (OperatingSystem.getCurrentPlatform() == OperatingSystem.LINUX) { - var linuxBridge: SteamVRBridge? = null - try { - linuxBridge = UnixSocketBridge( - this, - hmdTracker, - "steamvr", - "SteamVR Driver Bridge", - Paths.get(OperatingSystem.getTempDirectory(), "SlimeVRDriver").toString(), - computedTrackers - ) - } catch (ex: Exception) { - LogManager.severe("Failed to initiate Unix socket, disabling driver bridge...", ex) - } - driverBridge = linuxBridge - if (driverBridge != null) { - tasks.add(Runnable { driverBridge.startBridge() }) - bridges.add(driverBridge) - } - try { - val feederBridge: SteamVRBridge = UnixSocketBridge( - this, - null, - "steamvr_feeder", - "SteamVR Feeder Bridge", - Paths.get(OperatingSystem.getTempDirectory(), "SlimeVRInput").toString(), - FastList() - ) - tasks.add(Runnable { feederBridge.startBridge() }) - bridges.add(feederBridge) - } catch (ex: Exception) { - LogManager.severe("Failed to initiate Unix socket, disabling feeder bridge...", ex) - } - } else { - driverBridge = null } - // Add shutdown hook - Runtime.getRuntime().addShutdownHook( - Thread { - try { - (driverBridge as? UnixSocketBridge)?.close() - } catch (e: Exception) { - throw RuntimeException(e) - } - } - ) - // Create WebSocket server val wsBridge = WebSocketVRBridge(hmdTracker, computedTrackers, this) tasks.add(Runnable { wsBridge.startBridge() }) diff --git a/server/core/src/main/java/dev/slimevr/hardware/magentometer/Magneto.java b/server/core/src/main/java/dev/slimevr/hardware/magentometer/Magneto.java deleted file mode 100644 index 0bb551b66..000000000 --- a/server/core/src/main/java/dev/slimevr/hardware/magentometer/Magneto.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slimevr.hardware.magentometer; - -import com.sun.jna.Library; -import com.sun.jna.Native; - - -public interface Magneto extends Library { - - Magneto INSTANCE = Native.load("MagnetoLib", Magneto.class); - - void calculate(double[] data, int nlines, double nxsrej, double hm, double[] B, double[] A_1); - - double calculateHnorm(double[] data, int nlines); -} diff --git a/server/desktop/build.gradle.kts b/server/desktop/build.gradle.kts index fb9c22850..c1b5613ac 100644 --- a/server/desktop/build.gradle.kts +++ b/server/desktop/build.gradle.kts @@ -64,9 +64,10 @@ dependencies { implementation("commons-cli:commons-cli:1.5.0") implementation("org.apache.commons:commons-lang3:3.12.0") + implementation("net.java.dev.jna:jna:5.+") + implementation("net.java.dev.jna:jna-platform:5.+") } - tasks.shadowJar { minimize { exclude(dependency("com.fazecast:jSerialComm:.*")) @@ -97,13 +98,15 @@ buildConfig { useKotlinOutput { topLevelConstants = true } packageName("dev.slimevr.desktop") - val gitVersionTag = grgit.describe(mapOf( - "tags" to true, - "abbrev" to 0, - )) + val gitVersionTag = grgit.describe( + mapOf( + "tags" to true, + "abbrev" to 0 + ) + ) val latestCommitTag = grgit.tag.list().find { it.name == gitVersionTag }!!.commit.abbreviatedId == grgit.head().abbreviatedId - val gitLatestVersionTag = if (latestCommitTag) { gitVersionTag} else { "" } + val gitLatestVersionTag = if (latestCommitTag) { gitVersionTag } else { "" } buildConfigField("String", "GIT_COMMIT_HASH", "\"${grgit.head().abbreviatedId}\"") buildConfigField("String", "GIT_VERSION_TAG", "\"${gitLatestVersionTag}\"") buildConfigField("boolean", "GIT_CLEAN", grgit.status().isClean.toString()) diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt index a9c553e1f..4f5200b8f 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt @@ -4,6 +4,12 @@ package dev.slimevr.desktop import dev.slimevr.Keybinding import dev.slimevr.VRServer +import dev.slimevr.desktop.platform.linux.UnixSocketBridge +import dev.slimevr.desktop.platform.windows.WindowsNamedPipeBridge +import dev.slimevr.platform.SteamVRBridge +import dev.slimevr.tracking.trackers.Tracker +import io.eiren.util.OperatingSystem +import io.eiren.util.collections.FastList import io.eiren.util.logging.LogManager import org.apache.commons.cli.CommandLine import org.apache.commons.cli.CommandLineParser @@ -15,6 +21,7 @@ import java.io.File import java.io.IOException import java.lang.System import java.net.ServerSocket +import java.nio.file.Paths import javax.swing.JOptionPane import kotlin.concurrent.thread import kotlin.system.exitProcess @@ -99,7 +106,7 @@ fun main(args: Array) { return } try { - val vrServer = VRServer() + val vrServer = VRServer(::provideSteamVRBridge, ::provideFeederBridge, "vrconfig.yml") vrServer.start() Keybinding(vrServer) val scanner = thread { @@ -119,3 +126,89 @@ fun main(args: Array) { exitProcess(1) } } + +fun provideSteamVRBridge( + server: VRServer, + hmdTracker: Tracker, + computedTrackers: List, +): SteamVRBridge? { + val driverBridge: SteamVRBridge? + if (OperatingSystem.getCurrentPlatform() == OperatingSystem.WINDOWS) { + // Create named pipe bridge for SteamVR driver + driverBridge = WindowsNamedPipeBridge( + server, + hmdTracker, + "steamvr", + "SteamVR Driver Bridge", + """\\.\pipe\SlimeVRDriver""", + computedTrackers + ) + } else if (OperatingSystem.getCurrentPlatform() == OperatingSystem.LINUX) { + var linuxBridge: SteamVRBridge? = null + try { + linuxBridge = UnixSocketBridge( + server, + hmdTracker, + "steamvr", + "SteamVR Driver Bridge", + Paths.get(OperatingSystem.getTempDirectory(), "SlimeVRDriver") + .toString(), + computedTrackers + ) + } catch (ex: Exception) { + LogManager.severe( + "Failed to initiate Unix socket, disabling driver bridge...", + ex + ) + } + driverBridge = linuxBridge + if (driverBridge != null) { + // Close the named socket on shutdown, or otherwise it's not going to get removed + Runtime.getRuntime().addShutdownHook( + Thread { + try { + (driverBridge as? UnixSocketBridge)?.close() + } catch (e: Exception) { + throw RuntimeException(e) + } + } + ) + } + } else { + driverBridge = null + } + + return driverBridge +} + +fun provideFeederBridge( + server: VRServer, +): SteamVRBridge? { + val feederBridge: SteamVRBridge? + if (OperatingSystem.getCurrentPlatform() == OperatingSystem.WINDOWS) { + // Create named pipe bridge for SteamVR input + // TODO: how do we want to handle HMD input from the feeder app? + feederBridge = WindowsNamedPipeBridge( + server, + null, + "steamvr_feeder", + "SteamVR Feeder Bridge", + """\\.\pipe\SlimeVRInput""", + FastList() + ) + } else if (OperatingSystem.getCurrentPlatform() == OperatingSystem.LINUX) { + feederBridge = UnixSocketBridge( + server, + null, + "steamvr_feeder", + "SteamVR Feeder Bridge", + Paths.get(OperatingSystem.getTempDirectory(), "SlimeVRInput") + .toString(), + FastList() + ) + } else { + feederBridge = null + } + + return feederBridge +} diff --git a/server/core/src/main/java/dev/slimevr/platform/linux/UnixSocketBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java similarity index 89% rename from server/core/src/main/java/dev/slimevr/platform/linux/UnixSocketBridge.java rename to server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java index 980547478..0a28b0b1e 100644 --- a/server/core/src/main/java/dev/slimevr/platform/linux/UnixSocketBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java @@ -1,4 +1,4 @@ -package dev.slimevr.platform.linux; +package dev.slimevr.desktop.platform.linux; import com.google.protobuf.InvalidProtocolBufferException; import dev.slimevr.VRServer; @@ -9,7 +9,10 @@ import dev.slimevr.tracking.trackers.Tracker; import io.eiren.util.ann.ThreadSafe; import io.eiren.util.logging.LogManager; +import java.io.File; import java.io.IOException; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.ServerSocketChannel; @@ -21,6 +24,7 @@ import java.util.List; public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { public final String socketPath; + public final UnixDomainSocketAddress socketAddress; private final ByteBuffer dst = ByteBuffer.allocate(2048); private final ByteBuffer src = ByteBuffer.allocate(2048).order(ByteOrder.LITTLE_ENDIAN); @@ -39,8 +43,13 @@ public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { ) { super(server, hmd, "Named socket thread", bridgeName, bridgeSettingsKey, shareableTrackers); this.socketPath = socketPath; + this.socketAddress = UnixDomainSocketAddress.of(socketPath); - throw new RuntimeException("Unix socket cannot be run on Android."); + File socketFile = new File(socketPath); + if (socketFile.exists()) { + throw new RuntimeException(socketPath + " socket already exists."); + } + socketFile.deleteOnExit(); } @Override @@ -218,7 +227,10 @@ public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { } private ServerSocketChannel createSocket() throws IOException { - return null; + ServerSocketChannel server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(this.socketAddress); + LogManager.info("[" + bridgeName + "] Socket " + this.socketPath + " created"); + return server; } @Override diff --git a/server/core/src/main/java/dev/slimevr/platform/windows/WindowsNamedPipeBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java similarity index 99% rename from server/core/src/main/java/dev/slimevr/platform/windows/WindowsNamedPipeBridge.java rename to server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java index b45813aba..520beb9c1 100644 --- a/server/core/src/main/java/dev/slimevr/platform/windows/WindowsNamedPipeBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java @@ -1,4 +1,4 @@ -package dev.slimevr.platform.windows; +package dev.slimevr.desktop.platform.windows; import com.google.protobuf.CodedOutputStream; import com.google.protobuf.InvalidProtocolBufferException; diff --git a/server/core/src/main/java/dev/slimevr/platform/windows/WindowsNamedPipeVRBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeVRBridge.java similarity index 99% rename from server/core/src/main/java/dev/slimevr/platform/windows/WindowsNamedPipeVRBridge.java rename to server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeVRBridge.java index 8a85ceb72..ba57ff60d 100644 --- a/server/core/src/main/java/dev/slimevr/platform/windows/WindowsNamedPipeVRBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeVRBridge.java @@ -1,4 +1,4 @@ -package dev.slimevr.platform.windows; +package dev.slimevr.desktop.platform.windows; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinBase; diff --git a/server/core/src/main/java/dev/slimevr/platform/windows/WindowsPipe.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsPipe.java similarity index 92% rename from server/core/src/main/java/dev/slimevr/platform/windows/WindowsPipe.java rename to server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsPipe.java index 948ac5ab0..464321b65 100644 --- a/server/core/src/main/java/dev/slimevr/platform/windows/WindowsPipe.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsPipe.java @@ -1,4 +1,4 @@ -package dev.slimevr.platform.windows; +package dev.slimevr.desktop.platform.windows; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.WinNT.HANDLE; diff --git a/server/core/spotless.xml b/server/spotless.xml similarity index 100% rename from server/core/spotless.xml rename to server/spotless.xml