Checker Framework integration (#126)
This commit is contained in:
@@ -2,9 +2,13 @@ plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
apply from: '../gradle/checkerframework.gradle'
|
||||
|
||||
dependencies {
|
||||
compile "com.google.guava:guava:${guavaVersion}"
|
||||
compile "io.netty:netty-buffer:${nettyVersion}"
|
||||
compile "org.checkerframework:checker-qual:${checkerFrameworkVersion}"
|
||||
|
||||
testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
|
||||
testCompile "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
|
||||
}
|
@@ -1,88 +1,64 @@
|
||||
package com.velocitypowered.natives.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class NativeCodeLoader<T> implements Supplier<T> {
|
||||
private final List<Variant<T>> variants;
|
||||
private volatile Variant<T> selected;
|
||||
public final class NativeCodeLoader<T> implements Supplier<T> {
|
||||
private final Variant<T> selected;
|
||||
|
||||
public NativeCodeLoader(List<Variant<T>> variants) {
|
||||
this.variants = ImmutableList.copyOf(variants);
|
||||
NativeCodeLoader(List<Variant<T>> variants) {
|
||||
this.selected = getVariant(variants);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return tryLoad().object;
|
||||
return selected.object;
|
||||
}
|
||||
|
||||
private Variant<T> tryLoad() {
|
||||
if (selected != null) {
|
||||
return selected;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (selected != null) {
|
||||
return selected;
|
||||
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
|
||||
for (Variant<T> variant : variants) {
|
||||
T got = variant.get();
|
||||
if (got == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Variant<T> variant : variants) {
|
||||
T got = variant.get();
|
||||
if (got == null) {
|
||||
continue;
|
||||
}
|
||||
selected = variant;
|
||||
return selected;
|
||||
}
|
||||
throw new IllegalArgumentException("Can't find any suitable variants");
|
||||
return variant;
|
||||
}
|
||||
throw new IllegalArgumentException("Can't find any suitable variants");
|
||||
}
|
||||
|
||||
public String getLoadedVariant() {
|
||||
return tryLoad().name;
|
||||
return selected.name;
|
||||
}
|
||||
|
||||
static class Variant<T> {
|
||||
private volatile boolean available;
|
||||
private Status status;
|
||||
private final Runnable setup;
|
||||
private final String name;
|
||||
private final T object;
|
||||
private volatile boolean hasBeenSetup = false;
|
||||
|
||||
Variant(BooleanSupplier available, Runnable setup, String name, T object) {
|
||||
this.available = available.getAsBoolean();
|
||||
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
|
||||
this.status = possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
|
||||
this.setup = setup;
|
||||
this.name = name;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
if (!available) {
|
||||
public @Nullable T get() {
|
||||
if (status == Status.NOT_AVAILABLE || status == Status.SETUP_FAILURE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make sure setup happens only once
|
||||
if (!hasBeenSetup) {
|
||||
synchronized (this) {
|
||||
// We change availability if need be below, may as well check it again here for sanity.
|
||||
if (!available) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Okay, now try the setup if we haven't done so yet.
|
||||
if (!hasBeenSetup) {
|
||||
try {
|
||||
setup.run();
|
||||
hasBeenSetup = true;
|
||||
return object;
|
||||
} catch (Exception e) {
|
||||
available = false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (status == Status.POSSIBLY_AVAILABLE) {
|
||||
try {
|
||||
setup.run();
|
||||
status = Status.SETUP;
|
||||
} catch (Exception e) {
|
||||
status = Status.SETUP_FAILURE;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +66,16 @@ public class NativeCodeLoader<T> implements Supplier<T> {
|
||||
}
|
||||
}
|
||||
|
||||
static final BooleanSupplier MACOS = () -> System.getProperty("os.name").equalsIgnoreCase("Mac OS X") &&
|
||||
private enum Status {
|
||||
NOT_AVAILABLE,
|
||||
POSSIBLY_AVAILABLE,
|
||||
SETUP,
|
||||
SETUP_FAILURE
|
||||
}
|
||||
|
||||
static final BooleanSupplier MACOS = () -> System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X") &&
|
||||
System.getProperty("os.arch").equals("x86_64");
|
||||
static final BooleanSupplier LINUX = () -> System.getProperties().getProperty("os.name").equalsIgnoreCase("Linux") &&
|
||||
static final BooleanSupplier LINUX = () -> System.getProperties().getProperty("os.name", "").equalsIgnoreCase("Linux") &&
|
||||
System.getProperty("os.arch").equals("amd64");
|
||||
static final BooleanSupplier ALWAYS = () -> true;
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import com.velocitypowered.natives.encryption.JavaVelocityCipher;
|
||||
import com.velocitypowered.natives.encryption.VelocityCipherFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
@@ -21,7 +22,12 @@ public class Natives {
|
||||
return () -> {
|
||||
try {
|
||||
Path tempFile = Files.createTempFile("native-", path.substring(path.lastIndexOf('.')));
|
||||
Files.copy(Natives.class.getResourceAsStream(path), tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
InputStream nativeLib = Natives.class.getResourceAsStream(path);
|
||||
if (nativeLib == null) {
|
||||
throw new IllegalStateException("Native library " + path + " not found.");
|
||||
}
|
||||
|
||||
Files.copy(nativeLib, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
Files.deleteIfExists(tempFile);
|
||||
|
Reference in New Issue
Block a user