diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java index 5c203d9c0..57c46ce78 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java @@ -13,6 +13,7 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.utils.CompletableFutureList; +import dev.sheldan.abstracto.core.utils.ParseUtils; import dev.sheldan.abstracto.twitch.config.TwitchFeatureConfig; import dev.sheldan.abstracto.twitch.config.TwitchFeatureDefinition; import dev.sheldan.abstracto.twitch.config.TwitchFeatureMode; @@ -26,6 +27,8 @@ import dev.sheldan.abstracto.twitch.model.template.*; import dev.sheldan.abstracto.twitch.service.management.StreamSessionManagementService; import dev.sheldan.abstracto.twitch.service.management.StreamSessionSectionManagementService; import dev.sheldan.abstracto.twitch.service.management.StreamerManagementService; +import java.time.Duration; +import java.time.Instant; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; @@ -92,6 +95,9 @@ public class StreamerServiceBean implements StreamerService { @Autowired private MessageService messageService; + @Autowired + private ConfigService configService; + @Autowired private StreamerServiceBean self; @@ -277,6 +283,8 @@ public class StreamerServiceBean implements StreamerService { log.debug("Searching through {} servers for twitch notifications and {} have twitch feature enabled.", servers.size(), serversWithEnabledFeature.size()); serversWithEnabledFeature.forEach(server -> { List streamersInServer = streamerManagementService.getStreamersForServer(server); + String refreshDurationString = configService.getStringValueOrConfigDefault(TwitchFeatureConfig.TWITCH_REFRESH_INTERVAL, server.getId()); + Duration refreshDuration = ParseUtils.parseDuration(refreshDurationString); Map streamerIdMap = streamersInServer .stream() .collect(Collectors.toMap(Streamer::getId, Function.identity())); @@ -295,7 +303,7 @@ public class StreamerServiceBean implements StreamerService { List streamsOfUsers = twitchService.getStreamsByUserIds(userIds); Set onlineStreamers = new HashSet<>(); Map updateNotificationFlagValues = new HashMap<>(); - streamsOfUsers.forEach(stream -> self.processOnlineStreamer(server, streamerMap, onlineStreamers, updateNotificationFlagValues, stream)); + streamsOfUsers.forEach(stream -> self.processOnlineStreamer(server, streamerMap, onlineStreamers, updateNotificationFlagValues, stream, refreshDuration)); Set allStreamersInServer = streamerIdMap.keySet(); allStreamersInServer.removeAll(onlineStreamers); // then we have those that went offline Map deleteFlagValues = new HashMap<>(); @@ -370,7 +378,8 @@ public class StreamerServiceBean implements StreamerService { } @Transactional(propagation = Propagation.REQUIRES_NEW) - public void processOnlineStreamer(AServer server, Map streamerMap, Set onlineStreamers, Map updateNotificationFlagValues, Stream stream) { + public void processOnlineStreamer(AServer server, Map streamerMap, Set onlineStreamers, Map updateNotificationFlagValues, + Stream stream, Duration refreshDuration) { Streamer streamer = streamerMap.get(stream.getUserId()); Long streamerId = streamer.getId(); onlineStreamers.add(streamerId); @@ -378,18 +387,19 @@ public class StreamerServiceBean implements StreamerService { // that is the case if you add an online streamer User streamerUser = twitchService.getStreamerById(stream.getUserId()); StreamSession currentSession = streamer.getCurrentSession(); + Long serverId = streamer.getServer().getId(); if (Boolean.TRUE.equals(streamer.getOnline()) && currentSession != null) { // we already know that this streamer is online log.debug("Not notifying for streamer {} in server {} - streamer is already online.", streamerId, server.getId()); if(!stream.getGameId().equals(streamer.getCurrentGameId())) { log.info("Streamer {} changed game from {} to {} - storing new section.", streamerId, streamer.getCurrentGameId(), stream.getGameId()); streamSessionSectionService.createSectionFromStream(currentSession, stream); + currentSession.setLastUpdated(Instant.now()); if (updateNotificationFlagValues.computeIfAbsent(streamer.getServer().getId(), aLong -> featureModeService.featureModeActive(TwitchFeatureDefinition.TWITCH, aLong, TwitchFeatureMode.UPDATE_NOTIFICATION))) { log.info("Updating notification is enabled - updating notification for streamer {}.", streamer.getId()); Long notificationMessageId = currentSession.getId(); Long notificationChannelId = currentSession.getChannel().getId(); - Long serverId = streamer.getServer().getId(); updateExistingNotification(stream, streamer, streamerUser).thenAccept(unused -> { log.info("Updating existing notification {} for server {} in channel {} about streamer {}.", notificationMessageId, serverId, notificationChannelId, streamerId); @@ -400,6 +410,20 @@ public class StreamerServiceBean implements StreamerService { }); } streamer.setCurrentGameId(stream.getGameId()); + } else if(currentSession.getLastUpdated().isBefore(Instant.now().minus(refreshDuration)) && + updateNotificationFlagValues.computeIfAbsent(streamer.getServer().getId(), + serverIdKey -> featureModeService.featureModeActive(TwitchFeatureDefinition.TWITCH, serverIdKey, TwitchFeatureMode.UPDATE_NOTIFICATION))) { + Long notificationMessageId = currentSession.getId(); + currentSession.setLastUpdated(Instant.now()); + Long notificationChannelId = currentSession.getChannel().getId(); + updateExistingNotification(stream, streamer, streamerUser).thenAccept(unused -> { + log.info("Updating existing notification {} for server {} in channel {} about streamer {}.", + notificationMessageId, serverId, notificationChannelId, streamerId); + }).exceptionally(throwable -> { + log.error("Failed to update existing notification {} for server {} in channel {} about streamer {}.", + notificationMessageId, serverId, notificationChannelId, streamerId, throwable); + return null; + }); } } else if(currentSession == null && !postTargetService.postTargetUsableInServer(TwitchPostTarget.TWITCH_LIVE_NOTIFICATION, server.getId())) { diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/management/StreamSessionManagementServiceBean.java b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/management/StreamSessionManagementServiceBean.java index 48a3e0abc..bd2cffef2 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/management/StreamSessionManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/management/StreamSessionManagementServiceBean.java @@ -6,6 +6,7 @@ import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.twitch.model.database.Streamer; import dev.sheldan.abstracto.twitch.model.database.StreamSession; import dev.sheldan.abstracto.twitch.repository.StreamSessionRepository; +import java.time.Instant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -26,6 +27,7 @@ public class StreamSessionManagementServiceBean implements StreamSessionManageme .id(messageId) .startTime(stream.getStartedAtInstant()) .channel(channel) + .lastUpdated(Instant.now()) .streamer(streamer) .streamId(stream.getId()) .build(); diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/collection.xml b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/collection.xml new file mode 100644 index 000000000..39bc28c3c --- /dev/null +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/collection.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/tables/stream_session.xml b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/tables/stream_session.xml new file mode 100644 index 000000000..956154682 --- /dev/null +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/tables/stream_session.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/tables/tables.xml b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/tables/tables.xml new file mode 100644 index 000000000..ef4b2e006 --- /dev/null +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/1.6.25/tables/tables.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/twitch-changeLog.xml b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/twitch-changeLog.xml index f53b67498..efeb8fa9f 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/twitch-changeLog.xml +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/migrations/twitch-changeLog.xml @@ -3,4 +3,5 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" > + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/twitch-config.properties b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/twitch-config.properties index 8675b58d6..511f44dec 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/twitch-config.properties +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/resources/twitch-config.properties @@ -12,4 +12,7 @@ abstracto.featureModes.deleteNotification.enabled=true abstracto.featureModes.updateNotification.featureName=twitch abstracto.featureModes.updateNotification.mode=updateNotification -abstracto.featureModes.updateNotification.enabled=true \ No newline at end of file +abstracto.featureModes.updateNotification.enabled=true + +abstracto.systemConfigs.twitchRefreshInterval.name=twitchRefreshInterval +abstracto.systemConfigs.twitchRefreshInterval.stringValue=30m \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/config/TwitchFeatureConfig.java b/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/config/TwitchFeatureConfig.java index fc22278f1..8ea2689b5 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/config/TwitchFeatureConfig.java +++ b/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/config/TwitchFeatureConfig.java @@ -11,6 +11,9 @@ import java.util.List; @Component public class TwitchFeatureConfig implements FeatureConfig { + + public static final String TWITCH_REFRESH_INTERVAL = "twitchRefreshInterval"; + @Override public FeatureDefinition getFeature() { return TwitchFeatureDefinition.TWITCH; @@ -25,4 +28,9 @@ public class TwitchFeatureConfig implements FeatureConfig { public List getAvailableModes() { return Arrays.asList(TwitchFeatureMode.DELETE_NOTIFICATION, TwitchFeatureMode.UPDATE_NOTIFICATION); } + + @Override + public List getRequiredSystemConfigKeys() { + return List.of(TWITCH_REFRESH_INTERVAL); + } } diff --git a/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/model/database/StreamSession.java b/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/model/database/StreamSession.java index 130b0f63e..9ef9c0abb 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/model/database/StreamSession.java +++ b/abstracto-application/abstracto-modules/twitch/twitch-int/src/main/java/dev/sheldan/abstracto/twitch/model/database/StreamSession.java @@ -39,6 +39,9 @@ public class StreamSession { @Column(name = "updated", insertable = false, updatable = false) private Instant updated; + @Column(name = "lastUpdated") + private Instant lastUpdated; + @Column(name = "startTime", nullable = false) private Instant startTime;