Browse Source

feat: wireguard / vproxy configuration

master
jb 2 weeks ago
parent
commit
c622abf194
10 changed files with 398 additions and 45 deletions
  1. +13
    -0
      envs
  2. +1
    -0
      go.mod
  3. +2
    -0
      go.sum
  4. +42
    -0
      internal/tui/cmds.go
  5. +47
    -0
      internal/tui/config.go
  6. +33
    -0
      internal/tui/docker.go
  7. +140
    -38
      internal/tui/model.go
  8. +4
    -1
      internal/tui/steps.go
  9. +101
    -6
      internal/tui/update.go
  10. +15
    -0
      internal/tui/view.go

+ 13
- 0
envs View File

@ -0,0 +1,13 @@
PRIVKEY=odkqwjdoqwjdoi
VIP=127.0.0.1
PSK=qowdjoqwijdoqwi
PROXY_EDPS=qodjoqwjdoqwij
# MTU Opcional
MTU=1380
# Especifica o protocolo de transmissao
# Default: UDP -> Manter se possivel, melhor performance e estabilidade.
# Alguns firewalls restritivos podem impedir o trafego UDP.
# Se nao for possivel negociar a abertura com o cliente, tentar usar TCP
PROTO=UDP

+ 1
- 0
go.mod View File

@ -6,6 +6,7 @@ require (
charm.land/bubbles/v2 v2.0.0 charm.land/bubbles/v2 v2.0.0
charm.land/bubbletea/v2 v2.0.1 charm.land/bubbletea/v2 v2.0.1
charm.land/lipgloss/v2 v2.0.0 charm.land/lipgloss/v2 v2.0.0
github.com/BurntSushi/toml v1.6.0
) )
require ( require (


+ 2
- 0
go.sum View File

@ -4,6 +4,8 @@ charm.land/bubbletea/v2 v2.0.1 h1:B8e9zzK7x9JJ+XvHGF4xnYu9Xa0E0y0MyggY6dbaCfQ=
charm.land/bubbletea/v2 v2.0.1/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ= charm.land/bubbletea/v2 v2.0.1/go.mod h1:3LRff2U4WIYXy7MTxfbAQ+AdfM3D8Xuvz2wbsOD9OHQ=
charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo= charm.land/lipgloss/v2 v2.0.0 h1:sd8N/B3x892oiOjFfBQdXBQp3cAkvjGaU5TvVZC3ivo=
charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14= charm.land/lipgloss/v2 v2.0.0/go.mod h1:w6SnmsBFBmEFBodiEDurGS/sdUY/u1+v72DqUzc6J14=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM= github.com/aymanbagabas/go-udiff v0.4.0 h1:TKnLPh7IbnizJIBKFWa9mKayRUBQ9Kh1BPCk6w2PnYM=


+ 42
- 0
internal/tui/cmds.go View File

@ -65,6 +65,28 @@ func DownloadImageCmd(username, password string) tea.Cmd {
} }
} }
func DownloadWireguardImageCmd(username, password string) tea.Cmd {
return func() tea.Msg {
url := wireguardImageName
loginOut, err := exec.Command(
"docker", "login", url,
"-u", username,
"-p", password,
).CombinedOutput()
if err != nil {
return ImageDownloadFinishedMsg{
Message: string(loginOut),
Err: fmt.Errorf("falha no login: %w", err),
}
}
message, err := PullImage(url)
return ImageDownloadFinishedMsg{Message: message, Err: err}
}
}
func CheckImageCmd(image string) tea.Cmd { func CheckImageCmd(image string) tea.Cmd {
return func() tea.Msg { return func() tea.Msg {
cmd := exec.Command("docker", "image", "inspect", image) cmd := exec.Command("docker", "image", "inspect", image)
@ -77,6 +99,16 @@ func CheckImageCmd(image string) tea.Cmd {
} }
} }
func GenerateWireguardConfigFile(cv ConfigValues, path string) tea.Cmd {
return func() tea.Msg {
err := WriteWireguardConfigFile(cv, path)
return ConfigFileMsg{
Err: err,
}
}
}
func GenerateConfigFile(cv ConfigValues, path string) tea.Cmd { func GenerateConfigFile(cv ConfigValues, path string) tea.Cmd {
return func() tea.Msg { return func() tea.Msg {
err := WriteConfigFile(cv, path) err := WriteConfigFile(cv, path)
@ -96,3 +128,13 @@ func RunAppContainer(image, name, filePath, destinationPath string, cv ConfigVal
} }
} }
} }
func RunWireguardContainer(path string, cv ConfigValues) tea.Cmd {
return func() tea.Msg {
err := RunWireguardDockerContainer(path, cv)
return DockerRunMsg{
Err: err,
}
}
}

+ 47
- 0
internal/tui/config.go View File

@ -30,6 +30,7 @@ func GenerateConfigTOML(cv ConfigValues) (string, error) {
// [certificate] // [certificate]
sb.WriteString("# Certificate Options\n") sb.WriteString("# Certificate Options\n")
sb.WriteString("[certificate]\n") sb.WriteString("[certificate]\n")
sb.WriteString(fmt.Sprintf("mapped_dir = %q\n", cv.Cert["cert_dir_path"]))
sb.WriteString(fmt.Sprintf("cert_path = %q\n", "/app/certs/"+cv.Cert["cert_name"])) sb.WriteString(fmt.Sprintf("cert_path = %q\n", "/app/certs/"+cv.Cert["cert_name"]))
sb.WriteString(fmt.Sprintf("key_path = %q\n", "/app/certs/"+cv.Cert["key_name"])) sb.WriteString(fmt.Sprintf("key_path = %q\n", "/app/certs/"+cv.Cert["key_name"]))
sb.WriteString(fmt.Sprintf("ca_path = %q\n", "/app/certs/"+cv.Cert["ca_name"])) sb.WriteString(fmt.Sprintf("ca_path = %q\n", "/app/certs/"+cv.Cert["ca_name"]))
@ -52,6 +53,36 @@ func GenerateConfigTOML(cv ConfigValues) (string, error) {
return sb.String(), nil return sb.String(), nil
} }
func GenerateWireguardConfig(cv ConfigValues) (string, error) {
var sb strings.Builder
// Primary Wireguard Settings
sb.WriteString(fmt.Sprintf("PRIVKEY=%s\n", cv.Wireguard["privkey"]))
sb.WriteString(fmt.Sprintf("VIP=%s\n", cv.Wireguard["vip"]))
sb.WriteString(fmt.Sprintf("PSK=%s\n", cv.Wireguard["psk"]))
sb.WriteString(fmt.Sprintf("PROXY_EDPS=%s\n", cv.Wireguard["proxy_edps"]))
sb.WriteString("\n# MTU Opcional\n")
if mtu, ok := cv.Wireguard["mtu"]; ok && mtu != "" {
sb.WriteString(fmt.Sprintf("MTU=%s\n", mtu))
} else {
sb.WriteString("# MTU=1380\n")
}
sb.WriteString("\n# Especifica o protocolo de transmissao\n")
sb.WriteString("# Default: UDP -> Manter se possivel, melhor performance e estabilidade.\n")
sb.WriteString("# Alguns firewalls restritivos podem impedir o trafego UDP.\n")
sb.WriteString("# Se nao for possivel negociar a abertura com o cliente, tentar usar TCP\n")
proto := cv.Wireguard["proto"]
if proto == "" {
proto = "UDP"
}
sb.WriteString(fmt.Sprintf("PROTO=%s\n", proto))
return sb.String(), nil
}
func WriteConfigFile(cv ConfigValues, path string) error { func WriteConfigFile(cv ConfigValues, path string) error {
// Validate numeric fields before writing // Validate numeric fields before writing
numericFields := map[string]string{ numericFields := map[string]string{
@ -73,3 +104,19 @@ func WriteConfigFile(cv ConfigValues, path string) error {
return os.WriteFile(path, []byte(content), 0644) return os.WriteFile(path, []byte(content), 0644)
} }
func WriteWireguardConfigFile(cv ConfigValues, path string) error {
// Validate numeric fields before writing
if mtu, ok := cv.Wireguard["mtu"]; ok && mtu != "" {
if _, err := strconv.Atoi(mtu); err != nil {
return fmt.Errorf("o campo MTU deve ser um número, recebido: %q", mtu)
}
}
content, err := GenerateWireguardConfig(cv)
if err != nil {
return err
}
return os.WriteFile(path, []byte(content), 0644)
}

+ 33
- 0
internal/tui/docker.go View File

@ -45,6 +45,39 @@ func PushFileToContainer(container, filePath, destinationPath string) bool {
return err == nil return err == nil
} }
func RunWireguardDockerContainer(envFilePath string, cv ConfigValues) error {
containerName := "vproxy"
removeExistingContainer(containerName)
absPath, err := filepath.Abs(envFilePath)
if err != nil {
return fmt.Errorf("erro ao resolver caminho absoluto: %w", err)
}
cmd := exec.Command(
"docker", "run", "-it", "-d",
"--name", containerName,
"--network", "app-dono_app",
"--restart", "unless-stopped",
"--cap-add=NET_ADMIN",
"--device", "/dev/net/tun:/dev/net/tun",
"--log-opt", "max-size=5m",
"--log-opt", "max-file=1",
"--env-file", absPath,
wireguardImageName,
)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("docker run falhou: %w\noutput: %s", err, string(out))
}
time.Sleep(2 * time.Second)
containerID := strings.TrimSpace(string(out))
return verifyContainerRunning(containerID)
}
func RunAppClienteContainer(image, containerName, configPath, configDestinationPath string, cv ConfigValues) error { func RunAppClienteContainer(image, containerName, configPath, configDestinationPath string, cv ConfigValues) error {
removeExistingContainer(containerName) removeExistingContainer(containerName)


+ 140
- 38
internal/tui/model.go View File

@ -1,8 +1,14 @@
package tui package tui
import ( import (
"fmt"
"os"
"path/filepath"
"strconv"
"charm.land/bubbles/v2/spinner" "charm.land/bubbles/v2/spinner"
tea "charm.land/bubbletea/v2" tea "charm.land/bubbletea/v2"
"github.com/BurntSushi/toml"
) )
type Model struct { type Model struct {
@ -23,11 +29,12 @@ type Model struct {
isPublicIP bool isPublicIP bool
loginForm FormStep
serverForm FormStep
dbForm FormStep
certForm FormStep
configValues ConfigValues
loginForm FormStep
wireguardForm FormStep
serverForm FormStep
dbForm FormStep
certForm FormStep
configValues ConfigValues
finishedFile bool finishedFile bool
configFileError error configFileError error
@ -43,13 +50,71 @@ type DockerLoginData struct {
} }
type ConfigValues struct { type ConfigValues struct {
Login map[string]string
Server map[string]string
Database map[string]string
Cert map[string]string
Login map[string]string
Wireguard map[string]string
Server map[string]string
Database map[string]string
Cert map[string]string
}
type AppConfig struct {
Server struct {
Port int64 `toml:"port"`
Timeout int64 `toml:"timeout_seconds"`
Environment string `toml:"environment"`
} `toml:"server"`
Database struct {
Type string `toml:"type"`
URL string `toml:"url"`
MaxConns int64 `toml:"max_conns"`
MinConns int64 `toml:"min_conns"`
} `toml:"database"`
Certificates struct {
DirPath string `toml:"mapped_dir"`
CertName string `toml:"cert_path"`
KeyName string `toml:"key_path"`
CAName string `toml:"ca_path"`
ServerName string `toml:"server_name"`
} `toml:"certificate"`
}
func loadConfig() AppConfig {
var config AppConfig
config.Server.Port = 8081
config.Server.Timeout = 30
config.Server.Environment = "production"
config.Database.Type = "postgres"
config.Database.URL = "postgres://usuario:senha@banco:5432/app_dono_db"
config.Database.MaxConns = 10
config.Database.MinConns = 2
config.Certificates.DirPath = "/caminho/para/diretorio"
config.Certificates.CertName = "certificado.crt"
config.Certificates.KeyName = "chave.key"
config.Certificates.CAName = "chaveCA.crt"
config.Certificates.ServerName = "client"
_, err := os.Stat("config.toml")
if err == nil {
if _, err := toml.DecodeFile("config.toml", &config); err != nil {
fmt.Printf("Error loading config: %v\n", err)
}
}
if err == nil {
config.Certificates.CertName = filepath.Base(config.Certificates.CertName)
config.Certificates.KeyName = filepath.Base(config.Certificates.KeyName)
config.Certificates.CAName = filepath.Base(config.Certificates.CAName)
}
return config
} }
func InitialModel() Model { func InitialModel() Model {
cfg := loadConfig()
s := spinner.New() s := spinner.New()
s.Spinner = spinner.Dot s.Spinner = spinner.Dot
s.Style = SpinnerStyle s.Style = SpinnerStyle
@ -70,12 +135,53 @@ func InitialModel() Model {
Type: FieldTypePassword, Type: FieldTypePassword,
}, },
}), }),
wireguardForm: NewFormStep("Configurações vproxy", []FormField{
{
Id: "privkey",
Label: "Chave Privada",
Placeholder: "",
Type: FieldTypeText,
},
{
Id: "vip",
Label: "IP Virtual",
Default: "127.0.0.1",
Placeholder: "127.0.0.1",
Type: FieldTypeText,
},
{
Id: "psk",
Label: "Pre-Shared Key",
Placeholder: "",
Type: FieldTypeText,
},
{
Id: "proxy_edps",
Label: "Proxy EDPS",
Placeholder: "22:127.0.0.1:22",
Type: FieldTypeText,
},
{
Id: "mtu",
Label: "MTU",
Default: "1380",
Placeholder: "1380",
Type: FieldTypeNumber,
},
{
Id: "proto",
Label: "Protocolo",
Default: "UDP",
Type: FieldTypeSelect,
Options: []string{"UDP", "TCP"},
},
}),
serverForm: NewFormStep("Servidor", []FormField{ serverForm: NewFormStep("Servidor", []FormField{
{ {
Id: "port", Id: "port",
Label: "Porta", Label: "Porta",
Placeholder: "8081", Placeholder: "8081",
Default: "8081",
Default: strconv.FormatInt(cfg.Server.Port, 10),
Type: FieldTypeNumber, Type: FieldTypeNumber,
CharLimit: 4, CharLimit: 4,
}, },
@ -83,14 +189,14 @@ func InitialModel() Model {
Id: "timeout", Id: "timeout",
Label: "Timeout (Segundos)", Label: "Timeout (Segundos)",
Placeholder: "30", Placeholder: "30",
Default: "30",
Default: strconv.FormatInt(cfg.Server.Timeout, 10),
Type: FieldTypeNumber, Type: FieldTypeNumber,
CharLimit: 3, CharLimit: 3,
}, },
{ {
Id: "environment", Id: "environment",
Label: "Ambiente", Label: "Ambiente",
Default: "production",
Default: cfg.Server.Environment,
Type: FieldTypeSelect, Type: FieldTypeSelect,
Options: []string{"development", "production"}, Options: []string{"development", "production"},
}, },
@ -99,7 +205,7 @@ func InitialModel() Model {
{ {
Id: "database_type", Id: "database_type",
Label: "Tipo do Banco", Label: "Tipo do Banco",
Default: "postgres",
Default: cfg.Database.Type,
Type: FieldTypeSelect, Type: FieldTypeSelect,
Options: []string{"postgres", "oracle"}, Options: []string{"postgres", "oracle"},
}, },
@ -107,59 +213,55 @@ func InitialModel() Model {
Id: "database_url", Id: "database_url",
Label: "URL de acesso", Label: "URL de acesso",
Placeholder: "postgres://usuario:senha@banco:5432/app_dono_db", Placeholder: "postgres://usuario:senha@banco:5432/app_dono_db",
Default: "postgres://usuario:senha@banco:5432/app_dono_db",
Default: cfg.Database.URL,
Type: FieldTypeText, Type: FieldTypeText,
}, },
{ {
Id: "max_conns", Id: "max_conns",
Label: "Conexões ativas (máximo)", Label: "Conexões ativas (máximo)",
Placeholder: "10", Placeholder: "10",
Default: "10",
Default: strconv.FormatInt(cfg.Database.MaxConns, 10),
Type: FieldTypeNumber, Type: FieldTypeNumber,
}, },
{ {
Id: "min_conns", Id: "min_conns",
Label: "Conexões ativas (mínimo)", Label: "Conexões ativas (mínimo)",
Placeholder: "2", Placeholder: "2",
Default: "2",
Default: strconv.FormatInt(cfg.Database.MinConns, 10),
Type: FieldTypeNumber, Type: FieldTypeNumber,
}, },
}), }),
certForm: NewFormStep("Certificado", []FormField{ certForm: NewFormStep("Certificado", []FormField{
{ {
Id: "cert_dir_path", Id: "cert_dir_path",
Label: "Caminho para o diretório dos certificados (será montado no container)",
Label: "Caminho para o diretório dos certificados",
Placeholder: "/caminho/para/diretorio", Placeholder: "/caminho/para/diretorio",
Default: "/caminho/para/diretorio",
Default: cfg.Certificates.DirPath,
Type: FieldTypeText, Type: FieldTypeText,
}, },
{ {
Id: "cert_name",
Label: "Nome do arquivo do certificado",
Placeholder: "certificado.crt",
Default: "certificado.crt",
Type: FieldTypeText,
Id: "cert_name",
Label: "Nome do arquivo do certificado",
Default: cfg.Certificates.CertName,
Type: FieldTypeText,
}, },
{ {
Id: "key_name",
Label: "Nome do arquivo da chave",
Placeholder: "chave.key",
Default: "chave.key",
Type: FieldTypeText,
Id: "key_name",
Label: "Nome do arquivo da chave",
Default: cfg.Certificates.KeyName,
Type: FieldTypeText,
}, },
{ {
Id: "ca_name",
Label: "Nome do arquivo da autoridade certificadora",
Placeholder: "chaveCA.crt",
Default: "chaveCA.crt",
Type: FieldTypeText,
Id: "ca_name",
Label: "Nome do arquivo da autoridade certificadora",
Default: cfg.Certificates.CAName,
Type: FieldTypeText,
}, },
{ {
Id: "server_name",
Label: "Nome do servidor",
Placeholder: "client",
Default: "client",
Type: FieldTypeText,
Id: "server_name",
Label: "Nome do servidor",
Default: cfg.Certificates.ServerName,
Type: FieldTypeText,
}, },
}), }),
spinner: s, spinner: s,


+ 4
- 1
internal/tui/steps.go View File

@ -13,7 +13,10 @@ const (
// IP Stuff // IP Stuff
StepIPQuestion StepIPQuestion
StepInstallWireguard
StepWireguardConfig
StepGenerateWireguardFile
StepDownloadWireguard
StepRunWireguard
// Docker Config // Docker Config
StepServerConfig StepServerConfig


+ 101
- 6
internal/tui/update.go View File

@ -9,8 +9,10 @@ import (
) )
const ( const (
imageName = "hub.davinti.com.br:443/app-dono/app-cliente:latest"
configPath = "config.toml"
imageName = "hub.davinti.com.br:443/app-dono/app-cliente:latest"
wireguardImageName = "hub.davinti.com.br:443/davinti-vproxy:latest"
configPath = "config.toml"
wireguardConfigPath = "envs"
) )
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@ -49,10 +51,32 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, cmd return m, cmd
case StepDownloadImage: case StepDownloadImage:
return m.updateDownloadImage(msg) return m.updateDownloadImage(msg)
// Ip & Wireguard
case StepIPQuestion: case StepIPQuestion:
return m.updateIPQuestion(msg) return m.updateIPQuestion(msg)
//case StepInstallWireguard
// return m.updateInstallWireguard(msg)
case StepWireguardConfig:
done, cmd := m.wireguardForm.Update(msg)
if done {
m.configValues.Wireguard = m.wireguardForm.Values()
m.downloadDone = false
m.downloadMessage = ""
m.downloadError = nil
m.currentStep = StepGenerateWireguardFile
return m, GenerateWireguardConfigFile(m.configValues, wireguardConfigPath)
}
return m, cmd
case StepGenerateWireguardFile:
return m.updateGenerateWireguardFile(msg)
case StepDownloadWireguard:
return m.updateDownloadWireguard(msg)
case StepRunWireguard:
return m.updateRunWireguardDocker(msg)
case StepServerConfig: case StepServerConfig:
done, cmd := m.serverForm.Update(msg) done, cmd := m.serverForm.Update(msg)
@ -78,6 +102,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.configValues.Cert = m.certForm.Values() m.configValues.Cert = m.certForm.Values()
m.currentStep = StepGenerateFile m.currentStep = StepGenerateFile
m.finishedFile = false
m.configFileError = nil
return m, GenerateConfigFile(m.configValues, configPath) return m, GenerateConfigFile(m.configValues, configPath)
} }
@ -169,8 +196,73 @@ func (m Model) updateIPQuestion(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil return m, nil
} }
m.currentStep = StepInstallWireguard
return m, nil
m.currentStep = StepWireguardConfig
}
}
return m, nil
}
func (m Model) updateDownloadWireguard(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case ImageDownloadFinishedMsg:
m.downloadDone = true
m.downloadMessage = msg.Message
m.downloadError = msg.Err
if m.downloadError == nil {
m.currentStep = StepRunWireguard
return m, RunWireguardContainer(wireguardConfigPath, m.configValues)
}
case tea.KeyPressMsg:
if m.downloadDone && m.downloadError == nil {
m.currentStep = StepRunWireguard
} else if m.downloadDone {
return m, tea.Quit
}
}
return m, nil
}
func (m Model) updateGenerateWireguardFile(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case ConfigFileMsg:
m.finishedFile = true
m.configFileError = msg.Err
if msg.Err == nil {
m.currentStep = StepDownloadWireguard
return m, DownloadWireguardImageCmd(m.configValues.Login["user"], m.configValues.Login["password"])
}
case tea.KeyPressMsg:
if m.finishedFile && m.configFileError != nil {
return m, tea.Quit
} else if m.finishedFile && m.configFileError == nil {
m.currentStep = StepDownloadWireguard
return m, DownloadWireguardImageCmd(m.configValues.Login["user"], m.configValues.Login["password"])
}
}
return m, nil
}
func (m Model) updateRunWireguardDocker(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case DockerRunMsg:
m.finishedDockerRun = true
m.dockerRunError = msg.Err
case tea.KeyPressMsg:
if m.finishedDockerRun && m.dockerRunError != nil {
return m, tea.Quit
} else if m.finishedDockerRun && m.dockerRunError == nil {
m.currentStep = StepServerConfig
} }
} }
@ -189,6 +281,9 @@ func (m Model) updateGenerateFile(msg tea.Msg) (tea.Model, tea.Cmd) {
} else if m.finishedFile && m.configFileError == nil { } else if m.finishedFile && m.configFileError == nil {
m.currentStep = StepRunDocker m.currentStep = StepRunDocker
m.finishedDockerRun = false
m.dockerRunError = nil
return m, RunAppContainer( return m, RunAppContainer(
imageName, imageName,
"app-dono-cliente", "app-dono-cliente",


+ 15
- 0
internal/tui/view.go View File

@ -36,6 +36,21 @@ func (m Model) View() tea.View {
// IP Stuff // IP Stuff
case StepIPQuestion: case StepIPQuestion:
body = m.viewIPQuestion() body = m.viewIPQuestion()
case StepWireguardConfig:
body = m.wireguardForm.View()
helpMsg = formMsg
case StepGenerateWireguardFile:
body = m.viewGenerateFile()
if m.finishedFile && m.configFileError != nil {
helpMsg = anyKeyOutMsg
}
case StepDownloadWireguard:
body = m.viewDownloadImage()
case StepRunWireguard:
body = m.viewDockerRun()
if m.finishedDockerRun && m.dockerRunError != nil {
helpMsg = anyKeyOutMsg
}
// App Config Stuff // App Config Stuff
case StepServerConfig: case StepServerConfig:


Loading…
Cancel
Save