add action items menu
This commit is contained in:
parent
4b92d2e7c4
commit
4266bfbfc2
5 changed files with 172 additions and 20 deletions
2
go.mod
2
go.mod
|
|
@ -5,7 +5,6 @@ go 1.25.6
|
||||||
require (
|
require (
|
||||||
github.com/charmbracelet/bubbles v0.21.0
|
github.com/charmbracelet/bubbles v0.21.0
|
||||||
github.com/charmbracelet/bubbletea v1.3.10
|
github.com/charmbracelet/bubbletea v1.3.10
|
||||||
github.com/joho/godotenv v1.5.1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
@ -25,6 +24,7 @@ require (
|
||||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/sahilm/fuzzy v0.1.1 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
golang.org/x/sys v0.36.0 // indirect
|
golang.org/x/sys v0.36.0 // indirect
|
||||||
golang.org/x/text v0.3.8 // indirect
|
golang.org/x/text v0.3.8 // indirect
|
||||||
|
|
|
||||||
10
go.sum
10
go.sum
|
|
@ -2,6 +2,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
|
||||||
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-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
|
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||||
|
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
|
||||||
|
|
@ -14,12 +16,14 @@ github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7
|
||||||
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
|
@ -37,6 +41,8 @@ github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||||
|
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"git.juancwu.dev/juancwu/porkbacon/internal/pass"
|
"git.juancwu.dev/juancwu/porkbacon/internal/pass"
|
||||||
"git.juancwu.dev/juancwu/porkbacon/internal/porkbun"
|
"git.juancwu.dev/juancwu/porkbacon/internal/porkbun"
|
||||||
|
"github.com/charmbracelet/bubbles/list"
|
||||||
"github.com/charmbracelet/bubbles/spinner"
|
"github.com/charmbracelet/bubbles/spinner"
|
||||||
"github.com/charmbracelet/bubbles/textinput"
|
"github.com/charmbracelet/bubbles/textinput"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|
@ -13,7 +14,9 @@ import (
|
||||||
const (
|
const (
|
||||||
StateInit uint = iota
|
StateInit uint = iota
|
||||||
StateLoadingCredentials
|
StateLoadingCredentials
|
||||||
StateIdle
|
StateMenu
|
||||||
|
StateExecuting
|
||||||
|
StateResult
|
||||||
)
|
)
|
||||||
|
|
||||||
type CredentialsLoadedMsg struct {
|
type CredentialsLoadedMsg struct {
|
||||||
|
|
@ -21,8 +24,20 @@ type CredentialsLoadedMsg struct {
|
||||||
SecretKey string
|
SecretKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PingResultMsg struct {
|
||||||
|
IP string
|
||||||
|
}
|
||||||
|
|
||||||
type ErrMsg error
|
type ErrMsg error
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
title, desc string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i item) Title() string { return i.title }
|
||||||
|
func (i item) Description() string { return i.desc }
|
||||||
|
func (i item) FilterValue() string { return i.title }
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
state uint
|
state uint
|
||||||
|
|
||||||
|
|
@ -32,7 +47,9 @@ type App struct {
|
||||||
|
|
||||||
textInput textinput.Model
|
textInput textinput.Model
|
||||||
spinner spinner.Model
|
spinner spinner.Model
|
||||||
|
list list.Model
|
||||||
|
|
||||||
|
result string
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,10 +62,24 @@ func New() App {
|
||||||
s := spinner.New()
|
s := spinner.New()
|
||||||
s.Spinner = spinner.Dot
|
s.Spinner = spinner.Dot
|
||||||
|
|
||||||
|
items := []list.Item{
|
||||||
|
item{title: "Domain: List All", desc: "List all domains in your account"},
|
||||||
|
item{title: "Domain: Get Details", desc: "Get details for a specific domain"},
|
||||||
|
item{title: "DNS: Retrieve Records", desc: "Retrieve DNS records for a domain"},
|
||||||
|
item{title: "DNS: Create Record", desc: "Create a new DNS record"},
|
||||||
|
item{title: "DNS: Edit Record", desc: "Edit an existing DNS record"},
|
||||||
|
item{title: "DNS: Delete Record", desc: "Delete a DNS record"},
|
||||||
|
item{title: "Util: Ping", desc: "Ping Porkbun"},
|
||||||
|
}
|
||||||
|
|
||||||
|
l := list.New(items, list.NewDefaultDelegate(), 0, 0)
|
||||||
|
l.Title = "Porkbun Actions"
|
||||||
|
|
||||||
return App{
|
return App{
|
||||||
state: StateInit,
|
state: StateInit,
|
||||||
textInput: ti,
|
textInput: ti,
|
||||||
spinner: s,
|
spinner: s,
|
||||||
|
list: l,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,20 +96,38 @@ func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c":
|
case "ctrl+c":
|
||||||
return a, tea.Quit
|
return a, tea.Quit
|
||||||
|
case "esc":
|
||||||
|
if a.state == StateResult {
|
||||||
|
a.state = StateMenu
|
||||||
|
a.result = ""
|
||||||
|
a.err = nil
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
case "enter":
|
case "enter":
|
||||||
if a.state == StateInit {
|
if a.state == StateInit {
|
||||||
return a.handleEnter()
|
return a.handleEnter()
|
||||||
|
} else if a.state == StateMenu {
|
||||||
|
return a.handleMenuEnter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case tea.WindowSizeMsg:
|
||||||
|
a.list.SetWidth(msg.Width)
|
||||||
|
a.list.SetHeight(msg.Height)
|
||||||
|
|
||||||
case CredentialsLoadedMsg:
|
case CredentialsLoadedMsg:
|
||||||
a.client = porkbun.New(msg.APIKey, msg.SecretKey)
|
a.client = porkbun.New(msg.APIKey, msg.SecretKey)
|
||||||
a.state = StateIdle
|
a.state = StateMenu
|
||||||
|
return a, nil
|
||||||
|
|
||||||
|
case PingResultMsg:
|
||||||
|
a.result = fmt.Sprintf("Ping successful!\nYour IP: %s", msg.IP)
|
||||||
|
a.state = StateResult
|
||||||
return a, nil
|
return a, nil
|
||||||
|
|
||||||
case ErrMsg:
|
case ErrMsg:
|
||||||
a.err = msg
|
a.err = msg
|
||||||
a.state = StateIdle // Or stay in error state
|
a.state = StateResult // Show error in result view
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,17 +136,26 @@ func (a *App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.state == StateLoadingCredentials {
|
if a.state == StateLoadingCredentials || a.state == StateExecuting {
|
||||||
a.spinner, cmd = a.spinner.Update(msg)
|
a.spinner, cmd = a.spinner.Update(msg)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.state == StateMenu {
|
||||||
|
a.list, cmd = a.list.Update(msg)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
return a, tea.Sequence(cmds...)
|
return a, tea.Sequence(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) View() string {
|
func (a *App) View() string {
|
||||||
|
if a.state == StateResult {
|
||||||
|
content := a.result
|
||||||
if a.err != nil {
|
if a.err != nil {
|
||||||
return fmt.Sprintf("Error: %v\n\nPress Ctrl+C to quit.", a.err)
|
content = fmt.Sprintf("Error: %v", a.err)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s\n\n(Press Esc to go back)", content)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch a.state {
|
switch a.state {
|
||||||
|
|
@ -105,20 +163,14 @@ func (a *App) View() string {
|
||||||
return a.renderPorkbunCredentialForm()
|
return a.renderPorkbunCredentialForm()
|
||||||
case StateLoadingCredentials:
|
case StateLoadingCredentials:
|
||||||
return fmt.Sprintf("%s Loading credentials...", a.spinner.View())
|
return fmt.Sprintf("%s Loading credentials...", a.spinner.View())
|
||||||
case StateIdle:
|
case StateMenu:
|
||||||
return fmt.Sprintf("Ready!\nAPI Key: %s...\nSecret: %s...\n",
|
return a.list.View()
|
||||||
mask(a.client.APIKey), mask(a.client.SecretAPIKey))
|
case StateExecuting:
|
||||||
|
return fmt.Sprintf("%s Executing...", a.spinner.View())
|
||||||
}
|
}
|
||||||
return "Invalid state"
|
return "Invalid state"
|
||||||
}
|
}
|
||||||
|
|
||||||
func mask(s string) string {
|
|
||||||
if len(s) > 4 {
|
|
||||||
return s[:4] + "...."
|
|
||||||
}
|
|
||||||
return "...."
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) renderPorkbunCredentialForm() string {
|
func (a *App) renderPorkbunCredentialForm() string {
|
||||||
title := "Enter Porkbun API Key Name (pass entry):"
|
title := "Enter Porkbun API Key Name (pass entry):"
|
||||||
if a.apiKeyName != "" {
|
if a.apiKeyName != "" {
|
||||||
|
|
@ -151,6 +203,30 @@ func (a *App) handleEnter() (tea.Model, tea.Cmd) {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) handleMenuEnter() (tea.Model, tea.Cmd) {
|
||||||
|
i, ok := a.list.SelectedItem().(item)
|
||||||
|
if !ok {
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch i.title {
|
||||||
|
case "Util: Ping":
|
||||||
|
a.state = StateExecuting
|
||||||
|
return a, a.performPing()
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) performPing() tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
resp, err := a.client.Ping()
|
||||||
|
if err != nil {
|
||||||
|
return ErrMsg(err)
|
||||||
|
}
|
||||||
|
return PingResultMsg{IP: resp.YourIP}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func retrievePorkbunCredentialsCmd(apiKeyName, secretKeyName string) tea.Cmd {
|
func retrievePorkbunCredentialsCmd(apiKeyName, secretKeyName string) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
apiKey, err := pass.Get(apiKeyName)
|
apiKey, err := pass.Get(apiKeyName)
|
||||||
|
|
|
||||||
|
|
@ -25,3 +25,49 @@ func New(apiKey, secretKey string) *Client {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Ping() (*PingResponse, error) {
|
||||||
|
reqBody := PingRequest{
|
||||||
|
BaseRequest: BaseRequest{
|
||||||
|
APIKey: c.APIKey,
|
||||||
|
SecretAPIKey: c.SecretAPIKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp PingResponse
|
||||||
|
err := c.post("/ping", reqBody, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) post(endpoint string, body interface{}, target interface{}) error {
|
||||||
|
jsonBody, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal request body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", BaseURL+endpoint, bytes.NewBuffer(jsonBody))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
res, err := c.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("request failed: %w", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("API returned error status: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
|
||||||
|
return fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
24
internal/porkbun/models.go
Normal file
24
internal/porkbun/models.go
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package porkbun
|
||||||
|
|
||||||
|
// BaseRequest contains the authentication fields required for most Porkbun API calls.
|
||||||
|
type BaseRequest struct {
|
||||||
|
APIKey string `json:"apikey"`
|
||||||
|
SecretAPIKey string `json:"secretapikey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseResponse contains the common fields returned by the Porkbun API.
|
||||||
|
type BaseResponse struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingRequest is used to verify credentials.
|
||||||
|
type PingRequest struct {
|
||||||
|
BaseRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingResponse is the response from the ping endpoint.
|
||||||
|
type PingResponse struct {
|
||||||
|
BaseResponse
|
||||||
|
YourIP string `json:"yourIp"`
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue