| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- package xpc
- import (
- "context"
- "fmt"
- "reflect"
- "sync"
- )
- // runtimeConfig holds runtime configuration.
- type runtimeConfig struct {
- TLSCertFile string
- TLSKeyFile string
- }
- // runtime defines the behavior of the XPC runtime.
- type runtime interface {
- // getInstance returns a client or instance for the given component interface.
- getInstance(ctx context.Context, intfType reflect.Type) (any, error)
- // shutdown gracefully stops the runtime and its components.
- shutdown(ctx context.Context) error
- }
- // newLocalRuntime creates a new local runtime.
- func newLocalRuntime(cfg runtimeConfig) runtime {
- return &localRuntime{
- instances: make(map[reflect.Type]any),
- config: cfg,
- }
- }
- // newClusterRuntime creates a new cluster runtime.
- func newClusterRuntime(cfg runtimeConfig) runtime {
- return &clusterRuntime{
- config: cfg,
- }
- }
- // localRuntime executes components in the same process.
- type localRuntime struct {
- mu sync.Mutex
- instances map[reflect.Type]any
- config runtimeConfig
- }
- func (r *localRuntime) getInstance(ctx context.Context, intfType reflect.Type) (any, error) {
- r.mu.Lock()
- if instance, ok := r.instances[intfType]; ok {
- r.mu.Unlock()
- return instance, nil
- }
- r.mu.Unlock() // Unlock before potentially long init
- info, ok := getComponentInfo(intfType)
- if !ok {
- return nil, fmt.Errorf("component implementation not found for interface %s", intfType.Name())
- }
- // Double-check locking for creation
- r.mu.Lock()
- if instance, ok := r.instances[intfType]; ok {
- r.mu.Unlock()
- return instance, nil
- }
- // Create new instance
- implPtr := info.NewFunc()
- // Store in cache before injection to support circular dependencies
- r.instances[intfType] = implPtr
- r.mu.Unlock()
- // Perform dependency injection
- if err := r.inject(ctx, implPtr); err != nil {
- return nil, err
- }
- // Lifecycle: Init
- if initializer, ok := implPtr.(interface{ Init(context.Context) error }); ok {
- if err := initializer.Init(ctx); err != nil {
- return nil, fmt.Errorf("component %s Init failed: %w", info.Name, err)
- }
- }
- return implPtr, nil
- }
- func (r *localRuntime) inject(ctx context.Context, implPtr any) error {
- val := reflect.ValueOf(implPtr).Elem()
- typ := val.Type()
- for i := 0; i < val.NumField(); i++ {
- field := val.Field(i)
- fieldType := typ.Field(i)
- // Skip unexported fields
- if !fieldType.IsExported() {
- continue
- }
- // If field is an interface and registered as a component, inject it
- if field.Kind() == reflect.Interface {
- if _, ok := getComponentInfo(field.Type()); ok {
- dep, err := r.getInstance(ctx, field.Type())
- if err != nil {
- return fmt.Errorf("failed to inject dependency %s: %w", fieldType.Name, err)
- }
- field.Set(reflect.ValueOf(dep))
- }
- }
- }
- return nil
- }
- func (r *localRuntime) shutdown(ctx context.Context) error {
- r.mu.Lock()
- defer r.mu.Unlock()
- var errs []error
- // In local mode, we just shutdown all instantiated components.
- // Note: Order isn't guaranteed here. For strict ordering, we'd need a dependency graph.
- for _, instance := range r.instances {
- if closer, ok := instance.(interface{ Shutdown(context.Context) error }); ok {
- if err := closer.Shutdown(ctx); err != nil {
- errs = append(errs, err)
- }
- }
- }
- if len(errs) > 0 {
- return fmt.Errorf("shutdown errors: %v", errs)
- }
- return nil
- }
- // clusterRuntime executes components across a Raft cluster.
- type clusterRuntime struct {
- config runtimeConfig
- // raftNode *raft.Node
- }
- func (r *clusterRuntime) getInstance(ctx context.Context, intfType reflect.Type) (any, error) {
- // TODO: Phase 2 - Raft Integration
- return nil, fmt.Errorf("cluster runtime: not implemented in this phase. use XPC_MODE=local")
- }
- func (r *clusterRuntime) shutdown(ctx context.Context) error {
- return nil
- }
|