refactor(config): centralize env loading and enforce typed access

- Centralize environment variable loading in config.MustLoad
- Parse and validate all env vars once at initialization
- Make config fields private and read-only
- Remove public Getenv usage in favor of typed accessors
- Improve validation and initialization order
- Normalize enum naming to be idiomatic and avoid constant collisions
This commit is contained in:
2026-01-21 19:43:19 +07:00
parent 1e12373359
commit 2bc20dd991
19 changed files with 414 additions and 257 deletions
+11 -10
View File
@@ -18,9 +18,9 @@ import (
)
type Interaction interface {
Mode() types.Mode
Mode() types.InteractiveMode
SetChannel(channel ssh.Channel)
SetMode(m types.Mode)
SetMode(m types.InteractiveMode)
SetWH(w, h int)
Start()
Redraw()
@@ -39,6 +39,7 @@ type Forwarder interface {
type CloseFunc func() error
type interaction struct {
config config.Config
channel ssh.Channel
slug slug.Slug
forwarder Forwarder
@@ -48,14 +49,14 @@ type interaction struct {
program *tea.Program
ctx context.Context
cancel context.CancelFunc
mode types.Mode
mode types.InteractiveMode
}
func (i *interaction) SetMode(m types.Mode) {
func (i *interaction) SetMode(m types.InteractiveMode) {
i.mode = m
}
func (i *interaction) Mode() types.Mode {
func (i *interaction) Mode() types.InteractiveMode {
return i.mode
}
@@ -75,9 +76,10 @@ func (i *interaction) SetWH(w, h int) {
}
}
func New(slug slug.Slug, forwarder Forwarder, sessionRegistry SessionRegistry, user string, closeFunc CloseFunc) Interaction {
func New(config config.Config, slug slug.Slug, forwarder Forwarder, sessionRegistry SessionRegistry, user string, closeFunc CloseFunc) Interaction {
ctx, cancel := context.WithCancel(context.Background())
return &interaction{
config: config,
channel: nil,
slug: slug,
forwarder: forwarder,
@@ -174,14 +176,13 @@ func (m *model) View() string {
}
func (i *interaction) Start() {
if i.mode == types.HEADLESS {
if i.mode == types.InteractiveModeHEADLESS {
return
}
lipgloss.SetColorProfile(termenv.TrueColor)
domain := config.Getenv("DOMAIN", "localhost")
protocol := "http"
if config.Getenv("TLS_ENABLED", "false") == "true" {
if i.config.TLSEnabled() {
protocol = "https"
}
@@ -209,7 +210,7 @@ func (i *interaction) Start() {
ti.Width = 50
m := &model{
domain: domain,
domain: i.config.Domain(),
protocol: protocol,
tunnelType: tunnelType,
port: port,
+1 -1
View File
@@ -41,7 +41,7 @@ type model struct {
}
func (m *model) getTunnelURL() string {
if m.tunnelType == types.HTTP {
if m.tunnelType == types.TunnelTypeHTTP {
return buildURL(m.protocol, m.interaction.slug.String(), m.domain)
}
return fmt.Sprintf("tcp://%s:%d", m.domain, m.port)
+6 -6
View File
@@ -15,7 +15,7 @@ import (
func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
if m.tunnelType != types.HTTP {
if m.tunnelType != types.TunnelTypeHTTP {
m.editingSlug = false
m.slugError = ""
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
@@ -30,10 +30,10 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
inputValue := m.slugInput.Value()
if err := m.interaction.sessionRegistry.Update(m.interaction.user, types.SessionKey{
Id: m.interaction.slug.String(),
Type: types.HTTP,
Type: types.TunnelTypeHTTP,
}, types.SessionKey{
Id: inputValue,
Type: types.HTTP,
Type: types.TunnelTypeHTTP,
}); err != nil {
m.slugError = err.Error()
return m, nil
@@ -130,7 +130,7 @@ func (m *model) slugView() string {
b.WriteString(titleStyle.Render(title))
b.WriteString("\n\n")
if m.tunnelType != types.HTTP {
if m.tunnelType != types.TunnelTypeHTTP {
warningBoxWidth := getResponsiveWidth(m.width, 10, 30, 60)
warningBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFA500")).
@@ -145,9 +145,9 @@ func (m *model) slugView() string {
var warningText string
if isVeryCompact {
warningText = "⚠️ TCP tunnels don't support custom subdomains."
warningText = "⚠️ TunnelTypeTCP tunnels don't support custom subdomains."
} else {
warningText = "⚠️ TCP tunnels cannot have custom subdomains. Only HTTP/HTTPS tunnels support subdomain customization."
warningText = "⚠️ TunnelTypeTCP tunnels cannot have custom subdomains. Only TunnelTypeHTTP/HTTPS tunnels support subdomain customization."
}
b.WriteString(warningBoxStyle.Render(warningText))
b.WriteString("\n\n")