Files
MyGoNavi/internal/jvm/http_provider.go
Syngnat 6f14e827ab feat(jvm): 完成资源治理与诊断增强
- 新增 JMX/Endpoint/Agent 三种 JVM 连接模式与配置归一化链路
- 支持资源浏览、变更预览、写入应用、审计记录与只读约束
- 接入 AI 结构化写入计划与诊断计划回填能力
- 新增 Agent Bridge、Arthas Tunnel、JMX Helper 诊断传输实现
- 增加诊断控制台、命令模板、输出历史与自动补全交互
- 补齐前后端契约、运行夹具与 JVM 相关回归测试
2026-04-24 16:45:34 +08:00

151 lines
3.8 KiB
Go

package jvm
import (
"context"
"fmt"
"net/http"
"net/url"
"time"
"GoNavi-Wails/internal/connection"
)
type HTTPProvider struct{}
func NewHTTPProvider() Provider { return &HTTPProvider{} }
func (p *HTTPProvider) Mode() string { return ModeEndpoint }
func (p *HTTPProvider) TestConnection(ctx context.Context, cfg connection.ConnectionConfig) error {
runtime, err := newEndpointRuntime(cfg)
if err != nil {
return err
}
resp, err := doContractProbe(ctx, runtime.contractRuntime, http.MethodHead)
if err != nil {
return err
}
if resp.StatusCode == http.StatusMethodNotAllowed || resp.StatusCode == http.StatusNotImplemented {
_ = resp.Body.Close()
resp, err = doContractProbe(ctx, runtime.contractRuntime, http.MethodGet)
if err != nil {
return err
}
}
defer resp.Body.Close()
if isReachableStatus(resp.StatusCode) {
return nil
}
return fmt.Errorf("endpoint returned unexpected status: %d", resp.StatusCode)
}
func (p *HTTPProvider) ProbeCapabilities(_ context.Context, cfg connection.ConnectionConfig) ([]Capability, error) {
if _, err := newEndpointRuntime(cfg); err != nil {
return nil, err
}
readOnly := cfg.JVM.ReadOnly != nil && *cfg.JVM.ReadOnly
return []Capability{{
Mode: ModeEndpoint,
CanBrowse: true,
CanWrite: !readOnly,
CanPreview: true,
DisplayLabel: "Endpoint",
Reason: func() string {
if readOnly {
return "当前连接只读"
}
return ""
}(),
}}, nil
}
func (p *HTTPProvider) ListResources(ctx context.Context, cfg connection.ConnectionConfig, parentPath string) ([]ResourceSummary, error) {
runtime, err := newEndpointRuntime(cfg)
if err != nil {
return nil, err
}
query := url.Values{}
query.Set("parentPath", parentPath)
var resources []ResourceSummary
if err := runtime.doJSON(ctx, http.MethodGet, "list resources", "resources", query, nil, &resources); err != nil {
return nil, err
}
return resources, nil
}
func (p *HTTPProvider) GetValue(ctx context.Context, cfg connection.ConnectionConfig, resourcePath string) (ValueSnapshot, error) {
runtime, err := newEndpointRuntime(cfg)
if err != nil {
return ValueSnapshot{}, err
}
query := url.Values{}
query.Set("resourcePath", resourcePath)
var snapshot ValueSnapshot
if err := runtime.doJSON(ctx, http.MethodGet, "get value", "value", query, nil, &snapshot); err != nil {
return ValueSnapshot{}, err
}
return snapshot, nil
}
func (p *HTTPProvider) PreviewChange(ctx context.Context, cfg connection.ConnectionConfig, req ChangeRequest) (ChangePreview, error) {
runtime, err := newEndpointRuntime(cfg)
if err != nil {
return ChangePreview{}, err
}
var preview ChangePreview
if err := runtime.doJSON(ctx, http.MethodPost, "preview change", "preview", nil, req, &preview); err != nil {
return ChangePreview{}, err
}
return preview, nil
}
func (p *HTTPProvider) ApplyChange(ctx context.Context, cfg connection.ConnectionConfig, req ChangeRequest) (ApplyResult, error) {
runtime, err := newEndpointRuntime(cfg)
if err != nil {
return ApplyResult{}, err
}
var result ApplyResult
if err := runtime.doJSON(ctx, http.MethodPost, "apply change", "apply", nil, req, &result); err != nil {
return ApplyResult{}, err
}
return result, nil
}
type endpointRuntime struct {
contractRuntime
}
func newEndpointRuntime(cfg connection.ConnectionConfig) (endpointRuntime, error) {
runtime, err := newContractRuntime(
cfg.JVM.Endpoint.BaseURL,
cfg.JVM.Endpoint.APIKey,
resolveEndpointTimeout(cfg),
"endpoint",
)
if err != nil {
return endpointRuntime{}, err
}
return endpointRuntime{
contractRuntime: runtime,
}, nil
}
func resolveEndpointTimeout(cfg connection.ConnectionConfig) time.Duration {
timeout := time.Duration(cfg.JVM.Endpoint.TimeoutSeconds) * time.Second
if timeout <= 0 {
timeout = time.Duration(cfg.Timeout) * time.Second
}
if timeout <= 0 {
timeout = 5 * time.Second
}
return timeout
}