Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@
import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceFeatureException;
import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage;
import io.github.blackspherefollower.buttplug4j.protocol.messages.InputReading;
import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient;
import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper;
import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import java.net.URI;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

public class ButtplugWSClientMockTest {

@Test
public void TestConnect() throws Exception {
try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) {
try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) {
Thread.sleep(500);
WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B");
Thread.sleep(500);
Expand Down Expand Up @@ -49,9 +50,8 @@ public void TestConnect() throws Exception {
}

@Test
@Disabled("See https://github.com/buttplugio/buttplug/issues/801")
public void TestBattery() throws Exception {
try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) {
try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) {
Thread.sleep(500);
WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B");
Thread.sleep(500);
Expand All @@ -65,9 +65,9 @@ public void TestBattery() throws Exception {
for (ButtplugClientDevice dev : client.getDevices()) {
for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) {
if (feat.HasBattery()) {
ButtplugMessage res = feat.ReadBattery().get();
if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) {
InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData();
ButtplugMessage res = feat.ReadBattery().get(2, TimeUnit.SECONDS);
if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.Battery) {
InputReading.Battery reading = (InputReading.Battery) ((InputReading) res).getData();
int battery = reading.getValue();
System.out.println("Battery is " + battery);
assertTrue(battery >= 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import javax.websocket.Session;
import javax.websocket.server.ServerEndpointConfig;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand All @@ -32,7 +31,7 @@ public void TestConnect() throws Exception {
ButtplugClientWSServerExample server = new ButtplugClientWSServerExample(lport, testDone);
Thread.sleep(500);

try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper(lport) ) {
try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper(lport)) {
Thread.sleep(500);
WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B");
testDone.get(10, TimeUnit.SECONDS);
Expand Down Expand Up @@ -90,8 +89,8 @@ public void onConnected(ButtplugClient client) {

firstDevice.get(5, TimeUnit.SECONDS);
for (ButtplugClientDevice dev : client.getDevices()) {
for(ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) {
if( feat.HasVibrate() ) {
for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) {
if (feat.HasVibrate()) {
feat.VibrateFloat(0.5F).get();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDevice;
import io.github.blackspherefollower.buttplug4j.client.ButtplugClientDeviceFeature;
import io.github.blackspherefollower.buttplug4j.client.ButtplugDeviceFeatureException;
import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient;
import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper;
import io.github.blackspherefollower.buttplug4j.protocol.ButtplugMessage;
import io.github.blackspherefollower.buttplug4j.protocol.messages.InputReading;

import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper;
import io.github.blackspherefollower.buttplug4j.utils.test.WSDMClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

Expand All @@ -22,7 +20,7 @@ public class ButtplugClientWSJettyClientTest {

@Test
public void TestConnect() throws Exception {
try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) {
try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) {
Thread.sleep(500);
WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B");
Thread.sleep(500);
Expand Down Expand Up @@ -55,9 +53,8 @@ public void TestConnect() throws Exception {
}

@Test
@Disabled("See https://github.com/buttplugio/buttplug/issues/801")
public void TestBattery() throws Exception {
try(IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper() ) {
try (IntifaceEngineWrapper wrapper = new IntifaceEngineWrapper()) {
Thread.sleep(500);
WSDMClient wsdev = new WSDMClient(new URI("ws://localhost:" + wrapper.dport), "LVS-Fake", "A9816725B");
Thread.sleep(500);
Expand All @@ -71,9 +68,9 @@ public void TestBattery() throws Exception {
for (ButtplugClientDevice dev : client.getDevices()) {
for (ButtplugClientDeviceFeature feat : dev.getDeviceFeatures().values()) {
if (feat.HasBattery()) {
ButtplugMessage res = feat.ReadBattery().get();
if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.BatteryData) {
InputReading.BatteryData reading = (InputReading.BatteryData) ((InputReading) res).getData();
ButtplugMessage res = feat.ReadBattery().get(2, TimeUnit.SECONDS);
if (res instanceof InputReading && ((InputReading) res).getData() instanceof InputReading.Battery) {
InputReading.Battery reading = (InputReading.Battery) ((InputReading) res).getData();
int battery = reading.getValue();
System.out.println("Battery is " + battery);
assertTrue(battery >= 0);
Expand Down
3 changes: 2 additions & 1 deletion buttplug4j.utils.mdns/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ repositories {
}

dependencies {
api 'org.jmdns:jmdns:3.6.1'
api 'org.jmdns:jmdns:3.6.3'
api 'org.slf4j:slf4j-simple:2.0.17'
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
testImplementation project(':buttplug4j.utils.test')
testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.13.4'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.13.4'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,51 @@
import javax.jmdns.JmmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceTypeListener;
import java.io.Closeable;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

public final class ButtplugDiscover implements ServiceListener {
public final class ButtplugDiscover implements ServiceListener, Closeable {
private final ConcurrentHashMap<String, ConcurrentSkipListSet<URI>> servers = new ConcurrentHashMap<>();
private final JmmDNS jmmdns;
private DiscovereyEventHandler discovereyEventHandler = null;

public ButtplugDiscover(DiscovereyEventHandler discovereyEventHandler) {
this.discovereyEventHandler = discovereyEventHandler;
JmmDNS jmmdns = JmmDNS.Factory.getInstance();
jmmdns = JmmDNS.Factory.getInstance();
jmmdns.addServiceListener("_intiface_engine._tcp.local.", this);
}
try {
jmmdns.addServiceTypeListener(new ServiceTypeListener() {
@Override
public void serviceTypeAdded(ServiceEvent serviceEvent) {
System.err.println("Added service type " + serviceEvent.getType());
}

public ButtplugDiscover() {
JmmDNS jmmdns = JmmDNS.Factory.getInstance();
jmmdns.addServiceListener("_intiface_engine._tcp.local.", this);
}
@Override
public void subTypeForServiceTypeAdded(ServiceEvent serviceEvent) {
System.err.println("Added sub type " + serviceEvent.getType());

public void setDiscovereyEventHandler(DiscovereyEventHandler discovereyEventHandler) {
this.discovereyEventHandler = discovereyEventHandler;
}
});
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void serviceAdded(ServiceEvent event) {
System.err.println("Added " + event.getName() + " " + event.getInfo().toString() + " " + event.getType());
}

@Override
public void serviceRemoved(ServiceEvent event) {
System.err.println("Removed " + event.getName() + " " + event.getInfo().toString() + " " + event.getType());
servers.remove(event.getInfo().getName());
if (discovereyEventHandler != null) {
discovereyEventHandler.LostButtplug(event.getInfo().getName());
Expand All @@ -43,6 +56,7 @@ public void serviceRemoved(ServiceEvent event) {

@Override
public void serviceResolved(ServiceEvent event) {
System.err.println("Resolved " + event.getName() + " " + event.getInfo().toString() + " " + event.getType());

ConcurrentSkipListSet<URI> set = new ConcurrentSkipListSet<>();
for (Inet4Address addr : event.getInfo().getInet4Addresses()) {
Expand All @@ -68,6 +82,11 @@ public ConcurrentHashMap<String, ConcurrentSkipListSet<URI>> GetServers() {
return servers;
}

@Override
public void close() throws IOException {
jmmdns.close();
}

public interface DiscovereyEventHandler {
void FoundButtplug(String name, Set<URI> addresses);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
package io.github.blackspherefollower.buttplug4j.utils.mdns;

import io.github.blackspherefollower.buttplug4j.utils.test.IntifaceEngineWrapper;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ButtplugDiscoverTest {

@Disabled
@Disabled("Not able to get mDNS this working right now")
@Test
public void TestConnect() throws Exception {

ButtplugDiscover discover = new ButtplugDiscover(new ButtplugDiscover.DiscovereyEventHandler() {
@Override
public void FoundButtplug(String name, Set<URI> addresses) {
System.out.println("WOO, a buttplug appeared : " + name + " : " + String.join(", ", addresses.stream().map(uri -> uri.toString()).collect(Collectors.toList())));
}
CompletableFuture<Boolean> seen1 = new CompletableFuture<>();
CompletableFuture<Boolean> seen2 = new CompletableFuture<>();
CompletableFuture<Boolean> gone1 = new CompletableFuture<>();
CompletableFuture<Boolean> gone2 = new CompletableFuture<>();
try (
IntifaceEngineWrapper wrapper1 = new IntifaceEngineWrapper(new ArrayList<>(Arrays.asList("--broadcast-server-mdns")));
IntifaceEngineWrapper wrapper2 = new IntifaceEngineWrapper(new ArrayList<>(Arrays.asList("--broadcast-server-mdns", "--mdns-suffix", "test-intiface-2")));

ButtplugDiscover discover = new ButtplugDiscover(new ButtplugDiscover.DiscovereyEventHandler() {
@Override
public void FoundButtplug(String name, Set<URI> addresses) {
System.out.println("WOO, a buttplug appeared : " + name + " : " + String.join(", ", addresses.stream().map(uri -> uri.toString()).collect(Collectors.toList())));
}

@Override
public void LostButtplug(String name) {
System.out.println("Oh... a buttplug disappeared : " + name);
}
});
) {

assertTrue(seen1.get(2, TimeUnit.MINUTES));
assertTrue(seen2.get(15, TimeUnit.SECONDS));

@Override
public void LostButtplug(String name) {
System.out.println("Oh... a buttplug disappeared : " + name);
}
});
assertFalse(gone1.isDone());
wrapper1.close();
assertTrue(gone1.get(15, TimeUnit.SECONDS));

Thread.sleep(60000);
assertFalse(gone2.isDone());
wrapper2.close();
assertTrue(gone2.get(15, TimeUnit.SECONDS));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;

public class IntifaceEngineWrapper implements Closeable {

Expand All @@ -15,20 +17,28 @@ public IntifaceEngineWrapper() throws Exception {
cport = (int) (Math.random() * 63000) + 1025;
dport = (int) (Math.random() * 63000) + 1025;

setup(true);
setup(true, new ArrayList<String>());
}

public IntifaceEngineWrapper(int lport) throws Exception {
cport = lport;
dport = (int) (Math.random() * 63000) + 1025;

setup(false);
setup(false, new ArrayList<String>());
}

public IntifaceEngineWrapper(ArrayList<String> extraArgs) throws Exception {
cport = (int) (Math.random() * 63000) + 1025;
dport = (int) (Math.random() * 63000) + 1025;

setup(true, extraArgs);
}

public void setup(boolean listen) throws Exception {
try{
public void setup(boolean listen, ArrayList<String> extraArgs) throws Exception {
try {
Runtime.getRuntime().exec("intiface-engine --version").waitFor();
} catch (IOException e) {
org.junit.jupiter.api.Assumptions.abort( "intiface-engine not found, skipping tests");
org.junit.jupiter.api.Assumptions.abort("intiface-engine not found, skipping tests");
}

Path userConfig = Files.createTempFile("user-config_", ".json");
Expand All @@ -46,27 +56,28 @@ public void setup(boolean listen) throws Exception {
}
}

ProcessBuilder pb =
new ProcessBuilder("intiface-engine", listen ? "--websocket-port" : "--websocket-client-address", listen ? String.valueOf(cport) : ("ws://127.0.0.1:" + String.valueOf(cport) + "/bob"), "--use-device-websocket-server", "--user-device-config-file", userConfig.toAbsolutePath().toString(), "--device-websocket-server-port", String.valueOf(dport), "--log", "TRACE");
ArrayList<String> args = new ArrayList<>(Arrays.asList("intiface-engine", listen ? "--websocket-port" : "--websocket-client-address", listen ? String.valueOf(cport) : ("ws://127.0.0.1:" + String.valueOf(cport) + "/bob"), "--use-device-websocket-server", "--user-device-config-file", userConfig.toAbsolutePath().toString(), "--device-websocket-server-port", String.valueOf(dport), "--log", "TRACE", "--allow-v4-spec"));
args.addAll(extraArgs);
ProcessBuilder pb = new ProcessBuilder(args);

Path log = Files.createTempFile("intiface_", ".log");
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.appendTo(log.toFile()));
proc = pb.start();

Thread.sleep(500);
if( !proc.isAlive()) {
if (!proc.isAlive()) {
close();
org.junit.jupiter.api.Assumptions.abort( "intiface-engine not started, skipping tests");
org.junit.jupiter.api.Assumptions.abort("intiface-engine not started, skipping tests");
}
}

@Override
public void close() {
if(proc != null) {
if (proc != null) {
proc.destroyForcibly();
}
if(userConfig != null) {
if (userConfig != null) {
try {
Files.deleteIfExists(userConfig);
} catch (IOException ignore) {
Expand Down
4 changes: 2 additions & 2 deletions buttplug4j/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ repositories {
}

dependencies {
api 'com.fasterxml.jackson.core:jackson-annotations:2.19.2'
api 'com.fasterxml.jackson.core:jackson-databind:2.19.2'
api 'com.fasterxml.jackson.core:jackson-annotations:2.20.1'
api 'com.fasterxml.jackson.core:jackson-databind:2.20.1'
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
testImplementation 'dev.harrel:json-schema:1.8.2'
testImplementation 'org.mockito:mockito-core:5.20.0'
Expand Down
Loading
Loading