From 84d6cab294e5350b3c45a949b7bc7760d6c156b4 Mon Sep 17 00:00:00 2001 From: lettimepassby <86416409@qq.com> Date: Wed, 3 Jun 2026 17:43:49 +0800 Subject: [PATCH] feat: Add MySQL Workbench support --- go-client/config.json | 23 +++- go-client/pkg/awaken/awaken_windows.go | 125 ++++++++++++++++++++ ui/assets/images/mysqlworkbench.png | Bin 0 -> 22577 bytes ui/components/SettingItems/settingItems.vue | 3 +- 4 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 ui/assets/images/mysqlworkbench.png diff --git a/go-client/config.json b/go-client/config.json index 481604037..b5a260d62 100644 --- a/go-client/config.json +++ b/go-client/config.json @@ -496,6 +496,27 @@ "is_internal": false, "is_default": false, "is_set": false + }, + { + "name": "mysqlworkbench", + "display_name": "MySQL Workbench", + "protocol": [ + "mysql" + ], + "comment": { + "zh": "MySQL Workbench 是一款专为 MySQL 设计的集成可视化工具。\n\n!!!手动下载安装,点击保存启用!!!", + "en": "MySQL Workbench is a unified visual tool for database architects, developers, and DBAs.\n\n!!!Manually download and install, click Save to activate!!!" + }, + "download_url": "https://dev.mysql.com/downloads/workbench/", + "type": "databases", + "path": "C:\\Program Files\\MySQL\\MySQL Workbench 8.0 CE\\MySQLWorkbench.exe", + "arg_format": "", + "match_first": [ + "mysql" + ], + "is_internal": false, + "is_default": false, + "is_set": false } ] }, @@ -894,4 +915,4 @@ } ] } -} +} \ No newline at end of file diff --git a/go-client/pkg/awaken/awaken_windows.go b/go-client/pkg/awaken/awaken_windows.go index a7e0fd138..a9bd5d298 100755 --- a/go-client/pkg/awaken/awaken_windows.go +++ b/go-client/pkg/awaken/awaken_windows.go @@ -1,6 +1,7 @@ package awaken import ( + "crypto/rand" "encoding/json" "fmt" "go-client/global" @@ -25,6 +26,14 @@ func EnsureDirExist(path string) { } } +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + func getNavicatURL(connectInfo map[string]string) string { re := regexp.MustCompile(`@(.+)$`) matches := re.FindStringSubmatch(connectInfo["name"]) @@ -293,6 +302,83 @@ func handleSSH(r *Rouse, cfg *config.AppConfig) *exec.Cmd { } } +// prepareWorkbenchConnection writes a minimal connection entry into MySQL Workbench's +// connections.xml so that the connection succeeds without OS mismatch warnings. +func prepareWorkbenchConnection(connName, host, port, username string) error { + dir, err := os.UserConfigDir() + if err != nil { + return fmt.Errorf("failed to get user config dir: %w", err) + } + wbDir := filepath.Join(dir, "MySQL", "Workbench") + EnsureDirExist(wbDir) + connFile := filepath.Join(wbDir, "connections.xml") + + // Generate a UUID for the connection entry + b := make([]byte, 16) + rand.Read(b) + connID := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", + b[0:4], b[4:6], b[6:8], b[8:10], b[10:16]) + + // Build the minimal connection XML entry + connEntry := fmt.Sprintf(` + + com.mysql.rdbms.mysql.driver.native + Mysql@%s:%s + 0 + + + %s + %s + %s + + %s + `, + connID, host, port, host, port, username, connName) + + var data []byte + if !fileExists(connFile) { + content := fmt.Sprintf(` + + %s + +`, connEntry) + data = []byte(content) + } else { + existing, err := ioutil.ReadFile(connFile) + if err != nil { + return fmt.Errorf("failed to read connections.xml: %w", err) + } + content := string(existing) + + // Remove existing JumpServer connection if it exists + re := regexp.MustCompile(`(?s)]*>.*?JumpServer.*?`) + content = re.ReplaceAllString(content, "") + + insertPos := strings.Index(content, "\n") + if insertPos == -1 { + insertPos = strings.Index(content, "\r\n") + } + if insertPos != -1 { + content = content[:insertPos] + connEntry + "\n " + content[insertPos:] + data = []byte(content) + } else { + content := fmt.Sprintf(` + + %s + +`, connEntry) + data = []byte(content) + } + } + + err = ioutil.WriteFile(connFile, data, 0644) + if err != nil { + return fmt.Errorf("failed to write connections.xml: %w", err) + } + + return nil +} + func handleDB(r *Rouse, cfg *config.AppConfig) *exec.Cmd { var appItem *config.AppItem appLst := cfg.Windows.Databases @@ -375,6 +461,45 @@ func handleDB(r *Rouse, cfg *config.AppConfig) *exec.Cmd { url := getNavicatURL(connectMap) connectMap["url"] = url } + if appItem.Name == "mysqlworkbench" { + connName := "JumpServer" + err := prepareWorkbenchConnection(connName, r.Host, strconv.Itoa(r.Port), r.getUserName()) + if err != nil { + global.LOG.Error("Failed to prepare MySQL Workbench connection: " + err.Error()) + return nil + } + global.LOG.Info("MySQL Workbench connection prepared: " + connName) + + autoit.LoadAuto() + + // Run Workbench with --query to directly open the connection tab + global.LOG.Info("Launching MySQL Workbench with query: " + connName) + autoit.Run(fmt.Sprintf(`"%s" --query "%s"`, appPath, connName)) + + // Wait for password prompt dialog + // The title is "Connect to MySQL Server" + pwdTitle := "[REGEXPTITLE:.*Connect to MySQL Server.*]" + active := false + for i := 0; i <= 30; i++ { + ret := autoit.WinWaitActive(pwdTitle, "", 1) + time.Sleep(300 * time.Millisecond) + if ret != 0 { + active = true + break + } + autoit.WinActivate(pwdTitle, "") + } + if active { + time.Sleep(500 * time.Millisecond) + // Send password in raw mode and press Enter + autoit.Send(r.Value, 1) + time.Sleep(100 * time.Millisecond) + autoit.Send("{ENTER}") + } else { + global.LOG.Error("MySQL Workbench password dialog not detected") + } + return exec.Command("cmd", "/C", "exit", "0") + } if len(appItem.AutoIt) == 0 { commands := getCommandFromArgs(connectMap, appItem.ArgFormat) if appItem.Name == "heidisql" && r.Protocol == "postgresql" { diff --git a/ui/assets/images/mysqlworkbench.png b/ui/assets/images/mysqlworkbench.png new file mode 100644 index 0000000000000000000000000000000000000000..8d928778eebfeb14d273b86357fb08af353c4088 GIT binary patch literal 22577 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 = { navicat17: getImageByName("navicat17"), royalts: getImageByName("royalts"), windows_rdm: getImageByName("windows_rdm"), - toad: getImageByName("toad") + toad: getImageByName("toad"), + mysqlworkbench: getImageByName("mysqlworkbench") }; const commentText = computed(() => {