File size: 2,538 Bytes
6a7089a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package instance

import (
	"fmt"
	"sync"

	"github.com/pinchtab/pinchtab/internal/bridge"
)

// Repository manages the in-memory store of instances and delegates
// process lifecycle to an InstanceLauncher (typically the Orchestrator).
type Repository struct {
	mu        sync.RWMutex
	instances map[string]*bridge.Instance
	launcher  InstanceLauncher
}

// NewRepository creates a Repository backed by the given launcher.
func NewRepository(launcher InstanceLauncher) *Repository {
	return &Repository{
		instances: make(map[string]*bridge.Instance),
		launcher:  launcher,
	}
}

// Launch starts a new instance and adds it to the store.
func (r *Repository) Launch(name, port string, headless bool) (*bridge.Instance, error) {
	inst, err := r.launcher.Launch(name, port, headless)
	if err != nil {
		return nil, fmt.Errorf("launch instance: %w", err)
	}
	r.mu.Lock()
	r.instances[inst.ID] = inst
	r.mu.Unlock()
	return inst, nil
}

// Stop terminates an instance and removes it from the store.
func (r *Repository) Stop(id string) error {
	if err := r.launcher.Stop(id); err != nil {
		return fmt.Errorf("stop instance %q: %w", id, err)
	}
	r.mu.Lock()
	delete(r.instances, id)
	r.mu.Unlock()
	return nil
}

// List returns all instances. The returned slice is a snapshot.
func (r *Repository) List() []bridge.Instance {
	r.mu.RLock()
	defer r.mu.RUnlock()
	out := make([]bridge.Instance, 0, len(r.instances))
	for _, inst := range r.instances {
		out = append(out, *inst)
	}
	return out
}

// Running returns only instances with status "running".
func (r *Repository) Running() []bridge.Instance {
	r.mu.RLock()
	defer r.mu.RUnlock()
	out := make([]bridge.Instance, 0, len(r.instances))
	for _, inst := range r.instances {
		if inst.Status == "running" {
			out = append(out, *inst)
		}
	}
	return out
}

// Get returns an instance by ID.
func (r *Repository) Get(id string) (*bridge.Instance, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	inst, ok := r.instances[id]
	if !ok {
		return nil, false
	}
	copy := *inst
	return &copy, true
}

// Add registers an existing instance (used for sync with external state).
func (r *Repository) Add(inst *bridge.Instance) {
	r.mu.Lock()
	r.instances[inst.ID] = inst
	r.mu.Unlock()
}

// Remove deletes an instance from the store without stopping it.
func (r *Repository) Remove(id string) {
	r.mu.Lock()
	delete(r.instances, id)
	r.mu.Unlock()
}

// Count returns the number of tracked instances.
func (r *Repository) Count() int {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return len(r.instances)
}