use of net.robinfriedli.aiode.persist.qb.QueryBuilderFactory in project aiode by robinfriedli.
the class DeleteGrantedRolesForDeletedRolesTask method run.
@Override
protected void run(JobExecutionContext jobExecutionContext) {
Aiode aiode = Aiode.get();
ShardManager shardManager = aiode.getShardManager();
QueryBuilderFactory queryBuilderFactory = aiode.getQueryBuilderFactory();
StaticSessionProvider.consumeSession(session -> {
List<GuildSpecification> guildSpecifications = queryBuilderFactory.find(GuildSpecification.class).build(session).getResultList();
int deletionCounter = 0;
for (GuildSpecification guildSpecification : guildSpecifications) {
Guild guild = guildSpecification.getGuild(shardManager);
if (guild == null) {
continue;
}
for (AccessConfiguration accessConfiguration : guildSpecification.getAccessConfigurations()) {
Set<GrantedRole> grantedRoles = accessConfiguration.getRoles();
for (GrantedRole grantedRole : grantedRoles) {
Role guildRole = grantedRole.getRole(guild);
if (guildRole == null) {
// role has been deleted
accessConfiguration.removeRole(grantedRole);
session.delete(grantedRole);
++deletionCounter;
}
}
}
}
if (deletionCounter > 0) {
logger.info("Deleted " + deletionCounter + " GrantedRole entities for roles that no longer exist");
}
});
}
use of net.robinfriedli.aiode.persist.qb.QueryBuilderFactory in project aiode by robinfriedli.
the class GuildManager method getActiveGuilds.
/**
* Return guilds that are active now (playing music) or were active withing the specified amount of milliseconds
* (by entering a command or listening a song).
*
* @param session the hibernate session
* @param delayMs the maximum amount of time since the last action for a guild to be considered active in milliseconds
* @return all active guilds
*/
public Set<Guild> getActiveGuilds(Session session, long delayMs) {
Aiode aiode = Aiode.get();
ShardManager shardManager = aiode.getShardManager();
QueryBuilderFactory queryBuilderFactory = aiode.getQueryBuilderFactory();
Set<Guild> activeGuilds = Sets.newHashSet();
Set<String> activeGuildIds = Sets.newHashSet();
if (ExecutionContext.Current.isSet()) {
activeGuilds.add(ExecutionContext.Current.require().getGuild());
}
for (Guild guild : shardManager.getGuilds()) {
AudioPlayback playback = audioManager.getPlaybackForGuild(guild);
if (playback.isPlaying()) {
activeGuilds.add(guild);
}
}
long startMillis = System.currentTimeMillis() - delayMs;
Set<String> recentCommandGuildIds = queryBuilderFactory.select(CommandHistory.class, "guildId", String.class).where((cb, root) -> cb.greaterThan(root.get("startMillis"), startMillis)).build(session).getResultStream().collect(Collectors.toSet());
activeGuildIds.addAll(recentCommandGuildIds);
LocalDateTime dateTime10MinutesAgo = LocalDateTime.ofInstant(Instant.ofEpochMilli(startMillis), ZoneId.systemDefault());
Set<String> recentPlaybackGuildIds = queryBuilderFactory.select(PlaybackHistory.class, "guildId", String.class).where((cb, root) -> cb.greaterThan(root.get("timestamp"), dateTime10MinutesAgo)).build(session).getResultStream().collect(Collectors.toSet());
activeGuildIds.addAll(recentPlaybackGuildIds);
for (String guildId : activeGuildIds) {
Guild guild = shardManager.getGuildById(guildId);
if (guild != null) {
activeGuilds.add(guild);
}
}
return activeGuilds;
}
use of net.robinfriedli.aiode.persist.qb.QueryBuilderFactory in project aiode by robinfriedli.
the class Artist method getOrCreateArtist.
/**
* Get the existing artist with the provided or create a new artist. This method runs synchronised on the artist id
* to avoid unique constraint violations during concurrent creation.
*
* @param artist the spotify artist
* @param session the hibernate session
*/
public static Artist getOrCreateArtist(ArtistSimplified artist, Session session) {
QueryBuilderFactory queryBuilderFactory = Aiode.get().getQueryBuilderFactory();
Mode mode = Mode.create().with(new MutexSyncMode<>(artist.getId(), ARTIST_SYNC));
return HibernateInvoker.create(session).invokeFunction(mode, currentSession -> {
Optional<Artist> existingArtist = queryBuilderFactory.find(Artist.class).where((cb, root) -> cb.equal(root.get("id"), artist.getId())).build(currentSession).uniqueResultOptional();
return existingArtist.orElseGet(() -> {
Artist newArtist = new Artist(artist.getId(), artist.getName());
currentSession.persist(newArtist);
currentSession.flush();
return newArtist;
});
});
}
use of net.robinfriedli.aiode.persist.qb.QueryBuilderFactory in project aiode by robinfriedli.
the class ChartsCommand method doRun.
@Override
public void doRun() {
Session session = getContext().getSession();
Guild guild = getContext().getGuild();
QueryBuilderFactory queryBuilderFactory = getQueryBuilderFactory();
LocalDateTime startOfMonth = LocalDate.now().withDayOfMonth(1).atStartOfDay();
Date dateAtStartOfMonth = Date.valueOf(startOfMonth.toLocalDate());
SelectQueryBuilder<PlaybackHistory> trackChartsQuery = queryBuilderFactory.select(PlaybackHistory.class, (from, cb) -> from.get("fkSource"), (from, cb) -> from.get("trackId"), (from, cb) -> cb.count(from.get("pk")), (from, cb) -> from.get("fkSpotifyItemKind")).where((cb, root) -> cb.isNotNull(root.get("trackId"))).groupBySeveral((from, cb) -> Lists.newArrayList(from.get("trackId"), from.get("fkSource"), from.get("fkSpotifyItemKind"))).orderBy((from, cb) -> cb.desc(cb.count(from.get("pk"))));
SelectQueryBuilder<PlaybackHistory> trackChartsQueryGuild = trackChartsQuery.fork().where((cb, root) -> cb.equal(root.get("guildId"), guild.getId()));
SelectQueryBuilder<PlaybackHistory> trackChartsQueryMonthly = trackChartsQuery.fork().where((cb, root) -> cb.greaterThan(root.get("timestamp"), startOfMonth));
SelectQueryBuilder<PlaybackHistory> trackChartsQueryMonthlyGuild = trackChartsQueryMonthly.fork().where((cb, root) -> cb.equal(root.get("guildId"), guild.getId()));
Query<Object[]> globalQuery = trackChartsQuery.build(session).setMaxResults(5);
Query<Object[]> guildQuery = trackChartsQueryGuild.build(session).setMaxResults(5);
Query<Object[]> globalQueryMonthly = trackChartsQueryMonthly.build(session).setMaxResults(5);
Query<Object[]> guildQueryMonthly = trackChartsQueryMonthlyGuild.build(session).setMaxResults(5);
List<Object[]> globalResults = globalQuery.getResultList();
List<Object[]> guildResults = guildQuery.getResultList();
List<Object[]> globalMonthlyResults = globalQueryMonthly.getResultList();
List<Object[]> guildMonthlyResults = guildQueryMonthly.getResultList();
@SuppressWarnings("unchecked") Query<Object[]> globalArtistQuery = session.createSQLQuery("select artist_pk, count(*) as c " + "from playback_history_artist group by artist_pk order by c desc limit 3");
@SuppressWarnings("unchecked") Query<Object[]> guildArtistQuery = session.createSQLQuery("select artist_pk, count(*) as c from " + "playback_history_artist as p where p.playback_history_pk in(select pk from playback_history where guild_id = ?) " + "group by artist_pk order by c desc limit 3");
guildArtistQuery.setParameter(1, guild.getId());
@SuppressWarnings("unchecked") Query<Object[]> globalArtistMonthlyQuery = session.createSQLQuery("select artist_pk, count(*) as c " + "from playback_history_artist as p " + "where p.playback_history_pk in(select pk from playback_history where timestamp > ?) " + "group by artist_pk order by c desc limit 3");
globalArtistMonthlyQuery.setParameter(1, dateAtStartOfMonth);
@SuppressWarnings("unchecked") Query<Object[]> guildArtistMonthlyQuery = session.createSQLQuery("select artist_pk, count(*) as c " + "from playback_history_artist where playback_history_pk in(select pk from playback_history " + "where timestamp > ? and guild_id = ?) " + "group by artist_pk order by c desc limit 3");
guildArtistMonthlyQuery.setParameter(1, dateAtStartOfMonth);
guildArtistMonthlyQuery.setParameter(2, guild.getId());
List<Object[]> globalArtists = globalArtistQuery.getResultList();
List<Object[]> guildArtists = guildArtistQuery.getResultList();
List<Object[]> globalArtistsMonthly = globalArtistMonthlyQuery.getResultList();
List<Object[]> guildArtistMonthly = guildArtistMonthlyQuery.getResultList();
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.addField("Global", "Shows the charts across all guilds", false);
addTrackCharts(globalResults, embedBuilder, "All time", session);
addArtists(globalArtists, embedBuilder, "All time");
embedBuilder.addBlankField(true);
addTrackCharts(globalMonthlyResults, embedBuilder, "Monthly", session);
addArtists(globalArtistsMonthly, embedBuilder, "Monthly");
embedBuilder.addBlankField(false);
embedBuilder.addField("Guild", "Shows the charts for this guild", false);
addTrackCharts(guildResults, embedBuilder, "All time", session);
addArtists(guildArtists, embedBuilder, "All time");
embedBuilder.addBlankField(true);
addTrackCharts(guildMonthlyResults, embedBuilder, "Monthly", session);
addArtists(guildArtistMonthly, embedBuilder, "Monthly");
sendMessage(embedBuilder);
}
use of net.robinfriedli.aiode.persist.qb.QueryBuilderFactory in project aiode by robinfriedli.
the class ConnectCommand method awaitPrivateMessage.
private void awaitPrivateMessage(ClientSession clientSession, long userId, Guild guild, User user, int attemptNumber) {
CompletableFuture<PrivateMessageReceivedEvent> futurePrivateMessage = getManager().getEventWaiter().awaitEvent(PrivateMessageReceivedEvent.class, event -> event.getAuthor().getIdLong() == userId).orTimeout(1, TimeUnit.MINUTES);
CompletableFutures.handleWhenComplete(futurePrivateMessage, (event, error) -> {
try {
MessageService messageService = getMessageService();
if (event != null) {
String token = event.getMessage().getContentRaw();
UUID sessionId;
try {
sessionId = UUID.fromString(token);
} catch (IllegalArgumentException e) {
String message = String.format("'%s' is not a valid token. ", token);
if (attemptNumber >= RETRY_COUNT) {
messageService.sendError(message + "Maximum retry count reached.", user);
} else {
messageService.sendError(message + String.format("Attempt %d / %d", attemptNumber, RETRY_COUNT), user);
awaitPrivateMessage(clientSession, userId, guild, user, attemptNumber + 1);
}
return;
}
QueryBuilderFactory queryBuilderFactory = getQueryBuilderFactory();
MutexSyncMode<UUID> mutexSyncMode = new MutexSyncMode<>(sessionId, TOKEN_SYNC);
HibernateInvoker.create().invokeConsumer(Mode.create().with(mutexSyncMode), session -> {
Optional<GeneratedToken> foundGeneratedToken = queryBuilderFactory.find(GeneratedToken.class).where((cb, root) -> cb.equal(root.get("token"), sessionId)).build(session).uniqueResultOptional();
if (foundGeneratedToken.isEmpty()) {
String message = "Token is invalid. Make sure it matches the token generated by your web client. Tokens may not be shared or reused. ";
if (attemptNumber >= RETRY_COUNT) {
messageService.sendError(message + "Maximum retry count reached.", user);
} else {
messageService.sendError(message + String.format("Attempt %d / %d", attemptNumber, RETRY_COUNT), user);
awaitPrivateMessage(clientSession, userId, guild, user, attemptNumber + 1);
}
return;
}
GeneratedToken generatedToken = foundGeneratedToken.get();
Long existingSessionCount = queryBuilderFactory.select(ClientSession.class, (from, cb) -> cb.count(from.get("pk")), Long.class).where((cb, root) -> cb.equal(root.get("sessionId"), sessionId)).build(session).uniqueResult();
if (existingSessionCount > 0) {
messageService.sendError("A session with this ID already exists. You are probably already signed in, try reloading your web client. If your client still can't sign in try generating a new token using the reload button and then try the connect command again.", user);
return;
}
clientSession.setLastRefresh(LocalDateTime.now());
clientSession.setSessionId(sessionId);
clientSession.setIpAddress(generatedToken.getIp());
session.persist(clientSession);
session.delete(generatedToken);
messageService.sendSuccess(String.format("Okay, a session connected to guild '%s' " + "has been prepared. You may return to the web client to complete the setup. The client should " + "connect automatically, else you can continue manually.", guild.getName()), user);
});
} else if (error != null) {
if (error instanceof TimeoutException) {
messageService.sendError("Your connection attempt timed out", user);
} else {
EmbedBuilder exceptionEmbed = ExceptionUtils.buildErrorEmbed(error);
exceptionEmbed.setTitle("Exception");
exceptionEmbed.setDescription("There has been an error awaiting private message to establish connection");
LoggerFactory.getLogger(getClass()).error("unexpected exception while awaiting private message", error);
sendMessage(exceptionEmbed.build());
}
setFailed(true);
}
} finally {
USERS_WITH_PENDING_CONNECTION.remove(userId);
}
}, e -> {
LoggerFactory.getLogger(getClass()).error("Unexpected error in whenComplete of event handler", e);
EmbedBuilder embedBuilder = ExceptionUtils.buildErrorEmbed(e).setTitle("Exception").setDescription("There has been an unexpected exception while trying to establish the connection");
getMessageService().send(embedBuilder.build(), user);
});
}
Aggregations