servercore

package module
v0.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 15 Imported by: 0

README

gitee.com/idcu-go/server-core

realtime-ping 分布式模式的中心汇总模块。

设计目标:只依赖 transport(协议契约)+ 公共模块 auth(Bearer 鉴权)/ jsonstore(原子落盘)/ timefmt(时间格式化), 不依赖 monitor / notify / metrics,形成一个可独立引入的中心服务内核。realtime-ping 的 server 模式直接挂载 Handler(), 也可被其它消费者复用——拆装自由。

包名为 servercore(导入路径 gitee.com/idcu-go/server-core)。

当前版本:v0.5.2

1. 定位 + 当前版本

模块类型:领域模块(中心注册表/配置下发/状态聚合)。

2. 安装

go get gitee.com/idcu-go/server-core@v0.5.1

依赖

  • 内部(gitee.com/idcu-go/*):authjsonstorekvstoretimefmttransport
    • 用途:auth 鉴权、jsonstore 落中心注册表、kvstore 提供共享 RedisConfigStore 后端(kvstore.Store 契约)、timefmt 时间格式化、transport 定义 agent↔server 的 HTTP 契约。httputil / idgen(indirect)随之引入。
  • 外部(第三方):无

3. API 签名

构造与生命周期
func NewRegistry(heartbeatTimeout time.Duration, store ConfigStore, writeToken string) *Registry
func NewRegistryWithTokens(heartbeatTimeout time.Duration, store ConfigStore, writeToken, readToken string) *Registry
func NewNodeConfigStore(path string) *NodeConfigStore
func NewRedisConfigStore(store kvstore.Store) *RedisConfigStore
func (r *Registry) StartBackgroundPruner(interval time.Duration) func()
状态读写
func (r *Registry) ApplyHeartbeat(hb transport.Heartbeat) (isNew bool)
func (r *Registry) Prune(now int64) []string
func (r *Registry) Snapshot() []NodeState
func (r *Registry) Regions() []RegionSummary
配置下发(期望状态)
func (r *Registry) SetNodeConfig(nodeID string, targets []transport.TargetSpec)
func (r *Registry) PutNodeConfig(nodeID string, targets []transport.TargetSpec) error
func (r *Registry) DeleteNodeConfig(nodeID string) error
func (r *Registry) NodeConfig(nodeID string) (transport.NodeConfig, bool)
func (r *Registry) LoadNodeConfigs() error
func (s *NodeConfigStore) Load() (map[string][]transport.TargetSpec, error)
func (s *NodeConfigStore) Save(m map[string][]transport.TargetSpec) error
HTTP Handler
func (r *Registry) Handler() http.Handler         // 全部端点(含拓扑页)
func (r *Registry) TopologyHandler() http.Handler // 仅拓扑 HTML 视图,便于与其他路由共存

Handler() 返回可直接挂载的 http.Handlermux.Handle("/", r.Handler()) 即可):

端点 方法 说明
/api/v1/heartbeat POST agent 上报心跳(transport.Heartbeat JSON);node_id 为空返回 400;不鉴权
/api/v1/nodes GET 返回全局节点汇总快照(JSON 数组);每个目标含 level 字段(告警级别,omitempty:""/down/recover/escalated/flapping);readToken 非空时需 Authorization: Bearer <token>
/api/v1/config?node_id= GET 返回指定节点的下发配置(transport.NodeConfig);未分配配置的节点返回空目标列表(200,非 404);readToken 非空时需 Bearer token
/api/v1/config?node_id= PUT 全量替换该节点目标并落盘(写操作,需 Authorization: Bearer <token>);node_id 以 query 为准,覆盖 body
/api/v1/config?node_id= DELETE 清空该节点目标并落盘(写操作,需 Bearer token
/api/v1/regions GET 多区域聚合视图:按节点 Region 标签分组返回 RegionSummary[](节点数/在线数/目标数/离线目标数),用于多机房总览;readToken 非空时需 Bearer token
/ GET 中心拓扑 HTML 视图:渲染所有节点卡片(在线/离线着色、RTT、诊断),每个目标额外显示 Kind(探测类型)、Level 徽章(down/escalated 红、flapping 黄、recover 绿、normal 灰)、离线判定阈值徽章(中心下发的 FailThreshold 显示「阈 N」,未下发显示「默认」)与升级策略徽章(下发了 escalate_after 时显示「升级 <时长>」);启用 writeToken 时每个节点卡片提供全字段配置编辑区(原生 JS + fetch 调 /api/v1/config,可编辑 name/host/probe_type/interval/timeout/fail_threshold/channels/escalate_after/escalate_channels 并支持新增/删除目标,保存即 PUT 全量替换,保存时现场输入写 token,无前端框架依赖);未启用写鉴权时仅显示只读提示。零依赖 html/templatereadToken 非空时需 Bearer token

4. 关键类型

Registry(节点注册表)

线程安全的内存注册表,维护所有 agent 上报的节点状态;nodeConfigs(下发配置的「期望状态」)可选经 NodeConfigStore 落盘。

方法 说明
NewRegistry(heartbeatTimeout, store *NodeConfigStore, writeToken string) *Registry 构造;超时为节点标记 stale 的阈值(建议 agent 周期的 2~3 倍,<=0 时兜底 30s);store 传 nil 为纯内存,writeToken 非空时写 API 需 Bearer 鉴权;读端点不鉴权(向后兼容)
NewRegistryWithTokens(heartbeatTimeout, store, writeToken, readToken string) *Registry NewRegistry 完整版:额外支持 readToken,对 /api/v1/nodes/api/v1/regions、GET /api/v1/config、拓扑页 GET / 做 Bearer 鉴权;readToken 为空=读端点不鉴权(向后兼容),非空=需匹配
(*Registry).ApplyHeartbeat(hb) bool 处理一次上报,注册或更新节点;返回是否首次出现;同时把各目标状态点追加到历史窗口
(*Registry).Prune(now int64) []string 标记超时未上报的节点为 stale(不删除),返回本次新变 stale 的 ID
(*Registry).Snapshot() []NodeState 返回所有节点快照(深拷贝,供读取/序列化)
(*Registry).Regions() []RegionSummary Region 标签聚合全局状态;未分区(空串)排最后,其余按名升序
(*Registry).SetNodeConfig(nodeID, []TargetSpec) 设置中心下发给某节点的监控目标(内存,不落盘)
(*Registry).PutNodeConfig(nodeID, []TargetSpec) error 全量替换某节点下发目标并落盘(PUT API 入口)
(*Registry).DeleteNodeConfig(nodeID) error 清空某节点下发目标并落盘(DELETE API 入口)
(*Registry).NodeConfig(nodeID) (NodeConfig, bool) 读取某节点的下发配置
(*Registry).LoadNodeConfigs() error 启动时从 store 加载全量配置到内存
(*Registry).StartBackgroundPruner(interval) func() 启动后台清理 goroutine(interval <= 0 时兜底 15s),返回 stop 函数
ConfigStore 接口与两种实现(配置持久化)

配置存储抽象为 ConfigStore 接口(Load / Save),默认文件型实现 NodeConfigStore(JSON + atomic rename 落盘,底层收敛到公共模块 jsonstore),另有共享 Redis 实现 RedisConfigStore(底层收敛到公共模块 kvstore + kvstore/redis)。

方法 说明
NewNodeConfigStore(path string) *NodeConfigStore 构造文件型实现;path 为空=纯内存(不落盘)
(*NodeConfigStore).Load() (map[string][]TargetSpec, error) 读全量配置(文件不存在返回空 map,非错误)
(*NodeConfigStore).Save(m) error 原子写全量配置(临时文件 + rename)
NewRedisConfigStore(store kvstore.Store) *RedisConfigStore 构造共享实现;storekvstore.Store 后端(如 kvstore/redis.NewStore 返回的 Redis 后端),单机也可传 kvstore.NewMemory()
(*RedisConfigStore).Load() (map[string][]TargetSpec, error) 读全量配置(键不存在返回空 map,非错误)
(*RedisConfigStore).Save(m) error 以单键 JSON 全量覆盖写(写语义与文件型一致,均为全量替换)
NodeState(节点状态)
type NodeState struct {
    Info     transport.NodeInfo        // 节点身份(含 Region 区域标签,omitempty)
    Targets  []transport.TargetStatus  // 最近一次上报的目标快照
    LastSeen int64                     // 最近心跳 Unix 秒
    Stale    bool                      // 是否超过超时未上报
    History  map[string][]HistoryPoint // 各目标最近状态窗口(key=target name,上限 historyWindow=120 点,环形覆盖)
}

type HistoryPoint struct {
    Up bool  // 该次采样是否可达
    Ts int64 // 采样 Unix 秒
}

type RegionSummary struct {
    Region      string // 区域标签;空串=未分区
    Nodes       int    // 区域节点总数
    OnlineNodes int    // 在线(非 stale)节点数
    Targets     int    // 区域目标总数
    DownTargets int    // 区域不可达目标数
}

5. 最小用法示例

import (
    "net/http"
    "time"

    servercore "gitee.com/idcu-go/server-core"
    "gitee.com/idcu-go/transport"
)

store := servercore.NewNodeConfigStore("/etc/realtime-ping/node-config.json")
// 读写分离鉴权:写 API 用 writeToken,读端点(拓扑页/节点快照/配置拉取)用 readToken。
// 只暴露读、不暴露写时,可只设 readToken;两者都空=全不鉴权(仅内网/测试)。
reg := servercore.NewRegistryWithTokens(30*time.Second, store, "write-secret", "read-secret")
if err := reg.LoadNodeConfigs(); err != nil { /* 处理 */ }
stop := reg.StartBackgroundPruner(15 * time.Second)
defer stop()
// 运行时动态编辑(需写 Bearer token):
//   PUT /api/v1/config?node_id=edge-bj  → 全量替换该节点目标,落盘持久化
//   DELETE /api/v1/config?node_id=edge-bj → 清空
// 读取(需读 Bearer token,若 readToken 非空):
//   GET /api/v1/nodes   GET /api/v1/regions   GET /api/v1/config?node_id=edge-bj   GET /  (拓扑页)
http.ListenAndServe(":8090", reg.Handler())

多实例共享 Redis 后端(多台 server 共读一份中心下发配置,替代单机 JSON 文件):

import (
    "context"

    servercore "gitee.com/idcu-go/server-core"
    kvredis "gitee.com/idcu-go/kvstore/redis"
)

ks, err := kvredis.NewStore(context.Background(), kvredis.Config{Backend: "redis", RedisAddr: "127.0.0.1:6379"})
if err != nil { /* 处理连接失败 */ }
defer ks.Close()
store := servercore.NewRedisConfigStore(ks)
reg := servercore.NewRegistryWithTokens(30*time.Second, store, "write-secret", "read-secret")
if err := reg.LoadNodeConfigs(); err != nil { /* 处理 */ }

纯内存 + 静态下发(可直接跑,取自测试用例):

reg := servercore.NewRegistry(30*time.Second, nil, "")
reg.SetNodeConfig("n1", []transport.TargetSpec{
    {Name: "api", Host: "10.0.0.1", ProbeType: "ping", FailThreshold: 3},
    {Name: "web", Host: "10.0.0.2", ProbeType: "http"},
})
reg.ApplyHeartbeat(transport.Heartbeat{
    Node:    transport.NodeInfo{NodeID: "n1", Name: "edge-1", Version: "v0.5.1"},
    Targets: []transport.TargetStatus{{Name: "api", Kind: "ping", Up: true, LastRTTMs: 12.3}},
    SentAt:  time.Now().Unix(),
})
snap := reg.Snapshot() // len(snap) == 1,snap[0].Info.NodeID == "n1"

6. 工作机制与边界语义

  • 读写分离鉴权:写操作(PUT/DELETE /api/v1/config)由 writeToken 保护,读端点(/api/v1/nodes/api/v1/regions、GET /api/v1/config、拓扑页 GET /)由 readToken 保护,两者独立设置,均委托公共模块 auth.Check 校验 Authorization: Bearer <token>。token 为空表示该侧不鉴权(向后兼容,面向纯内网/测试);非空则必须精确匹配,否则返回 401。拓扑页 401 时附带 WWW-Authenticate: BearerPOST /api/v1/heartbeat 始终不鉴权(agent 上报通道)。
  • 期望状态与存活状态解耦nodes 是 agent 上报的存活状态,nodeConfigs 是中心下发的期望状态,两者分开维护但共用同一把 sync.RWMutex,避免配置与存活状态出现不一致窗口。
  • 心跳超时清理Prune(now)now - LastSeen > heartbeatTimeout 的节点标记 stale 而非删除(灰显),便于前端区分「已离线」与「从未上线」;StartBackgroundPruner 按 interval 周期调用,返回的 stop 函数用于优雅退出。
  • 落盘语义PutNodeConfig / DeleteNodeConfig 在持锁前提下改内存后立即落盘(JSON + atomic rename,先写临时文件再 rename,避免半截写损坏,且不残留 .tmp);store 为 nil(或 path 为空)时退化为纯内存,落盘为 no-op。SetNodeConfig 只改内存、不落盘,用于静态初始化。刻意不引入 SQLite,以维持「可独立引入、零外部依赖」定位;多实例共享已由 RedisConfigStorekvstore.Store 契约)承接,替换构造处即可,对外 API 不变。
  • 写语义为全量替换PUT /api/v1/config 是全量覆盖而非 merge,语义简单且幂等;写入时对切片做深拷贝,避免调用方后续修改影响内部状态。node_id 以 query 参数为准(覆盖 body,避免歧义)。
  • 历史窗口有界:每个目标最多保留 historyWindow = 120 个采样点,超出后环形覆盖,防止内存无限增长。
  • 区域聚合排序稳定Regions() 中未分区(Region 为空串)固定排最后,其余按区域名升序,保证前端展示顺序稳定。
  • 零前端依赖:拓扑视图用标准库 html/template 内联渲染,配置编辑用原生 JS + fetch;写 token 不预置在前端,保存时由运维现场输入,避免泄露。

7. 适用场景

  • realtime-ping 分布式模式的中心汇总端:直接挂载 Handler(),接收各 agent 心跳、汇总全局节点与目标状态。
  • 可独立复用的中心服务内核:不依赖 monitor / notify / metrics,其它需要「节点注册 + 状态汇总 + 配置下发」的系统可直接引入。
  • 多机房 / 多区域总览:借 Regions()/api/v1/regionsRegion 标签聚合节点数、在线数、目标数与离线目标数。
  • 中心统一下发监控目标:通过 PUT/DELETE /api/v1/config 在运行时集中管理各节点应监控的目标,落盘持久化、重启不丢,agent 下次拉取即生效。
  • 轻量运维巡检面板:内置拓扑 HTML 页(含全字段配置编辑区),无需部署任何前端工程即可人工巡检与改配。

8. 变更记录

见仓库 tag v0.5.1。

Documentation

Overview

Package servercore 提供 realtime-ping 分布式模式的「中心汇总」能力。

设计目标:只依赖 transport(协议契约),不依赖 monitor / notify / metrics, 形成一个可独立引入的中心服务内核。realtime-ping 的 server 模式直接挂载 Handler, 也可被其他消费者复用——拆装自由。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConfigStore

type ConfigStore interface {
	// Load 读取全量节点配置映射;首次无数据时应返回空 map(而非错误)。
	Load() (map[string][]transport.TargetSpec, error)
	// Save 全量持久化配置映射。
	Save(m map[string][]transport.TargetSpec) error
}

ConfigStore 是中心下发配置「期望状态」的持久化抽象。

默认实现为文件型 NodeConfigStore(JSON atomic rename,零外部依赖)。当中心需要 多实例共享存储时,可提供基于 Redis / DB 的实现并替换到 Registry,对外 API 不变, 无需改动 topology / REST 层。类型安全(map[string][]transport.TargetSpec)由实现保证。

type HistoryPoint

type HistoryPoint struct {
	Up bool  `json:"up"` // 是否可达
	Ts int64 `json:"ts"` // 采样 Unix 时间戳(秒)
}

HistoryPoint 是某目标的一次状态采样点(用于长周期趋势展示)。

type NodeConfigStore

type NodeConfigStore struct {
	// contains filtered or unexported fields
}

NodeConfigStore 是 ConfigStore 的默认文件型实现。

设计取舍:server-core 刻意保持零外部依赖(仅依赖 transport),因此这里用 JSON 文件做持久化,而不是 SQLite。配置是低频写、启动读、内存热路径,JSON 文件 + atomic rename 足够,且运维可直接 cat/vi 编辑,符合「最小可运维」目标。

底层落盘已收敛到公共模块 jsonstore(atomic rename),本类型仅做类型安全的封装, 把 jsonstore 的 any 接口收敛为 server-core 专用的 map[string][]transport.TargetSpec。

并发安全:所有读写都走 Registry 的 mu(写 API 与心跳共用同一把锁,避免配置与 存活状态出现不一致窗口)。

func NewNodeConfigStore

func NewNodeConfigStore(path string) *NodeConfigStore

NewNodeConfigStore 构造文件型配置存储。path 为空表示纯内存(不落盘)。

func (*NodeConfigStore) Load

func (s *NodeConfigStore) Load() (map[string][]transport.TargetSpec, error)

Load 从磁盘读取全量节点配置映射。文件不存在时返回空 map(而非错误), 便于「首次启动无配置」场景。

func (*NodeConfigStore) Save

func (s *NodeConfigStore) Save(m map[string][]transport.TargetSpec) error

Save 原子写全量配置到磁盘(先写临时文件再 rename,避免半截写损坏)。

type NodeState

type NodeState struct {
	Info     transport.NodeInfo        `json:"info"`
	Targets  []transport.TargetStatus  `json:"targets"`
	LastSeen int64                     `json:"last_seen"`         // 最近一次心跳 Unix 时间戳(秒)
	Stale    bool                      `json:"stale"`             // 超过心跳超时未上报
	History  map[string][]HistoryPoint `json:"history,omitempty"` // 各目标最近状态窗口(key=target name)
}

NodeState 是 server 侧维护的单个节点运行状态。

type RedisConfigStore

type RedisConfigStore struct {
	// contains filtered or unexported fields
}

RedisConfigStore 是 ConfigStore 的共享存储实现,底层复用 kvstore.Store 契约 (内存 / Redis 后端可插拔)。它让中心下发配置「期望状态」脱离单机文件, 多个 server 实例共享同一份配置,实现多实例一致性。

设计取舍:本类型只依赖零外部依赖的 kvstore 核心接口(Store),真正的分布式 后端(kvstore/redis)由调用方在构造处注入(如 kvredis.NewStore + Backend:"redis"), 因此 server-core 自身依旧不引入任何第三方依赖。键值均为 JSON 编码的 map[string][]transport.TargetSpec,与 NodeConfigStore 落盘格式互通。

func NewRedisConfigStore

func NewRedisConfigStore(store kvstore.Store) *RedisConfigStore

NewRedisConfigStore 构造基于 kvstore.Store 的共享配置存储。 store 由调用方注入:单机可传 kvstore.NewMemory(),跨节点共享传 kvstore/redis 的 Redis 后端。store 为 nil 时退化为纯内存空实现(Load 返回空 map)。

func (*RedisConfigStore) Load

func (s *RedisConfigStore) Load() (map[string][]transport.TargetSpec, error)

Load 读取共享存储中的全量节点配置映射;无数据时返回空 map(而非错误)。

func (*RedisConfigStore) Save

Save 全量写入配置映射到共享存储。

type RegionSummary

type RegionSummary struct {
	Region      string `json:"region"`       // 区域标签;空串表示「未分区」
	Nodes       int    `json:"nodes"`        // 该区域节点总数
	OnlineNodes int    `json:"online_nodes"` // 在线(非 stale)节点数
	Targets     int    `json:"targets"`      // 该区域目标总数
	DownTargets int    `json:"down_targets"` // 该区域不可达目标数
}

RegionSummary 是多区域聚合视图的单项:按节点 Region 标签分组统计。

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry 是线程安全的节点注册表。 nodeConfigs(下发配置的「期望状态」)可选地经 ConfigStore 持久化;默认实现为 文件型 NodeConfigStore(JSON),需要多实例共享时替换为 Redis/DB 实现即可。

func NewRegistry

func NewRegistry(heartbeatTimeout time.Duration, store ConfigStore, writeToken string) *Registry

NewRegistry 构造注册表。heartbeatTimeout 建议与 agent 心跳周期的 2~3 倍一致。 store 传 nil 为纯内存模式;writeToken 非空时写 API 需要 Bearer 鉴权。 readToken 留空表示读端点不鉴权(向后兼容旧行为)。

func NewRegistryWithTokens

func NewRegistryWithTokens(heartbeatTimeout time.Duration, store ConfigStore, writeToken, readToken string) *Registry

NewRegistryWithTokens 是 NewRegistry 的完整版:额外支持 readToken, 对读端点(拓扑页 / 节点快照 / 配置拉取)做 Bearer 鉴权,便于将 server 安全暴露到内网/有限外网。 readToken 为空表示读端点不鉴权(向后兼容)。

func (*Registry) ApplyHeartbeat

func (r *Registry) ApplyHeartbeat(hb transport.Heartbeat) (isNew bool)

ApplyHeartbeat 处理一次 agent 上报,注册或更新节点。 返回该节点此前是否已存在(用于日志/计数)。 同时把本次每个目标的状态点追加到历史窗口(环形覆盖,上限 historyWindow)。

func (*Registry) DeleteNodeConfig

func (r *Registry) DeleteNodeConfig(nodeID string) error

DeleteNodeConfig 清空某节点的下发目标(保留节点存活状态),并落盘。 这是 DELETE /api/v1/config 的处理入口。

func (*Registry) Handler

func (r *Registry) Handler() http.Handler

Handler 返回可直接挂载到 http.Server 的路由 Handler。 暴露端点:

  • POST /api/v1/heartbeat : agent 上报心跳(transport.Heartbeat JSON)
  • GET /api/v1/nodes : 返回全局节点汇总快照(JSON;读鉴权)
  • GET /api/v1/regions : 多区域聚合视图(JSON;读鉴权)
  • GET / : 中心拓扑 HTML 视图(TopologyHandler 内部鉴权)
  • GET/PUT/DELETE /api/v1/config?node_id= : 配置下发;PUT/DELETE 需写鉴权
  • GET /api/v1/status : 公开状态 JSON(有意匿名)
  • GET /status : 公开状态 HTML(有意匿名)

func (*Registry) LoadNodeConfigs

func (r *Registry) LoadNodeConfigs() error

LoadNodeConfigs 在启动时把磁盘配置全量灌入内存(不含落盘,启动阶段本就来自磁盘)。

func (*Registry) NodeConfig

func (r *Registry) NodeConfig(nodeID string) (transport.NodeConfig, bool)

NodeConfig 返回指定节点的下发配置(GET /api/v1/config 使用)。

func (*Registry) Prune

func (r *Registry) Prune(now int64) []string

Prune 清理超过 heartbeatTimeout 未上报的节点,将其标记为 stale(不删除, 便于前端区分「已离线」与「从未上线」)。返回的列表为本次新变 stale 的节点 ID。

func (*Registry) PublicStatusHandler

func (r *Registry) PublicStatusHandler() http.Handler

PublicStatusHandler 返回 GET /status 的公开 HTML 状态页(匿名公开,只读)。

func (*Registry) PutNodeConfig

func (r *Registry) PutNodeConfig(nodeID string, targets []transport.TargetSpec) error

SetNodeConfig 在 Registry 上覆盖某节点的下发目标,并落盘(若配置了 store)。 这是 PUT /api/v1/config 的处理入口:全量替换(而非 merge),语义简单、幂等。

func (*Registry) Regions

func (r *Registry) Regions() []RegionSummary

Regions 按节点 Region 标签聚合全局状态,返回各区域汇总。 未带 Region 标签的节点归入空串区域("未分区")。

func (*Registry) SetNodeConfig

func (r *Registry) SetNodeConfig(nodeID string, targets []transport.TargetSpec)

nodeConfigs 是中心下发给各节点的「应监控目标」配置。 由运维通过 SetNodeConfig 注入(静态初始化)或 PUT /api/v1/config 写 API 注入, agent 拉取后用于构建本地 monitor。与 Registry.nodes 解耦:nodes 是存活状态, nodeConfigs 是期望状态。

func (*Registry) Snapshot

func (r *Registry) Snapshot() []NodeState

Snapshot 返回当前所有节点的只读快照(深拷贝,避免外部修改内部状态)。

func (*Registry) StartBackgroundPruner

func (r *Registry) StartBackgroundPruner(interval time.Duration) func()

StartBackgroundPruner 启动一个后台 goroutine,每隔 interval 调用 Prune。 返回的 stop 函数用于优雅退出。now 通过 time.Now().Unix 取得;间隔由 interval 指定。

func (*Registry) Status

func (r *Registry) Status() statusSummary

Status 返回公开状态页的只读快照。幂等、不加锁地聚合现有状态。

func (*Registry) StatusJSONHandler

func (r *Registry) StatusJSONHandler() http.Handler

StatusJSONHandler 返回 GET /api/v1/status 的 JSON 视图(匿名公开,只读)。

func (*Registry) TopologyHandler

func (r *Registry) TopologyHandler() http.Handler

TopologyHandler 返回中心拓扑 HTML 视图的 http.Handler(GET /)。 它复用 Registry 的 Snapshot,按「节点 → 目标」两层渲染实时状态。

鉴权(readToken / WWW-Authenticate 头)由调用方在上层中间件中处理(例如 Registry.Handler 里的 mwTopoHTML),本 handler 不判 Authorization:鉴权与内容职责分层,后续接入别的访问控制 时可直接替换中间件、无需改动视图逻辑。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL