runtime.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package xpc
  2. import (
  3. "context"
  4. "fmt"
  5. "reflect"
  6. "sync"
  7. )
  8. // runtimeConfig holds runtime configuration.
  9. type runtimeConfig struct {
  10. TLSCertFile string
  11. TLSKeyFile string
  12. }
  13. // runtime defines the behavior of the XPC runtime.
  14. type runtime interface {
  15. // getInstance returns a client or instance for the given component interface.
  16. getInstance(ctx context.Context, intfType reflect.Type) (any, error)
  17. // shutdown gracefully stops the runtime and its components.
  18. shutdown(ctx context.Context) error
  19. }
  20. // newLocalRuntime creates a new local runtime.
  21. func newLocalRuntime(cfg runtimeConfig) runtime {
  22. return &localRuntime{
  23. instances: make(map[reflect.Type]any),
  24. config: cfg,
  25. }
  26. }
  27. // newClusterRuntime creates a new cluster runtime.
  28. func newClusterRuntime(cfg runtimeConfig) runtime {
  29. return &clusterRuntime{
  30. config: cfg,
  31. }
  32. }
  33. // localRuntime executes components in the same process.
  34. type localRuntime struct {
  35. mu sync.Mutex
  36. instances map[reflect.Type]any
  37. config runtimeConfig
  38. }
  39. func (r *localRuntime) getInstance(ctx context.Context, intfType reflect.Type) (any, error) {
  40. r.mu.Lock()
  41. if instance, ok := r.instances[intfType]; ok {
  42. r.mu.Unlock()
  43. return instance, nil
  44. }
  45. r.mu.Unlock() // Unlock before potentially long init
  46. info, ok := getComponentInfo(intfType)
  47. if !ok {
  48. return nil, fmt.Errorf("component implementation not found for interface %s", intfType.Name())
  49. }
  50. // Double-check locking for creation
  51. r.mu.Lock()
  52. if instance, ok := r.instances[intfType]; ok {
  53. r.mu.Unlock()
  54. return instance, nil
  55. }
  56. // Create new instance
  57. implPtr := info.NewFunc()
  58. // Store in cache before injection to support circular dependencies
  59. r.instances[intfType] = implPtr
  60. r.mu.Unlock()
  61. // Perform dependency injection
  62. if err := r.inject(ctx, implPtr); err != nil {
  63. return nil, err
  64. }
  65. // Lifecycle: Init
  66. if initializer, ok := implPtr.(interface{ Init(context.Context) error }); ok {
  67. if err := initializer.Init(ctx); err != nil {
  68. return nil, fmt.Errorf("component %s Init failed: %w", info.Name, err)
  69. }
  70. }
  71. return implPtr, nil
  72. }
  73. func (r *localRuntime) inject(ctx context.Context, implPtr any) error {
  74. val := reflect.ValueOf(implPtr).Elem()
  75. typ := val.Type()
  76. for i := 0; i < val.NumField(); i++ {
  77. field := val.Field(i)
  78. fieldType := typ.Field(i)
  79. // Skip unexported fields
  80. if !fieldType.IsExported() {
  81. continue
  82. }
  83. // If field is an interface and registered as a component, inject it
  84. if field.Kind() == reflect.Interface {
  85. if _, ok := getComponentInfo(field.Type()); ok {
  86. dep, err := r.getInstance(ctx, field.Type())
  87. if err != nil {
  88. return fmt.Errorf("failed to inject dependency %s: %w", fieldType.Name, err)
  89. }
  90. field.Set(reflect.ValueOf(dep))
  91. }
  92. }
  93. }
  94. return nil
  95. }
  96. func (r *localRuntime) shutdown(ctx context.Context) error {
  97. r.mu.Lock()
  98. defer r.mu.Unlock()
  99. var errs []error
  100. // In local mode, we just shutdown all instantiated components.
  101. // Note: Order isn't guaranteed here. For strict ordering, we'd need a dependency graph.
  102. for _, instance := range r.instances {
  103. if closer, ok := instance.(interface{ Shutdown(context.Context) error }); ok {
  104. if err := closer.Shutdown(ctx); err != nil {
  105. errs = append(errs, err)
  106. }
  107. }
  108. }
  109. if len(errs) > 0 {
  110. return fmt.Errorf("shutdown errors: %v", errs)
  111. }
  112. return nil
  113. }
  114. // clusterRuntime executes components across a Raft cluster.
  115. type clusterRuntime struct {
  116. config runtimeConfig
  117. // raftNode *raft.Node
  118. }
  119. func (r *clusterRuntime) getInstance(ctx context.Context, intfType reflect.Type) (any, error) {
  120. // TODO: Phase 2 - Raft Integration
  121. return nil, fmt.Errorf("cluster runtime: not implemented in this phase. use XPC_MODE=local")
  122. }
  123. func (r *clusterRuntime) shutdown(ctx context.Context) error {
  124. return nil
  125. }