feat: implement deep auto-refresh for ComfyUI bridge with backend reset and frontend combo update
This commit is contained in:
@@ -55,7 +55,6 @@ public class Main extends JFrame {
|
||||
private final IModelValidator modelValidator;
|
||||
private final de.tki.comfymodels.service.impl.RestBridgeService restBridge;
|
||||
private final de.tki.comfymodels.service.impl.ArchiveService archiveService;
|
||||
private final de.tki.comfymodels.service.impl.ComfyUIBridgeClient bridgeClient;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
@@ -90,8 +89,7 @@ public class Main extends JFrame {
|
||||
public Main(IModelAnalyzer analyzer, IDownloadManager downloadManager,
|
||||
IWorkflowService workflowService, IModelSearchService searchService,
|
||||
IModelValidator modelValidator, de.tki.comfymodels.service.impl.RestBridgeService restBridge,
|
||||
de.tki.comfymodels.service.impl.ArchiveService archiveService,
|
||||
de.tki.comfymodels.service.impl.ComfyUIBridgeClient bridgeClient) {
|
||||
de.tki.comfymodels.service.impl.ArchiveService archiveService) {
|
||||
this.analyzer = analyzer;
|
||||
this.downloadManager = downloadManager;
|
||||
this.workflowService = workflowService;
|
||||
@@ -99,7 +97,6 @@ public class Main extends JFrame {
|
||||
this.modelValidator = modelValidator;
|
||||
this.restBridge = restBridge;
|
||||
this.archiveService = archiveService;
|
||||
this.bridgeClient = bridgeClient;
|
||||
}
|
||||
|
||||
public void launch(String[] args) {
|
||||
@@ -354,7 +351,7 @@ public class Main extends JFrame {
|
||||
try {
|
||||
configService.unlock(pass);
|
||||
restBridge.setApiToken(configService.getApiToken());
|
||||
syncBridgeToken();
|
||||
syncBridgeFiles(); // NEW: Automatically sync code & token on every unlock
|
||||
|
||||
// NEW: Auto-import model list on first start or vault reset
|
||||
if (configService.isVaultFresh()) {
|
||||
@@ -769,7 +766,6 @@ public class Main extends JFrame {
|
||||
() -> SwingUtilities.invokeLater(() -> {
|
||||
downloadButton.setEnabled(true);
|
||||
statusLabel.setText("Queue finished.");
|
||||
bridgeClient.notifyModelDownloaded();
|
||||
if (configService.isShutdownAfterDownloadEnabled()) performSystemShutdown();
|
||||
})
|
||||
);
|
||||
@@ -843,7 +839,7 @@ public class Main extends JFrame {
|
||||
return;
|
||||
}
|
||||
configService.setComfyUIPath(selectedPath);
|
||||
syncBridgeToken();
|
||||
syncBridgeFiles();
|
||||
JOptionPane.showMessageDialog(dialog, "API Token synchronized successfully.");
|
||||
});
|
||||
|
||||
@@ -1447,6 +1443,36 @@ public class Main extends JFrame {
|
||||
JTable archiveTable = new JTable(archiveTableModel);
|
||||
archiveTable.setRowHeight(25);
|
||||
archiveTable.getColumnModel().getColumn(0).setMaxWidth(50);
|
||||
|
||||
// Enable sorting with custom comparator for human-readable sizes
|
||||
javax.swing.table.TableRowSorter<DefaultTableModel> archiveSorter = new javax.swing.table.TableRowSorter<>(archiveTableModel);
|
||||
archiveSorter.setComparator(3, (s1, s2) -> Long.compare(parseSizeToBytes((String)s1), parseSizeToBytes((String)s2)));
|
||||
archiveSorter.setSortable(0, false); // Disable sorting for checkbox column to allow "Select All"
|
||||
archiveTable.setRowSorter(archiveSorter);
|
||||
|
||||
// Add "Select All" functionality to header
|
||||
archiveTable.getTableHeader().addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int viewIdx = archiveTable.columnAtPoint(e.getPoint());
|
||||
if (viewIdx == -1) return;
|
||||
int modelIdx = archiveTable.convertColumnIndexToModel(viewIdx);
|
||||
if (modelIdx == 0) {
|
||||
boolean allSelected = true;
|
||||
for (int i = 0; i < archiveTableModel.getRowCount(); i++) {
|
||||
if (!(Boolean) archiveTableModel.getValueAt(i, 0)) {
|
||||
allSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean newValue = !allSelected;
|
||||
for (int i = 0; i < archiveTableModel.getRowCount(); i++) {
|
||||
archiveTableModel.setValueAt(newValue, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JScrollPane archiveScroll = new JScrollPane(archiveTable);
|
||||
archivePanel.add(archiveScroll, BorderLayout.CENTER);
|
||||
|
||||
@@ -1494,6 +1520,36 @@ public class Main extends JFrame {
|
||||
JTable restoreTable = new JTable(restoreTableModel);
|
||||
restoreTable.setRowHeight(25);
|
||||
restoreTable.getColumnModel().getColumn(0).setMaxWidth(50);
|
||||
|
||||
// Enable sorting with custom comparator for human-readable sizes
|
||||
javax.swing.table.TableRowSorter<DefaultTableModel> restoreSorter = new javax.swing.table.TableRowSorter<>(restoreTableModel);
|
||||
restoreSorter.setComparator(3, (s1, s2) -> Long.compare(parseSizeToBytes((String)s1), parseSizeToBytes((String)s2)));
|
||||
restoreSorter.setSortable(0, false); // Disable sorting for checkbox column to allow "Select All"
|
||||
restoreTable.setRowSorter(restoreSorter);
|
||||
|
||||
// Add "Select All" functionality to header
|
||||
restoreTable.getTableHeader().addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int viewIdx = restoreTable.columnAtPoint(e.getPoint());
|
||||
if (viewIdx == -1) return;
|
||||
int modelIdx = restoreTable.convertColumnIndexToModel(viewIdx);
|
||||
if (modelIdx == 0) {
|
||||
boolean allSelected = true;
|
||||
for (int i = 0; i < restoreTableModel.getRowCount(); i++) {
|
||||
if (!(Boolean) restoreTableModel.getValueAt(i, 0)) {
|
||||
allSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean newValue = !allSelected;
|
||||
for (int i = 0; i < restoreTableModel.getRowCount(); i++) {
|
||||
restoreTableModel.setValueAt(newValue, i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JScrollPane restoreScroll = new JScrollPane(restoreTable);
|
||||
restorePanel.add(restoreScroll, BorderLayout.CENTER);
|
||||
|
||||
@@ -1611,6 +1667,7 @@ public class Main extends JFrame {
|
||||
JOptionPane.showMessageDialog(this, finalSuccess + " models successfully " + title.toLowerCase() + "ed.",
|
||||
"Operation Complete", JOptionPane.INFORMATION_MESSAGE);
|
||||
analyzeJsonContent();
|
||||
downloadManager.notifyComfyUI();
|
||||
});
|
||||
}).start();
|
||||
|
||||
@@ -1735,7 +1792,7 @@ public class Main extends JFrame {
|
||||
helpDialog.setVisible(true);
|
||||
}
|
||||
|
||||
private void syncBridgeToken() {
|
||||
private void syncBridgeFiles() {
|
||||
String comfyPath = configService.getComfyUIPath();
|
||||
if (comfyPath == null || comfyPath.isEmpty()) return;
|
||||
|
||||
@@ -1747,8 +1804,19 @@ public class Main extends JFrame {
|
||||
|
||||
Path targetDir = customNodesDir.resolve("comfyui-model-downloader");
|
||||
if (Files.exists(targetDir) && Files.isDirectory(targetDir)) {
|
||||
writeExtensionConfig(targetDir.toFile());
|
||||
System.out.println("Synchronized API token with ComfyUI bridge at: " + targetDir);
|
||||
try {
|
||||
// Always sync latest code files from resources to target
|
||||
extractResource("/comfyui-bridge/__init__.py", targetDir.resolve("__init__.py").toFile());
|
||||
Path webDir = targetDir.resolve("web");
|
||||
Files.createDirectories(webDir);
|
||||
extractResource("/comfyui-bridge/web/downloader.js", webDir.resolve("downloader.js").toFile());
|
||||
|
||||
// Also update config
|
||||
writeExtensionConfig(targetDir.toFile());
|
||||
System.out.println("[Bridge-Sync] Successfully synchronized latest bridge code and token.");
|
||||
} catch (IOException e) {
|
||||
System.err.println("[Bridge-Sync] Failed to sync code: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ public interface IDownloadManager {
|
||||
void stop();
|
||||
boolean isPaused();
|
||||
|
||||
/**
|
||||
* Triggers a refresh signal to the ComfyUI bridge.
|
||||
*/
|
||||
void notifyComfyUI();
|
||||
|
||||
/**
|
||||
* Returns a map of current statuses for each model in the queue.
|
||||
*/
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package de.tki.comfymodels.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
|
||||
@Service
|
||||
public class ComfyUIBridgeClient {
|
||||
|
||||
private final HttpClient httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(2))
|
||||
.build();
|
||||
|
||||
private String comfyUrl = "http://127.0.0.1:8188";
|
||||
|
||||
public void setComfyUrl(String url) {
|
||||
if (url != null && !url.isEmpty()) {
|
||||
this.comfyUrl = url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyModelDownloaded() {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(comfyUrl + "/kippster/model-downloaded"))
|
||||
.POST(HttpRequest.BodyPublishers.noBody())
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.build();
|
||||
|
||||
System.out.println("Notifying ComfyUI at: " + request.uri());
|
||||
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
|
||||
.thenAccept(response -> {
|
||||
if (response.statusCode() >= 200 && response.statusCode() < 300) {
|
||||
System.out.println("ComfyUI notified successfully: " + response.body());
|
||||
} else {
|
||||
System.err.println("Failed to notify ComfyUI. Status: " + response.statusCode());
|
||||
}
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
System.err.println("Could not reach ComfyUI for refresh: " + ex.getMessage());
|
||||
return null;
|
||||
});
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error creating notification request: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,15 @@ public class ConfigService {
|
||||
save();
|
||||
}
|
||||
|
||||
public String getComfyUIUrl() { return settings.optString("comfyui_url", "http://127.0.0.1:8188"); }
|
||||
public void setComfyUIUrl(String url) {
|
||||
if (url != null && !url.isEmpty()) {
|
||||
String sanitized = url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
|
||||
settings.put("comfyui_url", sanitized);
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public String getApiToken() {
|
||||
String token = settings.optString("api_token", "");
|
||||
if (token.isEmpty() && isUnlocked()) {
|
||||
|
||||
@@ -121,20 +121,68 @@ public class DefaultDownloadManager implements IDownloadManager {
|
||||
}
|
||||
|
||||
// NEU: Benachrichtigt ComfyUI
|
||||
private void notifyComfyUI() {
|
||||
@Override
|
||||
public void notifyComfyUI() {
|
||||
String comfyUrl = configService.getComfyUIUrl();
|
||||
if (sendRefreshPing(comfyUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto-Discovery: If configured URL fails, search for ComfyUI on common ports
|
||||
System.out.println("🔍 [Model-Downloader] ComfyUI unter " + comfyUrl + " nicht erreicht. Suche automatisch...");
|
||||
String discoveredUrl = discoverComfyUrl();
|
||||
if (discoveredUrl != null) {
|
||||
System.out.println("✨ [Model-Downloader] ComfyUI automatisch gefunden unter: " + discoveredUrl);
|
||||
configService.setComfyUIUrl(discoveredUrl);
|
||||
sendRefreshPing(discoveredUrl);
|
||||
} else {
|
||||
System.err.println("❌ [Model-Downloader] ComfyUI konnte nicht automatisch gefunden werden. Bitte stelle sicher, dass es läuft.");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendRefreshPing(String url) {
|
||||
try {
|
||||
System.out.println("🚀 [Model-Downloader] Sende Refresh-Ping an ComfyUI (Port 8188)...");
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create("http://127.0.0.1:8188/kippster/model-downloaded"))
|
||||
.uri(URI.create(url + "/kippster/model-downloaded"))
|
||||
.timeout(java.time.Duration.ofSeconds(2))
|
||||
.POST(HttpRequest.BodyPublishers.noBody())
|
||||
.build();
|
||||
|
||||
// Synchron senden, damit wir sehen, was passiert
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
System.out.println("✅ [Model-Downloader] ComfyUI hat geantwortet mit Status: " + response.statusCode());
|
||||
} catch (Exception e) {
|
||||
System.err.println("❌ [Model-Downloader] Konnte ComfyUI nicht erreichen. Läuft es auf Port 8188? Fehler: " + e.getMessage());
|
||||
if (response.statusCode() == 200) {
|
||||
System.out.println("✅ [Model-Downloader] ComfyUI (" + url + ") erfolgreich benachrichtigt.");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String discoverComfyUrl() {
|
||||
// Scan typical ComfyUI ports, including common alternatives like 8000
|
||||
int[] commonPorts = {8188, 8000, 8189, 8190, 3000, 8080};
|
||||
for (int port : commonPorts) {
|
||||
if (checkPort(port)) return "http://127.0.0.1:" + port;
|
||||
}
|
||||
|
||||
// Expanded range scan
|
||||
for (int port = 8191; port <= 8199; port++) {
|
||||
if (checkPort(port)) return "http://127.0.0.1:" + port;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean checkPort(int port) {
|
||||
String url = "http://127.0.0.1:" + port;
|
||||
try {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url + "/system_stats"))
|
||||
.timeout(java.time.Duration.ofMillis(300))
|
||||
.GET()
|
||||
.build();
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
return response.statusCode() == 200 && response.body().contains("system");
|
||||
} catch (Exception ignored) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSelected(int index) {
|
||||
|
||||
Reference in New Issue
Block a user