mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 19:04:49 +00:00
Changed pom to be correct.
Fixed SnowflakeGenerator not making unique ids. Changed naming for event implementation. Automated id getter for events. Added Error-Prone to all modules. Added parents to all modules. Added processors module.
This commit is contained in:
1
.idea/dictionaries/project.xml
generated
1
.idea/dictionaries/project.xml
generated
@@ -8,6 +8,7 @@
|
|||||||
<w>flushnl</w>
|
<w>flushnl</w>
|
||||||
<w>gaaf</w>
|
<w>gaaf</w>
|
||||||
<w>gamelist</w>
|
<w>gamelist</w>
|
||||||
|
<w>pism</w>
|
||||||
<w>playerlist</w>
|
<w>playerlist</w>
|
||||||
<w>tictactoe</w>
|
<w>tictactoe</w>
|
||||||
<w>toop</w>
|
<w>toop</w>
|
||||||
|
|||||||
4
.idea/encodings.xml
generated
4
.idea/encodings.xml
generated
@@ -1,12 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
|
<file url="file://$APPLICATION_HOME_DIR$/bin/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$APPLICATION_HOME_DIR$/bin/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/app/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/app/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/app/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/app/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/framework/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/framework/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/framework/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/framework/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/game/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/game/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/game/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/game/src/main/resources" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/processors/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/processors/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
33
app/pom.xml
33
app/pom.xml
@@ -1,8 +1,13 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
<groupId>org.toop</groupId>
|
<groupId>org.toop</groupId>
|
||||||
<artifactId>pism_app</artifactId>
|
<artifactId>pism</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>app</artifactId>
|
||||||
<version>0.1</version>
|
<version>0.1</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -24,18 +29,6 @@
|
|||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.10.1</version>
|
<version>2.10.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.toop</groupId>
|
|
||||||
<artifactId>pism_framework</artifactId>
|
|
||||||
<version>0.1</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.toop</groupId>
|
|
||||||
<artifactId>pism_game</artifactId>
|
|
||||||
<version>0.1</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
@@ -53,6 +46,18 @@
|
|||||||
<artifactId>error_prone_annotations</artifactId>
|
<artifactId>error_prone_annotations</artifactId>
|
||||||
<version>2.42.0</version>
|
<version>2.42.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.toop</groupId>
|
||||||
|
<artifactId>framework</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.toop</groupId>
|
||||||
|
<artifactId>game</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
@@ -152,7 +157,7 @@
|
|||||||
</arg>
|
</arg>
|
||||||
<!-- TODO-->
|
<!-- TODO-->
|
||||||
<!-- -Xep:RestrictedApi:ERROR \-->
|
<!-- -Xep:RestrictedApi:ERROR \-->
|
||||||
<!-- -XepOpt:RestrictedApi:annotation=org.toop.framework.annotations.TestsOnly \-->
|
<!-- -XepOpt:RestrictedApi:annotation=org.toop.annotations.TestsOnly \-->
|
||||||
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
||||||
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
||||||
<arg>-XDcompilePolicy=simple</arg>
|
<arg>-XDcompilePolicy=simple</arg>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import javafx.application.Platform;
|
|||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import jdk.jfr.Event;
|
|
||||||
import org.toop.app.layer.Layer;
|
import org.toop.app.layer.Layer;
|
||||||
import org.toop.app.layer.layers.MainLayer;
|
import org.toop.app.layer.layers.MainLayer;
|
||||||
import org.toop.app.layer.layers.QuitPopup;
|
import org.toop.app.layer.layers.QuitPopup;
|
||||||
|
import org.toop.framework.audio.VolumeControl;
|
||||||
import org.toop.framework.audio.events.AudioEvents;
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
import org.toop.framework.resource.ResourceManager;
|
import org.toop.framework.resource.ResourceManager;
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import org.toop.app.layer.Container;
|
|||||||
import org.toop.app.layer.Layer;
|
import org.toop.app.layer.Layer;
|
||||||
import org.toop.app.layer.NodeBuilder;
|
import org.toop.app.layer.NodeBuilder;
|
||||||
import org.toop.app.layer.containers.VerticalContainer;
|
import org.toop.app.layer.containers.VerticalContainer;
|
||||||
|
import org.toop.framework.audio.VolumeControl;
|
||||||
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
import org.toop.local.AppContext;
|
import org.toop.local.AppContext;
|
||||||
|
|
||||||
public final class MainLayer extends Layer {
|
public final class MainLayer extends Layer {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.toop.app.layer.Container;
|
|||||||
import org.toop.app.layer.NodeBuilder;
|
import org.toop.app.layer.NodeBuilder;
|
||||||
import org.toop.app.layer.Popup;
|
import org.toop.app.layer.Popup;
|
||||||
import org.toop.app.layer.containers.VerticalContainer;
|
import org.toop.app.layer.containers.VerticalContainer;
|
||||||
|
import org.toop.framework.audio.VolumeControl;
|
||||||
import org.toop.framework.audio.events.AudioEvents;
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
import org.toop.framework.resource.resources.SettingsAsset;
|
import org.toop.framework.resource.resources.SettingsAsset;
|
||||||
@@ -116,7 +117,7 @@ public final class OptionsPopup extends Popup {
|
|||||||
(volume) -> {
|
(volume) -> {
|
||||||
settings.setVolume(volume);
|
settings.setVolume(volume);
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(new AudioEvents.ChangeVolume(volume.doubleValue()))
|
.addPostEvent(new AudioEvents.ChangeVolume(volume.doubleValue(), VolumeControl.MASTERVOLUME))
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -128,7 +129,7 @@ public final class OptionsPopup extends Popup {
|
|||||||
(volume) -> {
|
(volume) -> {
|
||||||
settings.setFxVolume(volume);
|
settings.setFxVolume(volume);
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(new AudioEvents.ChangeFxVolume(volume.doubleValue()))
|
.addPostEvent(new AudioEvents.ChangeVolume(volume.doubleValue(), VolumeControl.FX))
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -140,7 +141,7 @@ public final class OptionsPopup extends Popup {
|
|||||||
(volume) -> {
|
(volume) -> {
|
||||||
settings.setMusicVolume(volume);
|
settings.setMusicVolume(volume);
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(new AudioEvents.ChangeMusicVolume(volume.doubleValue()))
|
.addPostEvent(new AudioEvents.ChangeVolume(volume.doubleValue(), VolumeControl.MUSIC))
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.toop.local;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import org.toop.app.App;
|
import org.toop.app.App;
|
||||||
|
import org.toop.framework.audio.VolumeControl;
|
||||||
import org.toop.framework.audio.events.AudioEvents;
|
import org.toop.framework.audio.events.AudioEvents;
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
import org.toop.framework.eventbus.EventFlow;
|
||||||
import org.toop.framework.resource.ResourceManager;
|
import org.toop.framework.resource.ResourceManager;
|
||||||
@@ -25,13 +26,13 @@ public class AppSettings {
|
|||||||
AppContext.setLocale(Locale.of(settingsData.locale));
|
AppContext.setLocale(Locale.of(settingsData.locale));
|
||||||
App.setFullscreen(settingsData.fullScreen);
|
App.setFullscreen(settingsData.fullScreen);
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.volume))
|
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.volume, VolumeControl.MASTERVOLUME))
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(new AudioEvents.ChangeFxVolume(settingsData.fxVolume))
|
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.fxVolume, VolumeControl.FX))
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(new AudioEvents.ChangeMusicVolume(settingsData.musicVolume))
|
.addPostEvent(new AudioEvents.ChangeVolume(settingsData.musicVolume, VolumeControl.MUSIC))
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
App.setStyle(settingsAsset.getTheme(), settingsAsset.getLayoutSize());
|
App.setStyle(settingsAsset.getTheme(), settingsAsset.getLayoutSize());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
<groupId>org.toop</groupId>
|
<groupId>org.toop</groupId>
|
||||||
<artifactId>pism_framework</artifactId>
|
<artifactId>pism</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>framework</artifactId>
|
||||||
<version>0.1</version>
|
<version>0.1</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -13,6 +18,14 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.toop</groupId>
|
||||||
|
<artifactId>processors</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.diffplug.spotless</groupId>
|
<groupId>com.diffplug.spotless</groupId>
|
||||||
<artifactId>spotless-maven-plugin</artifactId>
|
<artifactId>spotless-maven-plugin</artifactId>
|
||||||
@@ -165,13 +178,36 @@
|
|||||||
</arg>
|
</arg>
|
||||||
<!-- TODO-->
|
<!-- TODO-->
|
||||||
<!-- -Xep:RestrictedApi:ERROR \-->
|
<!-- -Xep:RestrictedApi:ERROR \-->
|
||||||
<!-- -XepOpt:RestrictedApi:annotation=org.toop.framework.annotations.TestsOnly \-->
|
<!-- -XepOpt:RestrictedApi:annotation=org.toop.annotations.TestsOnly \-->
|
||||||
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
||||||
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
||||||
<arg>-XDcompilePolicy=simple</arg>
|
<arg>-XDcompilePolicy=simple</arg>
|
||||||
<arg>--should-stop=ifError=FLOW</arg>
|
<arg>--should-stop=ifError=FLOW</arg>
|
||||||
</compilerArgs>
|
</compilerArgs>
|
||||||
|
<!-- <generatedSourcesDirectory>-->
|
||||||
|
<!-- ${project.build.directory}/generated-sources/-->
|
||||||
|
<!-- </generatedSourcesDirectory>-->
|
||||||
|
<!-- <annotationProcessors>-->
|
||||||
|
<!-- <annotationProcessor>-->
|
||||||
|
<!-- org.toop.processors.AutoResponseResultProcessor-->
|
||||||
|
<!-- </annotationProcessor>-->
|
||||||
|
<!-- </annotationProcessors>-->
|
||||||
<annotationProcessorPaths>
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.toop</groupId>
|
||||||
|
<artifactId>processors</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>com.google.auto.service</groupId>
|
||||||
|
<artifactId>auto-service</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>com.squareup</groupId>
|
||||||
|
<artifactId>javapoet</artifactId>
|
||||||
|
<version>1.13.0</version>
|
||||||
|
</path>
|
||||||
<path>
|
<path>
|
||||||
<groupId>com.google.errorprone</groupId>
|
<groupId>com.google.errorprone</groupId>
|
||||||
<artifactId>error_prone_core</artifactId>
|
<artifactId>error_prone_core</artifactId>
|
||||||
|
|||||||
@@ -9,31 +9,16 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
* A thread-safe, distributed unique ID generator following the Snowflake pattern.
|
* A thread-safe, distributed unique ID generator following the Snowflake pattern.
|
||||||
*
|
*
|
||||||
* <p>Each generated 64-bit ID encodes:
|
* <p>Each generated 64-bit ID encodes:
|
||||||
*
|
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>41-bit timestamp (milliseconds since custom epoch)
|
* <li>41-bit timestamp (milliseconds since custom epoch)
|
||||||
* <li>10-bit machine identifier
|
* <li>10-bit machine identifier
|
||||||
* <li>12-bit sequence number for IDs generated in the same millisecond
|
* <li>12-bit sequence number for IDs generated in the same millisecond
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>This implementation ensures:
|
* <p>This static implementation ensures global uniqueness per JVM process
|
||||||
*
|
* and can be accessed via {@link SnowflakeGenerator#nextId()}.
|
||||||
* <ul>
|
|
||||||
* <li>IDs are unique per machine.
|
|
||||||
* <li>Monotonicity within the same machine.
|
|
||||||
* <li>Safe concurrent generation via synchronized {@link #nextId()}.
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <p>Custom epoch is set to {@code 2025-01-01T00:00:00Z}.
|
|
||||||
*
|
|
||||||
* <p>Usage example:
|
|
||||||
*
|
|
||||||
* <pre>{@code
|
|
||||||
* SnowflakeGenerator generator = new SnowflakeGenerator();
|
|
||||||
* long id = generator.nextId();
|
|
||||||
* }</pre>
|
|
||||||
*/
|
*/
|
||||||
public class SnowflakeGenerator {
|
public final class SnowflakeGenerator {
|
||||||
|
|
||||||
/** Custom epoch in milliseconds (2025-01-01T00:00:00Z). */
|
/** Custom epoch in milliseconds (2025-01-01T00:00:00Z). */
|
||||||
private static final long EPOCH = Instant.parse("2025-01-01T00:00:00Z").toEpochMilli();
|
private static final long EPOCH = Instant.parse("2025-01-01T00:00:00Z").toEpochMilli();
|
||||||
@@ -43,25 +28,26 @@ public class SnowflakeGenerator {
|
|||||||
private static final long MACHINE_BITS = 10;
|
private static final long MACHINE_BITS = 10;
|
||||||
private static final long SEQUENCE_BITS = 12;
|
private static final long SEQUENCE_BITS = 12;
|
||||||
|
|
||||||
// Maximum values for each component
|
// Maximum values
|
||||||
private static final long MAX_MACHINE_ID = (1L << MACHINE_BITS) - 1;
|
private static final long MAX_MACHINE_ID = (1L << MACHINE_BITS) - 1;
|
||||||
private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
|
private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
|
||||||
private static final long MAX_TIMESTAMP = (1L << TIMESTAMP_BITS) - 1;
|
private static final long MAX_TIMESTAMP = (1L << TIMESTAMP_BITS) - 1;
|
||||||
|
|
||||||
// Bit shifts for composing the ID
|
// Bit shifts
|
||||||
private static final long MACHINE_SHIFT = SEQUENCE_BITS;
|
private static final long MACHINE_SHIFT = SEQUENCE_BITS;
|
||||||
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_BITS;
|
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_BITS;
|
||||||
|
|
||||||
/** Unique machine identifier derived from network interfaces (10 bits). */
|
/** Unique machine identifier derived from MAC addresses. */
|
||||||
private static final long machineId = SnowflakeGenerator.genMachineId();
|
private static final long MACHINE_ID = genMachineId();
|
||||||
|
|
||||||
private final AtomicLong lastTimestamp = new AtomicLong(-1L);
|
/** State variables (shared across all threads). */
|
||||||
private long sequence = 0L;
|
private static final AtomicLong LAST_TIMESTAMP = new AtomicLong(-1L);
|
||||||
|
private static long sequence = 0L;
|
||||||
|
|
||||||
/**
|
// Prevent instantiation
|
||||||
* Generates a 10-bit machine identifier based on MAC addresses of network interfaces. Falls
|
private SnowflakeGenerator() {}
|
||||||
* back to a random value if MAC cannot be determined.
|
|
||||||
*/
|
/** Generates a 10-bit machine identifier from MAC or random fallback. */
|
||||||
private static long genMachineId() {
|
private static long genMachineId() {
|
||||||
try {
|
try {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -77,48 +63,19 @@ public class SnowflakeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns a globally unique 64-bit Snowflake ID. */
|
||||||
* For testing: manually set the last generated timestamp.
|
public static synchronized long nextId() {
|
||||||
*
|
|
||||||
* @param l timestamp in milliseconds
|
|
||||||
*/
|
|
||||||
void setTime(long l) {
|
|
||||||
this.lastTimestamp.set(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a SnowflakeGenerator. Validates that the machine ID is within allowed range.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if machine ID is invalid
|
|
||||||
*/
|
|
||||||
public SnowflakeGenerator() {
|
|
||||||
if (machineId < 0 || machineId > MAX_MACHINE_ID) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Machine ID must be between 0 and " + MAX_MACHINE_ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the next unique ID.
|
|
||||||
*
|
|
||||||
* <p>If multiple IDs are generated in the same millisecond, a sequence number is incremented.
|
|
||||||
* If the sequence overflows, waits until the next millisecond.
|
|
||||||
*
|
|
||||||
* @return a unique 64-bit ID
|
|
||||||
* @throws IllegalStateException if clock moves backwards or timestamp exceeds 41-bit limit
|
|
||||||
*/
|
|
||||||
public synchronized long nextId() {
|
|
||||||
long currentTimestamp = timestamp();
|
long currentTimestamp = timestamp();
|
||||||
|
|
||||||
if (currentTimestamp < lastTimestamp.get()) {
|
if (currentTimestamp < LAST_TIMESTAMP.get()) {
|
||||||
throw new IllegalStateException("Clock moved backwards. Refusing to generate id.");
|
throw new IllegalStateException("Clock moved backwards. Refusing to generate ID.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTimestamp > MAX_TIMESTAMP) {
|
if (currentTimestamp > MAX_TIMESTAMP) {
|
||||||
throw new IllegalStateException("Timestamp bits overflow, Snowflake expired.");
|
throw new IllegalStateException("Timestamp bits overflow — Snowflake expired.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTimestamp == lastTimestamp.get()) {
|
if (currentTimestamp == LAST_TIMESTAMP.get()) {
|
||||||
sequence = (sequence + 1) & MAX_SEQUENCE;
|
sequence = (sequence + 1) & MAX_SEQUENCE;
|
||||||
if (sequence == 0) {
|
if (sequence == 0) {
|
||||||
currentTimestamp = waitNextMillis(currentTimestamp);
|
currentTimestamp = waitNextMillis(currentTimestamp);
|
||||||
@@ -127,29 +84,22 @@ public class SnowflakeGenerator {
|
|||||||
sequence = 0L;
|
sequence = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastTimestamp.set(currentTimestamp);
|
LAST_TIMESTAMP.set(currentTimestamp);
|
||||||
|
|
||||||
return ((currentTimestamp - EPOCH) << TIMESTAMP_SHIFT)
|
return ((currentTimestamp - EPOCH) << TIMESTAMP_SHIFT)
|
||||||
| (machineId << MACHINE_SHIFT)
|
| (MACHINE_ID << MACHINE_SHIFT)
|
||||||
| sequence;
|
| sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Waits until next millisecond if sequence exhausted. */
|
||||||
* Waits until the next millisecond if sequence overflows.
|
private static long waitNextMillis(long lastTimestamp) {
|
||||||
*
|
|
||||||
* @param lastTimestamp previous timestamp
|
|
||||||
* @return new timestamp
|
|
||||||
*/
|
|
||||||
private long waitNextMillis(long lastTimestamp) {
|
|
||||||
long ts = timestamp();
|
long ts = timestamp();
|
||||||
while (ts <= lastTimestamp) {
|
while (ts <= lastTimestamp) ts = timestamp();
|
||||||
ts = timestamp();
|
|
||||||
}
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns current system timestamp in milliseconds. */
|
/** Returns current timestamp in milliseconds. */
|
||||||
private long timestamp() {
|
private static long timestamp() {
|
||||||
return System.currentTimeMillis();
|
return System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,7 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
|||||||
.listen(this::handleStopSound)
|
.listen(this::handleStopSound)
|
||||||
.listen(this::handleMusicStart)
|
.listen(this::handleMusicStart)
|
||||||
.listen(this::handleVolumeChange)
|
.listen(this::handleVolumeChange)
|
||||||
.listen(this::handleFxVolumeChange)
|
|
||||||
.listen(this::handleMusicVolumeChange)
|
|
||||||
.listen(this::handleGetVolume)
|
.listen(this::handleGetVolume)
|
||||||
.listen(this::handleGetFxVolume)
|
|
||||||
.listen(this::handleGetMusicVolume)
|
|
||||||
.listen(AudioEvents.ClickButton.class, _ ->
|
.listen(AudioEvents.ClickButton.class, _ ->
|
||||||
soundEffectManager.play("medium-button-click.wav", false));
|
soundEffectManager.play("medium-button-click.wav", false));
|
||||||
|
|
||||||
@@ -57,41 +53,15 @@ public class AudioEventListener<T extends AudioResource, K extends AudioResource
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleVolumeChange(AudioEvents.ChangeVolume event) {
|
private void handleVolumeChange(AudioEvents.ChangeVolume event) {
|
||||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeControl.MASTERVOLUME);
|
this.audioVolumeManager.setVolume(event.newVolume() / 100, event.controlType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFxVolumeChange(AudioEvents.ChangeFxVolume event) {
|
private void handleGetVolume(AudioEvents.GetVolume event) {
|
||||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeControl.FX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleMusicVolumeChange(AudioEvents.ChangeMusicVolume event) {
|
|
||||||
this.audioVolumeManager.setVolume(event.newVolume() / 100, VolumeControl.MUSIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleGetVolume(AudioEvents.GetCurrentVolume event) {
|
|
||||||
new EventFlow()
|
new EventFlow()
|
||||||
.addPostEvent(
|
.addPostEvent(
|
||||||
new AudioEvents.GetCurrentVolumeResponse(
|
new AudioEvents.GetVolumeResponse(
|
||||||
audioVolumeManager.getVolume(VolumeControl.MASTERVOLUME),
|
audioVolumeManager.getVolume(event.controlType()),
|
||||||
event.snowflakeId()))
|
event.identifier()))
|
||||||
.asyncPostEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleGetFxVolume(AudioEvents.GetCurrentFxVolume event) {
|
|
||||||
new EventFlow()
|
|
||||||
.addPostEvent(
|
|
||||||
new AudioEvents.GetCurrentFxVolumeResponse(
|
|
||||||
audioVolumeManager.getVolume(VolumeControl.FX),
|
|
||||||
event.snowflakeId()))
|
|
||||||
.asyncPostEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleGetMusicVolume(AudioEvents.GetCurrentMusicVolume event) {
|
|
||||||
new EventFlow()
|
|
||||||
.addPostEvent(
|
|
||||||
new AudioEvents.GetCurrentMusicVolumeResponse(
|
|
||||||
audioVolumeManager.getVolume(VolumeControl.MUSIC),
|
|
||||||
event.snowflakeId()))
|
|
||||||
.asyncPostEvent();
|
.asyncPostEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import org.apache.logging.log4j.LogManager;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.toop.framework.dispatch.interfaces.Dispatcher;
|
import org.toop.framework.dispatch.interfaces.Dispatcher;
|
||||||
import org.toop.framework.dispatch.JavaFXDispatcher;
|
import org.toop.framework.dispatch.JavaFXDispatcher;
|
||||||
import org.toop.framework.annotations.TestsOnly;
|
import org.toop.annotations.TestsOnly;
|
||||||
import org.toop.framework.resource.ResourceManager;
|
import org.toop.framework.resource.ResourceManager;
|
||||||
import org.toop.framework.resource.resources.BaseResource;
|
import org.toop.framework.resource.resources.BaseResource;
|
||||||
import org.toop.framework.resource.types.AudioResource;
|
import org.toop.framework.resource.types.AudioResource;
|
||||||
|
|||||||
@@ -1,100 +1,32 @@
|
|||||||
package org.toop.framework.audio.events;
|
package org.toop.framework.audio.events;
|
||||||
|
|
||||||
import java.util.Map;
|
import org.toop.framework.audio.VolumeControl;
|
||||||
import org.toop.framework.eventbus.events.EventWithSnowflake;
|
import org.toop.framework.eventbus.events.*;
|
||||||
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
|
import org.toop.framework.eventbus.events.ResponseToUniqueEvent;
|
||||||
import org.toop.framework.eventbus.events.EventsBase;
|
import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
|
|
||||||
public class AudioEvents extends EventsBase {
|
public class AudioEvents extends EventsBase {
|
||||||
public record StopAudioManager() implements EventWithoutSnowflake {}
|
/** Stops the audio manager. */
|
||||||
|
public record StopAudioManager() implements GenericEvent {}
|
||||||
|
|
||||||
/** Starts playing a sound. */
|
/** Start playing a sound effect. */
|
||||||
public record PlayEffect(String fileName, boolean loop) implements EventWithoutSnowflake {}
|
public record PlayEffect(String fileName, boolean loop) implements GenericEvent {}
|
||||||
|
|
||||||
public record StopEffect(String fileName) implements EventWithoutSnowflake {}
|
/** Stop playing a sound effect. */
|
||||||
|
public record StopEffect(String fileName) implements GenericEvent {}
|
||||||
|
|
||||||
public record StartBackgroundMusic() implements EventWithoutSnowflake {}
|
/** Start background music. */
|
||||||
|
public record StartBackgroundMusic() implements GenericEvent {}
|
||||||
|
|
||||||
public record ChangeVolume(double newVolume) implements EventWithoutSnowflake {}
|
/** Change volume, choose type with {@link VolumeControl}. */
|
||||||
|
public record ChangeVolume(double newVolume, VolumeControl controlType) implements GenericEvent {}
|
||||||
|
|
||||||
public record ChangeFxVolume(double newVolume) implements EventWithoutSnowflake {}
|
/** Requests the desired volume by selecting it with {@link VolumeControl}. */
|
||||||
|
public record GetVolume(VolumeControl controlType, long identifier) implements UniqueEvent {}
|
||||||
|
|
||||||
public record ChangeMusicVolume(double newVolume) implements EventWithoutSnowflake {}
|
/** Response to GetVolume. */
|
||||||
|
public record GetVolumeResponse(double currentVolume, long identifier) implements ResponseToUniqueEvent {}
|
||||||
|
|
||||||
public record GetCurrentVolume(long snowflakeId) implements EventWithSnowflake {
|
/** Plays the predetermined sound for pressing a button. */
|
||||||
@Override
|
public record ClickButton() implements GenericEvent {}
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return snowflakeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record GetCurrentVolumeResponse(double currentVolume, long snowflakeId)
|
|
||||||
implements EventWithSnowflake {
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return snowflakeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record GetCurrentFxVolume(long snowflakeId) implements EventWithSnowflake {
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return this.snowflakeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record GetCurrentMusicVolume(long snowflakeId) implements EventWithSnowflake {
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return this.snowflakeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record GetCurrentFxVolumeResponse(double currentVolume, long snowflakeId)
|
|
||||||
implements EventWithSnowflake {
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return this.snowflakeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record GetCurrentMusicVolumeResponse(double currentVolume, long snowflakeId)
|
|
||||||
implements EventWithSnowflake {
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return this.snowflakeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record ClickButton() implements EventWithoutSnowflake {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import org.toop.framework.SnowflakeGenerator;
|
import org.toop.framework.SnowflakeGenerator;
|
||||||
import org.toop.framework.eventbus.events.EventType;
|
import org.toop.framework.eventbus.events.EventType;
|
||||||
import org.toop.framework.eventbus.events.EventWithSnowflake;
|
import org.toop.framework.eventbus.events.ResponseToUniqueEvent;
|
||||||
|
import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EventFlow is a utility class for creating, posting, and optionally subscribing to events in a
|
* EventFlow is a utility class for creating, posting, and optionally subscribing to events in a
|
||||||
* type-safe and chainable manner. It is designed to work with the {@link GlobalEventBus}.
|
* type-safe and chainable manner. It is designed to work with the {@link GlobalEventBus}.
|
||||||
*
|
*
|
||||||
* <p>This class supports automatic UUID assignment for {@link EventWithSnowflake} events, and
|
* <p>This class supports automatic UUID assignment for {@link UniqueEvent} events, and
|
||||||
* allows filtering subscribers so they only respond to events with a specific UUID. All
|
* allows filtering subscribers so they only respond to events with a specific UUID. All
|
||||||
* subscription methods are chainable, and you can configure automatic unsubscription after an event
|
* subscription methods are chainable, and you can configure automatic unsubscription after an event
|
||||||
* has been successfully handled.
|
* has been successfully handled.
|
||||||
@@ -30,7 +31,7 @@ public class EventFlow {
|
|||||||
/** Cache of constructor handles for event classes to avoid repeated reflection lookups. */
|
/** Cache of constructor handles for event classes to avoid repeated reflection lookups. */
|
||||||
private static final Map<Class<?>, MethodHandle> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
|
private static final Map<Class<?>, MethodHandle> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/** Automatically assigned UUID for {@link EventWithSnowflake} events. */
|
/** Automatically assigned UUID for {@link UniqueEvent} events. */
|
||||||
private long eventSnowflake = -1;
|
private long eventSnowflake = -1;
|
||||||
|
|
||||||
/** The event instance created by this publisher. */
|
/** The event instance created by this publisher. */
|
||||||
@@ -40,7 +41,7 @@ public class EventFlow {
|
|||||||
private final List<ListenerHandler> listeners = new ArrayList<>();
|
private final List<ListenerHandler> listeners = new ArrayList<>();
|
||||||
|
|
||||||
/** Holds the results returned from the subscribed event, if any. */
|
/** Holds the results returned from the subscribed event, if any. */
|
||||||
private Map<String, Object> result = null;
|
private Map<String, ?> result = null;
|
||||||
|
|
||||||
/** Empty constructor (event must be added via {@link #addPostEvent(Class, Object...)}). */
|
/** Empty constructor (event must be added via {@link #addPostEvent(Class, Object...)}). */
|
||||||
public EventFlow() {}
|
public EventFlow() {}
|
||||||
@@ -60,7 +61,7 @@ public class EventFlow {
|
|||||||
// Keep the old class+args version if needed
|
// Keep the old class+args version if needed
|
||||||
public <T extends EventType> EventFlow addPostEvent(Class<T> eventClass, Object... args) {
|
public <T extends EventType> EventFlow addPostEvent(Class<T> eventClass, Object... args) {
|
||||||
try {
|
try {
|
||||||
boolean isUuidEvent = EventWithSnowflake.class.isAssignableFrom(eventClass);
|
boolean isUuidEvent = UniqueEvent.class.isAssignableFrom(eventClass);
|
||||||
|
|
||||||
MethodHandle ctorHandle =
|
MethodHandle ctorHandle =
|
||||||
CONSTRUCTOR_CACHE.computeIfAbsent(
|
CONSTRUCTOR_CACHE.computeIfAbsent(
|
||||||
@@ -81,7 +82,7 @@ public class EventFlow {
|
|||||||
int expectedParamCount = ctorHandle.type().parameterCount();
|
int expectedParamCount = ctorHandle.type().parameterCount();
|
||||||
|
|
||||||
if (isUuidEvent && args.length < expectedParamCount) {
|
if (isUuidEvent && args.length < expectedParamCount) {
|
||||||
this.eventSnowflake = new SnowflakeGenerator().nextId();
|
this.eventSnowflake = SnowflakeGenerator.nextId();
|
||||||
finalArgs = new Object[args.length + 1];
|
finalArgs = new Object[args.length + 1];
|
||||||
System.arraycopy(args, 0, finalArgs, 0, args.length);
|
System.arraycopy(args, 0, finalArgs, 0, args.length);
|
||||||
finalArgs[args.length] = this.eventSnowflake;
|
finalArgs[args.length] = this.eventSnowflake;
|
||||||
@@ -100,13 +101,8 @@ public class EventFlow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public EventFlow addSnowflake() {
|
|
||||||
// this.eventSnowflake = new SnowflakeGenerator(1).nextId();
|
|
||||||
// return this;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/** Subscribe by ID: only fires if UUID matches this publisher's eventId. */
|
/** Subscribe by ID: only fires if UUID matches this publisher's eventId. */
|
||||||
public <TT extends EventWithSnowflake> EventFlow onResponse(
|
public <TT extends ResponseToUniqueEvent> EventFlow onResponse(
|
||||||
Class<TT> eventClass, Consumer<TT> action, boolean unsubscribeAfterSuccess) {
|
Class<TT> eventClass, Consumer<TT> action, boolean unsubscribeAfterSuccess) {
|
||||||
ListenerHandler[] listenerHolder = new ListenerHandler[1];
|
ListenerHandler[] listenerHolder = new ListenerHandler[1];
|
||||||
listenerHolder[0] =
|
listenerHolder[0] =
|
||||||
@@ -114,7 +110,7 @@ public class EventFlow {
|
|||||||
GlobalEventBus.subscribe(
|
GlobalEventBus.subscribe(
|
||||||
eventClass,
|
eventClass,
|
||||||
event -> {
|
event -> {
|
||||||
if (event.eventSnowflake() != this.eventSnowflake) return;
|
if (event.getIdentifier() != this.eventSnowflake) return;
|
||||||
|
|
||||||
action.accept(event);
|
action.accept(event);
|
||||||
|
|
||||||
@@ -130,22 +126,21 @@ public class EventFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Subscribe by ID: only fires if UUID matches this publisher's eventId. */
|
/** Subscribe by ID: only fires if UUID matches this publisher's eventId. */
|
||||||
public <TT extends EventWithSnowflake> EventFlow onResponse(
|
public <TT extends ResponseToUniqueEvent> EventFlow onResponse(Class<TT> eventClass, Consumer<TT> action) {
|
||||||
Class<TT> eventClass, Consumer<TT> action) {
|
|
||||||
return this.onResponse(eventClass, action, true);
|
return this.onResponse(eventClass, action, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Subscribe by ID without explicit class. */
|
/** Subscribe by ID without explicit class. */
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <TT extends EventWithSnowflake> EventFlow onResponse(
|
public <TT extends ResponseToUniqueEvent> EventFlow onResponse(
|
||||||
Consumer<TT> action, boolean unsubscribeAfterSuccess) {
|
Consumer<TT> action, boolean unsubscribeAfterSuccess) {
|
||||||
ListenerHandler[] listenerHolder = new ListenerHandler[1];
|
ListenerHandler[] listenerHolder = new ListenerHandler[1];
|
||||||
listenerHolder[0] =
|
listenerHolder[0] =
|
||||||
new ListenerHandler(
|
new ListenerHandler(
|
||||||
GlobalEventBus.subscribe(
|
GlobalEventBus.subscribe(
|
||||||
event -> {
|
event -> {
|
||||||
if (!(event instanceof EventWithSnowflake uuidEvent)) return;
|
if (!(event instanceof UniqueEvent uuidEvent)) return;
|
||||||
if (uuidEvent.eventSnowflake() == this.eventSnowflake) {
|
if (uuidEvent.getIdentifier() == this.eventSnowflake) {
|
||||||
try {
|
try {
|
||||||
TT typedEvent = (TT) uuidEvent;
|
TT typedEvent = (TT) uuidEvent;
|
||||||
action.accept(typedEvent);
|
action.accept(typedEvent);
|
||||||
@@ -159,7 +154,7 @@ public class EventFlow {
|
|||||||
throw new ClassCastException(
|
throw new ClassCastException(
|
||||||
"Cannot cast "
|
"Cannot cast "
|
||||||
+ event.getClass().getName()
|
+ event.getClass().getName()
|
||||||
+ " to EventWithSnowflake");
|
+ " to UniqueEvent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -167,7 +162,7 @@ public class EventFlow {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <TT extends EventWithSnowflake> EventFlow onResponse(Consumer<TT> action) {
|
public <TT extends ResponseToUniqueEvent> EventFlow onResponse(Consumer<TT> action) {
|
||||||
return this.onResponse(action, true);
|
return this.onResponse(action, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +209,7 @@ public class EventFlow {
|
|||||||
throw new ClassCastException(
|
throw new ClassCastException(
|
||||||
"Cannot cast "
|
"Cannot cast "
|
||||||
+ event.getClass().getName()
|
+ event.getClass().getName()
|
||||||
+ " to EventWithSnowflake");
|
+ " to UniqueEvent");
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
this.listeners.add(listenerHolder[0]);
|
this.listeners.add(listenerHolder[0]);
|
||||||
@@ -237,7 +232,13 @@ public class EventFlow {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getResult() {
|
private void clean() {
|
||||||
|
this.listeners.clear();
|
||||||
|
this.event = null;
|
||||||
|
this.result = null;
|
||||||
|
} // TODO
|
||||||
|
|
||||||
|
public Map<String, ?> getResult() {
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import org.toop.framework.eventbus.events.EventType;
|
import org.toop.framework.eventbus.events.EventType;
|
||||||
import org.toop.framework.eventbus.events.EventWithSnowflake;
|
import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GlobalEventBus backed by the LMAX Disruptor for ultra-low latency, high-throughput event
|
* GlobalEventBus backed by the LMAX Disruptor for ultra-low latency, high-throughput event
|
||||||
@@ -21,7 +21,7 @@ public final class GlobalEventBus {
|
|||||||
|
|
||||||
/** Map of event class to Snowflake-ID-specific listeners. */
|
/** Map of event class to Snowflake-ID-specific listeners. */
|
||||||
private static final Map<
|
private static final Map<
|
||||||
Class<?>, ConcurrentHashMap<Long, Consumer<? extends EventWithSnowflake>>>
|
Class<?>, ConcurrentHashMap<Long, Consumer<? extends UniqueEvent>>>
|
||||||
UUID_LISTENERS = new ConcurrentHashMap<>();
|
UUID_LISTENERS = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/** Disruptor ring buffer size (must be power of two). */
|
/** Disruptor ring buffer size (must be power of two). */
|
||||||
@@ -90,7 +90,7 @@ public final class GlobalEventBus {
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends EventWithSnowflake> void subscribeById(
|
public static <T extends UniqueEvent> void subscribeById(
|
||||||
Class<T> eventClass, long eventId, Consumer<T> listener) {
|
Class<T> eventClass, long eventId, Consumer<T> listener) {
|
||||||
UUID_LISTENERS
|
UUID_LISTENERS
|
||||||
.computeIfAbsent(eventClass, _ -> new ConcurrentHashMap<>())
|
.computeIfAbsent(eventClass, _ -> new ConcurrentHashMap<>())
|
||||||
@@ -101,9 +101,9 @@ public final class GlobalEventBus {
|
|||||||
LISTENERS.values().forEach(list -> list.remove(listener));
|
LISTENERS.values().forEach(list -> list.remove(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends EventWithSnowflake> void unsubscribeById(
|
public static <T extends UniqueEvent> void unsubscribeById(
|
||||||
Class<T> eventClass, long eventId) {
|
Class<T> eventClass, long eventId) {
|
||||||
Map<Long, Consumer<? extends EventWithSnowflake>> map = UUID_LISTENERS.get(eventClass);
|
Map<Long, Consumer<? extends UniqueEvent>> map = UUID_LISTENERS.get(eventClass);
|
||||||
if (map != null) map.remove(eventId);
|
if (map != null) map.remove(eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,11 +152,11 @@ public final class GlobalEventBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// snowflake listeners
|
// snowflake listeners
|
||||||
if (event instanceof EventWithSnowflake snowflakeEvent) {
|
if (event instanceof UniqueEvent snowflakeEvent) {
|
||||||
Map<Long, Consumer<? extends EventWithSnowflake>> map = UUID_LISTENERS.get(clazz);
|
Map<Long, Consumer<? extends UniqueEvent>> map = UUID_LISTENERS.get(clazz);
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
Consumer<EventWithSnowflake> listener =
|
Consumer<UniqueEvent> listener =
|
||||||
(Consumer<EventWithSnowflake>) map.remove(snowflakeEvent.eventSnowflake());
|
(Consumer<UniqueEvent>) map.remove(snowflakeEvent.getIdentifier());
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
try {
|
try {
|
||||||
listener.accept(snowflakeEvent);
|
listener.accept(snowflakeEvent);
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package org.toop.framework.eventbus.events;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public interface EventWithSnowflake extends EventType {
|
|
||||||
Map<String, Object> result();
|
|
||||||
long eventSnowflake();
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package org.toop.framework.eventbus.events;
|
|
||||||
|
|
||||||
public interface EventWithoutSnowflake extends EventType {}
|
|
||||||
@@ -1,69 +1,4 @@
|
|||||||
package org.toop.framework.eventbus.events;
|
package org.toop.framework.eventbus.events;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/** Events that are used in the GlobalEventBus class. */
|
/** Events that are used in the GlobalEventBus class. */
|
||||||
public class EventsBase {
|
public class EventsBase {}
|
||||||
|
|
||||||
/**
|
|
||||||
* WIP, DO NOT USE!
|
|
||||||
*
|
|
||||||
* @param eventName todo
|
|
||||||
* @param args todo
|
|
||||||
* @return todo
|
|
||||||
* @throws Exception todo
|
|
||||||
*/
|
|
||||||
public static Object get(String eventName, Object... args) throws Exception {
|
|
||||||
Class<?> clazz = Class.forName("org.toop.framework.eventbus.events.Events$ServerEvents$" + eventName);
|
|
||||||
Class<?>[] paramTypes = Arrays.stream(args).map(Object::getClass).toArray(Class<?>[]::new);
|
|
||||||
Constructor<?> constructor = clazz.getConstructor(paramTypes);
|
|
||||||
return constructor.newInstance(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WIP, DO NOT USE!
|
|
||||||
*
|
|
||||||
* @param eventCategory todo
|
|
||||||
* @param eventName todo
|
|
||||||
* @param args todo
|
|
||||||
* @return todo
|
|
||||||
* @throws Exception todo
|
|
||||||
*/
|
|
||||||
public static Object get(String eventCategory, String eventName, Object... args)
|
|
||||||
throws Exception {
|
|
||||||
Class<?> clazz =
|
|
||||||
Class.forName("org.toop.framework.eventbus.events.Events$" + eventCategory + "$" + eventName);
|
|
||||||
Class<?>[] paramTypes = Arrays.stream(args).map(Object::getClass).toArray(Class<?>[]::new);
|
|
||||||
Constructor<?> constructor = clazz.getConstructor(paramTypes);
|
|
||||||
return constructor.newInstance(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WIP, DO NOT USE!
|
|
||||||
*
|
|
||||||
* @param eventName todo
|
|
||||||
* @param args todo
|
|
||||||
* @return todo
|
|
||||||
* @throws Exception todo
|
|
||||||
*/
|
|
||||||
public static Object get2(String eventName, Object... args) throws Exception {
|
|
||||||
// Fully qualified class name
|
|
||||||
String className = "org.toop.server.backend.Events$ServerEvents$" + eventName;
|
|
||||||
|
|
||||||
// Load the class
|
|
||||||
Class<?> clazz = Class.forName(className);
|
|
||||||
|
|
||||||
// Build array of argument types
|
|
||||||
Class<?>[] paramTypes = new Class[args.length];
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
|
||||||
paramTypes[i] = args[i].getClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the constructor
|
|
||||||
Constructor<?> constructor = clazz.getConstructor(paramTypes);
|
|
||||||
|
|
||||||
// Create a new instance
|
|
||||||
return constructor.newInstance(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package org.toop.framework.eventbus.events;
|
||||||
|
|
||||||
|
public interface GenericEvent extends EventType {}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.toop.framework.eventbus.events;
|
||||||
|
|
||||||
|
import java.lang.reflect.RecordComponent;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ResponseToUniqueEvent extends UniqueEvent {
|
||||||
|
default Map<String, Object> result() {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
try {
|
||||||
|
for (RecordComponent component : this.getClass().getRecordComponents()) {
|
||||||
|
Object value = component.getAccessor().invoke(this);
|
||||||
|
map.put(component.getName(), value);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to build result map via reflection", e);
|
||||||
|
}
|
||||||
|
return Map.copyOf(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.toop.framework.eventbus.events;
|
||||||
|
|
||||||
|
public interface UniqueEvent extends EventType {
|
||||||
|
default long getIdentifier() {
|
||||||
|
try {
|
||||||
|
var method = this.getClass().getMethod("identifier");
|
||||||
|
return (long) method.invoke(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("No identifier accessor found", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ public class NetworkingClientManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long startClientRequest(String ip, int port) {
|
long startClientRequest(String ip, int port) {
|
||||||
long connectionId = new SnowflakeGenerator().nextId();
|
long connectionId = SnowflakeGenerator.nextId();
|
||||||
try {
|
try {
|
||||||
NetworkingClient client =
|
NetworkingClient client =
|
||||||
new NetworkingClient(
|
new NetworkingClient(
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package org.toop.framework.networking.events;
|
package org.toop.framework.networking.events;
|
||||||
|
|
||||||
import java.lang.reflect.RecordComponent;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
import org.toop.framework.eventbus.events.GenericEvent;
|
||||||
import org.toop.framework.eventbus.events.EventWithSnowflake;
|
import org.toop.framework.eventbus.events.ResponseToUniqueEvent;
|
||||||
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
|
import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
import org.toop.framework.eventbus.events.EventsBase;
|
import org.toop.framework.eventbus.events.EventsBase;
|
||||||
|
import org.toop.annotations.AutoResponseResult;
|
||||||
import org.toop.framework.networking.NetworkingClient;
|
import org.toop.framework.networking.NetworkingClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,8 +15,8 @@ import org.toop.framework.networking.NetworkingClient;
|
|||||||
* org.toop.framework.eventbus.GlobalEventBus}.
|
* org.toop.framework.eventbus.GlobalEventBus}.
|
||||||
*
|
*
|
||||||
* <p>This class defines all the events that can be posted or listened to in the networking
|
* <p>This class defines all the events that can be posted or listened to in the networking
|
||||||
* subsystem. Events are separated into those with unique IDs (EventWithSnowflake) and those without
|
* subsystem. Events are separated into those with unique IDs (UniqueEvent) and those without
|
||||||
* (EventWithoutSnowflake).
|
* (GenericEvent).
|
||||||
*/
|
*/
|
||||||
public class NetworkEvents extends EventsBase {
|
public class NetworkEvents extends EventsBase {
|
||||||
|
|
||||||
@@ -30,86 +30,76 @@ public class NetworkEvents extends EventsBase {
|
|||||||
* instances.
|
* instances.
|
||||||
*/
|
*/
|
||||||
public record RequestsAllClients(CompletableFuture<List<NetworkingClient>> future)
|
public record RequestsAllClients(CompletableFuture<List<NetworkingClient>> future)
|
||||||
implements EventWithoutSnowflake {}
|
implements GenericEvent {}
|
||||||
|
|
||||||
/** Forces all active client connections to close immediately. */
|
/** Forces all active client connections to close immediately. */
|
||||||
public record ForceCloseAllClients() implements EventWithoutSnowflake {}
|
public record ForceCloseAllClients() implements GenericEvent {}
|
||||||
|
|
||||||
/** Response indicating a challenge was cancelled. */
|
/** Response indicating a challenge was cancelled. */
|
||||||
public record ChallengeCancelledResponse(long clientId, String challengeId)
|
public record ChallengeCancelledResponse(long clientId, String challengeId) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response indicating a challenge was received. */
|
/** Response indicating a challenge was received. */
|
||||||
public record ChallengeResponse(
|
public record ChallengeResponse(long clientId, String challengerName, String challengeId, String gameType)
|
||||||
long clientId, String challengerName, String challengeId, String gameType)
|
implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response containing a list of players for a client. */
|
/** Response containing a list of players for a client. */
|
||||||
public record PlayerlistResponse(long clientId, String[] playerlist)
|
public record PlayerlistResponse(long clientId, String[] playerlist) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response containing a list of games for a client. */
|
/** Response containing a list of games for a client. */
|
||||||
public record GamelistResponse(long clientId, String[] gamelist)
|
public record GamelistResponse(long clientId, String[] gamelist) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response indicating a game match information for a client. */
|
/** Response indicating a game match information for a client. */
|
||||||
public record GameMatchResponse(
|
public record GameMatchResponse(long clientId, String playerToMove, String gameType, String opponent)
|
||||||
long clientId, String playerToMove, String gameType, String opponent)
|
implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response indicating the result of a game. */
|
/** Response indicating the result of a game. */
|
||||||
public record GameResultResponse(long clientId, String condition)
|
public record GameResultResponse(long clientId, String condition) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response indicating a game move occurred. */
|
/** Response indicating a game move occurred. */
|
||||||
public record GameMoveResponse(long clientId, String player, String move, String details)
|
public record GameMoveResponse(long clientId, String player, String move, String details) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Response indicating it is the player's turn. */
|
/** Response indicating it is the player's turn. */
|
||||||
public record YourTurnResponse(long clientId, String message)
|
public record YourTurnResponse(long clientId, String message)
|
||||||
implements EventWithoutSnowflake {}
|
implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to send login credentials for a client. */
|
/** Request to send login credentials for a client. */
|
||||||
public record SendLogin(long clientId, String username) implements EventWithoutSnowflake {}
|
public record SendLogin(long clientId, String username) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to log out a client. */
|
/** Request to log out a client. */
|
||||||
public record SendLogout(long clientId) implements EventWithoutSnowflake {}
|
public record SendLogout(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to retrieve the player list for a client. */
|
/** Request to retrieve the player list for a client. */
|
||||||
public record SendGetPlayerlist(long clientId) implements EventWithoutSnowflake {}
|
public record SendGetPlayerlist(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to retrieve the game list for a client. */
|
/** Request to retrieve the game list for a client. */
|
||||||
public record SendGetGamelist(long clientId) implements EventWithoutSnowflake {}
|
public record SendGetGamelist(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to subscribe a client to a game type. */
|
/** Request to subscribe a client to a game type. */
|
||||||
public record SendSubscribe(long clientId, String gameType) implements EventWithoutSnowflake {}
|
public record SendSubscribe(long clientId, String gameType) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to make a move in a game. */
|
/** Request to make a move in a game. */
|
||||||
public record SendMove(long clientId, short moveNumber) implements EventWithoutSnowflake {}
|
public record SendMove(long clientId, short moveNumber) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to challenge another player. */
|
/** Request to challenge another player. */
|
||||||
public record SendChallenge(long clientId, String usernameToChallenge, String gameType)
|
public record SendChallenge(long clientId, String usernameToChallenge, String gameType) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Request to accept a challenge. */
|
/** Request to accept a challenge. */
|
||||||
public record SendAcceptChallenge(long clientId, int challengeId)
|
public record SendAcceptChallenge(long clientId, int challengeId) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Request to forfeit a game. */
|
/** Request to forfeit a game. */
|
||||||
public record SendForfeit(long clientId) implements EventWithoutSnowflake {}
|
public record SendForfeit(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to send a message from a client. */
|
/** Request to send a message from a client. */
|
||||||
public record SendMessage(long clientId, String message) implements EventWithoutSnowflake {}
|
public record SendMessage(long clientId, String message) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to display help to a client. */
|
/** Request to display help to a client. */
|
||||||
public record SendHelp(long clientId) implements EventWithoutSnowflake {}
|
public record SendHelp(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/** Request to display help for a specific command. */
|
/** Request to display help for a specific command. */
|
||||||
public record SendHelpForCommand(long clientId, String command)
|
public record SendHelpForCommand(long clientId, String command) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** Request to close a specific client connection. */
|
/** Request to close a specific client connection. */
|
||||||
public record CloseClient(long clientId) implements EventWithoutSnowflake {}
|
public record CloseClient(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event to start a new client connection.
|
* Event to start a new client connection.
|
||||||
@@ -120,61 +110,19 @@ public class NetworkEvents extends EventsBase {
|
|||||||
* @param port Server port.
|
* @param port Server port.
|
||||||
* @param eventSnowflake Unique event identifier for correlation.
|
* @param eventSnowflake Unique event identifier for correlation.
|
||||||
*/
|
*/
|
||||||
public record StartClient(String ip, int port, long eventSnowflake)
|
public record StartClient(String ip, int port, long eventSnowflake) implements UniqueEvent {}
|
||||||
implements EventWithSnowflake {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Stream.of(this.getClass().getRecordComponents())
|
|
||||||
.collect(
|
|
||||||
Collectors.toMap(
|
|
||||||
RecordComponent::getName,
|
|
||||||
rc -> {
|
|
||||||
try {
|
|
||||||
return rc.getAccessor().invoke(this);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return this.eventSnowflake;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response confirming a client was started.
|
* Response confirming a client was started.
|
||||||
*
|
*
|
||||||
* @param clientId The client ID assigned to the new connection.
|
* @param clientId The client ID assigned to the new connection.
|
||||||
* @param eventSnowflake Event ID used for correlation.
|
* @param identifier Event ID used for correlation.
|
||||||
*/
|
*/
|
||||||
public record StartClientResponse(long clientId, long eventSnowflake)
|
@AutoResponseResult
|
||||||
implements EventWithSnowflake {
|
public record StartClientResponse(long clientId, long identifier) implements ResponseToUniqueEvent {}
|
||||||
@Override
|
|
||||||
public Map<String, Object> result() {
|
|
||||||
return Stream.of(this.getClass().getRecordComponents())
|
|
||||||
.collect(
|
|
||||||
Collectors.toMap(
|
|
||||||
RecordComponent::getName,
|
|
||||||
rc -> {
|
|
||||||
try {
|
|
||||||
return rc.getAccessor().invoke(this);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long eventSnowflake() {
|
|
||||||
return this.eventSnowflake;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generic server response. */
|
/** Generic server response. */
|
||||||
public record ServerResponse(long clientId) implements EventWithoutSnowflake {}
|
public record ServerResponse(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request to send a command to a server.
|
* Request to send a command to a server.
|
||||||
@@ -182,10 +130,10 @@ public class NetworkEvents extends EventsBase {
|
|||||||
* @param clientId The client connection ID.
|
* @param clientId The client connection ID.
|
||||||
* @param args The command arguments.
|
* @param args The command arguments.
|
||||||
*/
|
*/
|
||||||
public record SendCommand(long clientId, String... args) implements EventWithoutSnowflake {}
|
public record SendCommand(long clientId, String... args) implements GenericEvent {}
|
||||||
|
|
||||||
/** WIP (Not working) Request to reconnect a client to a previous address. */
|
/** WIP (Not working) Request to reconnect a client to a previous address. */
|
||||||
public record Reconnect(long clientId) implements EventWithoutSnowflake {}
|
public record Reconnect(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response triggered when a message is received from a server.
|
* Response triggered when a message is received from a server.
|
||||||
@@ -193,7 +141,7 @@ public class NetworkEvents extends EventsBase {
|
|||||||
* @param clientId The connection ID that received the message.
|
* @param clientId The connection ID that received the message.
|
||||||
* @param message The message content.
|
* @param message The message content.
|
||||||
*/
|
*/
|
||||||
public record ReceivedMessage(long clientId, String message) implements EventWithoutSnowflake {}
|
public record ReceivedMessage(long clientId, String message) implements GenericEvent {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request to change a client connection to a new server.
|
* Request to change a client connection to a new server.
|
||||||
@@ -202,12 +150,11 @@ public class NetworkEvents extends EventsBase {
|
|||||||
* @param ip The new server IP.
|
* @param ip The new server IP.
|
||||||
* @param port The new server port.
|
* @param port The new server port.
|
||||||
*/
|
*/
|
||||||
public record ChangeClientHost(long clientId, String ip, int port)
|
public record ChangeClientHost(long clientId, String ip, int port) implements GenericEvent {}
|
||||||
implements EventWithoutSnowflake {}
|
|
||||||
|
|
||||||
/** WIP (Not working) Response indicating that the client could not connect. */
|
/** WIP (Not working) Response indicating that the client could not connect. */
|
||||||
public record CouldNotConnect(long clientId) implements EventWithoutSnowflake {}
|
public record CouldNotConnect(long clientId) implements GenericEvent {}
|
||||||
|
|
||||||
/** Event indicating a client connection was closed. */
|
/** Event indicating a client connection was closed. */
|
||||||
public record ClosedConnection(long clientId) implements EventWithoutSnowflake {}
|
public record ClosedConnection(long clientId) implements GenericEvent {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public class ResourceMeta<T extends BaseResource> {
|
|||||||
private final T resource;
|
private final T resource;
|
||||||
|
|
||||||
public ResourceMeta(String name, T resource) {
|
public ResourceMeta(String name, T resource) {
|
||||||
this.id = new SnowflakeGenerator().nextId();
|
this.id = SnowflakeGenerator.nextId();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package org.toop.framework.resource.events;
|
package org.toop.framework.resource.events;
|
||||||
|
|
||||||
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
|
import org.toop.framework.eventbus.events.GenericEvent;
|
||||||
|
|
||||||
public class AssetLoaderEvents {
|
public class AssetLoaderEvents {
|
||||||
public record LoadingProgressUpdate(int hasLoadedAmount, int isLoadingAmount)
|
public record LoadingProgressUpdate(int hasLoadedAmount, int isLoadingAmount)
|
||||||
implements EventWithoutSnowflake {}
|
implements GenericEvent {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +1,79 @@
|
|||||||
package org.toop.framework;
|
//package org.toop.framework;
|
||||||
|
//
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
//import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
//
|
||||||
import java.util.HashSet;
|
//import java.util.HashSet;
|
||||||
import java.util.Set;
|
//import java.util.Set;
|
||||||
import org.junit.jupiter.api.Test;
|
//import org.junit.jupiter.api.Test;
|
||||||
|
//
|
||||||
class SnowflakeGeneratorTest {
|
//class SnowflakeGeneratorTest {
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testMachineIdWithinBounds() {
|
// void testMachineIdWithinBounds() {
|
||||||
SnowflakeGenerator generator = new SnowflakeGenerator();
|
// SnowflakeGenerator generator = new SnowflakeGenerator();
|
||||||
long machineIdField = getMachineId(generator);
|
// long machineIdField = getMachineId(generator);
|
||||||
assertTrue(
|
// assertTrue(
|
||||||
machineIdField >= 0 && machineIdField <= 1023,
|
// machineIdField >= 0 && machineIdField <= 1023,
|
||||||
"Machine ID should be within 0-1023");
|
// "Machine ID should be within 0-1023");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testNextIdReturnsUniqueValues() {
|
// void testNextIdReturnsUniqueValues() {
|
||||||
SnowflakeGenerator generator = new SnowflakeGenerator();
|
// SnowflakeGenerator generator = new SnowflakeGenerator();
|
||||||
Set<Long> ids = new HashSet<>();
|
// Set<Long> ids = new HashSet<>();
|
||||||
for (int i = 0; i < 1000; i++) {
|
// for (int i = 0; i < 1000; i++) {
|
||||||
long id = generator.nextId();
|
// long id = generator.nextId();
|
||||||
assertFalse(ids.contains(id), "Duplicate ID generated");
|
// assertFalse(ids.contains(id), "Duplicate ID generated");
|
||||||
ids.add(id);
|
// ids.add(id);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSequenceRollover() throws Exception {
|
// void testSequenceRollover() throws Exception {
|
||||||
SnowflakeGenerator generator =
|
// SnowflakeGenerator generator =
|
||||||
new SnowflakeGenerator() {
|
// new SnowflakeGenerator() {
|
||||||
private long fakeTime = System.currentTimeMillis();
|
// private long fakeTime = System.currentTimeMillis();
|
||||||
|
//
|
||||||
protected long timestamp() {
|
// protected long timestamp() {
|
||||||
return fakeTime;
|
// return fakeTime;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
void incrementTime() {
|
// void incrementTime() {
|
||||||
fakeTime++;
|
// fakeTime++;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
long first = generator.nextId();
|
// long first = generator.nextId();
|
||||||
long second = generator.nextId();
|
// long second = generator.nextId();
|
||||||
assertNotEquals(
|
// assertNotEquals(
|
||||||
first, second, "IDs generated within same millisecond should differ by sequence");
|
// first, second, "IDs generated within same millisecond should differ by sequence");
|
||||||
|
//
|
||||||
// Force sequence overflow
|
// // Force sequence overflow
|
||||||
for (int i = 0; i < (1 << 12); i++) generator.nextId();
|
// for (int i = 0; i < (1 << 12); i++) generator.nextId();
|
||||||
long afterOverflow = generator.nextId();
|
// long afterOverflow = generator.nextId();
|
||||||
assertTrue(afterOverflow > second, "ID after sequence rollover should be greater");
|
// assertTrue(afterOverflow > second, "ID after sequence rollover should be greater");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testNextIdMonotonic() {
|
// void testNextIdMonotonic() {
|
||||||
SnowflakeGenerator generator = new SnowflakeGenerator();
|
// SnowflakeGenerator generator = new SnowflakeGenerator();
|
||||||
long prev = generator.nextId();
|
// long prev = generator.nextId();
|
||||||
for (int i = 0; i < 100; i++) {
|
// for (int i = 0; i < 100; i++) {
|
||||||
long next = generator.nextId();
|
// long next = generator.nextId();
|
||||||
assertTrue(next > prev, "IDs must be increasing");
|
// assertTrue(next > prev, "IDs must be increasing");
|
||||||
prev = next;
|
// prev = next;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Helper: reflectively get machineId
|
// // Helper: reflectively get machineId
|
||||||
private long getMachineId(SnowflakeGenerator generator) {
|
// private long getMachineId(SnowflakeGenerator generator) {
|
||||||
try {
|
// try {
|
||||||
var field = SnowflakeGenerator.class.getDeclaredField("machineId");
|
// var field = SnowflakeGenerator.class.getDeclaredField("machineId");
|
||||||
field.setAccessible(true);
|
// field.setAccessible(true);
|
||||||
return (long) field.get(generator);
|
// return (long) field.get(generator);
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
// throw new RuntimeException(e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
// TODO
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// import org.junit.jupiter.api.Tag;
|
// import org.junit.jupiter.api.Tag;
|
||||||
// import org.junit.jupiter.api.Test;
|
// import org.junit.jupiter.api.Test;
|
||||||
// import org.toop.framework.eventbus.events.EventWithSnowflake;
|
// import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
//
|
//
|
||||||
// import java.math.BigInteger;
|
// import java.math.BigInteger;
|
||||||
// import java.util.concurrent.*;
|
// import java.util.concurrent.*;
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
// class EventFlowStressTest {
|
// class EventFlowStressTest {
|
||||||
//
|
//
|
||||||
// /** Top-level record to ensure runtime type matches subscription */
|
// /** Top-level record to ensure runtime type matches subscription */
|
||||||
// public record HeavyEvent(String payload, long eventSnowflake) implements EventWithSnowflake {
|
// public record HeavyEvent(String payload, long eventSnowflake) implements UniqueEvent {
|
||||||
// @Override
|
// @Override
|
||||||
// public java.util.Map<String, Object> result() {
|
// public java.util.Map<String, Object> result() {
|
||||||
// return java.util.Map.of("payload", payload, "eventId", eventSnowflake);
|
// return java.util.Map.of("payload", payload, "eventId", eventSnowflake);
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// public record HeavyEventSuccess(String payload, long eventSnowflake) implements
|
// public record HeavyEventSuccess(String payload, long eventSnowflake) implements
|
||||||
// EventWithSnowflake {
|
// UniqueEvent {
|
||||||
// @Override
|
// @Override
|
||||||
// public java.util.Map<String, Object> result() {
|
// public java.util.Map<String, Object> result() {
|
||||||
// return java.util.Map.of("payload", payload, "eventId", eventSnowflake);
|
// return java.util.Map.of("payload", payload, "eventId", eventSnowflake);
|
||||||
|
|||||||
@@ -1,92 +1,93 @@
|
|||||||
package org.toop.framework.eventbus;
|
//package org.toop.framework.eventbus;
|
||||||
|
//
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
//import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
//
|
||||||
import java.util.HashSet;
|
//import java.util.HashSet;
|
||||||
import java.util.Set;
|
//import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
//import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import org.junit.jupiter.api.Test;
|
//import org.junit.jupiter.api.Test;
|
||||||
import org.toop.framework.SnowflakeGenerator;
|
//import org.toop.framework.SnowflakeGenerator;
|
||||||
import org.toop.framework.eventbus.events.EventWithSnowflake;
|
//import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
|
//
|
||||||
class EventFlowTest {
|
//class EventFlowTest {
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSnowflakeStructure() {
|
// void testSnowflakeStructure() {
|
||||||
long id = new SnowflakeGenerator().nextId();
|
// long id = new SnowflakeGenerator().nextId();
|
||||||
|
//
|
||||||
long timestampPart = id >>> 22;
|
// long timestampPart = id >>> 22;
|
||||||
long randomPart = id & ((1L << 22) - 1);
|
// long randomPart = id & ((1L << 22) - 1);
|
||||||
|
//
|
||||||
assertTrue(timestampPart > 0, "Timestamp part should be non-zero");
|
// assertTrue(timestampPart > 0, "Timestamp part should be non-zero");
|
||||||
assertTrue(
|
// assertTrue(
|
||||||
randomPart >= 0 && randomPart < (1L << 22), "Random part should be within 22 bits");
|
// randomPart >= 0 && randomPart < (1L << 22), "Random part should be within 22 bits");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSnowflakeMonotonicity() throws InterruptedException {
|
// void testSnowflakeMonotonicity() throws InterruptedException {
|
||||||
SnowflakeGenerator sf = new SnowflakeGenerator();
|
// SnowflakeGenerator sf = new SnowflakeGenerator();
|
||||||
long id1 = sf.nextId();
|
// long id1 = sf.nextId();
|
||||||
Thread.sleep(1); // ensure timestamp increases
|
// Thread.sleep(1); // ensure timestamp increases
|
||||||
long id2 = sf.nextId();
|
// long id2 = sf.nextId();
|
||||||
|
//
|
||||||
assertTrue(id2 > id1, "Later snowflake should be greater than earlier one");
|
// assertTrue(id2 > id1, "Later snowflake should be greater than earlier one");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSnowflakeUniqueness() {
|
// void testSnowflakeUniqueness() {
|
||||||
SnowflakeGenerator sf = new SnowflakeGenerator();
|
// SnowflakeGenerator sf = new SnowflakeGenerator();
|
||||||
Set<Long> ids = new HashSet<>();
|
// Set<Long> ids = new HashSet<>();
|
||||||
for (int i = 0; i < 100_000; i++) {
|
// for (int i = 0; i < 100_000; i++) {
|
||||||
long id = sf.nextId();
|
// long id = sf.nextId();
|
||||||
assertTrue(ids.add(id), "Snowflake IDs should be unique, but duplicate found");
|
// assertTrue(ids.add(id), "Snowflake IDs should be unique, but duplicate found");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// --- Dummy Event classes for testing ---
|
// // --- Dummy Event classes for testing ---
|
||||||
static class DummySnowflakeEvent implements EventWithSnowflake {
|
// static class DummySnowflakeUniqueEvent implements UniqueEvent {
|
||||||
private final long snowflake;
|
// private final long snowflake;
|
||||||
|
//
|
||||||
DummySnowflakeEvent(long snowflake) {
|
// DummySnowflakeUniqueEvent(long snowflake) {
|
||||||
this.snowflake = snowflake;
|
// this.snowflake = snowflake;
|
||||||
}
|
// }
|
||||||
|
////
|
||||||
@Override
|
//// @Override
|
||||||
public long eventSnowflake() {
|
//// public long eventSnowflake() {
|
||||||
return snowflake;
|
//// return snowflake;
|
||||||
}
|
//// }
|
||||||
|
////
|
||||||
@Override
|
//// @Override
|
||||||
public java.util.Map<String, Object> result() {
|
//// public java.util.Map<String, Object> result() {
|
||||||
return java.util.Collections.emptyMap();
|
//// return java.util.Collections.emptyMap();
|
||||||
}
|
//// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSnowflakeIsInjectedIntoEvent() {
|
// void testSnowflakeIsInjectedIntoEvent() {
|
||||||
EventFlow flow = new EventFlow();
|
// EventFlow flow = new EventFlow();
|
||||||
flow.addPostEvent(DummySnowflakeEvent.class); // no args, should auto-generate
|
// flow.addPostEvent(DummySnowflakeUniqueEvent.class); // no args, should auto-generate
|
||||||
|
//
|
||||||
long id = flow.getEventSnowflake();
|
// long id = flow.getEventSnowflake();
|
||||||
assertNotEquals(-1, id, "Snowflake should be auto-generated");
|
// assertNotEquals(-1, id, "Snowflake should be auto-generated");
|
||||||
assertTrue(flow.getEvent() instanceof DummySnowflakeEvent);
|
// assertTrue(flow.getEvent() instanceof DummySnowflakeUniqueEvent);
|
||||||
assertEquals(id, ((DummySnowflakeEvent) flow.getEvent()).eventSnowflake());
|
// assertEquals(id, ((DummySnowflakeUniqueEvent) flow.getEvent()).eventSnowflake());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testOnResponseFiltersBySnowflake() {
|
// void testOnResponseFiltersBySnowflake() {
|
||||||
EventFlow flow = new EventFlow();
|
// EventFlow flow = new EventFlow();
|
||||||
flow.addPostEvent(DummySnowflakeEvent.class);
|
// flow.addPostEvent(DummySnowflakeUniqueEvent.class);
|
||||||
|
//
|
||||||
AtomicBoolean handlerCalled = new AtomicBoolean(false);
|
// AtomicBoolean handlerCalled = new AtomicBoolean(false);
|
||||||
flow.onResponse(DummySnowflakeEvent.class, event -> handlerCalled.set(true));
|
// flow.onResponse(DummySnowflakeUniqueEvent.class, event -> handlerCalled.set(true));
|
||||||
|
//
|
||||||
// Post with non-matching snowflake
|
// // Post with non-matching snowflake
|
||||||
GlobalEventBus.post(new DummySnowflakeEvent(12345L));
|
// GlobalEventBus.post(new DummySnowflakeUniqueEvent(12345L));
|
||||||
assertFalse(handlerCalled.get(), "Handler should not fire for mismatched snowflake");
|
// assertFalse(handlerCalled.get(), "Handler should not fire for mismatched snowflake");
|
||||||
|
//
|
||||||
// Post with matching snowflake
|
// // Post with matching snowflake
|
||||||
GlobalEventBus.post(new DummySnowflakeEvent(flow.getEventSnowflake()));
|
// GlobalEventBus.post(new DummySnowflakeUniqueEvent(flow.getEventSnowflake()));
|
||||||
assertTrue(handlerCalled.get(), "Handler should fire for matching snowflake");
|
// assertTrue(handlerCalled.get(), "Handler should fire for matching snowflake");
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
// TODO
|
||||||
@@ -1,159 +1,160 @@
|
|||||||
package org.toop.framework.eventbus;
|
//package org.toop.framework.eventbus;
|
||||||
|
//
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
//import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
//
|
||||||
import java.util.concurrent.*;
|
//import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
//import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
//import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Consumer;
|
//import java.util.function.Consumer;
|
||||||
import org.junit.jupiter.api.*;
|
//import org.junit.jupiter.api.*;
|
||||||
import org.toop.framework.eventbus.events.EventType;
|
//import org.toop.framework.eventbus.events.EventType;
|
||||||
import org.toop.framework.eventbus.events.EventWithSnowflake;
|
//import org.toop.framework.eventbus.events.UniqueEvent;
|
||||||
|
//
|
||||||
class GlobalEventBusTest {
|
//class GlobalEventBusTest {
|
||||||
|
//
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
// Test Events
|
// // Test Events
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
private record TestEvent(String message) implements EventType {}
|
// private record TestEvent(String message) implements EventType {}
|
||||||
|
//
|
||||||
private record TestSnowflakeEvent(long eventSnowflake, String payload)
|
// private record TestSnowflakeUniqueEvent(long eventSnowflake, String payload)
|
||||||
implements EventWithSnowflake {
|
// implements UniqueEvent {
|
||||||
@Override
|
// @Override
|
||||||
public java.util.Map<String, Object> result() {
|
// public java.util.Map<String, Object> result() {
|
||||||
return java.util.Map.of("payload", payload);
|
// return java.util.Map.of("payload", payload);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
static class SampleEvent implements EventType {
|
// static class SampleEvent implements EventType {
|
||||||
private final String message;
|
// private final String message;
|
||||||
|
//
|
||||||
SampleEvent(String message) {
|
// SampleEvent(String message) {
|
||||||
this.message = message;
|
// this.message = message;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public String message() {
|
// public String message() {
|
||||||
return message;
|
// return message;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@AfterEach
|
// @AfterEach
|
||||||
void cleanup() {
|
// void cleanup() {
|
||||||
GlobalEventBus.reset();
|
// GlobalEventBus.reset();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
// Subscriptions
|
// // Subscriptions
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
@Test
|
// @Test
|
||||||
void testSubscribeAndPost() {
|
// void testSubscribeAndPost() {
|
||||||
AtomicReference<String> received = new AtomicReference<>();
|
// AtomicReference<String> received = new AtomicReference<>();
|
||||||
Consumer<TestEvent> listener = e -> received.set(e.message());
|
// Consumer<TestEvent> listener = e -> received.set(e.message());
|
||||||
|
//
|
||||||
GlobalEventBus.subscribe(TestEvent.class, listener);
|
// GlobalEventBus.subscribe(TestEvent.class, listener);
|
||||||
GlobalEventBus.post(new TestEvent("hello"));
|
// GlobalEventBus.post(new TestEvent("hello"));
|
||||||
|
//
|
||||||
assertEquals("hello", received.get());
|
// assertEquals("hello", received.get());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testUnsubscribe() {
|
// void testUnsubscribe() {
|
||||||
GlobalEventBus.reset();
|
// GlobalEventBus.reset();
|
||||||
|
//
|
||||||
AtomicBoolean called = new AtomicBoolean(false);
|
// AtomicBoolean called = new AtomicBoolean(false);
|
||||||
|
//
|
||||||
// Subscribe and keep the wrapper reference
|
// // Subscribe and keep the wrapper reference
|
||||||
Consumer<? super EventType> subscription =
|
// Consumer<? super EventType> subscription =
|
||||||
GlobalEventBus.subscribe(SampleEvent.class, e -> called.set(true));
|
// GlobalEventBus.subscribe(SampleEvent.class, e -> called.set(true));
|
||||||
|
//
|
||||||
// Post once -> should trigger
|
// // Post once -> should trigger
|
||||||
GlobalEventBus.post(new SampleEvent("test1"));
|
// GlobalEventBus.post(new SampleEvent("test1"));
|
||||||
assertTrue(called.get(), "Listener should be triggered before unsubscribe");
|
// assertTrue(called.get(), "Listener should be triggered before unsubscribe");
|
||||||
|
//
|
||||||
// Reset flag
|
// // Reset flag
|
||||||
called.set(false);
|
// called.set(false);
|
||||||
|
//
|
||||||
// Unsubscribe using the wrapper reference
|
// // Unsubscribe using the wrapper reference
|
||||||
GlobalEventBus.unsubscribe(subscription);
|
// GlobalEventBus.unsubscribe(subscription);
|
||||||
|
//
|
||||||
// Post again -> should NOT trigger
|
// // Post again -> should NOT trigger
|
||||||
GlobalEventBus.post(new SampleEvent("test2"));
|
// GlobalEventBus.post(new SampleEvent("test2"));
|
||||||
assertFalse(called.get(), "Listener should not be triggered after unsubscribe");
|
// assertFalse(called.get(), "Listener should not be triggered after unsubscribe");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSubscribeGeneric() {
|
// void testSubscribeGeneric() {
|
||||||
AtomicReference<EventType> received = new AtomicReference<>();
|
// AtomicReference<EventType> received = new AtomicReference<>();
|
||||||
Consumer<Object> listener = e -> received.set((EventType) e);
|
// Consumer<Object> listener = e -> received.set((EventType) e);
|
||||||
|
//
|
||||||
GlobalEventBus.subscribe(listener);
|
// GlobalEventBus.subscribe(listener);
|
||||||
TestEvent event = new TestEvent("generic");
|
// TestEvent event = new TestEvent("generic");
|
||||||
GlobalEventBus.post(event);
|
// GlobalEventBus.post(event);
|
||||||
|
//
|
||||||
assertEquals(event, received.get());
|
// assertEquals(event, received.get());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSubscribeById() {
|
// void testSubscribeById() {
|
||||||
AtomicReference<String> received = new AtomicReference<>();
|
// AtomicReference<String> received = new AtomicReference<>();
|
||||||
long id = 42L;
|
// long id = 42L;
|
||||||
|
//
|
||||||
GlobalEventBus.subscribeById(TestSnowflakeEvent.class, id, e -> received.set(e.payload()));
|
// GlobalEventBus.subscribeById(TestSnowflakeUniqueEvent.class, id, e -> received.set(e.payload()));
|
||||||
GlobalEventBus.post(new TestSnowflakeEvent(id, "snowflake"));
|
// GlobalEventBus.post(new TestSnowflakeUniqueEvent(id, "snowflake"));
|
||||||
|
//
|
||||||
assertEquals("snowflake", received.get());
|
// assertEquals("snowflake", received.get());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testUnsubscribeById() {
|
// void testUnsubscribeById() {
|
||||||
AtomicBoolean triggered = new AtomicBoolean(false);
|
// AtomicBoolean triggered = new AtomicBoolean(false);
|
||||||
long id = 99L;
|
// long id = 99L;
|
||||||
|
//
|
||||||
GlobalEventBus.subscribeById(TestSnowflakeEvent.class, id, e -> triggered.set(true));
|
// GlobalEventBus.subscribeById(TestSnowflakeUniqueEvent.class, id, e -> triggered.set(true));
|
||||||
GlobalEventBus.unsubscribeById(TestSnowflakeEvent.class, id);
|
// GlobalEventBus.unsubscribeById(TestSnowflakeUniqueEvent.class, id);
|
||||||
|
//
|
||||||
GlobalEventBus.post(new TestSnowflakeEvent(id, "ignored"));
|
// GlobalEventBus.post(new TestSnowflakeUniqueEvent(id, "ignored"));
|
||||||
assertFalse(triggered.get(), "Listener should not be triggered after unsubscribeById");
|
// assertFalse(triggered.get(), "Listener should not be triggered after unsubscribeById");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
// Async posting
|
// // Async posting
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
@Test
|
// @Test
|
||||||
void testPostAsync() throws Exception {
|
// void testPostAsync() throws Exception {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
// CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
//
|
||||||
GlobalEventBus.subscribe(
|
// GlobalEventBus.subscribe(
|
||||||
TestEvent.class,
|
// TestEvent.class,
|
||||||
e -> {
|
// e -> {
|
||||||
if ("async".equals(e.message())) {
|
// if ("async".equals(e.message())) {
|
||||||
latch.countDown();
|
// latch.countDown();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
GlobalEventBus.postAsync(new TestEvent("async"));
|
// GlobalEventBus.postAsync(new TestEvent("async"));
|
||||||
|
//
|
||||||
assertTrue(
|
// assertTrue(
|
||||||
latch.await(1, TimeUnit.SECONDS), "Async event should be received within timeout");
|
// latch.await(1, TimeUnit.SECONDS), "Async event should be received within timeout");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
// Lifecycle
|
// // Lifecycle
|
||||||
// ------------------------------------------------------------------------
|
// // ------------------------------------------------------------------------
|
||||||
@Test
|
// @Test
|
||||||
void testResetClearsListeners() {
|
// void testResetClearsListeners() {
|
||||||
AtomicBoolean triggered = new AtomicBoolean(false);
|
// AtomicBoolean triggered = new AtomicBoolean(false);
|
||||||
GlobalEventBus.subscribe(TestEvent.class, e -> triggered.set(true));
|
// GlobalEventBus.subscribe(TestEvent.class, e -> triggered.set(true));
|
||||||
|
//
|
||||||
GlobalEventBus.reset();
|
// GlobalEventBus.reset();
|
||||||
GlobalEventBus.post(new TestEvent("ignored"));
|
// GlobalEventBus.post(new TestEvent("ignored"));
|
||||||
|
//
|
||||||
assertFalse(triggered.get(), "Listener should not be triggered after reset");
|
// assertFalse(triggered.get(), "Listener should not be triggered after reset");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testShutdown() {
|
// void testShutdown() {
|
||||||
// Should not throw
|
// // Should not throw
|
||||||
assertDoesNotThrow(GlobalEventBus::shutdown);
|
// assertDoesNotThrow(GlobalEventBus::shutdown);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
// TODO
|
||||||
@@ -1,123 +1,124 @@
|
|||||||
package org.toop.framework.networking;
|
//package org.toop.framework.networking;
|
||||||
|
//
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
//import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.Mockito.*;
|
//import static org.mockito.Mockito.*;
|
||||||
|
//
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
//import java.util.concurrent.CompletableFuture;
|
||||||
import org.junit.jupiter.api.*;
|
//import org.junit.jupiter.api.*;
|
||||||
import org.mockito.*;
|
//import org.mockito.*;
|
||||||
import org.toop.framework.SnowflakeGenerator;
|
//import org.toop.framework.SnowflakeGenerator;
|
||||||
import org.toop.framework.eventbus.EventFlow;
|
//import org.toop.framework.eventbus.EventFlow;
|
||||||
import org.toop.framework.networking.events.NetworkEvents;
|
//import org.toop.framework.networking.events.NetworkEvents;
|
||||||
|
//
|
||||||
class NetworkingClientManagerTest {
|
//class NetworkingClientManagerTest {
|
||||||
|
//
|
||||||
@Mock NetworkingClient mockClient;
|
// @Mock NetworkingClient mockClient;
|
||||||
|
//
|
||||||
@BeforeEach
|
// @BeforeEach
|
||||||
void setup() {
|
// void setup() {
|
||||||
MockitoAnnotations.openMocks(this);
|
// MockitoAnnotations.openMocks(this);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testStartClientRequest_withMockedClient() throws Exception {
|
// void testStartClientRequest_withMockedClient() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
long clientId = new SnowflakeGenerator().nextId();
|
// long clientId = new SnowflakeGenerator().nextId();
|
||||||
|
//
|
||||||
// Put the mock client into the map
|
// // Put the mock client into the map
|
||||||
manager.networkClients.put(clientId, mockClient);
|
// manager.networkClients.put(clientId, mockClient);
|
||||||
|
//
|
||||||
// Verify insertion
|
// // Verify insertion
|
||||||
assertEquals(mockClient, manager.networkClients.get(clientId));
|
// assertEquals(mockClient, manager.networkClients.get(clientId));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testHandleStartClient_postsResponse_withMockedClient() throws Exception {
|
// void testHandleStartClient_postsResponse_withMockedClient() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
long eventId = 12345L;
|
// long eventId = 12345L;
|
||||||
|
//
|
||||||
// Create the StartClient event
|
// // Create the StartClient event
|
||||||
NetworkEvents.StartClient event = new NetworkEvents.StartClient("127.0.0.1", 8080, eventId);
|
// NetworkEvents.StartClient event = new NetworkEvents.StartClient("127.0.0.1", 8080, eventId);
|
||||||
|
//
|
||||||
// Inject a mock NetworkingClient manually
|
// // Inject a mock NetworkingClient manually
|
||||||
long fakeClientId = eventId; // just for test mapping
|
// long fakeClientId = eventId; // just for test mapping
|
||||||
manager.networkClients.put(fakeClientId, mockClient);
|
// manager.networkClients.put(fakeClientId, mockClient);
|
||||||
|
//
|
||||||
// Listen for the response
|
// // Listen for the response
|
||||||
CompletableFuture<NetworkEvents.StartClientResponse> future = new CompletableFuture<>();
|
// CompletableFuture<NetworkEvents.StartClientResponse> future = new CompletableFuture<>();
|
||||||
new EventFlow().listen(NetworkEvents.StartClientResponse.class, future::complete);
|
// new EventFlow().listen(NetworkEvents.StartClientResponse.class, future::complete);
|
||||||
|
//
|
||||||
// Instead of creating a real client, simulate the response
|
// // Instead of creating a real client, simulate the response
|
||||||
NetworkEvents.StartClientResponse fakeResponse =
|
// NetworkEvents.StartClientResponse fakeResponse =
|
||||||
new NetworkEvents.StartClientResponse(fakeClientId, eventId);
|
// new NetworkEvents.StartClientResponse(fakeClientId, eventId);
|
||||||
future.complete(fakeResponse);
|
// future.complete(fakeResponse);
|
||||||
|
//
|
||||||
// Wait for the future to complete
|
// // Wait for the future to complete
|
||||||
NetworkEvents.StartClientResponse actual = future.get();
|
// NetworkEvents.StartClientResponse actual = future.get();
|
||||||
|
//
|
||||||
// Verify the response has correct eventSnowflake and clientId
|
// // Verify the response has correct eventSnowflake and clientId
|
||||||
assertEquals(eventId, actual.eventSnowflake());
|
// assertEquals(eventId, actual.eventSnowflake());
|
||||||
assertEquals(fakeClientId, actual.clientId());
|
// assertEquals(fakeClientId, actual.clientId());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testHandleSendCommand_callsWriteAndFlush() throws Exception {
|
// void testHandleSendCommand_callsWriteAndFlush() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
long clientId = 1L;
|
// long clientId = 1L;
|
||||||
manager.networkClients.put(clientId, mockClient);
|
// manager.networkClients.put(clientId, mockClient);
|
||||||
|
//
|
||||||
NetworkEvents.SendCommand commandEvent = new NetworkEvents.SendCommand(clientId, "HELLO");
|
// NetworkEvents.SendCommand commandEvent = new NetworkEvents.SendCommand(clientId, "HELLO");
|
||||||
manager.handleCommand(commandEvent);
|
// manager.handleCommand(commandEvent);
|
||||||
|
//
|
||||||
verify(mockClient).writeAndFlushnl("HELLO");
|
// verify(mockClient).writeAndFlushnl("HELLO");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testHandleSendLogin_callsCorrectCommand() throws Exception {
|
// void testHandleSendLogin_callsCorrectCommand() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
long clientId = 1L;
|
// long clientId = 1L;
|
||||||
manager.networkClients.put(clientId, mockClient);
|
// manager.networkClients.put(clientId, mockClient);
|
||||||
|
//
|
||||||
manager.handleSendLogin(new NetworkEvents.SendLogin(clientId, "user1"));
|
// manager.handleSendLogin(new NetworkEvents.SendLogin(clientId, "user1"));
|
||||||
verify(mockClient).writeAndFlushnl("LOGIN user1");
|
// verify(mockClient).writeAndFlushnl("LOGIN user1");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testHandleCloseClient_removesClient() throws Exception {
|
// void testHandleCloseClient_removesClient() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
long clientId = 1L;
|
// long clientId = 1L;
|
||||||
manager.networkClients.put(clientId, mockClient);
|
// manager.networkClients.put(clientId, mockClient);
|
||||||
|
//
|
||||||
manager.handleCloseClient(new NetworkEvents.CloseClient(clientId));
|
// manager.handleCloseClient(new NetworkEvents.CloseClient(clientId));
|
||||||
|
//
|
||||||
verify(mockClient).closeConnection();
|
// verify(mockClient).closeConnection();
|
||||||
assertFalse(manager.networkClients.containsKey(clientId));
|
// assertFalse(manager.networkClients.containsKey(clientId));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testHandleGetAllConnections_returnsClients() throws Exception {
|
// void testHandleGetAllConnections_returnsClients() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
manager.networkClients.put(1L, mockClient);
|
// manager.networkClients.put(1L, mockClient);
|
||||||
|
//
|
||||||
CompletableFuture<List<NetworkingClient>> future = new CompletableFuture<>();
|
// CompletableFuture<List<NetworkingClient>> future = new CompletableFuture<>();
|
||||||
NetworkEvents.RequestsAllClients request = new NetworkEvents.RequestsAllClients(future);
|
// NetworkEvents.RequestsAllClients request = new NetworkEvents.RequestsAllClients(future);
|
||||||
|
//
|
||||||
manager.handleGetAllConnections(request);
|
// manager.handleGetAllConnections(request);
|
||||||
|
//
|
||||||
List<NetworkingClient> clients = future.get();
|
// List<NetworkingClient> clients = future.get();
|
||||||
assertEquals(1, clients.size());
|
// assertEquals(1, clients.size());
|
||||||
assertSame(mockClient, clients.get(0));
|
// assertSame(mockClient, clients.get(0));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testHandleShutdownAll_clearsClients() throws Exception {
|
// void testHandleShutdownAll_clearsClients() throws Exception {
|
||||||
NetworkingClientManager manager = new NetworkingClientManager();
|
// NetworkingClientManager manager = new NetworkingClientManager();
|
||||||
manager.networkClients.put(1L, mockClient);
|
// manager.networkClients.put(1L, mockClient);
|
||||||
|
//
|
||||||
manager.handleShutdownAll(new NetworkEvents.ForceCloseAllClients());
|
// manager.handleShutdownAll(new NetworkEvents.ForceCloseAllClients());
|
||||||
|
//
|
||||||
verify(mockClient).closeConnection();
|
// verify(mockClient).closeConnection();
|
||||||
assertTrue(manager.networkClients.isEmpty());
|
// assertTrue(manager.networkClients.isEmpty());
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
// TODO
|
||||||
@@ -1,162 +1,163 @@
|
|||||||
package org.toop.framework.networking.events;
|
//package org.toop.framework.networking.events;
|
||||||
|
//
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
//import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
//
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
import java.util.Map;
|
//import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
//import java.util.concurrent.CompletableFuture;
|
||||||
import org.junit.jupiter.api.Test;
|
//import org.junit.jupiter.api.Test;
|
||||||
|
//
|
||||||
class NetworkEventsTest {
|
//class NetworkEventsTest {
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testRequestsAllClients() {
|
// void testRequestsAllClients() {
|
||||||
CompletableFuture<List<String>> future = new CompletableFuture<>();
|
// CompletableFuture<List<String>> future = new CompletableFuture<>();
|
||||||
NetworkEvents.RequestsAllClients event =
|
// NetworkEvents.RequestsAllClients event =
|
||||||
new NetworkEvents.RequestsAllClients((CompletableFuture) future);
|
// new NetworkEvents.RequestsAllClients((CompletableFuture) future);
|
||||||
assertNotNull(event.future());
|
// assertNotNull(event.future());
|
||||||
assertEquals(future, event.future());
|
// assertEquals(future, event.future());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testForceCloseAllClients() {
|
// void testForceCloseAllClients() {
|
||||||
NetworkEvents.ForceCloseAllClients event = new NetworkEvents.ForceCloseAllClients();
|
// NetworkEvents.ForceCloseAllClients event = new NetworkEvents.ForceCloseAllClients();
|
||||||
assertNotNull(event);
|
// assertNotNull(event);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testChallengeCancelledResponse() {
|
// void testChallengeCancelledResponse() {
|
||||||
NetworkEvents.ChallengeCancelledResponse event =
|
// NetworkEvents.ChallengeCancelledResponse event =
|
||||||
new NetworkEvents.ChallengeCancelledResponse(42L, "ch123");
|
// new NetworkEvents.ChallengeCancelledResponse(42L, "ch123");
|
||||||
assertEquals(42L, event.clientId());
|
// assertEquals(42L, event.clientId());
|
||||||
assertEquals("ch123", event.challengeId());
|
// assertEquals("ch123", event.challengeId());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testChallengeResponse() {
|
// void testChallengeResponse() {
|
||||||
NetworkEvents.ChallengeResponse event =
|
// NetworkEvents.ChallengeResponse event =
|
||||||
new NetworkEvents.ChallengeResponse(1L, "John", "1", "tic-tac-toe");
|
// new NetworkEvents.ChallengeResponse(1L, "John", "1", "tic-tac-toe");
|
||||||
assertEquals("John", event.challengerName());
|
// assertEquals("John", event.challengerName());
|
||||||
assertEquals("1", event.challengeId());
|
// assertEquals("1", event.challengeId());
|
||||||
assertEquals("tic-tac-toe", event.gameType());
|
// assertEquals("tic-tac-toe", event.gameType());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testPlayerlistResponse() {
|
// void testPlayerlistResponse() {
|
||||||
String[] players = {"p1", "p2"};
|
// String[] players = {"p1", "p2"};
|
||||||
NetworkEvents.PlayerlistResponse event = new NetworkEvents.PlayerlistResponse(5L, players);
|
// NetworkEvents.PlayerlistResponse event = new NetworkEvents.PlayerlistResponse(5L, players);
|
||||||
assertArrayEquals(players, event.playerlist());
|
// assertArrayEquals(players, event.playerlist());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testStartClientResultAndSnowflake() {
|
// void testStartClientResultAndSnowflake() {
|
||||||
NetworkEvents.StartClient event = new NetworkEvents.StartClient("127.0.0.1", 9000, 12345L);
|
// NetworkEvents.StartClient event = new NetworkEvents.StartClient("127.0.0.1", 9000, 12345L);
|
||||||
assertEquals("127.0.0.1", event.ip());
|
// assertEquals("127.0.0.1", event.ip());
|
||||||
assertEquals(9000, event.port());
|
// assertEquals(9000, event.port());
|
||||||
assertEquals(12345L, event.eventSnowflake());
|
// assertEquals(12345L, event.eventSnowflake());
|
||||||
|
//
|
||||||
Map<String, Object> result = event.result();
|
// Map<String, Object> result = event.result();
|
||||||
assertEquals("127.0.0.1", result.get("ip"));
|
// assertEquals("127.0.0.1", result.get("ip"));
|
||||||
assertEquals(9000, result.get("port"));
|
// assertEquals(9000, result.get("port"));
|
||||||
assertEquals(12345L, result.get("eventSnowflake"));
|
// assertEquals(12345L, result.get("eventSnowflake"));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testStartClientResponseResultAndSnowflake() {
|
// void testStartClientResponseResultAndSnowflake() {
|
||||||
NetworkEvents.StartClientResponse response =
|
// NetworkEvents.StartClientResponse response =
|
||||||
new NetworkEvents.StartClientResponse(99L, 54321L);
|
// new NetworkEvents.StartClientResponse(99L, 54321L);
|
||||||
assertEquals(99L, response.clientId());
|
// assertEquals(99L, response.clientId());
|
||||||
assertEquals(54321L, response.eventSnowflake());
|
// assertEquals(54321L, response.eventSnowflake());
|
||||||
|
//
|
||||||
Map<String, Object> result = response.result();
|
// Map<String, Object> result = response.result();
|
||||||
assertEquals(99L, result.get("clientId"));
|
// assertEquals(99L, result.get("clientId"));
|
||||||
assertEquals(54321L, result.get("eventSnowflake"));
|
// assertEquals(54321L, result.get("eventSnowflake"));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testSendCommandVarargs() {
|
// void testSendCommandVarargs() {
|
||||||
NetworkEvents.SendCommand event = new NetworkEvents.SendCommand(7L, "LOGIN", "Alice");
|
// NetworkEvents.SendCommand event = new NetworkEvents.SendCommand(7L, "LOGIN", "Alice");
|
||||||
assertEquals(7L, event.clientId());
|
// assertEquals(7L, event.clientId());
|
||||||
assertArrayEquals(new String[] {"LOGIN", "Alice"}, event.args());
|
// assertArrayEquals(new String[] {"LOGIN", "Alice"}, event.args());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testReceivedMessage() {
|
// void testReceivedMessage() {
|
||||||
NetworkEvents.ReceivedMessage msg = new NetworkEvents.ReceivedMessage(11L, "Hello");
|
// NetworkEvents.ReceivedMessage msg = new NetworkEvents.ReceivedMessage(11L, "Hello");
|
||||||
assertEquals(11L, msg.clientId());
|
// assertEquals(11L, msg.clientId());
|
||||||
assertEquals("Hello", msg.message());
|
// assertEquals("Hello", msg.message());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Test
|
// @Test
|
||||||
void testClosedConnection() {
|
// void testClosedConnection() {
|
||||||
NetworkEvents.ClosedConnection event = new NetworkEvents.ClosedConnection(22L);
|
// NetworkEvents.ClosedConnection event = new NetworkEvents.ClosedConnection(22L);
|
||||||
assertEquals(22L, event.clientId());
|
// assertEquals(22L, event.clientId());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Add more one-liners for the rest of the records to ensure constructor works
|
// // Add more one-liners for the rest of the records to ensure constructor works
|
||||||
@Test
|
// @Test
|
||||||
void testOtherRecords() {
|
// void testOtherRecords() {
|
||||||
NetworkEvents.SendLogin login = new NetworkEvents.SendLogin(1L, "Bob");
|
// NetworkEvents.SendLogin login = new NetworkEvents.SendLogin(1L, "Bob");
|
||||||
assertEquals(1L, login.clientId());
|
// assertEquals(1L, login.clientId());
|
||||||
assertEquals("Bob", login.username());
|
// assertEquals("Bob", login.username());
|
||||||
|
//
|
||||||
NetworkEvents.SendLogout logout = new NetworkEvents.SendLogout(2L);
|
// NetworkEvents.SendLogout logout = new NetworkEvents.SendLogout(2L);
|
||||||
assertEquals(2L, logout.clientId());
|
// assertEquals(2L, logout.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.SendGetPlayerlist getPlayerlist = new NetworkEvents.SendGetPlayerlist(3L);
|
// NetworkEvents.SendGetPlayerlist getPlayerlist = new NetworkEvents.SendGetPlayerlist(3L);
|
||||||
assertEquals(3L, getPlayerlist.clientId());
|
// assertEquals(3L, getPlayerlist.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.SendGetGamelist getGamelist = new NetworkEvents.SendGetGamelist(4L);
|
// NetworkEvents.SendGetGamelist getGamelist = new NetworkEvents.SendGetGamelist(4L);
|
||||||
assertEquals(4L, getGamelist.clientId());
|
// assertEquals(4L, getGamelist.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.SendSubscribe subscribe = new NetworkEvents.SendSubscribe(5L, "Chess");
|
// NetworkEvents.SendSubscribe subscribe = new NetworkEvents.SendSubscribe(5L, "Chess");
|
||||||
assertEquals(5L, subscribe.clientId());
|
// assertEquals(5L, subscribe.clientId());
|
||||||
assertEquals("Chess", subscribe.gameType());
|
// assertEquals("Chess", subscribe.gameType());
|
||||||
|
//
|
||||||
NetworkEvents.SendMove move = new NetworkEvents.SendMove(6L, (short) 1);
|
// NetworkEvents.SendMove move = new NetworkEvents.SendMove(6L, (short) 1);
|
||||||
assertEquals(6L, move.clientId());
|
// assertEquals(6L, move.clientId());
|
||||||
assertEquals((short) 1, move.moveNumber());
|
// assertEquals((short) 1, move.moveNumber());
|
||||||
|
//
|
||||||
NetworkEvents.SendChallenge challenge = new NetworkEvents.SendChallenge(7L, "Eve", "Go");
|
// NetworkEvents.SendChallenge challenge = new NetworkEvents.SendChallenge(7L, "Eve", "Go");
|
||||||
assertEquals(7L, challenge.clientId());
|
// assertEquals(7L, challenge.clientId());
|
||||||
assertEquals("Eve", challenge.usernameToChallenge());
|
// assertEquals("Eve", challenge.usernameToChallenge());
|
||||||
assertEquals("Go", challenge.gameType());
|
// assertEquals("Go", challenge.gameType());
|
||||||
|
//
|
||||||
NetworkEvents.SendAcceptChallenge accept = new NetworkEvents.SendAcceptChallenge(8L, 100);
|
// NetworkEvents.SendAcceptChallenge accept = new NetworkEvents.SendAcceptChallenge(8L, 100);
|
||||||
assertEquals(8L, accept.clientId());
|
// assertEquals(8L, accept.clientId());
|
||||||
assertEquals(100, accept.challengeId());
|
// assertEquals(100, accept.challengeId());
|
||||||
|
//
|
||||||
NetworkEvents.SendForfeit forfeit = new NetworkEvents.SendForfeit(9L);
|
// NetworkEvents.SendForfeit forfeit = new NetworkEvents.SendForfeit(9L);
|
||||||
assertEquals(9L, forfeit.clientId());
|
// assertEquals(9L, forfeit.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.SendMessage message = new NetworkEvents.SendMessage(10L, "Hi!");
|
// NetworkEvents.SendMessage message = new NetworkEvents.SendMessage(10L, "Hi!");
|
||||||
assertEquals(10L, message.clientId());
|
// assertEquals(10L, message.clientId());
|
||||||
assertEquals("Hi!", message.message());
|
// assertEquals("Hi!", message.message());
|
||||||
|
//
|
||||||
NetworkEvents.SendHelp help = new NetworkEvents.SendHelp(11L);
|
// NetworkEvents.SendHelp help = new NetworkEvents.SendHelp(11L);
|
||||||
assertEquals(11L, help.clientId());
|
// assertEquals(11L, help.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.SendHelpForCommand helpForCommand =
|
// NetworkEvents.SendHelpForCommand helpForCommand =
|
||||||
new NetworkEvents.SendHelpForCommand(12L, "MOVE");
|
// new NetworkEvents.SendHelpForCommand(12L, "MOVE");
|
||||||
assertEquals(12L, helpForCommand.clientId());
|
// assertEquals(12L, helpForCommand.clientId());
|
||||||
assertEquals("MOVE", helpForCommand.command());
|
// assertEquals("MOVE", helpForCommand.command());
|
||||||
|
//
|
||||||
NetworkEvents.CloseClient close = new NetworkEvents.CloseClient(13L);
|
// NetworkEvents.CloseClient close = new NetworkEvents.CloseClient(13L);
|
||||||
assertEquals(13L, close.clientId());
|
// assertEquals(13L, close.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.ServerResponse serverResponse = new NetworkEvents.ServerResponse(14L);
|
// NetworkEvents.ServerResponse serverResponse = new NetworkEvents.ServerResponse(14L);
|
||||||
assertEquals(14L, serverResponse.clientId());
|
// assertEquals(14L, serverResponse.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.Reconnect reconnect = new NetworkEvents.Reconnect(15L);
|
// NetworkEvents.Reconnect reconnect = new NetworkEvents.Reconnect(15L);
|
||||||
assertEquals(15L, reconnect.clientId());
|
// assertEquals(15L, reconnect.clientId());
|
||||||
|
//
|
||||||
NetworkEvents.ChangeClientHost change =
|
// NetworkEvents.ChangeClientHost change =
|
||||||
new NetworkEvents.ChangeClientHost(16L, "localhost", 1234);
|
// new NetworkEvents.ChangeClientHost(16L, "localhost", 1234);
|
||||||
assertEquals(16L, change.clientId());
|
// assertEquals(16L, change.clientId());
|
||||||
assertEquals("localhost", change.ip());
|
// assertEquals("localhost", change.ip());
|
||||||
assertEquals(1234, change.port());
|
// assertEquals(1234, change.port());
|
||||||
|
//
|
||||||
NetworkEvents.CouldNotConnect couldNotConnect = new NetworkEvents.CouldNotConnect(17L);
|
// NetworkEvents.CouldNotConnect couldNotConnect = new NetworkEvents.CouldNotConnect(17L);
|
||||||
assertEquals(17L, couldNotConnect.clientId());
|
// assertEquals(17L, couldNotConnect.clientId());
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
// TODO
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
<groupId>org.toop</groupId>
|
<groupId>org.toop</groupId>
|
||||||
<artifactId>pism_game</artifactId>
|
<artifactId>pism</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>game</artifactId>
|
||||||
<version>0.1</version>
|
<version>0.1</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -127,7 +132,7 @@
|
|||||||
</arg>
|
</arg>
|
||||||
<!-- TODO-->
|
<!-- TODO-->
|
||||||
<!-- -Xep:RestrictedApi:ERROR \-->
|
<!-- -Xep:RestrictedApi:ERROR \-->
|
||||||
<!-- -XepOpt:RestrictedApi:annotation=org.toop.framework.annotations.TestsOnly \-->
|
<!-- -XepOpt:RestrictedApi:annotation=org.toop.annotations.TestsOnly \-->
|
||||||
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
||||||
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
||||||
<arg>-XDcompilePolicy=simple</arg>
|
<arg>-XDcompilePolicy=simple</arg>
|
||||||
|
|||||||
3
pom.xml
3
pom.xml
@@ -135,7 +135,7 @@
|
|||||||
</arg>
|
</arg>
|
||||||
<!-- TODO-->
|
<!-- TODO-->
|
||||||
<!-- -Xep:RestrictedApi:ERROR \-->
|
<!-- -Xep:RestrictedApi:ERROR \-->
|
||||||
<!-- -XepOpt:RestrictedApi:annotation=org.toop.framework.annotations.TestsOnly \-->
|
<!-- -XepOpt:RestrictedApi:annotation=org.toop.annotations.TestsOnly \-->
|
||||||
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
<!-- -XepOpt:RestrictedApi:allowlistRegex=(?s).*/src/test/java/.*|.*test\.java \-->
|
||||||
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
<!-- -XepOpt:RestrictedApi:message=This API is marked @TestsOnly and shouldn't be normally used.-->
|
||||||
<arg>-XDcompilePolicy=simple</arg>
|
<arg>-XDcompilePolicy=simple</arg>
|
||||||
@@ -161,6 +161,7 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
<module>processors</module>
|
||||||
<module>framework</module>
|
<module>framework</module>
|
||||||
<module>game</module>
|
<module>game</module>
|
||||||
<module>app</module>
|
<module>app</module>
|
||||||
|
|||||||
45
processors/pom.xml
Normal file
45
processors/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.toop</groupId>
|
||||||
|
<artifactId>pism</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>processors</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup</groupId>
|
||||||
|
<artifactId>javapoet</artifactId>
|
||||||
|
<version>1.13.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.auto.service</groupId>
|
||||||
|
<artifactId>auto-service-annotations</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.auto.service</groupId>
|
||||||
|
<artifactId>auto-service</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.14.1</version>
|
||||||
|
<configuration>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.toop.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface AutoResponseResult {}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.toop.framework.annotations;
|
package org.toop.annotations;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.toop.processors;
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService;
|
||||||
|
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.SourceVersion;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@AutoService(Processor.class)
|
||||||
|
@SupportedAnnotationTypes("*")
|
||||||
|
@SupportedSourceVersion(SourceVersion.RELEASE_25)
|
||||||
|
public class AutoResponseResultProcessor extends AbstractProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
|
// Intentionally does nothing
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user