Browse Source

логирование и подгрузка данных на ходу при вызове эндпоинта

master
gsd 2 years ago
parent
commit
7defa9c446
  1. 2
      ext/python-a2s-rcon-api/RCONPlayerModel.py
  2. 2
      ext/python-a2s-rcon-api/docker-compose.yaml
  3. 8
      ext/python-a2s-rcon-api/service.py
  4. 6
      src/main/java/app/annotations/impl/PermitionFlagAspect.java
  5. 31
      src/main/java/app/annotations/impl/UpdatePlayersAspect.java
  6. 11
      src/main/java/app/annotations/impl/WebAccessAspect.java
  7. 11
      src/main/java/app/annotations/interfaces/BurstUpdatePlayers.java
  8. 2
      src/main/java/app/controllers/StatsController.java
  9. 2
      src/main/java/app/controllers/admin/BanController.java
  10. 2
      src/main/java/app/controllers/admin/KickController.java
  11. 2
      src/main/java/app/controllers/user/DetailController.java
  12. 3
      src/main/java/app/controllers/user/ProfileController.java
  13. 18
      src/main/java/app/entities/a2s/external/ExternalValveClient.java
  14. 23
      src/main/java/app/updates/PlayersUpdater.java
  15. 3
      src/main/resources/application.yaml

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

@ -45,6 +45,6 @@ class RCONPlayer:
self.steam2 = splited[len - 6] self.steam2 = splited[len - 6]
self.name = " ".join(splited[2:len-6])[1:-1] self.name = " ".join(splited[2:len-6])[1:-1]
self.steam = GetSteam(self.steam2) self.steam = GetSteam(self.steam2)
except ValueError as err: except (ValueError, IndexError) as err:
print(splited) print(splited)
raise err raise err

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

@ -2,6 +2,6 @@ services:
a2s_backend: a2s_backend:
build: ./ build: ./
extra_hosts: extra_hosts:
- "tf2.pblr-nyk.pro:192.168.3.1" - "tf2.pblr-nyk.pro:192.168.3.3"
ports: ports:
- 8085:8082 - 8085:8082

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

@ -34,6 +34,10 @@ class RCON_Request(A2S_request):
def fulled_data(self): def fulled_data(self):
return self.server and self.password and self.command return self.server and self.password and self.command
class EndpointFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
return record.getMessage().find("/api") == -1
class SourceBackend: class SourceBackend:
app = None app = None
@ -43,7 +47,7 @@ class SourceBackend:
def run(self, host = "0.0.0.0", port = 45353): def run(self, host = "0.0.0.0", port = 45353):
import uvicorn import uvicorn
logging.getLogger("uvicorn.info").disabled = True logging.getLogger("uvicorn.access").addFilter(EndpointFilter())
uvicorn.run(self.app, host = host, port = port) uvicorn.run(self.app, host = host, port = port)
def setup_routes(self): def setup_routes(self):
@ -119,7 +123,7 @@ class SourceBackend:
continue continue
try: try:
players.append(RCONPlayer(line).__dict__) players.append(RCONPlayer(line).__dict__)
except BotPlayer: except (BotPlayer, ValueError, IndexError):
pass pass
except: except:
traceback.print_exc() traceback.print_exc()

6
src/main/java/app/annotations/impl/PermitionFlagAspect.java

@ -11,6 +11,8 @@ import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -22,6 +24,8 @@ import java.util.List;
public class PermitionFlagAspect { public class PermitionFlagAspect {
ProfileService profileService; ProfileService profileService;
private final Logger logger = LoggerFactory.getLogger(PermitionFlagAspect.class);
@Autowired @Autowired
public PermitionFlagAspect(ProfileService profileService) { public PermitionFlagAspect(ProfileService profileService) {
this.profileService = profileService; this.profileService = profileService;
@ -37,7 +41,7 @@ public class PermitionFlagAspect {
@Before(value = "@annotation(app.annotations.interfaces.CheckPermitionFlag) && args(request,..)") @Before(value = "@annotation(app.annotations.interfaces.CheckPermitionFlag) && args(request,..)")
public void before(JoinPoint joinPoint, HttpServletRequest request){ public void before(JoinPoint joinPoint, HttpServletRequest request){
String flag = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckPermitionFlag.class).flag(); String flag = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckPermitionFlag.class).flag();
System.out.println("check permition flag"); logger.info("check permition flag, requested: {}", flag);
if(!(request instanceof HttpServletRequest)) { if(!(request instanceof HttpServletRequest)) {
throw new RuntimeException("invalid request"); throw new RuntimeException("invalid request");
} }

31
src/main/java/app/annotations/impl/UpdatePlayersAspect.java

@ -0,0 +1,31 @@
package app.annotations.impl;
import app.updates.PlayersUpdater;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.time.Instant;
@Aspect
@Configuration
public class UpdatePlayersAspect {
PlayersUpdater playersUpdater;
private long last_burst_update = 0;
private int burst_timeout = 5;
@Autowired
public UpdatePlayersAspect(PlayersUpdater playersUpdater) {
this.playersUpdater = playersUpdater;
}
@Before("@annotation(app.annotations.interfaces.BurstUpdatePlayers) && args(..)")
public void before() {
if (Instant.now().getEpochSecond() - last_burst_update < burst_timeout) {
return;
}
playersUpdater.burstUpdater();
last_burst_update = Instant.now().getEpochSecond();
}
}

11
src/main/java/app/annotations/impl/WebAccessAspect.java

@ -5,12 +5,15 @@ import app.annotations.exceptions.InvalidCookie;
import app.annotations.exceptions.InvalidSecretKey; import app.annotations.exceptions.InvalidSecretKey;
import app.annotations.exceptions.NeedCookie; import app.annotations.exceptions.NeedCookie;
import app.annotations.interfaces.CheckWebAccess; import app.annotations.interfaces.CheckWebAccess;
import app.entities.a2s.external.ExternalValveClient;
import app.utils.SaltedCookie; import app.utils.SaltedCookie;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -19,6 +22,8 @@ import org.springframework.context.annotation.Configuration;
public class WebAccessAspect { public class WebAccessAspect {
SaltedCookie saltedCookie; SaltedCookie saltedCookie;
private final Logger logger = LoggerFactory.getLogger(WebAccessAspect.class);
@Autowired @Autowired
public WebAccessAspect(SaltedCookie saltedCookie) { public WebAccessAspect(SaltedCookie saltedCookie) {
this.saltedCookie = saltedCookie; this.saltedCookie = saltedCookie;
@ -27,7 +32,7 @@ public class WebAccessAspect {
@Before("@annotation(app.annotations.interfaces.CheckWebAccess) && args(request,..)") @Before("@annotation(app.annotations.interfaces.CheckWebAccess) && args(request,..)")
public void before(JoinPoint joinPoint, HttpServletRequest request){ public void before(JoinPoint joinPoint, HttpServletRequest request){
AuthMethod auth_method = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckWebAccess.class).auth_method(); AuthMethod auth_method = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CheckWebAccess.class).auth_method();
System.out.println("check web access"); logger.info("check web access");
if(!(request instanceof HttpServletRequest)) { if(!(request instanceof HttpServletRequest)) {
throw new RuntimeException("cannot read cookie from invalid request"); throw new RuntimeException("cannot read cookie from invalid request");
} }
@ -62,7 +67,7 @@ public class WebAccessAspect {
case COMBINED -> { case COMBINED -> {
if (!secret_key.isEmpty() && !steam64.isEmpty()) { if (!secret_key.isEmpty() && !steam64.isEmpty()) {
if (saltedCookie.ValidateSecretKey(secret_key)) { if (saltedCookie.ValidateSecretKey(secret_key)) {
System.out.println("used secret key with steamid"); logger.info("used secret key with steamid: {}", steam64);
return; return;
} else { } else {
throw new InvalidSecretKey(); throw new InvalidSecretKey();
@ -73,7 +78,7 @@ public class WebAccessAspect {
case SECRET_KEY -> { case SECRET_KEY -> {
if (secret_key.isEmpty()) throw new InvalidSecretKey(); if (secret_key.isEmpty()) throw new InvalidSecretKey();
if (saltedCookie.ValidateSecretKey(secret_key)) { if (saltedCookie.ValidateSecretKey(secret_key)) {
System.out.println("used secret key without steamid"); logger.info("used secret key without steamid");
return; return;
} else { } else {
throw new InvalidSecretKey(); throw new InvalidSecretKey();

11
src/main/java/app/annotations/interfaces/BurstUpdatePlayers.java

@ -0,0 +1,11 @@
package app.annotations.interfaces;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BurstUpdatePlayers {
}

2
src/main/java/app/controllers/StatsController.java

@ -1,5 +1,6 @@
package app.controllers; package app.controllers;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.entities.Stats; import app.entities.Stats;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -19,6 +20,7 @@ public class StatsController {
} }
@GetMapping @GetMapping
@BurstUpdatePlayers
public ResponseEntity GetStats(){ public ResponseEntity GetStats(){
return new ResponseEntity<>(stats, HttpStatus.OK); return new ResponseEntity<>(stats, HttpStatus.OK);
} }

2
src/main/java/app/controllers/admin/BanController.java

@ -1,6 +1,7 @@
package app.controllers.admin; package app.controllers.admin;
import app.annotations.enums.AuthMethod; import app.annotations.enums.AuthMethod;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.annotations.interfaces.CheckPermitionFlag; import app.annotations.interfaces.CheckPermitionFlag;
import app.annotations.interfaces.CheckWebAccess; import app.annotations.interfaces.CheckWebAccess;
import app.entities.db.Ban; import app.entities.db.Ban;
@ -35,6 +36,7 @@ public class BanController {
@PostMapping @PostMapping
@CheckWebAccess @CheckWebAccess
@CheckPermitionFlag(flag = "d") @CheckPermitionFlag(flag = "d")
@BurstUpdatePlayers
public ResponseEntity banPlayer( public ResponseEntity banPlayer(
HttpServletRequest request, HttpServletRequest request,
@CookieValue(value = "steam64") String admin_steam64, @CookieValue(value = "steam64") String admin_steam64,

2
src/main/java/app/controllers/admin/KickController.java

@ -1,5 +1,6 @@
package app.controllers.admin; package app.controllers.admin;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.annotations.interfaces.CheckPermitionFlag; import app.annotations.interfaces.CheckPermitionFlag;
import app.annotations.interfaces.CheckWebAccess; import app.annotations.interfaces.CheckWebAccess;
import app.entities.PlayerProfile; import app.entities.PlayerProfile;
@ -34,6 +35,7 @@ public class KickController {
@PostMapping @PostMapping
@CheckWebAccess @CheckWebAccess
@CheckPermitionFlag(flag = "c") @CheckPermitionFlag(flag = "c")
@BurstUpdatePlayers
public ResponseEntity kickPlayer( public ResponseEntity kickPlayer(
HttpServletRequest request, HttpServletRequest request,
@CookieValue(value = "steam64") String steam64, @CookieValue(value = "steam64") String steam64,

2
src/main/java/app/controllers/user/DetailController.java

@ -1,6 +1,7 @@
package app.controllers.user; package app.controllers.user;
import app.annotations.enums.AuthMethod; import app.annotations.enums.AuthMethod;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.annotations.interfaces.CheckWebAccess; import app.annotations.interfaces.CheckWebAccess;
import app.entities.other.SteamID; import app.entities.other.SteamID;
import app.services.ProfileService; import app.services.ProfileService;
@ -24,6 +25,7 @@ public class DetailController {
@GetMapping @GetMapping
@CheckWebAccess(auth_method = AuthMethod.SECRET_KEY) @CheckWebAccess(auth_method = AuthMethod.SECRET_KEY)
@BurstUpdatePlayers
public ResponseEntity GetUser(HttpServletRequest request, public ResponseEntity GetUser(HttpServletRequest request,
@RequestParam String steam64) { @RequestParam String steam64) {
return new ResponseEntity(profileService.GetProfile(steam64), HttpStatus.OK); return new ResponseEntity(profileService.GetProfile(steam64), HttpStatus.OK);

3
src/main/java/app/controllers/user/ProfileController.java

@ -1,6 +1,7 @@
package app.controllers.user; package app.controllers.user;
import app.annotations.enums.AuthMethod; import app.annotations.enums.AuthMethod;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.annotations.interfaces.CheckWebAccess; import app.annotations.interfaces.CheckWebAccess;
import app.entities.SocialAuth; import app.entities.SocialAuth;
import app.services.ProfileService; import app.services.ProfileService;
@ -37,6 +38,7 @@ public class ProfileController {
@GetMapping @GetMapping
@CheckWebAccess @CheckWebAccess
@BurstUpdatePlayers
public ResponseEntity GetCurrentUser(HttpServletRequest request, public ResponseEntity GetCurrentUser(HttpServletRequest request,
@CookieValue(value = "steam64", defaultValue = "") String steam64, @CookieValue(value = "steam64", defaultValue = "") String steam64,
@RequestParam(value = "requests", defaultValue = "") String requests @RequestParam(value = "requests", defaultValue = "") String requests
@ -63,6 +65,7 @@ public class ProfileController {
@PostMapping("/report") @PostMapping("/report")
@CheckWebAccess @CheckWebAccess
@BurstUpdatePlayers
public ResponseEntity<Long> ReportUser(HttpServletRequest request, public ResponseEntity<Long> ReportUser(HttpServletRequest request,
@CookieValue(value = "steam64", defaultValue = "") String steam64, @CookieValue(value = "steam64", defaultValue = "") String steam64,
@RequestParam(value = "steam64", defaultValue = "") String reported_steam64, @RequestParam(value = "steam64", defaultValue = "") String reported_steam64,

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

@ -3,7 +3,10 @@ package app.entities.a2s.external;
import app.entities.a2s.requests.A2SRequest; import app.entities.a2s.requests.A2SRequest;
import app.entities.a2s.requests.RCONRequest; import app.entities.a2s.requests.RCONRequest;
import app.entities.server.players.RCONPlayer; import app.entities.server.players.RCONPlayer;
import app.updates.BaseUpdater;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.*; import java.util.*;
@ -16,35 +19,38 @@ public abstract class ExternalValveClient {
@JsonIgnore @JsonIgnore
public String gateway = System.getenv("A2S_BACKEND_URL"); public String gateway = System.getenv("A2S_BACKEND_URL");
private final Logger logger = LoggerFactory.getLogger(ExternalValveClient.class);
public ExternalValveClient(){ public ExternalValveClient(){
restTemplate = new RestTemplate(); restTemplate = new RestTemplate();
CheckApi(); CheckApi();
} }
public void CheckApi(){ public void CheckApi(){
System.out.printf("Check status: %s/api/ping\n", gateway); logger.info("Check status: {}/api/ping", gateway);
try { try {
enabled = restTemplate.getForEntity("%s/api/ping".formatted(gateway), HashMap.class).getBody().containsKey("pong"); enabled = restTemplate.getForEntity("%s/api/ping".formatted(gateway), HashMap.class).getBody().containsKey("pong");
} catch (Exception err) { } catch (Exception err) {
System.out.print("A2S Backend not respond\n"); logger.error("A2S Backend {} not respond", gateway);
} }
} }
@JsonIgnore @JsonIgnore
public String ExecuteRCON(RCONRequest request){ public String ExecuteRCON(RCONRequest request){
if(!enabled) { if(!enabled) {
System.out.printf("External client not enabled, cannot get rcon on %s\n", gateway); logger.warn("External client not enabled, cannot get rcon on {}", gateway);
return "not enabled"; return "not enabled";
} }
try { try {
return restTemplate.postForEntity("%s/api/rcon".formatted(gateway), request, String.class).getBody(); return restTemplate.postForEntity("%s/api/rcon".formatted(gateway), request, String.class).getBody();
} catch (Exception err) { } catch (Exception err) {
logger.error("Cannot execute rcon on {}, command: {}", request.getServer(), request.getCommand());
return "backend error"; return "backend error";
} }
} }
@JsonIgnore @JsonIgnore
public HashMap GetA2SInfo(A2SRequest request){ public HashMap GetA2SInfo(A2SRequest request){
if(!enabled) { if(!enabled) {
System.out.printf("External client not enabled, cannot get a2s on %s\n", gateway); logger.warn("External client not enabled, cannot get a2s on {}", gateway);
return null; return null;
} }
try { try {
@ -56,13 +62,13 @@ public abstract class ExternalValveClient {
public ArrayList<RCONPlayer> GetRCONPlayers(RCONRequest request){ public ArrayList<RCONPlayer> GetRCONPlayers(RCONRequest request){
if(!enabled) { if(!enabled) {
System.out.printf("External client not enabled, cannot get rcon players on %s\n", gateway); logger.warn("External client not enabled, cannot get rcon players on {}", gateway);
return null; return null;
} }
try { try {
return new ArrayList<>(Arrays.asList(restTemplate.postForEntity("%s/api/players".formatted(gateway), request, RCONPlayer[].class).getBody())); return new ArrayList<>(Arrays.asList(restTemplate.postForEntity("%s/api/players".formatted(gateway), request, RCONPlayer[].class).getBody()));
} catch (Exception err) { } catch (Exception err) {
System.out.printf("Cannot get rcon players from %s\n", request.getServer()); logger.error("Cannot get rcon players from {}", request.getServer());
return new ArrayList<>(); return new ArrayList<>();
} }
} }

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

@ -11,7 +11,12 @@ import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component @Component
public class PlayersUpdater extends BaseUpdater{ public class PlayersUpdater extends BaseUpdater{
@ -40,4 +45,22 @@ public class PlayersUpdater extends BaseUpdater{
}); });
} }
} }
public void burstUpdater() {
ExecutorService executor = Executors.newCachedThreadPool();
List tasks = new ArrayList<>();
stats.getServers().forEach((server_name, server) -> {
tasks.add((Callable<Void>) () -> {
server.RefreshServerA2SData();
return null;
});
});
try {
executor.invokeAll(tasks);
executor.shutdown();
} catch (InterruptedException err) {
logger.error("Cancel burst servers update");
}
}
} }

3
src/main/resources/application.yaml

@ -54,4 +54,5 @@ backend:
logging: logging:
level: level:
com.ibasco.agql.core.util.*: OFF com.ibasco.agql.core.util.*: OFF
app.updates.PlayersUpdater: ERROR
Loading…
Cancel
Save