ProjectAres/PGM/src/main/java/tc/oc/pgm/listing/ListingServiceImpl.java

119 lines
3.6 KiB
Java

package tc.oc.pgm.listing;
import java.security.SecureRandom;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.google.common.util.concurrent.ListenableFuture;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import tc.oc.api.http.HttpClient;
import tc.oc.api.http.HttpOption;
import tc.oc.api.message.types.Reply;
import tc.oc.commons.bukkit.chat.Audiences;
import tc.oc.commons.core.commands.CommandFutureCallback;
import tc.oc.commons.core.concurrent.Flexecutor;
import tc.oc.minecraft.api.event.Enableable;
import tc.oc.minecraft.api.server.LocalServer;
import tc.oc.minecraft.scheduler.Sync;
@Singleton
class ListingServiceImpl implements ListingService, Enableable {
private final HttpClient http;
private final ListingConfiguration config;
private final LocalServer localServer;
private final SecureRandom random = new SecureRandom();
private final Flexecutor executor;
private final Audiences audiences;
private final ConsoleCommandSender console;
private boolean online;
private @Nullable String sessionId;
private @Nullable String sessionDigest;
@Inject ListingServiceImpl(HttpClient http, ListingConfiguration config, LocalServer localServer, @Sync(defer = true) Flexecutor executor, Audiences audiences, ConsoleCommandSender console) {
this.http = http;
this.config = config;
this.localServer = localServer;
this.executor = executor;
this.audiences = audiences;
this.console = console;
}
@Override
public @Nullable String sessionDigest() {
return sessionDigest;
}
@Override
public void enable() {
if(config.enabled()) {
// Don't announce until we are ready to receive the ping
executor.execute(() -> update(true));
}
}
@Override
public void disable() {
if(online) {
update(false);
}
}
@Override
public ListenableFuture<Reply> update(boolean online) {
return update(online, console);
}
@Override
public ListenableFuture<Reply> update(boolean online, CommandSender sender) {
this.online = online;
if(sessionId == null) {
final byte[] bytes = new byte[20];
random.nextBytes(bytes);
sessionId = Hex.encodeHexString(bytes);
sessionDigest = DigestUtils.sha1Hex(sessionId);
}
final ListenableFuture<Reply> future = http.post(config.announceUrl().toString(), new ListingUpdate() {
@Override public @Nullable String host() {
return config.serverHost();
}
@Override
public int port() {
return config.serverPort().orElseGet(localServer::getPort);
}
@Override
public boolean online() {
return online;
}
@Override
public String session() {
return sessionId;
}
}, Reply.class, HttpOption.INFINITE_RETRY);
executor.callback(
future,
CommandFutureCallback.onSuccess(sender, reply -> {
if(!online) {
sessionId = sessionDigest = null;
}
audiences.get(sender).sendMessage(new TranslatableComponent(online ? "announce.online" : "announce.offline"));
})
);
return future;
}
}