Cache implementation
All checks were successful
Deploy API / docker (ubuntu-latest, 2.44.0) (push) Successful in 52s
All checks were successful
Deploy API / docker (ubuntu-latest, 2.44.0) (push) Successful in 52s
This commit is contained in:
parent
d2937cc0aa
commit
b00694ecf8
@ -2,6 +2,6 @@
|
|||||||
An API designed to provide real-time access to a user's Discord data.
|
An API designed to provide real-time access to a user's Discord data.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- [ ] Caching
|
- [x] Caching
|
||||||
- [ ] WebSockets
|
- [ ] WebSockets
|
||||||
- [ ] User account for extra data? (about me, connections, etc)
|
- [ ] User account for extra data? (about me, connections, etc)
|
30
src/main/java/me/braydon/tether/model/CachedDiscordUser.java
Normal file
30
src/main/java/me/braydon/tether/model/CachedDiscordUser.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package me.braydon.tether.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.Setter;
|
||||||
|
import net.dv8tion.jda.api.entities.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model representing a cached Discord user.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor @Setter @Getter
|
||||||
|
public final class CachedDiscordUser {
|
||||||
|
/**
|
||||||
|
* The cached user.
|
||||||
|
*/
|
||||||
|
@NonNull private final User user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cached user profile.
|
||||||
|
*/
|
||||||
|
@NonNull private final User.Profile profile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unix time of when this user was cached.
|
||||||
|
*/
|
||||||
|
private long cached;
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package me.braydon.tether.service;
|
package me.braydon.tether.service;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
@ -7,6 +9,7 @@ import lombok.extern.log4j.Log4j2;
|
|||||||
import me.braydon.tether.exception.impl.BadRequestException;
|
import me.braydon.tether.exception.impl.BadRequestException;
|
||||||
import me.braydon.tether.exception.impl.ResourceNotFoundException;
|
import me.braydon.tether.exception.impl.ResourceNotFoundException;
|
||||||
import me.braydon.tether.exception.impl.ServiceUnavailableException;
|
import me.braydon.tether.exception.impl.ServiceUnavailableException;
|
||||||
|
import me.braydon.tether.model.CachedDiscordUser;
|
||||||
import me.braydon.tether.model.DiscordUser;
|
import me.braydon.tether.model.DiscordUser;
|
||||||
import me.braydon.tether.model.response.DiscordUserResponse;
|
import me.braydon.tether.model.response.DiscordUserResponse;
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
@ -18,6 +21,8 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service is responsible for
|
* This service is responsible for
|
||||||
* interacting with the Discord API.
|
* interacting with the Discord API.
|
||||||
@ -35,6 +40,13 @@ public final class DiscordService {
|
|||||||
*/
|
*/
|
||||||
private JDA jda;
|
private JDA jda;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache of users retrieved from Discord.
|
||||||
|
*/
|
||||||
|
private final Cache<Long, CachedDiscordUser> cachedUsers = Caffeine.newBuilder()
|
||||||
|
.expireAfterAccess(3L, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
connectBot();
|
connectBot();
|
||||||
@ -67,9 +79,21 @@ public final class DiscordService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Then retrieve the user
|
||||||
|
CachedDiscordUser cachedUser = cachedUsers.getIfPresent(snowflake);
|
||||||
|
boolean fromCache = cachedUser != null;
|
||||||
|
if (cachedUser == null) { // No cache, retrieve fresh data
|
||||||
User user = jda.retrieveUserById(snowflake).complete();
|
User user = jda.retrieveUserById(snowflake).complete();
|
||||||
User.Profile profile = user.retrieveProfile().complete();
|
cachedUser = new CachedDiscordUser(
|
||||||
return new DiscordUserResponse(DiscordUser.buildFromEntity(user, profile, member), -1L);
|
user, user.retrieveProfile().complete(), System.currentTimeMillis()
|
||||||
|
);
|
||||||
|
cachedUsers.put(snowflake, cachedUser);
|
||||||
|
}
|
||||||
|
// Finally build the response and respond with it
|
||||||
|
return new DiscordUserResponse(
|
||||||
|
DiscordUser.buildFromEntity(cachedUser.getUser(), cachedUser.getProfile(), member),
|
||||||
|
fromCache ? cachedUser.getCached() : -1L
|
||||||
|
);
|
||||||
} catch (ErrorResponseException ex) {
|
} catch (ErrorResponseException ex) {
|
||||||
// Failed to lookup the user, handle appropriately
|
// Failed to lookup the user, handle appropriately
|
||||||
if (ex.getErrorCode() == 10013) {
|
if (ex.getErrorCode() == 10013) {
|
||||||
|
Loading…
Reference in New Issue
Block a user