Skip to content

Commit

Permalink
feat: 实现简易权限序列化
Browse files Browse the repository at this point in the history
  • Loading branch information
huanmeng-qwq committed Oct 18, 2024
1 parent 71540f4 commit 7f023d7
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 41 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,5 @@ run/
.console_history
logs
kbc.yml
plugins
plugins
permissions.json
99 changes: 65 additions & 34 deletions src/main/java/snw/kookbc/impl/KBCClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import snw.kookbc.impl.network.Session;
import snw.kookbc.impl.network.webhook.JLHttpWebhookNetworkSystem;
import snw.kookbc.impl.network.ws.OkhttpWebSocketNetworkSystem;
import snw.kookbc.impl.permissions.UserPermissionSaved;
import snw.kookbc.impl.plugin.InternalPlugin;
import snw.kookbc.impl.plugin.SimplePluginManager;
import snw.kookbc.impl.scheduler.SchedulerImpl;
Expand All @@ -59,7 +60,10 @@
import snw.kookbc.util.ReturnNotNullFunction;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -89,6 +93,7 @@ public class KBCClient {
protected final ExecutorService eventExecutor;
protected final NetworkSystem networkSystem;
protected List<Plugin> plugins;
protected final Map<String, UserPermissionSaved> userPermissions = new HashMap<>();

// Use the second one instead, that's recommended
// However, if you have already specified the network mode in the config object, feel free to use this one
Expand All @@ -111,17 +116,9 @@ private static ConfigurationSection editNetworkMode(ConfigurationSection config,
return config;
}

public KBCClient(
CoreImpl core, ConfigurationSection config, File pluginsFolder, String token,
public KBCClient(CoreImpl core, ConfigurationSection config, File pluginsFolder, String token,
/* Customizable components are following: */
@Nullable ReturnNotNullFunction<KBCClient, CommandManager> commandManager,
@Nullable ReturnNotNullFunction<KBCClient, NetworkClient> networkClient,
@Nullable ReturnNotNullFunction<KBCClient, EntityStorage> storage,
@Nullable ReturnNotNullFunction<KBCClient, EntityBuilder> entityBuilder,
@Nullable ReturnNotNullFunction<KBCClient, MessageBuilder> msgBuilder,
@Nullable ReturnNotNullFunction<KBCClient, EventFactory> eventFactory,
@Nullable ReturnNotNullFunction<KBCClient, NetworkSystem> networkSystem
) {
@Nullable ReturnNotNullFunction<KBCClient, CommandManager> commandManager, @Nullable ReturnNotNullFunction<KBCClient, NetworkClient> networkClient, @Nullable ReturnNotNullFunction<KBCClient, EntityStorage> storage, @Nullable ReturnNotNullFunction<KBCClient, EntityBuilder> entityBuilder, @Nullable ReturnNotNullFunction<KBCClient, MessageBuilder> msgBuilder, @Nullable ReturnNotNullFunction<KBCClient, EventFactory> eventFactory, @Nullable ReturnNotNullFunction<KBCClient, NetworkSystem> networkSystem) {
if (pluginsFolder != null) {
Validate.isTrue(pluginsFolder.isDirectory(), "The provided pluginsFolder object is not a directory.");
}
Expand Down Expand Up @@ -155,6 +152,44 @@ public KBCClient(
} else {
this.networkSystem = networkSystem.apply(this);
}
loadPermissions();
}

protected void loadPermissions() {
String path = System.getProperty("kookbc.permissions.file", "permissions.json");
File file = new File(path);
if (!file.exists()) {
return;
}
try (FileInputStream inputStream = new FileInputStream(file)) {
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
String json = new String(bytes, StandardCharsets.UTF_8);
List<UserPermissionSaved> parseList = UserPermissionSaved.parseList(json);
for (UserPermissionSaved userPermissionSaved : parseList) {
this.userPermissions.put(userPermissionSaved.getUid(), userPermissionSaved);
}
} catch (IOException e) {
getCore().getLogger().error("Failed to load permissions", e);
}
}

public void savePermissions() {
String path = System.getProperty("kookbc.permissions.file", "permissions.json");
try {
File file = new File(path);
if (file.getParentFile()!=null && !file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
try (FileOutputStream outputStream = new FileOutputStream(file)) {
outputStream.write(UserPermissionSaved.toString(this.userPermissions.values().toArray(new UserPermissionSaved[0])).getBytes(StandardCharsets.UTF_8));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

// The result of this method can prevent the users to execute the console command,
Expand Down Expand Up @@ -220,8 +255,7 @@ public synchronized void start() {
}

core.getLogger().debug("Fetching Bot user object");
User botUser = getEntityBuilder().buildUser(
getNetworkClient().get(HttpAPIRoute.USER_ME.toFullURL()));
User botUser = getEntityBuilder().buildUser(getNetworkClient().get(HttpAPIRoute.USER_ME.toFullURL()));
getStorage().addUser(botUser);
core.setUser(botUser);
registerInternal();
Expand Down Expand Up @@ -257,8 +291,7 @@ private void enablePlugins() {
if (plugins == null || getPluginsFolder() == null) {
return; // no plugins loaded (or no plugin folder available), so no plugins can be enabled
}
@SuppressWarnings("DataFlowIssue")
List<File> newIncomingFiles = new ArrayList<>(Arrays.asList(getPluginsFolder().listFiles(File::isFile)));
@SuppressWarnings("DataFlowIssue") List<File> newIncomingFiles = new ArrayList<>(Arrays.asList(getPluginsFolder().listFiles(File::isFile)));

getCore().getLogger().debug("Before filtering: {}", newIncomingFiles);
getCore().getLogger().debug("Current known plugins: {}", this.plugins);
Expand Down Expand Up @@ -383,8 +416,7 @@ protected void finishStart() {
getCore().getLogger().warn("Invalid UUID of BotMarket. We won't schedule the PING task for BotMarket.");
}
*/
getCore().getLogger()
.warn("BotMarket Ping is currently deprecated, as they are upgrading their system.");
getCore().getLogger().warn("BotMarket Ping is currently deprecated, as they are upgrading their system.");
}
}
// endregion
Expand Down Expand Up @@ -505,8 +537,7 @@ protected void registerInternal() {
commands.add(StopCommand.class);
}
if (commandConfig.getBoolean("help", true)) {
this.core.getEventManager()
.registerHandlers(this.internalPlugin, new UserClickButtonListener(this));
this.core.getEventManager().registerHandlers(this.internalPlugin, new UserClickButtonListener(this));
commands.add(HelpCommand.class);
}
if (commandConfig.getBoolean("plugins", true)) {
Expand All @@ -516,25 +547,25 @@ protected void registerInternal() {
}

private void registerCommands(List<Class<?>> commands) {
LiteKookFactory.builder(getInternalPlugin())
.settings((k) -> {
if (!getConfig().contains("internal-commands-reply-result-type")) {
return k;
}
try {
ResultTypes resultTypes = ResultTypes.valueOf(getConfig().getString("internal-commands-reply-result-type"));
k.defaultResultType(resultTypes);
} catch (Exception e) {
getCore().getLogger().error("`internal-commands-reply-result-type` is not a valid result-type");
}
return k;
})
.commands(commands.toArray())
.build()
;
LiteKookFactory.builder(getInternalPlugin()).settings((k) -> {
if (!getConfig().contains("internal-commands-reply-result-type")) {
return k;
}
try {
ResultTypes resultTypes = ResultTypes.valueOf(getConfig().getString("internal-commands-reply-result-type"));
k.defaultResultType(resultTypes);
} catch (Exception e) {
getCore().getLogger().error("`internal-commands-reply-result-type` is not a valid result-type");
}
return k;
}).commands(commands.toArray()).build();
}

public CommandManager getCommandManager() {
return commandManager;
}

public Map<String, UserPermissionSaved> getUserPermissions() {
return userPermissions;
}
}
10 changes: 9 additions & 1 deletion src/main/java/snw/kookbc/impl/entity/UserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import snw.kookbc.impl.network.HttpAPIRoute;
import snw.kookbc.impl.pageiter.UserJoinedVoiceChannelIterator;
import snw.kookbc.impl.permissions.SimplePermsImpl;
import snw.kookbc.impl.permissions.UserPermissionSaved;
import snw.kookbc.interfaces.LazyLoadable;
import snw.kookbc.interfaces.Updatable;
import snw.kookbc.util.MapBuilder;
Expand All @@ -67,11 +68,13 @@ public class UserImpl implements User, Updatable, LazyLoadable {
private String vipAvatarUrl;
private boolean completed;

private final SimplePermsImpl perms = new SimplePermsImpl(this);
private final SimplePermsImpl perms;

public UserImpl(KBCClient client, String id) {
this.client = requireNonNull(client);
this.id = requireNonNull(id);
this.perms = new SimplePermsImpl(this.client, this);
this.perms.load();
}

public UserImpl(KBCClient client, String id, boolean bot, String name, int identify, boolean ban, boolean vip,
Expand Down Expand Up @@ -387,6 +390,11 @@ public boolean isPermissionSet(@Nullable Channel context, @NotNull PermissionNod
@Override
public void recalculatePermissions() {
this.perms.recalculatePermissions();
if (this.perms.isLoading()) {
return;
}
client.getUserPermissions().put(getId(), new UserPermissionSaved(getId(), this.perms.getEffectivePermissions(null)));
client.savePermissions();
}

public Map<Permission, Boolean> calculateChannel(Channel channel) {
Expand Down
30 changes: 25 additions & 5 deletions src/main/java/snw/kookbc/impl/permissions/SimplePermsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,36 @@
import snw.jkook.entity.channel.Channel;
import snw.jkook.permissions.*;
import snw.jkook.plugin.Plugin;
import snw.kookbc.impl.KBCClient;
import snw.kookbc.impl.entity.UserImpl;

import java.util.*;

public class SimplePermsImpl implements Permissible {
private final KBCClient client;
private final UserImpl own;
private final Map<String, PermissionAttachmentInfo> permissions;
private final List<PermissionAttachment> attachments = new LinkedList<>();

public SimplePermsImpl(UserImpl own) {
private boolean loading = true;

public SimplePermsImpl(KBCClient client, UserImpl own) {
this.client = client;
this.own = own;
this.permissions = new HashMap<>();
}

public void load() {
if (!this.loading) return;
UserPermissionSaved permissionSaved = client.getUserPermissions().get(own.getId());
if (permissionSaved != null) {
permissionSaved.getPermissions().forEach((perms, v) -> {
addAttachment(client.getInternalPlugin(), perms, v);
});
this.loading = false;
}
}

@Override
public boolean hasPermission(@Nullable Channel context, @Nullable String permission) {
if (permission == null) return true;
Expand Down Expand Up @@ -102,7 +118,7 @@ public void removeAttachment(PermissionAttachment permissionAttachment) {
}

if (this.attachments.remove(permissionAttachment)) {
recalculatePermissions();
this.own.recalculatePermissions();
} else {
throw new IllegalArgumentException("Given attachment is not part of Permissible object " + this.own);
}
Expand All @@ -119,12 +135,12 @@ public void removeAttachment(PermissionAttachment permissionAttachment) {
if (pemrs == null)
throw new IllegalArgumentException("Cannot add this permission: " + name);
context.addPermission(this.own, pemrs.getPermissionEnum());
return new PermissionAttachment(plugin, this);
return new PermissionAttachment(plugin, this.own);
} else {
PermissionAttachment result = new PermissionAttachment(plugin, this);
PermissionAttachment result = new PermissionAttachment(plugin, this.own);
result.setPermission(name, value);
this.attachments.add(result);
this.recalculatePermissions();
this.own.recalculatePermissions();
return result;
}
}
Expand All @@ -141,4 +157,8 @@ public void removeAttachment(PermissionAttachment permissionAttachment) {
result.addAll(this.permissions.values());
return result;
}

public boolean isLoading() {
return loading;
}
}
66 changes: 66 additions & 0 deletions src/main/java/snw/kookbc/impl/permissions/UserPermissionSaved.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* KookBC -- The Kook Bot Client & JKook API standard implementation for Java.
* Copyright (C) 2022 - 2023 KookBC contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package snw.kookbc.impl.permissions;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import snw.jkook.permissions.PermissionAttachmentInfo;

import java.util.*;

public class UserPermissionSaved {
private final String uid;
private final Map<String, Boolean> permissions;

public UserPermissionSaved(String uid, Map<String, Boolean> permissions) {
this.uid = uid;
this.permissions = permissions;
}

public UserPermissionSaved(String uid, Set<PermissionAttachmentInfo> attachmentInfos) {
this.uid = uid;
this.permissions = new HashMap<>();
attachmentInfos.forEach(permissionAttachmentInfo -> {
this.permissions.put(permissionAttachmentInfo.getPermission().toLowerCase(Locale.ENGLISH), permissionAttachmentInfo.getValue());
});
}

public String getUid() {
return uid;
}

public Map<String, Boolean> getPermissions() {
return permissions;
}

public static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();

public static String toString(UserPermissionSaved... array) {
return GSON.toJson(array);
}

public static UserPermissionSaved parse(String json) {
return GSON.fromJson(json, UserPermissionSaved.class);
}

public static List<UserPermissionSaved> parseList(String json) {
return GSON.fromJson(json, new TypeToken<List<UserPermissionSaved>>() {
});
}
}

0 comments on commit 7f023d7

Please sign in to comment.