Browse Source

rewrite to python a2s side

master
gsd 2 years ago
parent
commit
dd26504958
  1. 2
      ext/python-a2s-rcon-api/Dockerfile
  2. 18
      ext/python-a2s-rcon-api/RCONPlayerModel.py
  3. 4
      ext/python-a2s-rcon-api/docker-compose.yaml
  4. 7
      ext/python-a2s-rcon-api/service.py
  5. 39
      src/main/java/app/entities/Stats.java
  6. 74
      src/main/java/app/entities/a2s/external/ExternalValveClient.java
  7. 162
      src/main/java/app/entities/a2s/internal/InternalValveClient.java
  8. 17
      src/main/java/app/entities/a2s/requests/A2SRequest.java
  9. 23
      src/main/java/app/entities/a2s/requests/RCONRequest.java
  10. 51
      src/main/java/app/entities/server/BaseServer.java
  11. 113
      src/main/java/app/entities/server/Server.java
  12. 1
      src/main/java/app/entities/server/players/DefaultPlayer.java
  13. 12
      src/main/java/app/entities/server/players/RCONPlayer.java
  14. 2
      src/main/java/app/updates/PlayersUpdater.java
  15. 2
      src/main/resources/application.yaml
  16. 29
      src/test/java/app/servers/TestExternalA2S.java

2
ext/python-a2s-rcon-api/Dockerfile

@ -1,5 +1,5 @@
FROM python:3.10
RUN python -m pip install git+https://github.com/Yepoleb/python-a2s git+https://github.com/conqp/rcon git+https://github.com/tiangolo/fastapi "uvicorn[standard]" && mkdir /app
RUN python -m pip install git+https://github.com/Yepoleb/python-a2s git+https://github.com/conqp/rcon git+https://github.com/tiangolo/fastapi "uvicorn[standard]" git+https://github.com/ValvePython/steam && mkdir /app
WORKDIR /app
COPY ./ ./
ENV PYTHONUNBUFFERED 1

18
ext/python-a2s-rcon-api/RCONPlayerModel.py

@ -1,15 +1,26 @@
from pydantic import BaseModel
from steam.steamid import SteamID
import re
class BotPlayer(Exception):
pass
def GetSteam(steamid):
steam_obj = SteamID(steamid)
return {
"steam3":steam_obj.as_steam3,
"steam2":steam_obj.as_steam2_zero,
"steam64":steam_obj.as_64,
"account_id":steam_obj.as_32,
"community_url":steam_obj.community_url
}
class RCONPlayer:
#DefaultPlayer
name: str
score: int
id: int = 0
steam = None
steam: dict
#RCONPlayer
duration: str
ip: str
@ -22,6 +33,7 @@ class RCONPlayer:
def __init__(self, status_line:str):
splited = re.split(r"\s+", status_line)
len = splited.__len__()
try:
self.id = int(splited[1])
self.ip = splited[len - 1]
self.state = splited[len - 2]
@ -32,3 +44,7 @@ class RCONPlayer:
self.duration = splited[len - 5]
self.steam2 = splited[len - 6]
self.name = " ".join(splited[2:len-6])[1:-1]
self.steam = GetSteam(self.steam2)
except ValueError as err:
print(splited)
raise err

4
ext/python-a2s-rcon-api/docker-compose.yaml

@ -1,5 +1,7 @@
services:
a2s_backend:
build: ./
extra_hosts:
- "tf2.pblr-nyk.pro:192.168.3.3"
ports:
- 8082:8082
- 8085:8082

7
ext/python-a2s-rcon-api/service.py

@ -50,6 +50,7 @@ class SourceBackend:
@self.app.post("/api/rcon")
async def execute_rcon(request: RCON_Request):
#print(request.__dict__)
if not request.fulled_data:
return Response(status_code=409)
try:
@ -64,6 +65,7 @@ class SourceBackend:
@self.app.post("/api/a2s/info")
async def get_a2s_info(request: A2S_request):
#print(request.__dict__)
if not request.address:
return Response(status_code=409)
try:
@ -74,6 +76,7 @@ class SourceBackend:
@self.app.post("/api/a2s/players")
async def get_a2s_players(request: A2S_request):
#print(request.__dict__)
if not request.address:
return Response(status_code=409)
try:
@ -84,7 +87,11 @@ class SourceBackend:
@self.app.post("/api/players")
async def get_players(request: RCON_Request):
#print(request.__dict__)
a2s_players = await VALVE_SERVER_PLAYERS(request.tuple_address)
if(request.password == None):
return Response(status_code = 403)
status_lines:str = await VALVE_SERVER_RCON(
"status",
host = request.address,

39
src/main/java/app/entities/Stats.java

@ -77,43 +77,4 @@ public class Stats {
uniq.merge(key, value, (x, y) -> y);
}
public void RefreshServerA2SData(String server_name) {
//try (SourceQueryClient sourceQueryClient = context.getBean(SourceQueryClient.class)) {
try (SourceQueryClient sourceQueryClient = getServers().get(server_name).GetSourceQueryClient()) {
sourceQueryClient.getInfo(getServers().get(server_name).getInetAddress()).whenComplete((info, error) -> {
if (!sourceQueryClient.getExecutor().isShutdown()) sourceQueryClient.getExecutor().shutdown();
if (error != null) {
getServers().get(server_name).SetDownStatus();
return;
}
getServers().get(server_name).UpdateStatusFromA2S(info);
}).join();
} catch (CompletionException | IOException err) {
}
if (!getServers().get(server_name).isStatus() || getServers().get(server_name).getPlayer_count() < 1) {
return;
}
////////////////////////////////////////////////////////////////////////
//If player count > 0 make base player request
////////////////////////////////////////////////////////////////////////
//try (SourceQueryClient sourceQueryClient = context.getBean(SourceQueryClient.class)) {
try (SourceQueryClient sourceQueryClient = getServers().get(server_name).GetSourceQueryClient()) {
sourceQueryClient.getPlayers(getServers().get(server_name).getInetAddress()).whenComplete((players, error) -> {
if (!sourceQueryClient.getExecutor().isShutdown()) sourceQueryClient.getExecutor().shutdown();
if (error != null) return;
getServers().get(server_name).UpdatePlayersFromA2S(players);
}).join();
} catch (CompletionException | IOException err) {}
///////////////////////////////////////////////////////////////////////
//Extend current players of rcon result
//////////////////////////////////////////////////////////////////////
try {
String response = getServers().get(server_name).ExecuteRCON("status");
getServers().get(server_name).UpdatePlayersFromRCON(response);
} catch (RconException | CompletionException err) {
return;
}
}
}

74
src/main/java/app/entities/a2s/external/ExternalValveClient.java

@ -0,0 +1,74 @@
package app.entities.a2s.external;
import app.entities.a2s.requests.A2SRequest;
import app.entities.a2s.requests.RCONRequest;
import app.entities.server.players.RCONPlayer;
import app.utils.SteamIDConverter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class ExternalValveClient {
@JsonIgnore
RestTemplate restTemplate;
@JsonIgnore
boolean enabled = true;
@JsonIgnore
public String gateway = System.getenv("A2S_BACKEND_URL");
public ExternalValveClient(){
restTemplate = new RestTemplate();
CheckApi();
}
public void CheckApi(){
System.out.printf("Check status: %s/api/ping\n", gateway);
try {
enabled = restTemplate.getForEntity("%s/api/ping".formatted(gateway), HashMap.class).getBody().containsKey("pong");
} catch (Exception err) {
System.out.print("A2S Backend not respond\n");
}
}
@JsonIgnore
public String ExecuteRCON(RCONRequest request){
if(!enabled) {
System.out.printf("External client not enabled, cannot get rcon on %s\n", gateway);
return "not enabled";
}
try {
return restTemplate.postForEntity("%s/api/rcon".formatted(gateway), request, String.class).getBody();
} catch (Exception err) {
return "backend error";
}
}
@JsonIgnore
public HashMap GetA2SInfo(A2SRequest request){
if(!enabled) {
System.out.printf("External client not enabled, cannot get a2s on %s\n", gateway);
return null;
}
try {
return restTemplate.postForEntity("%s/api/a2s/info".formatted(gateway), request, HashMap.class).getBody();
} catch (Exception err) {
return null;
}
}
public List<RCONPlayer> GetRCONPlayers(RCONRequest request){
if(!enabled) {
System.out.printf("External client not enabled, cannot get rcon players on %s\n", gateway);
return null;
}
try {
return restTemplate.postForEntity("%s/api/players".formatted(gateway), request, List.class).getBody();
} catch (Exception err) {
err.printStackTrace();
return List.of();
}
}
}

162
src/main/java/app/entities/a2s/internal/InternalValveClient.java

@ -0,0 +1,162 @@
package app.entities.a2s.internal;
import app.entities.a2s.requests.RCONRequest;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ibasco.agql.core.enums.RateLimitType;
import com.ibasco.agql.core.util.FailsafeOptions;
import com.ibasco.agql.core.util.GeneralOptions;
import com.ibasco.agql.protocols.valve.source.query.SourceQueryClient;
import com.ibasco.agql.protocols.valve.source.query.SourceQueryOptions;
import com.ibasco.agql.protocols.valve.source.query.rcon.SourceRconClient;
import com.ibasco.agql.protocols.valve.source.query.rcon.SourceRconOptions;
import com.ibasco.agql.protocols.valve.source.query.rcon.message.SourceRconAuthResponse;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class InternalValveClient {
@JsonIgnore
private ExecutorService executorServices_query;
@JsonIgnore
private ExecutorService executorServices_rcon;
@JsonIgnore
private SourceRconClient sourceRconClient;
@JsonIgnore
private SourceQueryClient sourceQueryClient;
@JsonIgnore
public SourceRconClient GetSourceRconClient() {
if (executorServices_rcon == null) executorServices_rcon = Executors.newCachedThreadPool();
if (sourceRconClient == null) {
SourceRconOptions options = SourceRconOptions.builder()
.option(FailsafeOptions.FAILSAFE_RATELIMIT_TYPE, RateLimitType.SMOOTH)
.option(GeneralOptions.THREAD_EXECUTOR_SERVICE, executorServices_rcon)
.build();
sourceRconClient = new SourceRconClient(options);
}
return sourceRconClient;
}
@JsonIgnore
public SourceQueryClient GetSourceQueryClient() {
if (executorServices_query == null) executorServices_query = Executors.newCachedThreadPool();
if (sourceQueryClient == null) {
SourceQueryOptions options = SourceQueryOptions.builder()
.option(FailsafeOptions.FAILSAFE_RATELIMIT_TYPE, RateLimitType.SMOOTH)
.option(GeneralOptions.THREAD_EXECUTOR_SERVICE, executorServices_query)
.build();
sourceQueryClient = new SourceQueryClient(options);
}
return sourceQueryClient;
}
@JsonIgnore
public String ExecuteRCON(RCONRequest request) {
try (SourceRconClient rconClient = GetSourceRconClient()) {
SourceRconAuthResponse response = rconClient.authenticate(request.getInetAddress(), request.getPassword().getBytes()).join();
if (!response.isAuthenticated()) {
if (!rconClient.getExecutor().isShutdown()) rconClient.getExecutor().shutdown();
return null;
}
return rconClient.execute(request.getInetAddress(), request.getCommand())
.thenApplyAsync(out -> {
rconClient.cleanup(true);
return out.getResult();
})
.join();
} catch (Exception err) {
return "";
}
}
/*
* public void UpdateStatusFromA2S(SourceQueryInfoResponse response) {
SetDownStatus();
if (response == null) return;
setMax_players(response.getResult().getMaxPlayers());
setPlayer_count(response.getResult().getNumOfPlayers());
setMap(response.getResult().getMapName());
setStatus(true);
}*/
/*
* public void RefreshServerA2SData(String server_name) {
//try (SourceQueryClient sourceQueryClient = context.getBean(SourceQueryClient.class)) {
try (SourceQueryClient sourceQueryClient = getServers().get(server_name).GetSourceQueryClient()) {
sourceQueryClient.getInfo(getServers().get(server_name).getInetAddress()).whenComplete((info, error) -> {
if (!sourceQueryClient.getExecutor().isShutdown()) sourceQueryClient.getExecutor().shutdown();
if (error != null) {
getServers().get(server_name).SetDownStatus();
return;
}
getServers().get(server_name).UpdateStatusFromA2S(info);
}).join();
} catch (CompletionException | IOException err) {
}
if (!getServers().get(server_name).isStatus() || getServers().get(server_name).getPlayer_count() < 1) {
return;
}
////////////////////////////////////////////////////////////////////////
//If player count > 0 make base player request
////////////////////////////////////////////////////////////////////////
//try (SourceQueryClient sourceQueryClient = context.getBean(SourceQueryClient.class)) {
try (SourceQueryClient sourceQueryClient = getServers().get(server_name).GetSourceQueryClient()) {
sourceQueryClient.getPlayers(getServers().get(server_name).getInetAddress()).whenComplete((players, error) -> {
if (!sourceQueryClient.getExecutor().isShutdown()) sourceQueryClient.getExecutor().shutdown();
if (error != null) return;
getServers().get(server_name).UpdatePlayersFromA2S(players);
}).join();
} catch (CompletionException | IOException err) {}
///////////////////////////////////////////////////////////////////////
//Extend current players of rcon result
//////////////////////////////////////////////////////////////////////
try {
String response = getServers().get(server_name).ExecuteRCON("status");
getServers().get(server_name).UpdatePlayersFromRCON(response);
} catch (RconException | CompletionException err) {
return;
}
}*/
/*
* public void UpdatePlayersFromA2S(SourceQueryPlayerResponse response) {
a2s_players.clear();
if (response != null) {
response.getResult().stream().map(app.entities.server.players.SourcePlayer::new).forEach(a2s_players::add);
}
}
public void UpdatePlayersFromRCON(String response) {
players.clear();
int start_index = response.indexOf("# userid");
if (start_index == -1) return;
List<String> players_list = Arrays.stream(response.substring(start_index, response.length()).split("\n")).toList();
boolean skip_table_header = true;
for(String player_text: players_list) {
if (skip_table_header || player_text.length() < 1) {
skip_table_header = false;
continue;
}
/////////////////////////////////////////////////////
List<String> player_line = Arrays.stream(player_text.split("\\s+")).toList();
RCONPlayer player;
try {
player = new RCONPlayer(player_line);
} catch (Exception parse_err) {
System.out.println("Cannot parse: " + player_line);
continue;
}
for (SourcePlayer sourcePlayer: a2s_players) {
if (sourcePlayer.getName().equals(player.getName())) {
player.setScore(sourcePlayer.getScore());
a2s_players.remove(sourcePlayer);
players.add(player);
break;
}
}
}
a2s_players.clear();
}*/
}

17
src/main/java/app/entities/a2s/requests/A2SRequest.java

@ -0,0 +1,17 @@
package app.entities.a2s.requests;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.AllArgsConstructor;
import lombok.Data;
@JsonSerialize
@Data
public class A2SRequest {
String server;
public A2SRequest(){}
public A2SRequest(String server){
this.server = server;
}
}

23
src/main/java/app/entities/a2s/requests/RCONRequest.java

@ -0,0 +1,23 @@
package app.entities.a2s.requests;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.net.InetSocketAddress;
@JsonSerialize
@AllArgsConstructor
@Getter
public class RCONRequest extends A2SRequest{
String server;
String password;
String command;
@JsonIgnore
public InetSocketAddress getInetAddress() {
String[] splitted_address = server.split(":", 2);
return new InetSocketAddress(splitted_address[0], Integer.parseInt(splitted_address[1]));
}
}

51
src/main/java/app/entities/server/BaseServer.java

@ -1,51 +0,0 @@
package app.entities.server;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ibasco.agql.core.enums.RateLimitType;
import com.ibasco.agql.core.util.FailsafeOptions;
import com.ibasco.agql.core.util.GeneralOptions;
import com.ibasco.agql.protocols.valve.source.query.SourceQueryClient;
import com.ibasco.agql.protocols.valve.source.query.SourceQueryOptions;
import com.ibasco.agql.protocols.valve.source.query.rcon.SourceRconClient;
import com.ibasco.agql.protocols.valve.source.query.rcon.SourceRconOptions;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class BaseServer {
@JsonIgnore
private ExecutorService executorServices_query;
@JsonIgnore
private ExecutorService executorServices_rcon;
@JsonIgnore
private SourceRconClient sourceRconClient;
@JsonIgnore
private SourceQueryClient sourceQueryClient;
@JsonIgnore
public SourceRconClient GetSourceRconClient() {
if (executorServices_rcon == null) executorServices_rcon = Executors.newCachedThreadPool();
if (sourceRconClient == null) {
SourceRconOptions options = SourceRconOptions.builder()
.option(FailsafeOptions.FAILSAFE_RATELIMIT_TYPE, RateLimitType.SMOOTH)
.option(GeneralOptions.THREAD_EXECUTOR_SERVICE, executorServices_rcon)
.build();
sourceRconClient = new SourceRconClient(options);
}
return sourceRconClient;
}
@JsonIgnore
public SourceQueryClient GetSourceQueryClient() {
if (executorServices_query == null) executorServices_query = Executors.newCachedThreadPool();
if (sourceQueryClient == null) {
SourceQueryOptions options = SourceQueryOptions.builder()
.option(FailsafeOptions.FAILSAFE_RATELIMIT_TYPE, RateLimitType.SMOOTH)
.option(GeneralOptions.THREAD_EXECUTOR_SERVICE, executorServices_query)
.build();
sourceQueryClient = new SourceQueryClient(options);
}
return sourceQueryClient;
}
}

113
src/main/java/app/entities/server/Server.java

@ -1,37 +1,24 @@
package app.entities.server;
import app.entities.a2s.requests.A2SRequest;
import app.entities.other.SteamID;
import app.entities.server.players.DefaultPlayer;
import app.entities.a2s.external.ExternalValveClient;
import app.entities.a2s.requests.RCONRequest;
import app.entities.server.players.RCONPlayer;
import app.entities.server.players.SourcePlayer;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.ibasco.agql.core.enums.RateLimitType;
import com.ibasco.agql.core.util.FailsafeOptions;
import com.ibasco.agql.core.util.GeneralOptions;
import com.ibasco.agql.protocols.valve.source.query.SourceQueryClient;
import com.ibasco.agql.protocols.valve.source.query.SourceQueryOptions;
import com.ibasco.agql.protocols.valve.source.query.info.SourceQueryInfoResponse;
import com.ibasco.agql.protocols.valve.source.query.players.SourceQueryPlayerResponse;
import com.ibasco.agql.protocols.valve.source.query.rcon.SourceRconClient;
import com.ibasco.agql.protocols.valve.source.query.rcon.SourceRconOptions;
import com.ibasco.agql.protocols.valve.source.query.rcon.message.SourceRconAuthResponse;
import com.ibasco.agql.protocols.valve.source.query.rcon.message.SourceRconCmdResponse;
import jakarta.persistence.criteria.CriteriaBuilder;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Data
public class Server extends BaseServer {
public class Server extends ExternalValveClient {
String name;
String description;
String address;
@ -45,8 +32,6 @@ public class Server extends BaseServer {
List<String> naming;
HashMap<String, Long> uniq = new HashMap<>();
List<RCONPlayer> players = new ArrayList<>();
@JsonIgnore
List<SourcePlayer> a2s_players = new ArrayList<>();
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String db;
@ -55,83 +40,45 @@ public class Server extends BaseServer {
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String rcon_password;
@Override
public String toString() {
return "Address: %s\nPlayers: %d/%d\nMap: %s".formatted(address, player_count, max_players, map);
}
public void UpdateUniq(String key, Long count) {
uniq.merge(key, count, (x,y) -> y);
}
@JsonIgnore
public InetSocketAddress getInetAddress() {
String[] splitted_address = address.split(":", 2);
return new InetSocketAddress(splitted_address[0], Integer.parseInt(splitted_address[1]));
public void RefreshServerA2SData() {
UpdateStatusFromA2S();
///////////////////////////////////////////
if (!isStatus() || getPlayer_count() < 1) {
return;
}
public void UpdateStatusFromA2S(SourceQueryInfoResponse response) {
SetDownStatus();
if (response == null) return;
setMax_players(response.getResult().getMaxPlayers());
setPlayer_count(response.getResult().getNumOfPlayers());
setMap(response.getResult().getMapName());
setStatus(true);
///////////////////////////////////////////
UpdatePlayers();
}
public void UpdatePlayersFromA2S(SourceQueryPlayerResponse response) {
a2s_players.clear();
public void UpdateStatusFromA2S(){
SetDownStatus();
HashMap response = super.GetA2SInfo(new A2SRequest(getAddress()));
if (response != null) {
response.getResult().stream().map(app.entities.server.players.SourcePlayer::new).forEach(a2s_players::add);
setMax_players((int) response.get("max_players"));
setPlayer_count((int) response.get("player_count"));
setMap((String) response.get("map_name"));
setStatus(true);
}
}
public void UpdatePlayersFromRCON(String response) {
public void UpdatePlayers(){
players.clear();
int start_index = response.indexOf("# userid");
if (start_index == -1) return;
List<String> players_list = Arrays.stream(response.substring(start_index, response.length()).split("\n")).toList();
boolean skip_table_header = true;
for(String player_text: players_list) {
if (skip_table_header || player_text.length() < 1) {
skip_table_header = false;
continue;
}
/////////////////////////////////////////////////////
List<String> player_line = Arrays.stream(player_text.split("\\s+")).toList();
RCONPlayer player;
try {
player = new RCONPlayer(player_line);
} catch (Exception parse_err) {
System.out.println("Cannot parse: " + player_line);
continue;
players = GetRCONPlayers(
new RCONRequest(getAddress(), getRcon_password(), "status")
);
}
for (SourcePlayer sourcePlayer: a2s_players) {
if (sourcePlayer.getName().equals(player.getName())) {
player.setScore(sourcePlayer.getScore());
a2s_players.remove(sourcePlayer);
players.add(player);
break;
}
}
}
a2s_players.clear();
}
@JsonIgnore
public String ExecuteRCON(String command) {
try (SourceRconClient rconClient = GetSourceRconClient()) {
SourceRconAuthResponse response = rconClient.authenticate(getInetAddress(), getRcon_password().getBytes()).join();
if (!response.isAuthenticated()) {
if (!rconClient.getExecutor().isShutdown()) rconClient.getExecutor().shutdown();
return null;
}
return rconClient.execute(getInetAddress(), command)
.thenApplyAsync(out -> {
rconClient.cleanup(true);
return out.getResult();
})
.join();
} catch (Exception err) {
return "";
}
public String ExecuteRCON(String command){
return super.ExecuteRCON(new RCONRequest(getAddress(), getRcon_password(), command));
}
public void SetDownStatus() {
@ -144,7 +91,7 @@ public class Server extends BaseServer {
@JsonIgnore
public RCONPlayer searchPlayer(SteamID steamID){
return (RCONPlayer) players.stream().filter(player -> player.getSteam().is(steamID)).findFirst().orElse(null);
return players.stream().filter(player -> player.getSteam().is(steamID)).findFirst().orElse(null);
}
@JsonIgnore

1
src/main/java/app/entities/server/players/DefaultPlayer.java

@ -8,5 +8,4 @@ public class DefaultPlayer {
String name;
int score;
int id = 0;
SteamID steam = new SteamID();
}

12
src/main/java/app/entities/server/players/RCONPlayer.java

@ -3,8 +3,13 @@ package app.entities.server.players;
import app.entities.other.SteamID;
import app.entities.server.players.DefaultPlayer;
import app.utils.SteamIDConverter;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import lombok.Getter;
import java.util.List;
@ -18,6 +23,13 @@ public class RCONPlayer extends DefaultPlayer {
int ping;
String state;
String steam2;
SteamID steam;
@JsonGetter("steam")
public SteamID getSteam() {
if (steam == null) steam = SteamIDConverter.getSteamID(steam2);
return steam;
}
public RCONPlayer(List<String> status_line) {
id = Integer.parseInt(status_line.get(1));

2
src/main/java/app/updates/PlayersUpdater.java

@ -29,7 +29,7 @@ public class PlayersUpdater extends BaseUpdater{
if (update) {
stats.getServers().forEach((server_name, server) -> {
CreateTaskUpdater(() -> {
stats.RefreshServerA2SData(server_name);
server.RefreshServerA2SData();
stats.getUpdates().merge(server_name, Instant.now().getEpochSecond(), (x, y) -> y);
return null;
}, timeout);

2
src/main/resources/application.yaml

@ -45,6 +45,8 @@ backend:
kd: 300
vip:
discord: ${VIP_DISCORD_WEBHOOK}
a2s:
backend_url: ${A2S_BACKEND_URL}
logging:
level:

29
src/test/java/app/servers/TestExternalA2S.java

@ -0,0 +1,29 @@
package app.servers;
import app.entities.a2s.external.ExternalValveClient;
import app.entities.server.Server;
import org.junit.Test;
public class TestExternalA2S {
Server server = new Server();
public TestExternalA2S(){
server.gateway = System.getenv("A2S_BACKEND_URL");
server.setAddress(System.getenv("TEST_SERVER"));
}
@Test
public void CheckA2SInfo(){
server.UpdateStatusFromA2S();
System.out.printf("%s\n", server);
}
@Test
public void CheckPlayers(){
server.setRcon_password(System.getenv("TEST_SERVER_PASSWORD"));
server.UpdatePlayers();
System.out.print(server.getPlayers());
}
}
Loading…
Cancel
Save