add skin part caching
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 1m24s
All checks were successful
Deploy App / docker (ubuntu-latest, 2.44.0, 17, 3.8.5) (push) Successful in 1m24s
This commit is contained in:
parent
3790d4a312
commit
28cd7f192d
@ -1,7 +1,6 @@
|
||||
package cc.fascinated.controller;
|
||||
|
||||
import cc.fascinated.common.PlayerUtils;
|
||||
import cc.fascinated.model.player.Player;
|
||||
import cc.fascinated.model.cache.CachedPlayer;
|
||||
import cc.fascinated.model.player.Skin;
|
||||
import cc.fascinated.service.PlayerService;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@ -21,11 +20,11 @@ import java.util.concurrent.TimeUnit;
|
||||
public class PlayerController {
|
||||
|
||||
private final CacheControl cacheControl = CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic();
|
||||
private final PlayerService playerManagerService;
|
||||
private final PlayerService playerService;
|
||||
|
||||
@Autowired
|
||||
public PlayerController(PlayerService playerManagerService) {
|
||||
this.playerManagerService = playerManagerService;
|
||||
this.playerService = playerManagerService;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@ -34,7 +33,7 @@ public class PlayerController {
|
||||
@Parameter(description = "The UUID or Username of the player", example = "ImFascinated") @PathVariable String id) {
|
||||
return ResponseEntity.ok()
|
||||
.cacheControl(cacheControl)
|
||||
.body(playerManagerService.getPlayer(id));
|
||||
.body(playerService.getPlayer(id));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{part}/{id}")
|
||||
@ -43,7 +42,7 @@ public class PlayerController {
|
||||
@Parameter(description = "The UUID or Username of the player", example = "ImFascinated") @PathVariable String id,
|
||||
@Parameter(description = "The size of the image", example = "256") @RequestParam(required = false, defaultValue = "256") int size,
|
||||
@Parameter(description = "Whether to download the image") @RequestParam(required = false, defaultValue = "false") boolean download) {
|
||||
Player player = playerManagerService.getPlayer(id);
|
||||
CachedPlayer player = playerService.getPlayer(id);
|
||||
Skin.Parts skinPart = Skin.Parts.fromName(part);
|
||||
String dispositionHeader = download ? "attachment; filename=%s.png" : "inline; filename=%s.png";
|
||||
|
||||
@ -52,6 +51,6 @@ public class PlayerController {
|
||||
.cacheControl(cacheControl)
|
||||
.contentType(MediaType.IMAGE_PNG)
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, dispositionHeader.formatted(player.getUsername()))
|
||||
.body(PlayerUtils.getSkinPartBytes(player.getSkin(), skinPart, size));
|
||||
.body(playerService.getSkinPart(player, skinPart, size).getBytes());
|
||||
}
|
||||
}
|
||||
|
22
src/main/java/cc.fascinated/model/cache/CachedPlayerSkinPart.java
vendored
Normal file
22
src/main/java/cc.fascinated/model/cache/CachedPlayerSkinPart.java
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
package cc.fascinated.model.cache;
|
||||
|
||||
import lombok.*;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.redis.core.RedisHash;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@RedisHash(value = "player", timeToLive = 60L * 60L) // 1 hour (in seconds)
|
||||
public class CachedPlayerSkinPart {
|
||||
|
||||
/**
|
||||
* The ID of the skin part
|
||||
*/
|
||||
@Id @NonNull private String id;
|
||||
|
||||
/**
|
||||
* The skin part bytes
|
||||
*/
|
||||
private byte[] bytes;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cc.fascinated.repository;
|
||||
|
||||
import cc.fascinated.model.cache.CachedPlayerName;
|
||||
import cc.fascinated.model.cache.CachedPlayerSkinPart;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* A cache repository for player skin parts.
|
||||
* <p>
|
||||
* This will allow us to easily lookup a
|
||||
* player skin part by it's id.
|
||||
* </p>
|
||||
*/
|
||||
public interface PlayerSkinPartCacheRepository extends CrudRepository<CachedPlayerSkinPart, String> { }
|
@ -8,12 +8,15 @@ import cc.fascinated.exception.impl.RateLimitException;
|
||||
import cc.fascinated.exception.impl.ResourceNotFoundException;
|
||||
import cc.fascinated.model.cache.CachedPlayer;
|
||||
import cc.fascinated.model.cache.CachedPlayerName;
|
||||
import cc.fascinated.model.cache.CachedPlayerSkinPart;
|
||||
import cc.fascinated.model.mojang.MojangProfile;
|
||||
import cc.fascinated.model.mojang.MojangUsernameToUuid;
|
||||
import cc.fascinated.model.player.Cape;
|
||||
import cc.fascinated.model.player.Player;
|
||||
import cc.fascinated.model.player.Skin;
|
||||
import cc.fascinated.repository.PlayerCacheRepository;
|
||||
import cc.fascinated.repository.PlayerNameCacheRepository;
|
||||
import cc.fascinated.repository.PlayerSkinPartCacheRepository;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -27,12 +30,15 @@ public class PlayerService {
|
||||
private final MojangService mojangAPIService;
|
||||
private final PlayerCacheRepository playerCacheRepository;
|
||||
private final PlayerNameCacheRepository playerNameCacheRepository;
|
||||
private final PlayerSkinPartCacheRepository playerSkinPartCacheRepository;
|
||||
|
||||
@Autowired
|
||||
public PlayerService(MojangService mojangAPIService, PlayerCacheRepository playerCacheRepository, PlayerNameCacheRepository playerNameCacheRepository) {
|
||||
public PlayerService(MojangService mojangAPIService, PlayerCacheRepository playerCacheRepository,
|
||||
PlayerNameCacheRepository playerNameCacheRepository, PlayerSkinPartCacheRepository playerSkinPartCacheRepository) {
|
||||
this.mojangAPIService = mojangAPIService;
|
||||
this.playerCacheRepository = playerCacheRepository;
|
||||
this.playerNameCacheRepository = playerNameCacheRepository;
|
||||
this.playerSkinPartCacheRepository = playerSkinPartCacheRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,4 +110,33 @@ public class PlayerService {
|
||||
throw new MojangAPIRateLimitException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a skin part from the player's skin.
|
||||
*
|
||||
* @param player the player
|
||||
* @param part the part of the skin
|
||||
* @return the skin part
|
||||
*/
|
||||
public CachedPlayerSkinPart getSkinPart(Player player, Skin.Parts part, int size) {
|
||||
log.info("Getting skin part: {} for player: {}", part.getName(), player.getUuid());
|
||||
String key = "%s-%s-%s".formatted(player.getUuid(), part.getName(), size);
|
||||
Optional<CachedPlayerSkinPart> cache = playerSkinPartCacheRepository.findById(key);
|
||||
|
||||
// The skin part is cached
|
||||
if (cache.isPresent()) {
|
||||
log.info("Skin part {} for player {} is cached", part.getName(), player.getUuid());
|
||||
return cache.get();
|
||||
}
|
||||
|
||||
byte[] skinPartBytes = PlayerUtils.getSkinPartBytes(player.getSkin(), part, size);
|
||||
CachedPlayerSkinPart skinPart = new CachedPlayerSkinPart(
|
||||
key,
|
||||
skinPartBytes
|
||||
);
|
||||
log.info("Fetched skin part: {} for player: {}", part.getName(), player.getUuid());
|
||||
|
||||
playerSkinPartCacheRepository.save(skinPart);
|
||||
return skinPart;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user