mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-11-21 11:45:25 +01:00
Improvements & fixes to AbstractSyncModule
This commit is contained in:
parent
72758ff888
commit
654bfb5907
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.discordsrv.api.punishment;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -70,6 +70,9 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> implements
|
||||
}
|
||||
|
||||
return entryFuture.thenApply(ban -> {
|
||||
if (ban == null) {
|
||||
return null;
|
||||
}
|
||||
Date expiration = ban.getExpiration();
|
||||
return new Punishment(expiration != null ? expiration.toInstant() : null, ban.getReason(), ban.getSource());
|
||||
});
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.bansync;
|
||||
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
@ -71,7 +89,7 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logName() {
|
||||
public String logFileName() {
|
||||
return "bansync";
|
||||
}
|
||||
|
||||
@ -91,8 +109,10 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isActive(Punishment state) {
|
||||
return state != null;
|
||||
protected @Nullable ISyncResult doesStateMatch(Punishment one, Punishment two) {
|
||||
boolean oneActive = one != null;
|
||||
boolean twoActive = two != null;
|
||||
return (oneActive == twoActive) ? GenericSyncResults.both(oneActive) : null;
|
||||
}
|
||||
|
||||
private PunishmentEvent upsertEvent(long userId, boolean newState) {
|
||||
@ -211,7 +231,7 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<ISyncResult> applyDiscord(BanSyncConfig config, long userId, Punishment state) {
|
||||
protected CompletableFuture<ISyncResult> applyDiscord(BanSyncConfig config, long userId, Punishment newState) {
|
||||
if (config.direction == SyncDirection.DISCORD_TO_MINECRAFT) {
|
||||
return CompletableFuture.completedFuture(GenericSyncResults.WRONG_DIRECTION);
|
||||
}
|
||||
@ -228,9 +248,10 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
UserSnowflake snowflake = UserSnowflake.fromId(userId);
|
||||
if (state != null) {
|
||||
if (newState != null) {
|
||||
return guild.ban(snowflake, config.discordMessageHoursToDelete, TimeUnit.HOURS)
|
||||
.reason(discordSRV.placeholderService().replacePlaceholders(config.discordBanReasonFormat, state))
|
||||
.reason(discordSRV.placeholderService().replacePlaceholders(config.discordBanReasonFormat,
|
||||
newState))
|
||||
.submit()
|
||||
.thenApply(v -> GenericSyncResults.ADD_DISCORD);
|
||||
} else {
|
||||
@ -242,7 +263,7 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<ISyncResult> applyGame(BanSyncConfig config, UUID playerUUID, Punishment state) {
|
||||
protected CompletableFuture<ISyncResult> applyGame(BanSyncConfig config, UUID playerUUID, Punishment newState) {
|
||||
if (config.direction == SyncDirection.MINECRAFT_TO_DISCORD) {
|
||||
return CompletableFuture.completedFuture(GenericSyncResults.WRONG_DIRECTION);
|
||||
}
|
||||
@ -252,9 +273,11 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
return CompletableFuture.completedFuture(BanSyncResult.NO_PUNISHMENT_INTEGRATION);
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
String reason = discordSRV.placeholderService().replacePlaceholders(config.gameBanReasonFormat, state);
|
||||
String punisher = discordSRV.placeholderService().replacePlaceholders(config.gamePunisherFormat, state);
|
||||
if (newState != null) {
|
||||
String reason = discordSRV.placeholderService().replacePlaceholders(config.gameBanReasonFormat,
|
||||
newState);
|
||||
String punisher = discordSRV.placeholderService().replacePlaceholders(config.gamePunisherFormat,
|
||||
newState);
|
||||
return bans.addBan(playerUUID, null, reason, punisher)
|
||||
.thenApply(v -> GenericSyncResults.ADD_GAME);
|
||||
} else {
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.bansync.enums;
|
||||
|
||||
import com.discordsrv.common.sync.cause.ISyncCause;
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.bansync.enums;
|
||||
|
||||
import com.discordsrv.common.sync.result.ISyncResult;
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.config.main;
|
||||
|
||||
import com.discordsrv.common.config.main.generic.AbstractSyncConfig;
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.config.main.generic;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
|
@ -66,7 +66,7 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logName() {
|
||||
public String logFileName() {
|
||||
return "groupsync";
|
||||
}
|
||||
|
||||
@ -86,8 +86,11 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isActive(Boolean state) {
|
||||
return state;
|
||||
protected @Nullable ISyncResult doesStateMatch(Boolean one, Boolean two) {
|
||||
if (one == two) {
|
||||
return GenericSyncResults.both(one);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -154,8 +157,8 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
groupChanged(player, groupName, serverContext, cause, false);
|
||||
}
|
||||
|
||||
private void roleChanged(long userId, long roleId, boolean state) {
|
||||
if (checkExpectation(expectedDiscordChanges, userId, roleId, state)) {
|
||||
private void roleChanged(long userId, long roleId, boolean newState) {
|
||||
if (checkExpectation(expectedDiscordChanges, userId, roleId, newState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -165,7 +168,7 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
return;
|
||||
}
|
||||
|
||||
discordChanged(GroupSyncCause.DISCORD_ROLE_CHANGE, Someone.of(userId), roleId, state);
|
||||
discordChanged(GroupSyncCause.DISCORD_ROLE_CHANGE, Someone.of(userId), roleId, newState);
|
||||
}
|
||||
|
||||
private void groupChanged(
|
||||
@ -173,7 +176,7 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
String groupName,
|
||||
Set<String> serverContext,
|
||||
GroupSyncCause cause,
|
||||
Boolean state
|
||||
boolean state
|
||||
) {
|
||||
if (cause.isDiscordSRVCanCause() && checkExpectation(expectedMinecraftChanges, playerUUID, groupName, state)) {
|
||||
return;
|
||||
@ -247,7 +250,7 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ISyncResult> applyDiscord(GroupSyncConfig.PairConfig config, long userId, Boolean state) {
|
||||
public CompletableFuture<ISyncResult> applyDiscord(GroupSyncConfig.PairConfig config, long userId, Boolean newState) {
|
||||
DiscordRole role = discordSRV.discordAPI().getRoleById(config.roleId);
|
||||
if (role == null) {
|
||||
return CompletableFutureUtil.failed(new SyncFail(GroupSyncResult.ROLE_DOESNT_EXIST));
|
||||
@ -255,11 +258,11 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
|
||||
Map<Long, Boolean> expected = expectedDiscordChanges.get(userId, key -> new ConcurrentHashMap<>());
|
||||
if (expected != null) {
|
||||
expected.put(config.roleId, state);
|
||||
expected.put(config.roleId, newState);
|
||||
}
|
||||
|
||||
return role.getGuild().retrieveMemberById(userId)
|
||||
.thenCompose(member -> state
|
||||
.thenCompose(member -> newState
|
||||
? member.addRole(role).thenApply(v -> (ISyncResult) GenericSyncResults.ADD_DISCORD)
|
||||
: member.removeRole(role).thenApply(v -> GenericSyncResults.REMOVE_DISCORD)
|
||||
).whenComplete((r, t) -> {
|
||||
@ -271,14 +274,14 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ISyncResult> applyGame(GroupSyncConfig.PairConfig config, UUID playerUUID, Boolean state) {
|
||||
public CompletableFuture<ISyncResult> applyGame(GroupSyncConfig.PairConfig config, UUID playerUUID, Boolean newState) {
|
||||
Map<String, Boolean> expected = expectedMinecraftChanges.get(playerUUID, key -> new ConcurrentHashMap<>());
|
||||
if (expected != null) {
|
||||
expected.put(config.groupName, state);
|
||||
expected.put(config.groupName, newState);
|
||||
}
|
||||
|
||||
CompletableFuture<ISyncResult> future =
|
||||
state
|
||||
newState
|
||||
? addGroup(playerUUID, config).thenApply(v -> GenericSyncResults.ADD_GAME)
|
||||
: removeGroup(playerUUID, config).thenApply(v -> GenericSyncResults.REMOVE_GAME);
|
||||
return future.exceptionally(t -> {
|
||||
|
@ -178,8 +178,8 @@ public class LuckPermsIntegration extends PluginIntegration<DiscordSRV> implemen
|
||||
|
||||
InheritanceNode node = InheritanceNode.builder(group).context(contexts).build();
|
||||
DataMutateResult result = function.apply(user.data(), node);
|
||||
if (result != DataMutateResult.SUCCESS) {
|
||||
return CompletableFutureUtil.failed(new MessageException(result.name()));
|
||||
if (!result.wasSuccessful()) {
|
||||
return CompletableFutureUtil.failed(new MessageException("Group mutate failed: " + result.name()));
|
||||
}
|
||||
|
||||
return luckPerms.getUserManager().saveUser(user);
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.someone;
|
||||
|
||||
import com.discordsrv.api.discord.entity.DiscordUser;
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync;
|
||||
|
||||
import com.discordsrv.api.DiscordSRVApi;
|
||||
@ -17,11 +35,12 @@ import com.discordsrv.common.sync.enums.SyncDirection;
|
||||
import com.discordsrv.common.sync.result.GenericSyncResults;
|
||||
import com.discordsrv.common.sync.enums.SyncSide;
|
||||
import com.discordsrv.common.sync.result.ISyncResult;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
@ -51,17 +70,17 @@ public abstract class AbstractSyncModule<
|
||||
super(discordSRV, new NamedLogger(discordSRV, loggerName));
|
||||
}
|
||||
|
||||
public abstract String syncName();
|
||||
public abstract String logName();
|
||||
protected abstract String syncName();
|
||||
protected abstract String logFileName();
|
||||
|
||||
public abstract String gameTerm();
|
||||
public abstract String discordTerm();
|
||||
protected abstract String gameTerm();
|
||||
protected abstract String discordTerm();
|
||||
|
||||
/**
|
||||
* Returns a list of all in use synchronizables.
|
||||
* @return a list of configurations for synchronizables
|
||||
*/
|
||||
public abstract List<C> configs();
|
||||
protected abstract List<C> configs();
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
@ -131,12 +150,11 @@ public abstract class AbstractSyncModule<
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provided state is active or inactive, should this not match for the state of the two sides, synchronization will occur.
|
||||
*
|
||||
* @param state the state
|
||||
* @return {@code true} indicating the provided state is "active"
|
||||
* Checks if the given new and current state are the same, basically meaning that no update is necessary.
|
||||
* @return the result stating the states are the same, otherwise {@code null} to state they are not
|
||||
*/
|
||||
protected abstract boolean isActive(S state);
|
||||
@Nullable
|
||||
protected abstract ISyncResult doesStateMatch(S one, S two);
|
||||
|
||||
/**
|
||||
* Gets the current state of the provided config for the specified user on Discord.
|
||||
@ -161,18 +179,18 @@ public abstract class AbstractSyncModule<
|
||||
*
|
||||
* @param config the configuration for the synchronizable
|
||||
* @param userId the Discord user id
|
||||
* @param state the state to apply
|
||||
* @param newState the newState to apply
|
||||
* @return a future with the result of the synchronization
|
||||
*/
|
||||
protected abstract CompletableFuture<ISyncResult> applyDiscord(C config, long userId, S state);
|
||||
protected abstract CompletableFuture<ISyncResult> applyDiscord(C config, long userId, S newState);
|
||||
|
||||
protected CompletableFuture<ISyncResult> applyDiscordIfNot(C config, long userId, S state) {
|
||||
return getDiscord(config, userId).thenCompose(value -> {
|
||||
boolean actualValue;
|
||||
if ((actualValue = isActive(state)) == isActive(value)) {
|
||||
return CompletableFuture.completedFuture(actualValue ? GenericSyncResults.BOTH_TRUE : GenericSyncResults.BOTH_FALSE);
|
||||
protected CompletableFuture<ISyncResult> applyDiscordIfDoesNotMatch(C config, long userId, S newState) {
|
||||
return getDiscord(config, userId).thenCompose(currentState -> {
|
||||
ISyncResult result = doesStateMatch(newState, currentState);
|
||||
if (result != null) {
|
||||
return CompletableFuture.completedFuture(result);
|
||||
} else {
|
||||
return applyDiscord(config, userId, state);
|
||||
return applyDiscord(config, userId, newState);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -182,23 +200,23 @@ public abstract class AbstractSyncModule<
|
||||
*
|
||||
* @param config the configuration for the synchronizable
|
||||
* @param playerUUID the Minecraft player {@link UUID}
|
||||
* @param state the state to apply
|
||||
* @param newState the newState to apply
|
||||
* @return a future with the result of the synchronization
|
||||
*/
|
||||
protected abstract CompletableFuture<ISyncResult> applyGame(C config, UUID playerUUID, S state);
|
||||
protected abstract CompletableFuture<ISyncResult> applyGame(C config, UUID playerUUID, S newState);
|
||||
|
||||
protected CompletableFuture<ISyncResult> applyGameIfNot(C config, UUID playerUUID, S state) {
|
||||
return getGame(config, playerUUID).thenCompose(value -> {
|
||||
boolean active;
|
||||
if ((active = isActive(state)) == isActive(value)) {
|
||||
return CompletableFuture.completedFuture(active ? GenericSyncResults.BOTH_TRUE : GenericSyncResults.BOTH_FALSE);
|
||||
protected CompletableFuture<ISyncResult> applyGameIfDoesNotMatch(C config, UUID playerUUID, S newState) {
|
||||
return getGame(config, playerUUID).thenCompose(currentState -> {
|
||||
ISyncResult result = doesStateMatch(currentState, newState);
|
||||
if (result != null) {
|
||||
return CompletableFuture.completedFuture(result);
|
||||
} else {
|
||||
return applyGame(config, playerUUID, state);
|
||||
return applyGame(config, playerUUID, newState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected CompletableFuture<SyncSummary<C>> discordChanged(ISyncCause cause, Someone someone, D discordId, S state) {
|
||||
protected CompletableFuture<SyncSummary<C>> discordChanged(ISyncCause cause, Someone someone, D discordId, S newState) {
|
||||
List<C> gameConfigs = configsForDiscord.get(discordId);
|
||||
if (gameConfigs == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
@ -206,10 +224,10 @@ public abstract class AbstractSyncModule<
|
||||
|
||||
return someone.withLinkedAccounts(discordSRV).thenApply(resolved -> {
|
||||
if (resolved == null) {
|
||||
return new SyncSummary<C>(cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
return new SyncSummary<>(this, cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
}
|
||||
|
||||
SyncSummary<C> summary = new SyncSummary<>(cause, resolved);
|
||||
SyncSummary<C> summary = new SyncSummary<>(this, cause, resolved);
|
||||
for (C config : gameConfigs) {
|
||||
SyncDirection direction = config.direction;
|
||||
if (direction == SyncDirection.MINECRAFT_TO_DISCORD) {
|
||||
@ -218,7 +236,7 @@ public abstract class AbstractSyncModule<
|
||||
continue;
|
||||
}
|
||||
|
||||
summary.appendResult(config, applyGameIfNot(config, resolved.playerUUID(), state));
|
||||
summary.appendResult(config, applyGameIfDoesNotMatch(config, resolved.playerUUID(), newState));
|
||||
|
||||
// If the sync is bidirectional, also sync anything else linked to the same Minecraft id
|
||||
if (direction == SyncDirection.DISCORD_TO_MINECRAFT) {
|
||||
@ -231,11 +249,11 @@ public abstract class AbstractSyncModule<
|
||||
}
|
||||
|
||||
for (C gameConfig : discordConfigs) {
|
||||
if (gameConfig.discordId() == discordId) {
|
||||
if (Objects.equals(gameConfig.discordId(), discordId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
summary.appendResult(gameConfig, applyDiscordIfNot(gameConfig, resolved.userId(), state));
|
||||
summary.appendResult(gameConfig, applyDiscordIfDoesNotMatch(gameConfig, resolved.userId(), newState));
|
||||
}
|
||||
}
|
||||
return summary;
|
||||
@ -246,7 +264,7 @@ public abstract class AbstractSyncModule<
|
||||
});
|
||||
}
|
||||
|
||||
protected CompletableFuture<SyncSummary<C>> gameChanged(ISyncCause cause, Someone someone, G gameId, S state) {
|
||||
protected CompletableFuture<SyncSummary<C>> gameChanged(ISyncCause cause, Someone someone, G gameId, S newState) {
|
||||
List<C> discordConfigs = configsForGame.get(gameId);
|
||||
if (discordConfigs == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
@ -254,10 +272,10 @@ public abstract class AbstractSyncModule<
|
||||
|
||||
return someone.withLinkedAccounts(discordSRV).thenApply(resolved -> {
|
||||
if (resolved == null) {
|
||||
return new SyncSummary<C>(cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
return new SyncSummary<>(this, cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
}
|
||||
|
||||
SyncSummary<C> summary = new SyncSummary<>(cause, resolved);
|
||||
SyncSummary<C> summary = new SyncSummary<>(this, cause, resolved);
|
||||
for (C config : discordConfigs) {
|
||||
SyncDirection direction = config.direction;
|
||||
if (direction == SyncDirection.DISCORD_TO_MINECRAFT) {
|
||||
@ -266,7 +284,7 @@ public abstract class AbstractSyncModule<
|
||||
continue;
|
||||
}
|
||||
|
||||
summary.appendResult(config, applyDiscordIfNot(config, resolved.userId(), state));
|
||||
summary.appendResult(config, applyDiscordIfDoesNotMatch(config, resolved.userId(), newState));
|
||||
|
||||
// If the sync is bidirectional, also sync anything else linked to the same Discord id
|
||||
if (direction == SyncDirection.MINECRAFT_TO_DISCORD) {
|
||||
@ -279,11 +297,11 @@ public abstract class AbstractSyncModule<
|
||||
}
|
||||
|
||||
for (C gameConfig : gameConfigs) {
|
||||
if (gameConfig.gameId() == gameId) {
|
||||
if (Objects.equals(gameConfig.gameId(), gameId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
summary.appendResult(gameConfig, applyGameIfNot(gameConfig, resolved.playerUUID(), state));
|
||||
summary.appendResult(gameConfig, applyGameIfDoesNotMatch(gameConfig, resolved.playerUUID(), newState));
|
||||
}
|
||||
}
|
||||
return summary;
|
||||
@ -297,11 +315,11 @@ public abstract class AbstractSyncModule<
|
||||
public CompletableFuture<SyncSummary<C>> resyncAll(ISyncCause cause, Someone someone) {
|
||||
return someone.withLinkedAccounts(discordSRV).thenApply(resolved -> {
|
||||
if (resolved == null) {
|
||||
return new SyncSummary<C>(cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
return new SyncSummary<>(this, cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
}
|
||||
|
||||
SyncSummary<C> summary = new SyncSummary<>(cause, resolved);
|
||||
List<C> configs = configs();
|
||||
SyncSummary<C> summary = new SyncSummary<>(this, cause, resolved);
|
||||
Set<C> configs = syncs.keySet();
|
||||
|
||||
for (C config : configs) {
|
||||
summary.appendResult(config, resync(config, resolved));
|
||||
@ -317,10 +335,10 @@ public abstract class AbstractSyncModule<
|
||||
protected CompletableFuture<SyncSummary<C>> resync(ISyncCause cause, C config, Someone someone) {
|
||||
return someone.withLinkedAccounts(discordSRV).thenApply(resolved -> {
|
||||
if (resolved == null) {
|
||||
return new SyncSummary<C>(cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
return new SyncSummary<>(this, cause, someone).fail(GenericSyncResults.NOT_LINKED);
|
||||
}
|
||||
|
||||
return new SyncSummary<C>(cause, resolved)
|
||||
return new SyncSummary<C>(this, cause, resolved)
|
||||
.appendResult(config, resync(config, resolved));
|
||||
}).whenComplete((summary, t) -> {
|
||||
if (summary != null) {
|
||||
@ -340,10 +358,9 @@ public abstract class AbstractSyncModule<
|
||||
S gameState = gameGet.join();
|
||||
S discordState = discordGet.join();
|
||||
|
||||
boolean bothState;
|
||||
if ((bothState = (gameState != null)) == (discordState != null)) {
|
||||
// Already in sync
|
||||
return CompletableFuture.completedFuture((ISyncResult) (bothState ? GenericSyncResults.BOTH_TRUE : GenericSyncResults.BOTH_FALSE));
|
||||
ISyncResult alreadyInSyncResult = doesStateMatch(gameState, discordState);
|
||||
if (alreadyInSyncResult != null) {
|
||||
return CompletableFuture.completedFuture(alreadyInSyncResult);
|
||||
}
|
||||
|
||||
SyncSide side = config.tieBreaker;
|
||||
@ -392,45 +409,71 @@ public abstract class AbstractSyncModule<
|
||||
|
||||
private String formatResults(SyncSummary<C> summary, List<String> results) {
|
||||
int count = results.size();
|
||||
return summary.who().toString()
|
||||
return summary.who() + " (sync cause: " + summary.cause() + ")"
|
||||
+ (count == 1 ? ": " : "\n")
|
||||
+ String.join("\n", results);
|
||||
}
|
||||
|
||||
private void logSummary(SyncSummary<C> summary) {
|
||||
summary.resultFuture().whenComplete((results, t) -> {
|
||||
Throwable throwableToLog = null;
|
||||
if (t != null) {
|
||||
logger().error("Failed to " + syncName() + " " + summary.who(), t);
|
||||
return;
|
||||
while (t instanceof CompletionException) {
|
||||
t = t.getCause();
|
||||
}
|
||||
if (t instanceof SyncFail) {
|
||||
SyncFail fail = (SyncFail) t;
|
||||
summary.fail(fail.getResult());
|
||||
throwableToLog = fail.getCause();
|
||||
} else {
|
||||
logger().error("Failed to " + syncName() + " " + summary.who() + " (sync cause: " + summary.cause() + ")", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ISyncResult allFailReason = summary.allFailReason();
|
||||
if (allFailReason != null) {
|
||||
String reason = allFailReason.format(gameTerm(), discordTerm());
|
||||
logger().debug("Failed to " + syncName() + " " + summary.who() + ": " + reason);
|
||||
String message = "Failed to " + syncName() + " " + summary.who() + " (sync cause: " + summary.cause() + "): " + reason;
|
||||
if (!allFailReason.isSuccess()) {
|
||||
logger().error(message, throwableToLog);
|
||||
} else {
|
||||
logger().debug(message, throwableToLog);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> logResults = new ArrayList<>();
|
||||
List<String> auditResults = new ArrayList<>();
|
||||
Map<ISyncResult, List<String>> groupedResults = new LinkedHashMap<>();
|
||||
for (Map.Entry<C, ISyncResult> entry : results.entrySet()) {
|
||||
C config = entry.getKey();
|
||||
ISyncResult result = entry.getValue();
|
||||
|
||||
String log = config.describe();
|
||||
if (StringUtils.isEmpty(log)) {
|
||||
log += ": ";
|
||||
}
|
||||
log += result.format(gameTerm(), discordTerm());
|
||||
groupedResults.computeIfAbsent(result, key -> new ArrayList<>()).add(config.describe());
|
||||
}
|
||||
|
||||
logResults.add(log);
|
||||
List<String> successResults = new ArrayList<>();
|
||||
List<String> failResults = new ArrayList<>();
|
||||
for (Map.Entry<ISyncResult, List<String>> entry : groupedResults.entrySet()) {
|
||||
ISyncResult result = entry.getKey();
|
||||
String line = result.format(gameTerm(), discordTerm())
|
||||
+ ": [" + String.join(", ", entry.getValue()) + "]";
|
||||
if (result.isSuccess()) {
|
||||
auditResults.add(log);
|
||||
successResults.add(line);
|
||||
} else {
|
||||
failResults.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
logger().debug(formatResults(summary, logResults));
|
||||
discordSRV.logger().writeLogForCurrentDay(logName(), formatResults(summary, auditResults));
|
||||
boolean anySuccess = !successResults.isEmpty();
|
||||
boolean anyFail = !failResults.isEmpty();
|
||||
String partially = anySuccess && anyFail ? " partially" : "";
|
||||
if (anySuccess) {
|
||||
logger().debug(syncName() + partially + " succeeded for " + formatResults(summary, successResults));
|
||||
}
|
||||
if (anyFail) {
|
||||
logger().error(syncName() + partially + " failed for " + formatResults(summary, failResults));
|
||||
}
|
||||
discordSRV.logger().writeLogForCurrentDay(logFileName(), formatResults(summary, successResults));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync;
|
||||
|
||||
import com.discordsrv.common.sync.result.ISyncResult;
|
||||
|
@ -1,5 +1,24 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.generic.AbstractSyncConfig;
|
||||
import com.discordsrv.common.future.util.CompletableFutureUtil;
|
||||
import com.discordsrv.common.someone.Someone;
|
||||
@ -9,16 +28,19 @@ import com.discordsrv.common.sync.result.ISyncResult;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SyncSummary<C extends AbstractSyncConfig<C, ?, ?>> {
|
||||
|
||||
private final AbstractSyncModule<? extends DiscordSRV, C, ?, ?, ?> syncModule;
|
||||
private final ISyncCause cause;
|
||||
private final Someone who;
|
||||
private ISyncResult allFailReason;
|
||||
private final Map<C, CompletableFuture<ISyncResult>> results = new ConcurrentHashMap<>();
|
||||
|
||||
public SyncSummary(ISyncCause cause, Someone who) {
|
||||
public SyncSummary(AbstractSyncModule<? extends DiscordSRV, C, ?, ?, ?> syncModule, ISyncCause cause, Someone who) {
|
||||
this.syncModule = syncModule;
|
||||
this.cause = cause;
|
||||
this.who = who;
|
||||
}
|
||||
@ -55,7 +77,25 @@ public class SyncSummary<C extends AbstractSyncConfig<C, ?, ?>> {
|
||||
.thenApply((__) -> {
|
||||
Map<C, ISyncResult> results = new HashMap<>();
|
||||
for (Map.Entry<C, CompletableFuture<ISyncResult>> entry : this.results.entrySet()) {
|
||||
results.put(entry.getKey(), entry.getValue().join());
|
||||
results.put(entry.getKey(), entry.getValue().exceptionally(t -> {
|
||||
while (t instanceof CompletionException) {
|
||||
t = t.getCause();
|
||||
}
|
||||
Throwable throwableToLog = t;
|
||||
ISyncResult result = null;
|
||||
if (t instanceof SyncFail) {
|
||||
throwableToLog = t.getCause();
|
||||
result = ((SyncFail) t).getResult();
|
||||
}
|
||||
|
||||
if (throwableToLog != null) {
|
||||
syncModule.logger().error(
|
||||
"Error in " + syncModule.syncName() + " "
|
||||
+ entry.getKey().describe() + " for " + who()
|
||||
+ " (sync cause: " + cause() + ")", throwableToLog);
|
||||
}
|
||||
return result;
|
||||
}).join());
|
||||
}
|
||||
return results;
|
||||
});
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync.cause;
|
||||
|
||||
public enum GenericSyncCauses implements ISyncCause {
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync.cause;
|
||||
|
||||
public interface ISyncCause {
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync.result;
|
||||
|
||||
public enum GenericSyncResults implements ISyncResult {
|
||||
@ -18,6 +36,10 @@ public enum GenericSyncResults implements ISyncResult {
|
||||
|
||||
;
|
||||
|
||||
public static GenericSyncResults both(boolean value) {
|
||||
return value ? BOTH_TRUE : BOTH_FALSE;
|
||||
}
|
||||
|
||||
private final String message;
|
||||
private final boolean success;
|
||||
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.sync.result;
|
||||
|
||||
import com.discordsrv.api.placeholder.util.Placeholders;
|
||||
|
Loading…
Reference in New Issue
Block a user