2.0.1 dcf7d6b

start.go RawHistoryFolder

1package cmd
2
3import (
4	"context"
5	"os"
6	"os/signal"
7	"sync"
8	"syscall"
9	"time"
10
11	"github.com/fsnotify/fsnotify"
12	"github.com/google/uuid"
13	"github.com/rs/zerolog"
14	"github.com/rs/zerolog/log"
15	"github.com/spf13/cobra"
16	"github.com/spf13/viper"
17	"gordon/internal/config"
18	"gordon/internal/container"
19	"gordon/internal/events"
20	"gordon/internal/proxy"
21	"gordon/internal/registry"
22)
23
24var startCmd = &cobra.Command{
25	Use:   "start",
26	Short: "Start the Gordon server",
27	Long:  `Start the container registry and reverse proxy server`,
28	Run:   runStart,
29}
30
31func init() {
32	rootCmd.AddCommand(startCmd)
33}
34
35func runStart(cmd *cobra.Command, args []string) {
36	// Configure zerolog
37	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
38	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
39
40	cfg, err := config.Load()
41	if err != nil {
42		log.Fatal().Err(err).Msg("Failed to load config")
43	}
44
45	log.Info().Msg("Starting Gordon server...")
46	log.Info().Int("registry_port", cfg.Server.RegistryPort).Msg("Registry server")
47	log.Info().Int("proxy_port", cfg.Server.Port).Msg("Proxy server")
48	log.Info().Str("runtime", cfg.Server.Runtime).Msg("Container runtime")
49
50	// Initialize event bus
51	eventBus := events.NewInMemoryEventBus(100)
52	if err := eventBus.Start(); err != nil {
53		log.Fatal().Err(err).Msg("Failed to start event bus")
54	}
55
56	// Initialize container manager
57	manager, err := container.NewManager(cfg)
58	if err != nil {
59		log.Fatal().Err(err).Msg("Failed to initialize container manager")
60	}
61
62	// Create and subscribe container event handler
63	containerHandler := events.NewContainerEventHandler(manager, cfg)
64	if err := eventBus.Subscribe(containerHandler); err != nil {
65		log.Fatal().Err(err).Msg("Failed to subscribe container event handler")
66	}
67
68	// Setup config file watching for live reload
69	viper.WatchConfig()
70	viper.OnConfigChange(func(e fsnotify.Event) {
71		log.Info().
72			Str("file", e.Name).
73			Str("op", e.Op.String()).
74			Msg("Configuration file changed, reloading...")
75
76		// Reload configuration
77		newCfg, err := config.Load()
78		if err != nil {
79			log.Error().Err(err).Msg("Failed to reload configuration")
80			return
81		}
82
83		// Update the configuration reference
84		cfg = newCfg
85
86		// Update container handler config
87		containerHandler = events.NewContainerEventHandler(manager, cfg)
88		if err := eventBus.Subscribe(containerHandler); err != nil {
89			log.Error().Err(err).Msg("Failed to re-subscribe container event handler")
90			return
91		}
92
93		// Publish config reload event
94		configReloadEvent := events.Event{
95			ID:        uuid.New().String(),
96			Type:      events.ConfigReload,
97			Timestamp: time.Now(),
98		}
99
100		if err := eventBus.Publish(configReloadEvent); err != nil {
101			log.Error().Err(err).Msg("Failed to publish config reload event")
102		} else {
103			log.Info().Msg("Configuration reloaded successfully")
104		}
105	})
106
107	// Sync existing containers
108	ctx, cancel := context.WithCancel(context.Background())
109	if err := manager.SyncContainers(ctx); err != nil {
110		log.Warn().Err(err).Msg("Failed to sync existing containers")
111	}
112
113	var wg sync.WaitGroup
114
115	// Start registry server
116	registryServer, err := registry.NewServer(cfg, eventBus)
117	if err != nil {
118		log.Fatal().Err(err).Msg("Failed to initialize registry server")
119	}
120	wg.Add(1)
121	go func() {
122		defer wg.Done()
123		if err := registryServer.Start(ctx); err != nil {
124			log.Error().Err(err).Msg("Registry server error")
125		}
126	}()
127
128	// Start proxy server
129	proxyServer := proxy.NewServer(cfg, manager)
130	wg.Add(1)
131	go func() {
132		defer wg.Done()
133		if err := proxyServer.Start(ctx); err != nil {
134			log.Error().Err(err).Msg("Proxy server error")
135		}
136	}()
137
138	// Wait for interrupt signal
139	sigChan := make(chan os.Signal, 1)
140	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
141	<-sigChan
142
143	log.Info().Msg("Shutting down servers...")
144	cancel()
145
146	// Stop event bus
147	if err := eventBus.Stop(); err != nil {
148		log.Error().Err(err).Msg("Failed to stop event bus")
149	}
150
151	// Give servers time to shutdown gracefully
152	done := make(chan struct{})
153	go func() {
154		wg.Wait()
155		close(done)
156	}()
157
158	select {
159	case <-done:
160		log.Info().Msg("Servers stopped gracefully")
161	case <-time.After(10 * time.Second):
162		log.Warn().Msg("Force shutdown after timeout")
163	}
164}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close