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.name = " ".join(splited[2:len-6])[1:-1]
self.steam = GetSteam(self.steam2)
except ValueError as err:
except (ValueError, IndexError) as err:
print(splited)
raise err

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

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

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

@ -34,6 +34,10 @@ class RCON_Request(A2S_request):
def fulled_data(self):
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:
app = None
@ -43,7 +47,7 @@ class SourceBackend:
def run(self, host = "0.0.0.0", port = 45353):
import uvicorn
logging.getLogger("uvicorn.info").disabled = True
logging.getLogger("uvicorn.access").addFilter(EndpointFilter())
uvicorn.run(self.app, host = host, port = port)
def setup_routes(self):
@ -119,7 +123,7 @@ class SourceBackend:
continue
try:
players.append(RCONPlayer(line).__dict__)
except BotPlayer:
except (BotPlayer, ValueError, IndexError):
pass
except:
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.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@ -22,6 +24,8 @@ import java.util.List;
public class PermitionFlagAspect {
ProfileService profileService;
private final Logger logger = LoggerFactory.getLogger(PermitionFlagAspect.class);
@Autowired
public PermitionFlagAspect(ProfileService profileService) {
this.profileService = profileService;
@ -37,7 +41,7 @@ public class PermitionFlagAspect {
@Before(value = "@annotation(app.annotations.interfaces.CheckPermitionFlag) && args(request,..)")
public void before(JoinPoint joinPoint, HttpServletRequest request){
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)) {
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.NeedCookie;
import app.annotations.interfaces.CheckWebAccess;
import app.entities.a2s.external.ExternalValveClient;
import app.utils.SaltedCookie;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@ -19,6 +22,8 @@ import org.springframework.context.annotation.Configuration;
public class WebAccessAspect {
SaltedCookie saltedCookie;
private final Logger logger = LoggerFactory.getLogger(WebAccessAspect.class);
@Autowired
public WebAccessAspect(SaltedCookie saltedCookie) {
this.saltedCookie = saltedCookie;
@ -27,7 +32,7 @@ public class WebAccessAspect {
@Before("@annotation(app.annotations.interfaces.CheckWebAccess) && args(request,..)")
public void before(JoinPoint joinPoint, HttpServletRequest request){
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)) {
throw new RuntimeException("cannot read cookie from invalid request");
}
@ -62,7 +67,7 @@ public class WebAccessAspect {
case COMBINED -> {
if (!secret_key.isEmpty() && !steam64.isEmpty()) {
if (saltedCookie.ValidateSecretKey(secret_key)) {
System.out.println("used secret key with steamid");
logger.info("used secret key with steamid: {}", steam64);
return;
} else {
throw new InvalidSecretKey();
@ -73,7 +78,7 @@ public class WebAccessAspect {
case SECRET_KEY -> {
if (secret_key.isEmpty()) throw new InvalidSecretKey();
if (saltedCookie.ValidateSecretKey(secret_key)) {
System.out.println("used secret key without steamid");
logger.info("used secret key without steamid");
return;
} else {
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;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.entities.Stats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@ -19,6 +20,7 @@ public class StatsController {
}
@GetMapping
@BurstUpdatePlayers
public ResponseEntity GetStats(){
return new ResponseEntity<>(stats, HttpStatus.OK);
}

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

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

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

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

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

@ -1,6 +1,7 @@
package app.controllers.user;
import app.annotations.enums.AuthMethod;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.annotations.interfaces.CheckWebAccess;
import app.entities.other.SteamID;
import app.services.ProfileService;
@ -24,6 +25,7 @@ public class DetailController {
@GetMapping
@CheckWebAccess(auth_method = AuthMethod.SECRET_KEY)
@BurstUpdatePlayers
public ResponseEntity GetUser(HttpServletRequest request,
@RequestParam String steam64) {
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;
import app.annotations.enums.AuthMethod;
import app.annotations.interfaces.BurstUpdatePlayers;
import app.annotations.interfaces.CheckWebAccess;
import app.entities.SocialAuth;
import app.services.ProfileService;
@ -37,6 +38,7 @@ public class ProfileController {
@GetMapping
@CheckWebAccess
@BurstUpdatePlayers
public ResponseEntity GetCurrentUser(HttpServletRequest request,
@CookieValue(value = "steam64", defaultValue = "") String steam64,
@RequestParam(value = "requests", defaultValue = "") String requests
@ -63,6 +65,7 @@ public class ProfileController {
@PostMapping("/report")
@CheckWebAccess
@BurstUpdatePlayers
public ResponseEntity<Long> ReportUser(HttpServletRequest request,
@CookieValue(value = "steam64", defaultValue = "") String 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.RCONRequest;
import app.entities.server.players.RCONPlayer;
import app.updates.BaseUpdater;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;
import java.util.*;
@ -16,35 +19,38 @@ public abstract class ExternalValveClient {
@JsonIgnore
public String gateway = System.getenv("A2S_BACKEND_URL");
private final Logger logger = LoggerFactory.getLogger(ExternalValveClient.class);
public ExternalValveClient(){
restTemplate = new RestTemplate();
CheckApi();
}
public void CheckApi(){
System.out.printf("Check status: %s/api/ping\n", gateway);
logger.info("Check status: {}/api/ping", 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");
logger.error("A2S Backend {} not respond", gateway);
}
}
@JsonIgnore
public String ExecuteRCON(RCONRequest request){
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";
}
try {
return restTemplate.postForEntity("%s/api/rcon".formatted(gateway), request, String.class).getBody();
} catch (Exception err) {
logger.error("Cannot execute rcon on {}, command: {}", request.getServer(), request.getCommand());
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);
logger.warn("External client not enabled, cannot get a2s on {}", gateway);
return null;
}
try {
@ -56,13 +62,13 @@ public abstract class ExternalValveClient {
public ArrayList<RCONPlayer> GetRCONPlayers(RCONRequest request){
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;
}
try {
return new ArrayList<>(Arrays.asList(restTemplate.postForEntity("%s/api/players".formatted(gateway), request, RCONPlayer[].class).getBody()));
} 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<>();
}
}

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

@ -11,7 +11,12 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
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.ExecutorService;
import java.util.concurrent.Executors;
@Component
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:
level:
com.ibasco.agql.core.util.*: OFF
com.ibasco.agql.core.util.*: OFF
app.updates.PlayersUpdater: ERROR
Loading…
Cancel
Save