Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ val lwjglNatives = "natives-windows"
dependencies {
implementation(project(":api"))
implementation(project(":core"))
implementation("com.google.code.gson:gson:2.11.0")
implementation("io.github.spair:imgui-java-app:$imguiVersion")
runtimeOnly("io.github.spair:imgui-java-natives-windows:$imguiVersion")
runtimeOnly("org.lwjgl:lwjgl:$lwjglVersion:$lwjglNatives")
Expand Down
79 changes: 77 additions & 2 deletions cli/src/main/java/com/botwithus/bot/cli/CliContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

import com.botwithus.bot.core.runtime.ScriptRunner;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.awt.image.BufferedImage;
import java.io.PrintStream;
import java.nio.file.Files;
Expand Down Expand Up @@ -297,14 +301,69 @@ public void openConfigPanel(ScriptRunner runner) {
if (configPanelOpener != null) configPanelOpener.accept(runner);
}

// --- Connection Group management ---
// --- Connection Group management & persistence ---

private static final Path GROUPS_FILE = Path.of(System.getProperty("user.home"), ".botwithus", "groups.json");

/** Simple DTO for JSON serialization of a group. */
private static class GroupData {
String description;
List<String> members;
GroupData() {}
GroupData(String description, List<String> members) {
this.description = description;
this.members = members;
}
}

/** Loads persisted groups from ~/.botwithus/groups.json. */
public void loadGroups() {
if (!Files.exists(GROUPS_FILE)) return;
try {
String json = Files.readString(GROUPS_FILE);
Gson gson = new Gson();
Map<String, GroupData> data = gson.fromJson(json,
new TypeToken<LinkedHashMap<String, GroupData>>() {}.getType());
if (data != null) {
groups.clear();
for (var entry : data.entrySet()) {
ConnectionGroup group = new ConnectionGroup(entry.getKey());
GroupData gd = entry.getValue();
if (gd.description != null) group.setDescription(gd.description);
if (gd.members != null) gd.members.forEach(group::add);
groups.put(entry.getKey(), group);
}
}
} catch (Exception e) {
System.err.println("[CliContext] Failed to load groups: " + e.getMessage());
}
}

/** Persists current groups to ~/.botwithus/groups.json. */
void saveGroups() {
try {
Files.createDirectories(GROUPS_FILE.getParent());
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Map<String, GroupData> data = new LinkedHashMap<>();
for (var entry : groups.entrySet()) {
ConnectionGroup g = entry.getValue();
data.put(entry.getKey(), new GroupData(g.getDescription(), new ArrayList<>(g.getConnectionNames())));
}
Files.writeString(GROUPS_FILE, gson.toJson(data));
} catch (Exception e) {
System.err.println("[CliContext] Failed to save groups: " + e.getMessage());
}
}

public void createGroup(String name) {
groups.put(name, new ConnectionGroup(name));
saveGroups();
}

public boolean deleteGroup(String name) {
return groups.remove(name) != null;
boolean removed = groups.remove(name) != null;
if (removed) saveGroups();
return removed;
}

public ConnectionGroup getGroup(String name) {
Expand All @@ -315,6 +374,22 @@ public Map<String, ConnectionGroup> getGroups() {
return Collections.unmodifiableMap(groups);
}

public void addToGroup(String groupName, String connectionName) {
ConnectionGroup group = groups.get(groupName);
if (group != null) {
group.add(connectionName);
saveGroups();
}
}

public void removeFromGroup(String groupName, String connectionName) {
ConnectionGroup group = groups.get(groupName);
if (group != null) {
group.remove(connectionName);
saveGroups();
}
}

/**
* Returns the list of active (connected) Connection objects for a group.
* Connections that are in the group but not currently connected are skipped.
Expand Down
11 changes: 5 additions & 6 deletions cli/src/main/java/com/botwithus/bot/cli/ClientManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public void setGroupDescription(String groupName, String description) {
ConnectionGroup group = ctx.getGroup(groupName);
if (group != null) {
group.setDescription(description);
ctx.saveGroups();
}
}

Expand All @@ -124,17 +125,15 @@ public Set<String> getGroupMembers(String groupName) {

@Override
public boolean addToGroup(String groupName, String clientName) {
ConnectionGroup group = ctx.getGroup(groupName);
if (group == null) return false;
group.add(clientName);
if (ctx.getGroup(groupName) == null) return false;
ctx.addToGroup(groupName, clientName);
return true;
}

@Override
public boolean removeFromGroup(String groupName, String clientName) {
ConnectionGroup group = ctx.getGroup(groupName);
if (group == null) return false;
group.remove(clientName);
if (ctx.getGroup(groupName) == null) return false;
ctx.removeFromGroup(groupName, clientName);
return true;
}

Expand Down
1 change: 1 addition & 0 deletions cli/src/main/java/com/botwithus/bot/cli/JBotCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static void main(String[] args) {

PrintStream out = logCapture.getOriginalOut();
CliContext ctx = new CliContext(logBuffer, logCapture);
ctx.loadGroups();
CommandRegistry registry = new CommandRegistry();

// Register commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private void addToGroup(String groupName, String connName, CliContext ctx) {
ctx.out().println("'" + connName + "' is already in group '" + groupName + "'.");
return;
}
group.add(connName);
ctx.addToGroup(groupName, connName);
ctx.out().println("Added '" + connName + "' to group '" + groupName + "'.");
}

Expand All @@ -93,7 +93,7 @@ private void removeFromGroup(String groupName, String connName, CliContext ctx)
ctx.out().println("'" + connName + "' is not in group '" + groupName + "'.");
return;
}
group.remove(connName);
ctx.removeFromGroup(groupName, connName);
ctx.out().println("Removed '" + connName + "' from group '" + groupName + "'.");
}

Expand Down
4 changes: 2 additions & 2 deletions cli/src/main/java/com/botwithus/bot/cli/gui/GroupsPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public void render(CliContext ctx) {
ImGui.sameLine(0, 12);
ImGui.pushID("member_rm_" + grpIdx + "_" + memberIdx);
if (ImGui.smallButton("Remove")) {
group.remove(memberName);
ctx.removeFromGroup(groupName, memberName);
}
ImGui.popID();
memberIdx++;
Expand Down Expand Up @@ -167,7 +167,7 @@ private void renderAddConnectionDropdown(CliContext ctx, String groupName, Conne
ImGui.popItemWidth();
ImGui.sameLine();
if (ImGui.smallButton("Add")) {
group.add(names[selected.get()]);
ctx.addToGroup(groupName, names[selected.get()]);
}
ImGui.popID();
}
Expand Down
1 change: 1 addition & 0 deletions cli/src/main/java/com/botwithus/bot/cli/gui/ImGuiApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ protected void initImGui(Configuration config) {
logCapture.install();

ctx = new CliContext(logBuffer, logCapture);
ctx.loadGroups();
ctx.setStreamManager(new StreamManager(outputBuffer, textureManager, guiOut));

ScriptProfileStore profileStore = new ScriptProfileStore();
Expand Down
1 change: 1 addition & 0 deletions cli/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module com.botwithus.bot.cli {
requires com.botwithus.bot.api;
requires com.botwithus.bot.core;
requires com.google.gson;
requires imgui.binding;
requires imgui.app;
requires org.lwjgl;
Expand Down