refactor(cyrene): 拆 wire.go 926 行 → 5 文件(纯搬移,零行为变化)
执行方案阶段 0 · G0-A:组合根 926 行是全仓第一大超限文件,且被 10+ 条裁决争用 (1.4/12.4.1、03.4.3、06.4.2、07.4.4、10.4.5、12.4.2、13.4.3、14.4.1、14.4.3、16.4.2) ⇒ 不先拆,后续全部被迫串行且必然破 500 行红线。 - wire.go(181):入口与共享 —— const 块、app struct、newApp - wire_runtime.go(362):loop/agent/model/memory/capacity/trace(buildPersonas、wireMemory、 wireRuntime、buildCapacity、onCapacity、onToolAudit、defaultPersonaID、defaultInstructions…) - wire_services.go(158):exec/task/iot/session/history/automations/backthink (wireAuxiliary、pushOutletConfig、close、resolveDataDir、resolveSQLitePath) - wire_channels.go(172):渠道/桥(ownerRegistrar、wireChannels、runtimeChannels、reviewFor…) - wire_frontend.go(117):gateway/webui/观测扇出(capacityEmitter、wireFrontend) 纯搬移机械证明:去 package/import/空行后两侧 **811=811 行、排序后 diff 为空、md5 相同**; 顶层声明集合 30 条守恒;唯一新增 = 各文件的 package 行与 import 块(原 import 块按声明归属 重分配给新文件)。未重命名/重排/改注释。 验证:go build/vet 绿;go test ./cmd/... 绿;linux/amd64 + darwin/arm64 交叉编译绿; 五文件 181/362/158/172/117 行均 ≤500;gofmt -l cmd/cyrene/ 无输出。 注:全量 go test 当前有 1 处红 —— internal/contract/enums 的 TestModeTableMatchesFrontendModes 读 frontend/web/src/lib/types.ts 找 MODES,而该文件 正被并行的前端拆分任务搬走;与本提交无关,随后修正该测试的读取路径。
This commit is contained in:
1 parent
deb0a3cb97
commit
e9afca9b29
5 files changed
+809
-745
No files matched your search
@@ -0,0 +1,117 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/auth"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/logger"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/knowledge"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/services/gateway"
|
||||
)
|
||||
|
||||
// capacityEmitter is the gateway-facing sink for capacity_awaken broadcasts.
|
||||
// *gateway.Server implements it; tests substitute a fake to capture the args.
|
||||
type capacityEmitter interface {
|
||||
BroadcastCapacityAwaken(sessionID, fromState, toState, tool string)
|
||||
}
|
||||
|
||||
// wireFrontend builds the gateway with the embedded/external SPA filesystem and
|
||||
// the JWT/RBAC authenticator. Session/Persona/Memories are wired to the concrete
|
||||
// managers so the admin/user list endpoints return real data.
|
||||
func (a *app) wireFrontend() error {
|
||||
jwt := auth.New(a.cfg.Auth)
|
||||
apiKeys := auth.NewAPIKey(a.cfg.Auth)
|
||||
ragStore := knowledge.New(knowledge.Deps{
|
||||
Projects: a.projStore,
|
||||
Retriever: a.retriever,
|
||||
DefaultPersona: a.defaultPersonaID(),
|
||||
VectorOn: a.vindex != nil,
|
||||
Log: a.log,
|
||||
})
|
||||
auditStore, aerr := gateway.NewSQLiteAuditStore(context.Background(), a.db, a.log)
|
||||
if aerr != nil {
|
||||
a.log.Warn("audit store unavailable, falling back to in-memory", "error", aerr)
|
||||
auditStore = nil
|
||||
}
|
||||
// Opaque refresh tokens (B2) share the primary SQLite handle. A failure here
|
||||
// degrades gracefully: login simply omits refreshToken and /auth/refresh
|
||||
// reports not-configured, rather than failing the whole boot. The store is
|
||||
// held as the interface so a constructor failure leaves it nil (a typed nil
|
||||
// pointer in the interface would be non-nil and panic on first call).
|
||||
var refreshStore gateway.RefreshGrantStore
|
||||
if store, rerr := auth.NewRefreshStore(context.Background(), a.db, a.log); rerr != nil {
|
||||
a.log.Warn("refresh token store unavailable", "error", rerr)
|
||||
} else {
|
||||
refreshStore = store
|
||||
}
|
||||
// a.history is built in wireAuxiliary so both the channel bridge (wireChannels)
|
||||
// and the gateway share the same persistent store. History was a no-op dependency
|
||||
// before the IM path, so nothing downstream depends on its creation order change.
|
||||
gw, err := gateway.New(a.cfg, gateway.Deps{
|
||||
Log: logger.WithSource(a.log, "gateway"),
|
||||
Auth: jwt,
|
||||
Bus: a.bus,
|
||||
Registry: a.caps,
|
||||
Loop: a.loop,
|
||||
Session: a.sessions,
|
||||
Personas: a.personas,
|
||||
Memories: a.memStore,
|
||||
History: a.history,
|
||||
IoT: a.iot,
|
||||
Scheduler: a.scheduler,
|
||||
Tasks: a.tasks,
|
||||
Automations: a.automation,
|
||||
Users: apiKeys,
|
||||
Refresh: refreshStore,
|
||||
Backthink: a.backthink,
|
||||
RAG: ragStore,
|
||||
LLM: a.llm,
|
||||
Channels: a.channels,
|
||||
Plugins: a.plugins,
|
||||
OwnerRegistrar: &ownerRegistrar{path: defaultOwnerPath, owner: a.owner, log: a.log},
|
||||
AuditStore: auditStore,
|
||||
Streaming: true,
|
||||
Frontend: resolveFrontendFS(a.log),
|
||||
Webhooks: a.channelBridge.WebhookHandlers(),
|
||||
DatabasePath: a.dbPath,
|
||||
DataDir: resolveDataDir(a.cfg),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("gateway: %w", err)
|
||||
}
|
||||
gw.SetVoice(a.voice)
|
||||
a.gw = gw // assign BEFORE wiring hooks below, which capture a.gw / gw (nil-receiver panic otherwise)
|
||||
// Observability trace sink (design/19 §2): now that the gateway exists, its
|
||||
// ring buffer must be fed by the loop's spans, or the admin trace/metrics
|
||||
// endpoints stay empty.
|
||||
wireGatewayTraceSink(a, gw)
|
||||
if a.channelBridge != nil {
|
||||
// Route the channel bridge's owner-private persisted messages into the same
|
||||
// `message_persisted` broadcast the orchestrator uses, so the Web client mirrors
|
||||
// IM messages with one, uniform frame (design/16 §4.4).
|
||||
a.channelBridge.SetOnPersisted(a.gw.BroadcastPersisted)
|
||||
// design/16 §4.6 §6: a message dropped by the platform's allow/deny
|
||||
// black-or-white lists is recorded in the gateway audit trail so the
|
||||
// rejection is "audit 可查" even though it never reaches the loop.
|
||||
a.channelBridge.SetOnRejected(func(msg adapter.UnifiedMessage, reason string) {
|
||||
a.gw.AuditEvent("bridge:"+msg.Platform, "channel.reject", reason)
|
||||
})
|
||||
}
|
||||
a.capacitySink = gw
|
||||
a.moodSink = gw
|
||||
|
||||
// Wire the backthink proactive sinks now that the gateway hub (active-client
|
||||
// route) and the channel bridge (IM fallback) both exist. They were absent when
|
||||
// backthink.New ran (the hub needs the loop and the bridge needs the loop and the
|
||||
// owner profile, all assembled later), so without this the pusher would resolve
|
||||
// RouteNone. Each setter rebuilds the pusher under the service's lifecycle lock.
|
||||
if a.backthink != nil {
|
||||
a.backthink.SetActiveSink(gw)
|
||||
if a.channelBridge != nil {
|
||||
a.backthink.SetIMSink(a.channelBridge)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user