remove the need to setup .env and ask for porkbun credential name directly
This commit is contained in:
parent
f9c8ed4f6c
commit
ec94e6ad46
7 changed files with 164 additions and 47 deletions
|
|
@ -1,33 +1,164 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"git.juancwu.dev/juancwu/porkbacon/internal/config"
|
||||
"fmt"
|
||||
|
||||
"git.juancwu.dev/juancwu/porkbacon/internal/pass"
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
const (
|
||||
StateInit uint = iota
|
||||
StateRetrivePorkbunCredentials
|
||||
StateIdle
|
||||
)
|
||||
|
||||
type App struct {
|
||||
cfg *config.Config
|
||||
state uint
|
||||
|
||||
apiKeyName string
|
||||
secretApiKeyName string
|
||||
apiKey string
|
||||
secretKey string
|
||||
loading bool
|
||||
|
||||
textInput textinput.Model
|
||||
spinner spinner.Model
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
func New(cfg *config.Config) App {
|
||||
return App{cfg: cfg}
|
||||
func New() App {
|
||||
ti := textinput.New()
|
||||
ti.Placeholder = "Pass/Name"
|
||||
ti.Focus()
|
||||
ti.Width = 20
|
||||
|
||||
s := spinner.New()
|
||||
s.Spinner = spinner.Dot
|
||||
|
||||
return App{
|
||||
state: StateInit,
|
||||
textInput: ti,
|
||||
spinner: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (a App) Init() tea.Cmd {
|
||||
return nil
|
||||
return tea.Sequence(textinput.Blink, a.spinner.Tick)
|
||||
}
|
||||
|
||||
func (a App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
var cmd tea.Cmd
|
||||
var key string
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
case "ctrl+c":
|
||||
return a, tea.Quit
|
||||
default:
|
||||
key = msg.String()
|
||||
}
|
||||
}
|
||||
return a, nil
|
||||
|
||||
if a.err != nil {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
if a.state == StateInit && key == "enter" {
|
||||
return a.handleEnter()
|
||||
}
|
||||
|
||||
if a.state == StateRetrivePorkbunCredentials && !a.loading {
|
||||
return a.retrievePorkbunCredentials()
|
||||
}
|
||||
|
||||
a.textInput, cmd = a.textInput.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
a.spinner, cmd = a.spinner.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
return a, tea.Sequence(cmds...)
|
||||
}
|
||||
|
||||
func (a App) View() string {
|
||||
return "porkbacon app"
|
||||
if a.err != nil {
|
||||
return a.err.Error()
|
||||
}
|
||||
|
||||
if a.loading {
|
||||
return fmt.Sprintf("%s Loading...", a.spinner.View())
|
||||
}
|
||||
|
||||
switch a.state {
|
||||
case StateInit:
|
||||
return a.renderPorkbunCredentialForm()
|
||||
case StateIdle:
|
||||
return fmt.Sprintf("API key: %s\nSecret Key: %s\n\n", a.apiKey, a.secretKey)
|
||||
}
|
||||
return "Invalid state"
|
||||
}
|
||||
|
||||
func (a *App) renderPorkbunCredentialForm() string {
|
||||
if a.apiKeyName == "" {
|
||||
return fmt.Sprintf("Enter Porkbun API Key Name:\n%s\n\n", a.textInput.View())
|
||||
}
|
||||
|
||||
if a.secretApiKeyName == "" {
|
||||
return fmt.Sprintf("Enter Porkbun Secret API Key Name:\n%s\n\n", a.textInput.View())
|
||||
}
|
||||
|
||||
return "Invalid state"
|
||||
}
|
||||
|
||||
func (a *App) handleEnter() (tea.Model, tea.Cmd) {
|
||||
switch a.state {
|
||||
case StateInit:
|
||||
if a.apiKeyName == "" && a.textInput.Value() != "" {
|
||||
a.apiKeyName = a.textInput.Value()
|
||||
a.textInput.Reset()
|
||||
} else if a.secretApiKeyName == "" && a.textInput.Value() != "" {
|
||||
a.secretApiKeyName = a.textInput.Value()
|
||||
a.textInput.Reset()
|
||||
a.state = StateRetrivePorkbunCredentials
|
||||
}
|
||||
}
|
||||
|
||||
return *a, nil
|
||||
}
|
||||
|
||||
func (a *App) retrievePorkbunCredentials() (tea.Model, tea.Cmd) {
|
||||
if a.apiKeyName == "" || a.secretApiKeyName == "" {
|
||||
panic(fmt.Errorf("Porkbun credentials incomplete. Either API key or secret API key not defined."))
|
||||
}
|
||||
|
||||
a.loading = true
|
||||
|
||||
apiKey, err := pass.Get(a.apiKeyName)
|
||||
if err != nil {
|
||||
a.err = err
|
||||
a.state = StateIdle
|
||||
a.loading = false
|
||||
return *a, nil
|
||||
}
|
||||
|
||||
secretKey, err := pass.Get(a.secretApiKeyName)
|
||||
if err != nil {
|
||||
a.err = err
|
||||
a.state = StateIdle
|
||||
a.loading = false
|
||||
return *a, nil
|
||||
}
|
||||
|
||||
a.apiKey = apiKey
|
||||
a.secretKey = secretKey
|
||||
a.state = StateIdle
|
||||
a.loading = false
|
||||
|
||||
return *a, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
PorkbunApiKeyName string
|
||||
PorkbunSecretApiKeyName string
|
||||
}
|
||||
|
||||
func Load() *Config {
|
||||
godotenv.Load()
|
||||
|
||||
cfg := &Config{
|
||||
PorkbunApiKeyName: envRequired("PORKBUN_API_KEY_NAME"),
|
||||
PorkbunSecretApiKeyName: envRequired("PORKBUN_SECRET_API_KEY_NAME"),
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func envRequired(key string) string {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok || value == "" {
|
||||
fmt.Printf("Error: required environment variable %s not set.\n", key)
|
||||
os.Exit(1)
|
||||
}
|
||||
return value
|
||||
}
|
||||
18
internal/pass/pass.go
Normal file
18
internal/pass/pass.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package pass
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Get(name string) (string, error) {
|
||||
cmd := exec.Command("pass", "show", name)
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("command execution failed: %w", err)
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(output)), nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue