feat: 补齐模块接口契约与管理 API 文档
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// Package port 定义 broker 与 app 之间的契约。
|
||||
//
|
||||
// broker(连接 N)实现 Downlink / ConnControl;app 各模块通过这些接口下行发布或踢线。
|
||||
// broker 在连接生命周期与上行帧到达时调用 UplinkHandler。
|
||||
// 本包不依赖 mochi,也不包含业务状态机。
|
||||
package port
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// ConnID 是连接代号(同一端编号新旧连接 ClientID 相同,用独立代号区分)。
|
||||
type ConnID string
|
||||
|
||||
// Transport 区分接入方式。
|
||||
type Transport string
|
||||
|
||||
const (
|
||||
TransportTCP Transport = "tcp"
|
||||
TransportWS Transport = "ws"
|
||||
)
|
||||
|
||||
// ConnInfo 描述一条已建立的 MQTT 连接(登录校验通过之后)。
|
||||
type ConnInfo struct {
|
||||
ConnID ConnID
|
||||
EndpointID string
|
||||
Transport Transport
|
||||
RemoteIP string
|
||||
// SessionToken 非空表示本次用密码登录后新签发的令牌(握手响应里交给端)。
|
||||
SessionToken string
|
||||
// MaxPacketSize 来自 CONNECT;0 表示未声明。
|
||||
MaxPacketSize uint32
|
||||
}
|
||||
|
||||
// HandshakeInfo 是握手完成时的补充信息。
|
||||
type HandshakeInfo struct {
|
||||
ConnInfo
|
||||
MaxReceiveBytes int // 0 表示不限(仍受 MaxPacketSize 约束)
|
||||
Client string
|
||||
}
|
||||
|
||||
// DisconnectReason 说明断开原因,便于 app 区分当前连接与被顶号的旧连接。
|
||||
type DisconnectReason string
|
||||
|
||||
const (
|
||||
DisconnectNormal DisconnectReason = "normal"
|
||||
DisconnectTakenOver DisconnectReason = "taken_over"
|
||||
DisconnectKicked DisconnectReason = "kicked"
|
||||
DisconnectFatal DisconnectReason = "fatal"
|
||||
DisconnectIdle DisconnectReason = "idle"
|
||||
)
|
||||
|
||||
// UplinkHandler 由 app 实现,broker 在钩子里调用。
|
||||
type UplinkHandler interface {
|
||||
// OnSessionEstablished 在 MQTT 会话建立、登录已通过后调用(握手前)。
|
||||
OnSessionEstablished(ctx context.Context, conn ConnInfo) error
|
||||
// OnHandshakeComplete 在 hello 成功处理后调用;此后该连接算在线并可推送。
|
||||
OnHandshakeComplete(ctx context.Context, hs HandshakeInfo) error
|
||||
// OnDisconnect 在连接断开时调用;是否为当前连接由 app 按 ConnID 判断。
|
||||
OnDisconnect(ctx context.Context, conn ConnInfo, reason DisconnectReason)
|
||||
// HandleUplink 处理上行应用帧原始 JSON(已从 MQTT 发布拷贝)。
|
||||
HandleUplink(ctx context.Context, conn ConnInfo, payload []byte) error
|
||||
}
|
||||
|
||||
// PublishOpts 控制下行发布。
|
||||
type PublishOpts struct {
|
||||
QoS byte // 0 或 1;msg/receipt/revoked/resp/fatal 用 1,presence/group_event 用 0
|
||||
}
|
||||
|
||||
// Downlink 由 broker 实现,供 app 向下行主题发布。
|
||||
type Downlink interface {
|
||||
// PublishDown 向 nix/c/{endpointID}/down 发布一帧。
|
||||
// connID 非空时仅在该连接仍是当前连接时发布;空表示发给该端当前连接。
|
||||
PublishDown(ctx context.Context, endpointID string, connID ConnID, payload []byte, opts PublishOpts) error
|
||||
}
|
||||
|
||||
// ConnControl 由 broker 实现,供 app/admin 踢线或发 fatal 后断开。
|
||||
type ConnControl interface {
|
||||
// Disconnect 断开指定连接;connID 为空则断开该端当前连接。
|
||||
Disconnect(ctx context.Context, endpointID string, connID ConnID, reason DisconnectReason) error
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package port
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStubDownlinkPublish(t *testing.T) {
|
||||
d := &StubDownlink{}
|
||||
if err := d.PublishDown(context.Background(), "a", "c1", []byte(`{}`), PublishOpts{QoS: 1}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.Published != 1 {
|
||||
t.Fatalf("published=%d", d.Published)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStubUplinkHandlerCompile(t *testing.T) {
|
||||
var h UplinkHandler = StubUplinkHandler{}
|
||||
if err := h.OnSessionEstablished(context.Background(), ConnInfo{EndpointID: "a"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package port
|
||||
|
||||
import "context"
|
||||
|
||||
// StubDownlink 吞掉所有下行发布。
|
||||
type StubDownlink struct {
|
||||
Published int
|
||||
}
|
||||
|
||||
func (s *StubDownlink) PublishDown(_ context.Context, _ string, _ ConnID, _ []byte, _ PublishOpts) error {
|
||||
s.Published++
|
||||
return nil
|
||||
}
|
||||
|
||||
// StubConnControl 记录断开请求。
|
||||
type StubConnControl struct {
|
||||
Calls []string
|
||||
}
|
||||
|
||||
func (s *StubConnControl) Disconnect(_ context.Context, endpointID string, _ ConnID, _ DisconnectReason) error {
|
||||
s.Calls = append(s.Calls, endpointID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StubUplinkHandler 空实现,供 broker 接线测试。
|
||||
type StubUplinkHandler struct{}
|
||||
|
||||
func (StubUplinkHandler) OnSessionEstablished(context.Context, ConnInfo) error { return nil }
|
||||
|
||||
func (StubUplinkHandler) OnHandshakeComplete(context.Context, HandshakeInfo) error { return nil }
|
||||
|
||||
func (StubUplinkHandler) OnDisconnect(context.Context, ConnInfo, DisconnectReason) {}
|
||||
|
||||
func (StubUplinkHandler) HandleUplink(context.Context, ConnInfo, []byte) error { return nil }
|
||||
|
||||
var (
|
||||
_ Downlink = (*StubDownlink)(nil)
|
||||
_ ConnControl = (*StubConnControl)(nil)
|
||||
_ UplinkHandler = StubUplinkHandler{}
|
||||
)
|
||||
Reference in New Issue
Block a user