mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Setup scheduler
This commit is contained in:
@@ -3,8 +3,10 @@ package dev.kruhlmann.imgfloat;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
public class ImgfloatApplication {
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.kruhlmann.imgfloat.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
@Configuration
|
||||
public class SchedulingConfig {
|
||||
|
||||
@Bean
|
||||
public TaskScheduler emoteSyncTaskScheduler() {
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.setPoolSize(1);
|
||||
scheduler.setThreadNamePrefix("emote-sync-");
|
||||
scheduler.initialize();
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,9 @@ public class Settings {
|
||||
@Column(nullable = false)
|
||||
private int canvasFramesPerSecond;
|
||||
|
||||
@Column(nullable = false)
|
||||
private int emoteSyncIntervalMinutes;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private Instant createdAt;
|
||||
|
||||
@@ -58,6 +61,7 @@ public class Settings {
|
||||
s.setMaxAssetVolumeFraction(5.0);
|
||||
s.setMaxCanvasSideLengthPixels(7680);
|
||||
s.setCanvasFramesPerSecond(60);
|
||||
s.setEmoteSyncIntervalMinutes(60);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -133,6 +137,14 @@ public class Settings {
|
||||
this.canvasFramesPerSecond = canvasFramesPerSecond;
|
||||
}
|
||||
|
||||
public int getEmoteSyncIntervalMinutes() {
|
||||
return emoteSyncIntervalMinutes;
|
||||
}
|
||||
|
||||
public void setEmoteSyncIntervalMinutes(int emoteSyncIntervalMinutes) {
|
||||
this.emoteSyncIntervalMinutes = emoteSyncIntervalMinutes;
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
public void initializeTimestamps() {
|
||||
Instant now = Instant.now();
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package dev.kruhlmann.imgfloat.service;
|
||||
|
||||
import dev.kruhlmann.imgfloat.model.Channel;
|
||||
import dev.kruhlmann.imgfloat.model.Settings;
|
||||
import dev.kruhlmann.imgfloat.repository.ChannelRepository;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.TriggerContext;
|
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class EmoteSyncScheduler implements SchedulingConfigurer {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EmoteSyncScheduler.class);
|
||||
private static final int DEFAULT_INTERVAL_MINUTES = 60;
|
||||
|
||||
private final SettingsService settingsService;
|
||||
private final ChannelRepository channelRepository;
|
||||
private final TwitchEmoteService twitchEmoteService;
|
||||
private final SevenTvEmoteService sevenTvEmoteService;
|
||||
private final TaskScheduler taskScheduler;
|
||||
|
||||
public EmoteSyncScheduler(
|
||||
SettingsService settingsService,
|
||||
ChannelRepository channelRepository,
|
||||
TwitchEmoteService twitchEmoteService,
|
||||
SevenTvEmoteService sevenTvEmoteService,
|
||||
@Qualifier("emoteSyncTaskScheduler") TaskScheduler taskScheduler
|
||||
) {
|
||||
this.settingsService = settingsService;
|
||||
this.channelRepository = channelRepository;
|
||||
this.twitchEmoteService = twitchEmoteService;
|
||||
this.sevenTvEmoteService = sevenTvEmoteService;
|
||||
this.taskScheduler = taskScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
|
||||
taskRegistrar.setScheduler(taskScheduler);
|
||||
taskRegistrar.addTriggerTask(this::syncEmotes, buildTrigger());
|
||||
}
|
||||
|
||||
private Trigger buildTrigger() {
|
||||
return (TriggerContext triggerContext) -> {
|
||||
Instant lastCompletion = triggerContext.lastCompletionTime() == null
|
||||
? Instant.now()
|
||||
: triggerContext.lastCompletionTime().toInstant();
|
||||
return Date.from(lastCompletion.plus(Duration.ofMinutes(resolveIntervalMinutes())));
|
||||
};
|
||||
}
|
||||
|
||||
private int resolveIntervalMinutes() {
|
||||
Settings settings = settingsService.get();
|
||||
int interval = settings.getEmoteSyncIntervalMinutes();
|
||||
return interval > 0 ? interval : DEFAULT_INTERVAL_MINUTES;
|
||||
}
|
||||
|
||||
private void syncEmotes() {
|
||||
int interval = resolveIntervalMinutes();
|
||||
LOG.info("Synchronizing emotes (interval {} minutes)", interval);
|
||||
|
||||
twitchEmoteService.refreshGlobalEmotes();
|
||||
List<Channel> channels = channelRepository.findAll();
|
||||
for (Channel channel : channels) {
|
||||
String broadcaster = channel.getBroadcaster();
|
||||
twitchEmoteService.refreshChannelEmotes(broadcaster);
|
||||
sevenTvEmoteService.refreshChannelEmotes(broadcaster);
|
||||
}
|
||||
|
||||
LOG.info("Completed emote sync for {} channels", channels.size());
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,14 @@ public class SevenTvEmoteService {
|
||||
return emotes.stream().map(CachedEmote::descriptor).toList();
|
||||
}
|
||||
|
||||
public void refreshChannelEmotes(String channelLogin) {
|
||||
if (channelLogin == null || channelLogin.isBlank()) {
|
||||
return;
|
||||
}
|
||||
String normalized = channelLogin.toLowerCase(Locale.ROOT);
|
||||
channelEmoteCache.put(normalized, fetchChannelEmotes(normalized));
|
||||
}
|
||||
|
||||
public Optional<EmoteAsset> loadEmoteAsset(String emoteId) {
|
||||
if (emoteId == null || emoteId.isBlank()) {
|
||||
return Optional.empty();
|
||||
|
||||
@@ -71,6 +71,10 @@ public class TwitchEmoteService {
|
||||
return globalEmotes.stream().map(CachedEmote::descriptor).toList();
|
||||
}
|
||||
|
||||
public void refreshGlobalEmotes() {
|
||||
warmGlobalEmotes();
|
||||
}
|
||||
|
||||
public List<EmoteDescriptor> getChannelEmotes(String channelLogin) {
|
||||
if (channelLogin == null || channelLogin.isBlank()) {
|
||||
return List.of();
|
||||
@@ -80,6 +84,14 @@ public class TwitchEmoteService {
|
||||
return emotes.stream().map(CachedEmote::descriptor).toList();
|
||||
}
|
||||
|
||||
public void refreshChannelEmotes(String channelLogin) {
|
||||
if (channelLogin == null || channelLogin.isBlank()) {
|
||||
return;
|
||||
}
|
||||
String normalized = channelLogin.toLowerCase(Locale.ROOT);
|
||||
channelEmoteCache.put(normalized, fetchChannelEmotes(normalized));
|
||||
}
|
||||
|
||||
public Optional<EmoteAsset> loadEmoteAsset(String emoteId) {
|
||||
if (emoteId == null || emoteId.isBlank()) {
|
||||
return Optional.empty();
|
||||
|
||||
Reference in New Issue
Block a user