Files
opsxdb/server/internal/aitools/connections.go
T
logan 0b68c8344d feat(mcp): P0 只读 MCP tool runtime + opsxdb-mcp stdio
- aitools 共用 runtime:list/describe/schema/query/redis(纯只读,无写确认)
- 白名单 ~/.opsxdb/mcp.json;审计 mcp-audit.jsonl;复用 danger.go
- 桌面 connections 双写 ~/.opsxdb/connections.json(ox1. 解码)
- Cursor 配置示例与任务书验收勾选更新;写操作与 Agent UI 留 P1
2026-10-15 11:14:08 +08:00

168 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package aitools
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"opsxdb/server/internal/db"
)
// SavedConnection 与桌面 store SavedConnection JSON 对齐(磁盘形态,密码可为 ox1. 混淆)。 // Logan.Li
type SavedConnection struct {
ID string `json:"id"`
Name string `json:"name"`
Driver string `json:"driver"`
Host string `json:"host"`
Port int `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Database string `json:"database"`
Service string `json:"service,omitempty"`
SSL bool `json:"ssl,omitempty"`
SSLMode string `json:"sslMode,omitempty"`
SSLCA string `json:"sslCA,omitempty"`
SSLCert string `json:"sslCert,omitempty"`
SSLKey string `json:"sslKey,omitempty"`
RedisMode string `json:"redisMode,omitempty"`
RedisNodes string `json:"redisNodes,omitempty"`
MasterName string `json:"masterName,omitempty"`
SentinelPassword string `json:"sentinelPassword,omitempty"`
SSHEnabled bool `json:"sshEnabled,omitempty"`
SSHHost string `json:"sshHost,omitempty"`
SSHPort int `json:"sshPort,omitempty"`
SSHUser string `json:"sshUser,omitempty"`
SSHAuth string `json:"sshAuth,omitempty"`
SSHPassword string `json:"sshPassword,omitempty"`
SSHPrivateKey string `json:"sshPrivateKey,omitempty"`
SSHPassphrase string `json:"sshPassphrase,omitempty"`
SavePassword *bool `json:"savePassword,omitempty"`
}
// ConnectionSummary 列表对外字段,永不含密码。
type ConnectionSummary struct {
ID string `json:"id"`
Name string `json:"name"`
Driver string `json:"driver"`
Host string `json:"host"`
Port int `json:"port"`
Database string `json:"database"`
}
func ConnectionsPath() (string, error) {
dir, err := opsxdbDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "connections.json"), nil
}
// LoadConnections 读 ~/.opsxdb/connections.json。
func LoadConnections() ([]SavedConnection, error) {
path, err := ConnectionsPath()
if err != nil {
return nil, err
}
b, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
var list []SavedConnection
if err := json.Unmarshal(b, &list); err != nil {
return nil, fmt.Errorf("connections.json: %w", err)
}
return list, nil
}
// SaveConnections 写 ~/.opsxdb/connections.json(0600);供桌面双写 API 调用。
func SaveConnections(list []SavedConnection) error {
path, err := ConnectionsPath()
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return err
}
b, err := json.MarshalIndent(list, "", " ")
if err != nil {
return err
}
return os.WriteFile(path, b, 0600)
}
func FindConnection(id string) (*SavedConnection, error) {
list, err := LoadConnections()
if err != nil {
return nil, err
}
for i := range list {
if list[i].ID == id {
c := list[i]
return &c, nil
}
}
return nil, fmt.Errorf("connection not found: %s", id)
}
// ToConnReq 映射为 db.ConnReq(解码 ox1. 密码)。
func (c SavedConnection) ToConnReq() db.ConnReq {
sslOn := c.SSL || (c.SSLMode != "" && c.SSLMode != "disable")
mode := c.SSLMode
if sslOn {
if mode == "" || mode == "disable" {
mode = "require"
}
} else {
mode = "disable"
}
return db.ConnReq{
Driver: c.Driver,
Host: c.Host,
Port: c.Port,
User: c.User,
Password: DecodeSecret(c.Password),
Database: c.Database,
Service: c.Service,
SSL: sslOn,
SSLMode: mode,
SSLCA: c.SSLCA,
SSLCert: c.SSLCert,
SSLKey: c.SSLKey,
RedisMode: orDefault(c.RedisMode, "standalone"),
RedisNodes: c.RedisNodes,
MasterName: c.MasterName,
SentinelPassword: DecodeSecret(c.SentinelPassword),
SSHEnabled: c.SSHEnabled,
SSHHost: c.SSHHost,
SSHPort: c.SSHPort,
SSHUser: c.SSHUser,
SSHAuth: c.SSHAuth,
SSHPassword: DecodeSecret(c.SSHPassword),
SSHPrivateKey: c.SSHPrivateKey,
SSHPassphrase: DecodeSecret(c.SSHPassphrase),
}
}
func (c SavedConnection) Summary() ConnectionSummary {
return ConnectionSummary{
ID: c.ID,
Name: c.Name,
Driver: c.Driver,
Host: c.Host,
Port: c.Port,
Database: c.Database,
}
}
func orDefault(s, def string) string {
if strings.TrimSpace(s) == "" {
return def
}
return s
}