mirror of
https://github.com/proxiodev/RedisBungee.git
synced 2026-03-29 03:10:47 +00:00
implement the ProxyManager
untested
This commit is contained in:
parent
f9017a5f44
commit
dd317c5cce
@ -0,0 +1,15 @@
|
|||||||
|
description = "Api functions for valiobungee"
|
||||||
|
|
||||||
|
java {
|
||||||
|
withJavadocJar()
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation(libs.testing.juipter)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present ValioBungee contributors
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Apache License Version 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
*/
|
||||||
|
package net.limework.valiobungee.api;
|
||||||
|
|
||||||
|
public interface NetworkPlayer {}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present ValioBungee contributors
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Apache License Version 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0.txt
|
||||||
|
*/
|
||||||
|
package net.limework.valiobungee.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy is an object for online proxy in a network
|
||||||
|
*
|
||||||
|
* @author Ham1255
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public interface NetworkProxy {
|
||||||
|
/**
|
||||||
|
* @return return the proxy id of this proxy
|
||||||
|
*/
|
||||||
|
String proxyId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return online players number in this proxy
|
||||||
|
*/
|
||||||
|
int onlinePlayers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return returns true if this object is proxy on it
|
||||||
|
*/
|
||||||
|
boolean isMe();
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ plugins {
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply { plugin("com.diffplug.spotless") }
|
apply { plugin("com.diffplug.spotless") }
|
||||||
apply { plugin("java-library")}
|
apply { plugin("java-library") }
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
@ -33,6 +33,9 @@ subprojects {
|
|||||||
} else {
|
} else {
|
||||||
licenseHeaderFile(rootProject.file("copyright_header.txt"))
|
licenseHeaderFile(rootProject.file("copyright_header.txt"))
|
||||||
}
|
}
|
||||||
|
if (project.name == "valiobungee-core") {
|
||||||
|
targetExclude("**/net/limework/valiobungee/core/proto/**")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.blossom)
|
alias(libs.plugins.blossom)
|
||||||
alias(libs.plugins.indragit)
|
alias(libs.plugins.indragit)
|
||||||
|
alias(libs.plugins.protobuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
description = "Core functions for valiobungee"
|
description = "Core functions for valiobungee"
|
||||||
@ -20,3 +21,24 @@ java {
|
|||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":valiobungee-api"))
|
||||||
|
api(libs.protobuf)
|
||||||
|
api(libs.caffeine)
|
||||||
|
api(libs.slf4j)
|
||||||
|
|
||||||
|
testImplementation(libs.testing.juipter)
|
||||||
|
testImplementation(libs.testing.slf4j.simple)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
protobuf {
|
||||||
|
protoc {
|
||||||
|
artifact = libs.protoc.get().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present ValioBungee contributors
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU GENERAL PUBLIC LICENSE Version 3
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
*/
|
||||||
|
package net.limework.valiobungee.core;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||||
|
import com.github.benmanes.caffeine.cache.RemovalListener;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.limework.valiobungee.core.proto.messages.*;
|
||||||
|
import net.limework.valiobungee.core.util.logging.LogProviderFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This abstract class is responsible for proxy discovery and count online players as its cached
|
||||||
|
* locally Why abstract? Because it allows us to develop alternative implementation to use other
|
||||||
|
* software than valkey or redis
|
||||||
|
*/
|
||||||
|
public abstract class ProxyManager {
|
||||||
|
|
||||||
|
protected final UUID proxyManagerId = UUID.randomUUID();
|
||||||
|
protected final ValioBungeePlatform platform;
|
||||||
|
|
||||||
|
public ProxyManager(ValioBungeePlatform platform) {
|
||||||
|
this.platform = platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Logger log = LogProviderFactory.get();
|
||||||
|
|
||||||
|
// proxy info class here stores the ProxyManager ID hence we use another cache for online players
|
||||||
|
// reason we use caffeine cache it allows us to auto remove entries without need for scheduled
|
||||||
|
// tasks in the proxies when a proxy disappears without sending death message
|
||||||
|
private final Cache<String, Heartbeat> heartbeats =
|
||||||
|
Caffeine.newBuilder()
|
||||||
|
.expireAfterWrite(Duration.ofSeconds(30))
|
||||||
|
.removalListener(
|
||||||
|
(RemovalListener<String, Heartbeat>)
|
||||||
|
(key, value, cause) -> {
|
||||||
|
if (cause == RemovalCause.EXPIRED) {
|
||||||
|
assert value != null;
|
||||||
|
log.warn("proxy {} has disconnected but did not send death message", value);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
protected void handleProxyHeartBeat(Heartbeat payload) {
|
||||||
|
if (!this.heartbeats.asMap().containsKey(payload.getSender().getProxyId()))
|
||||||
|
log.info("Proxy {} has connected!", payload.getSender().getProxyId());
|
||||||
|
this.heartbeats.put(payload.getSender().getProxyId(), payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void handleProxyDeath(Death payload) {
|
||||||
|
this.heartbeats.invalidate(payload.getSender().getProxyId());
|
||||||
|
log.info("Proxy {} has disconnected", payload.getSender().getProxyId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int onlinePlayersCount() {
|
||||||
|
// reason we + local online players because our proxy is not inside it own heartbeat cache
|
||||||
|
return heartbeats.asMap().values().stream().mapToInt(Heartbeat::getOnlinePlayersCount).sum()
|
||||||
|
+ platform.localOnlinePlayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int onlinePlayersCount(String proxyId) {
|
||||||
|
if (proxyId.equals(this.platform.proxyId())) {
|
||||||
|
return platform.localOnlinePlayers();
|
||||||
|
} else {
|
||||||
|
if (!heartbeats.asMap().containsKey(proxyId)) return 0; // don't error?
|
||||||
|
return heartbeats.asMap().get(proxyId).getOnlinePlayersCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ProxyInfo createProxyInfo() {
|
||||||
|
return ProxyInfo.newBuilder()
|
||||||
|
.setProxyId(platform.proxyId())
|
||||||
|
.setProxyManagerId(this.proxyManagerId.toString())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Death createDeathPayload() {
|
||||||
|
return Death.newBuilder().setSender(createProxyInfo()).setReason(DeathReason.SHUTDOWN).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Heartbeat createHeartbeatPayload() {
|
||||||
|
return Heartbeat.newBuilder()
|
||||||
|
.setSender(createProxyInfo())
|
||||||
|
.setOnlinePlayersCount(platform.localOnlinePlayers())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void publishDeathPayload();
|
||||||
|
|
||||||
|
protected abstract void publishHeartbeatPayload();
|
||||||
|
|
||||||
|
public abstract void init();
|
||||||
|
|
||||||
|
public abstract void close();
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present ValioBungee contributors
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU GENERAL PUBLIC LICENSE Version 3
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
*/
|
||||||
|
package net.limework.valiobungee.core;
|
||||||
|
|
||||||
|
public interface ValioBungeePlatform {
|
||||||
|
|
||||||
|
int localOnlinePlayers();
|
||||||
|
|
||||||
|
String platformProxyVendor();
|
||||||
|
|
||||||
|
String networkId();
|
||||||
|
|
||||||
|
String proxyId();
|
||||||
|
|
||||||
|
ProxyManager proxyManager();
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present ValioBungee contributors
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU GENERAL PUBLIC LICENSE Version 3
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
*/
|
||||||
|
package net.limework.valiobungee.core.api.impl;
|
||||||
|
|
||||||
|
import net.limework.valiobungee.api.NetworkProxy;
|
||||||
|
import net.limework.valiobungee.core.ValioBungeePlatform;
|
||||||
|
|
||||||
|
public class ImplNetworkProxy implements NetworkProxy {
|
||||||
|
|
||||||
|
private final ValioBungeePlatform platform;
|
||||||
|
|
||||||
|
private final String proxyId;
|
||||||
|
|
||||||
|
public ImplNetworkProxy(ValioBungeePlatform platform, String proxyId) {
|
||||||
|
this.platform = platform;
|
||||||
|
this.proxyId = proxyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String proxyId() {
|
||||||
|
return this.proxyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onlinePlayers() {
|
||||||
|
return this.platform.proxyManager().onlinePlayersCount(this.proxyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMe() {
|
||||||
|
return this.platform.proxyId().equals(proxyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026-present ValioBungee contributors
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU GENERAL PUBLIC LICENSE Version 3
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
*/
|
||||||
|
package net.limework.valiobungee.core.util.logging;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
public class LogProviderFactory {
|
||||||
|
private static Logger instance;
|
||||||
|
|
||||||
|
public static void register(Logger logger) {
|
||||||
|
if (instance != null) throw new IllegalStateException("Logger already registered");
|
||||||
|
instance = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger get() {
|
||||||
|
if (instance == null) throw new IllegalStateException("No logger registered");
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
core/src/main/proto/message-protocol.proto
Normal file
28
core/src/main/proto/message-protocol.proto
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package net.limework.valiobungee.core.proto.messages;
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
message ProxyInfo {
|
||||||
|
string proxy_id = 1; // UNIQUE ID
|
||||||
|
string proxy_manager_id = 2; // ProxyManager id. changes every reboot, used to detect duplicate proxy names
|
||||||
|
}
|
||||||
|
|
||||||
|
// heartbeat ._.?
|
||||||
|
|
||||||
|
message Heartbeat {
|
||||||
|
ProxyInfo sender = 1;
|
||||||
|
int32 online_players_count = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// death
|
||||||
|
enum DeathReason {
|
||||||
|
UNSPECIFIED = 0; // TESTING ONLY
|
||||||
|
RELOAD = 1; // plugin reload
|
||||||
|
SHUTDOWN = 2; // proxy shutdown
|
||||||
|
}
|
||||||
|
message Death {
|
||||||
|
ProxyInfo sender = 1; // proxy that died
|
||||||
|
DeathReason reason = 2;
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,10 +1,24 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
protobuf-plugin = "0.9.5"
|
||||||
|
protobuf = "3.25.8" # needed for reference to be used for protoc
|
||||||
|
slf4j = "2.0.17"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
blossom = "net.kyori.blossom:2.2.0"
|
blossom = "net.kyori.blossom:2.2.0"
|
||||||
indragit = "net.kyori.indra.git:4.0.0"
|
indragit = "net.kyori.indra.git:4.0.0"
|
||||||
shadow = "com.gradleup.shadow:9.3.1"
|
shadow = "com.gradleup.shadow:9.3.1"
|
||||||
spotless = "com.diffplug.spotless:8.2.0"
|
spotless = "com.diffplug.spotless:8.2.0"
|
||||||
|
protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" }
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
redisson = "org.redisson:redisson:4.3.0"
|
||||||
|
protobuf = { group = "com.google.protobuf", name = "protobuf-java", version.ref = "protobuf" }
|
||||||
|
protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" }
|
||||||
|
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3"
|
||||||
|
|
||||||
|
# logging
|
||||||
|
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
|
||||||
|
# testing
|
||||||
|
testing-juipter = "org.junit.jupiter:junit-jupiter:6.0.3"
|
||||||
|
testing-slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user