Skip to content

Commit

Permalink
Add server config cache support (#241)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuanmomo committed May 2, 2024
1 parent ec0257a commit 01cca4e
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 33 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ dependencies{
// Discord
implementation "net.dv8tion:JDA:5.0.0-beta.20"

implementation("com.github.ben-manes.caffeine:caffeine:2.9.3")

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,77 @@

import com.dl.officialsite.activity.constant.TaskTypeEnum;
import com.dl.officialsite.activity.model.MemberTaskStatus;
import com.dl.officialsite.config.bean.Configurable;
import com.dl.officialsite.config.constant.ConfigEnum;
import com.dl.officialsite.config.service.ServerConfigCacheService;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Data
@EqualsAndHashCode(callSuper = false)
@ToString
@Configuration
@ConfigurationProperties(prefix = "activity", ignoreInvalidFields = true)
public class ActivityConfig {
private String name;
private Map<TaskTypeEnum, List<Task>> taskMap;

@Service
@Slf4j
public class ActivityConfig implements Configurable {
private static long taskCount;
private AnnualActivityConfig annualActivityConfig;

@Autowired
private ServerConfigCacheService serverConfigCacheService;

@PostConstruct
@EventListener(ApplicationReadyEvent.class)
public void init() {
taskCount = Optional.of(taskMap).orElse(Collections.emptyMap()).values().stream().
map(Collection::size).mapToInt(Integer::intValue).sum();
annualActivityConfig = this.serverConfigCacheService.get(ConfigEnum.ANNUAL_ACTIVITY_3ND, AnnualActivityConfig.class);

taskCount = Optional.ofNullable(annualActivityConfig)
.map(AnnualActivityConfig::getTaskMap).orElse(Collections.emptyMap())
.values().stream()
.map(Collection::size).mapToInt(Integer::intValue).sum();

log.info("Init ActivityConfig:[{}], taskCount:[{}]", this, taskCount);
}

public Optional<Task> findTask(TaskTypeEnum taskType, String target) {
return Optional.ofNullable(taskMap.get(taskType))
return Optional.ofNullable(annualActivityConfig)
.map(AnnualActivityConfig::getTaskMap)
.map(map -> map.get(taskType))
.flatMap(list -> list.stream().filter(task -> StringUtils.equalsIgnoreCase(task.getTarget(), target))
.reduce((a, b) -> {
throw new IllegalStateException("Shouldn't be multiple records");
}));
}

public List<MemberTaskStatus> fetchMemberTaskStatusList() {
return taskMap.entrySet().stream().flatMap(entry ->
Map<TaskTypeEnum, List<Task>> taskTypeEnumListMap =
Optional.ofNullable(annualActivityConfig).map(AnnualActivityConfig::getTaskMap).orElse(Collections.emptyMap());

return taskTypeEnumListMap.entrySet().stream().flatMap(entry ->
entry.getValue().stream().map(task -> new MemberTaskStatus(entry.getKey(), task.getName(), task.getTarget(),
task.getTargetUrl()))
).collect(Collectors.toList());
}

}
public String getName() {
return Optional.ofNullable(annualActivityConfig).map(AnnualActivityConfig::getName).orElse("");
}
}

@Data
class AnnualActivityConfig implements Configurable {
private String name;
private Map<TaskTypeEnum, List<Task>> taskMap;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dl.officialsite.activity.constant;

import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

@Getter
public enum TaskTypeEnum {
Expand All @@ -13,4 +14,13 @@ public enum TaskTypeEnum {
private TaskTypeEnum(String value) {
this.value = value;
}

public static TaskTypeEnum fromValue(String value) {
for (TaskTypeEnum taskTypeEnum : TaskTypeEnum.values()) {
if (StringUtils.equalsIgnoreCase(taskTypeEnum.getValue(), value)) {
return taskTypeEnum;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.dl.officialsite.config.bean;

public interface Configurable {
}
55 changes: 55 additions & 0 deletions src/main/java/com/dl/officialsite/config/bean/ServerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.dl.officialsite.config.bean;

import com.dl.officialsite.config.constant.ConfigEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@AllArgsConstructor
@NoArgsConstructor
@Data
@EntityListeners(AuditingEntityListener.class)
@Entity
@DynamicUpdate
@Table(name = "server_config", schema = "dl", uniqueConstraints = {
@UniqueConstraint(name = "unique_config_name", columnNames = {"configName"})
})
public class ServerConfig {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(length = 64)
@Enumerated(EnumType.STRING)
private ConfigEnum configName;

@Column(length = 2048)
private String configValue;

@CreatedDate
@Column(updatable = false)
private Long createTime;

@LastModifiedDate
@Column(updatable = true, nullable = false)
private Long updateTime;

private String remark;

private String editBy;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.dl.officialsite.config.bean;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.Optional;

public interface ServerConfigRepository extends JpaRepository<ServerConfig, Long>, JpaSpecificationExecutor<ServerConfig> {
@Query(value = "select * from server_config where config_name=:configName", nativeQuery = true)
Optional<ServerConfig> findOneByConfigName(@Param("configName") String configName);

}
20 changes: 20 additions & 0 deletions src/main/java/com/dl/officialsite/config/constant/ConfigEnum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
*
*/


package com.dl.officialsite.config.constant;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
@AllArgsConstructor
public enum ConfigEnum {
ANNUAL_ACTIVITY_3ND("annual_activity_3nd");

private String configName;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.dl.officialsite.config.service;

import com.dl.officialsite.activity.constant.TaskTypeEnum;
import com.dl.officialsite.config.bean.Configurable;
import com.dl.officialsite.config.bean.ServerConfig;
import com.dl.officialsite.config.bean.ServerConfigRepository;
import com.dl.officialsite.config.constant.ConfigEnum;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Optional;

@Slf4j
@Service
public class ServerConfigCacheService {
private static Gson gson = null;

@Autowired
private ServerConfigRepository serverConfigRepository;

static {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(TaskTypeEnum.class,
(JsonDeserializer<TaskTypeEnum>) (jsonElement, type, jsonDeserializationContext) -> TaskTypeEnum.fromValue(
jsonElement.getAsString()));
gson = gsonBuilder.create();
}

private static final Cache<ConfigEnum, ServerConfig> SERVER_CONFIG_CACHE = Caffeine.newBuilder()
.maximumSize(512)
.expireAfterWrite(Duration.ofHours(4))
.build();

public <T extends Configurable> T get(ConfigEnum configEnum, Class<T> clazz) {
ServerConfig serverConfig = SERVER_CONFIG_CACHE.get(configEnum, config ->
this.serverConfigRepository.findOneByConfigName(config.getConfigName()).orElse(null)
);
return Optional.ofNullable(serverConfig).map(config -> gson.fromJson(config.getConfigValue(), clazz)).orElse(null);
}

public void remove(ConfigEnum configEnum) {
SERVER_CONFIG_CACHE.invalidate(configEnum);
}

public void removeAll() {
SERVER_CONFIG_CACHE.invalidateAll();
}
}
18 changes: 1 addition & 17 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,20 +163,4 @@ debank:
protocolList: https://pro-openapi.debank.com/v1/user/all_simple_protocol_list
userTokenList: https://pro-openapi.debank.com/v1/user/all_token_list
totalBalance: https://pro-openapi.debank.com/v1/user/total_balance
key:

activity:
name: THIRD_ANNIVERSARY_EVENT
taskMap:
GitHub:
- name: Star the official GitHub Repository
target: Dapp-Learning-DAO/dapp-learning
targetUrl: https://github.com/Dapp-Learning-DAO/dapp-learning
Telegram:
- name: Join official Telegram channel
target: ${TG_DAPP_LEARNING_GROUP_ID}
targetUrl: ${TELEGRAM_INVITE_URL}
Discord:
- name: Join official Discord channel
target: ${GUILD_DAPP_LEARNING_ID}
targetUrl: ${DISCORD_INVITE_URL}
key:

0 comments on commit 01cca4e

Please sign in to comment.