app.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package app
  2. import (
  3. "context"
  4. "database/sql"
  5. "maps"
  6. "sync"
  7. "time"
  8. "github.com/kujtimiihoxha/termai/internal/db"
  9. "github.com/kujtimiihoxha/termai/internal/history"
  10. "github.com/kujtimiihoxha/termai/internal/llm/agent"
  11. "github.com/kujtimiihoxha/termai/internal/logging"
  12. "github.com/kujtimiihoxha/termai/internal/lsp"
  13. "github.com/kujtimiihoxha/termai/internal/message"
  14. "github.com/kujtimiihoxha/termai/internal/permission"
  15. "github.com/kujtimiihoxha/termai/internal/session"
  16. )
  17. type App struct {
  18. Sessions session.Service
  19. Messages message.Service
  20. Files history.Service
  21. Permissions permission.Service
  22. CoderAgent agent.Service
  23. LSPClients map[string]*lsp.Client
  24. clientsMutex sync.RWMutex
  25. watcherCancelFuncs []context.CancelFunc
  26. cancelFuncsMutex sync.Mutex
  27. watcherWG sync.WaitGroup
  28. }
  29. func New(ctx context.Context, conn *sql.DB) (*App, error) {
  30. q := db.New(conn)
  31. sessions := session.NewService(q)
  32. messages := message.NewService(q)
  33. files := history.NewService(q)
  34. app := &App{
  35. Sessions: sessions,
  36. Messages: messages,
  37. Files: files,
  38. Permissions: permission.NewPermissionService(),
  39. LSPClients: make(map[string]*lsp.Client),
  40. }
  41. var err error
  42. app.CoderAgent, err = agent.NewCoderAgent(
  43. app.Permissions,
  44. app.Sessions,
  45. app.Messages,
  46. app.LSPClients,
  47. )
  48. if err != nil {
  49. logging.Error("Failed to create coder agent", err)
  50. return nil, err
  51. }
  52. app.initLSPClients(ctx)
  53. return app, nil
  54. }
  55. // Shutdown performs a clean shutdown of the application
  56. func (app *App) Shutdown() {
  57. // Cancel all watcher goroutines
  58. app.cancelFuncsMutex.Lock()
  59. for _, cancel := range app.watcherCancelFuncs {
  60. cancel()
  61. }
  62. app.cancelFuncsMutex.Unlock()
  63. app.watcherWG.Wait()
  64. // Perform additional cleanup for LSP clients
  65. app.clientsMutex.RLock()
  66. clients := make(map[string]*lsp.Client, len(app.LSPClients))
  67. maps.Copy(clients, app.LSPClients)
  68. app.clientsMutex.RUnlock()
  69. for name, client := range clients {
  70. shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  71. if err := client.Shutdown(shutdownCtx); err != nil {
  72. logging.Error("Failed to shutdown LSP client", "name", name, "error", err)
  73. }
  74. cancel()
  75. }
  76. }