| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- package main
-
- import (
- "context"
- "log"
-
- "git.x2erp.com/qdy/go-base/config"
- "git.x2erp.com/qdy/go-base/container"
- "git.x2erp.com/qdy/go-base/graceful"
- "git.x2erp.com/qdy/go-base/logger"
- "git.x2erp.com/qdy/go-base/sdk/configure"
- "git.x2erp.com/qdy/go-base/webx"
- "git.x2erp.com/qdy/go-base/webx/health"
- "git.x2erp.com/qdy/go-base/webx/router"
- "git.x2erp.com/qdy/go-db/factory/mongodb"
-
- "git.x2erp.com/qdy/go-svc-code/internal/opencode"
- "git.x2erp.com/qdy/go-svc-code/internal/routes"
- "git.x2erp.com/qdy/go-svc-code/internal/service/event"
- "git.x2erp.com/qdy/go-svc-code/internal/service/menu"
- )
-
- var (
- appName = "svc-code"
- appVersion = "1"
- )
-
- // 全局变量存储 opencode 进程信息
- var (
- //opencodeProcess *opencode.Process
- opencodePort int
- //opencodeMutex sync.Mutex
- )
-
- func main() {
- // 0. 初始化启动日志
- logBootFactory := logger.InitBootLog()
-
- // 1. 获取配置文件
- cfg := config.GetConfig()
- cfg.SetAppName(appName)
- cfg.SetAppVersion(appVersion)
-
- // 2. 创建关闭容器
- ctr := container.NewContainer(cfg)
-
- // 注册日志,实现自动关闭
- container.Reg(ctr, logBootFactory)
-
- // 3. 启用运行日志(需要在启动 opencode 服务之前)
- container.Create(ctr, logger.InitRuntimeLogger)
-
- // 创建mongodb
- mongoDBFactory := container.Create(ctr, mongodb.CreateFactory)
- mongoDBFactory.TestConnection()
-
- // 创建会话-菜单映射服务
- mappingService := menu.NewMappingService(mongoDBFactory)
- // 确保索引存在
- ctx := context.Background()
- if err := mappingService.EnsureIndexes(ctx); err != nil {
- log.Printf("警告:创建会话-菜单映射索引失败: %v", err)
- } else {
- log.Printf("会话-菜单映射索引确保成功")
- }
-
- // 4. 创建 configure 客户端
- configClient, err := configure.NewClient()
- if err != nil {
- log.Fatalf("创建 configure 客户端失败: %v", err)
- }
-
- // 5. 创建 opencode 客户端(使用 DirectClient,连接外部 opencode 服务)
- opencodePort = opencode.DefaultOpenCodePort
- client, err := opencode.NewDirectClient(opencodePort)
- if err != nil {
- log.Fatalf("创建 opencode 客户端失败: %v", err)
- }
- log.Printf("opencode 客户端已创建,连接端口: %d", opencodePort)
-
- // 启动事件分发器(用于多用户流式对话隔离)
- dispatcher := event.GetEventDispatcher(client.GetBaseURL(), client.GetPort())
- if err := dispatcher.Start(context.Background()); err != nil {
- log.Printf("警告:事件分发器启动失败(流式功能可能受影响): %v", err)
- } else {
- log.Printf("事件分发器已启动")
- defer dispatcher.Stop()
- }
-
- // 注册诊断钩子(用于调试和日志输出)
- dispatcher.RegisterHook(&event.DiagnosticHook{})
- log.Printf("诊断钩子已注册")
-
- // 设置消息完成回调函数(简单方案)
- dispatcher.SetOnMessageCompleteFunc(func(sessionID string, messageID string, completeText string, messageType event.MessageType, metadata map[string]interface{}) {
- textLength := len(completeText)
- log.Printf("🔔 消息完成总结 sessionID=%s messageID=%s type=%s textLength=%d",
- sessionID, messageID, messageType, textLength)
-
- if textLength > 0 {
- preview := completeText
- if len(preview) > 200 {
- preview = preview[:200] + "..."
- }
- log.Printf("📝 文本预览: %s", preview)
- } else {
- log.Printf("📭 空文本完成事件")
- }
-
- // 记录元数据(如果有)
- if metadata != nil && len(metadata) > 0 {
- log.Printf("📊 元数据: %+v", metadata)
- }
- })
- log.Printf("消息完成回调函数已设置")
-
- // 设置事件处理回调函数(记录所有事件)
- dispatcher.SetOnEventProcessedFunc(func(sessionID string, eventType string, eventData string, eventMap map[string]interface{}) {
- // 记录所有事件类型(不限于message.part.updated等)
- dataPreview := eventData
- if len(dataPreview) > 200 {
- dataPreview = dataPreview[:200] + "..."
- }
- log.Printf("📡 事件处理: sessionID=%s eventType=%s dataPreview=%s",
- sessionID, eventType, dataPreview)
-
- // 函数内部可以决定是否要保存特定类型的事件
- // 例如:只保存message.part.updated事件
- if eventType == "message.part.updated" {
- // 可以在这里提取更多信息并保存
- log.Printf("💾 需要保存的事件类型: %s", eventType)
- }
- })
- log.Printf("事件处理回调函数已设置")
-
- // 初始化订阅服务单例(暂时注释,使用简单回调方案)
- // event.InitSubscriptionService(dispatcher, mongoDBFactory)
- // log.Printf("订阅服务单例已初始化")
-
- // 6. 得到 webservice 服务工厂
- webxFactory := webx.GetWebServiceFactory()
-
- // 7. 建立 httpService 服务
- webService, err := webxFactory.CreateService(cfg.GetServiceConfig())
- if err != nil {
- log.Fatalf("创建 HTTP 服务失败: %v", err)
- }
-
- // 8. 建立路由-api
- routerService := router.NewWebService(webService.GetRouter())
-
- // 注册健康检查-api
- health.RegisterConsulHealthCheck(routerService)
-
- // 9. 注册路由--api
- registerRoutes(routerService, webService, configClient, client, nil, opencodePort, mappingService)
-
- // 9. 注册前端静态文件服务
- //registerStaticFiles(webService)
-
- // 10. 启动服务
- webService.Run()
-
- // 11. 启用运行日志
- container.Create(ctr, logger.InitRuntimeLogger)
-
- // 12. 等待关闭
- graceful.WaitForShutdown(cfg.GetServiceConfig().ServiceName, ctr, webService.GetServer())
- }
-
- // registerRoutes 注册所有 API 路由
- func registerRoutes(ws *router.RouterService, webService *webx.WebService, configClient *configure.Client, client opencode.OpenCodeClient, opencodeProcess *opencode.Process, opencodePort int, mappingService *menu.MappingService) {
- // 认证路由(公开登录接口)
- routes.RegisterAuthRoutes(ws, configClient)
-
- // 会话管理路由
- routes.RegisterSessionRoutes(ws, client, mappingService)
-
- // 同步对话路由
- routes.RegisterPromptSyncRoutes(ws, client)
-
- // 流式对话路由(需要直接 HTTP 处理器)
- routes.RegisterPromptStreamRoutes(ws, webService, client)
-
- // 日志流路由(需要直接 HTTP 处理器)
- routes.RegisterLogStreamRoutes(ws, webService, opencodeProcess, opencodePort)
-
- // 菜单路由
- routes.RegisterMenuRoutes(ws, mappingService)
- }
|