Skip to content

Commit

Permalink
feat(cmd): complete poll logic and prettify with a spinner
Browse files Browse the repository at this point in the history
  • Loading branch information
rektdeckard committed Jul 19, 2024
1 parent 81a7e15 commit 55c77b1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 32 deletions.
97 changes: 65 additions & 32 deletions cmd/lk/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"net/url"
"time"

"github.com/charmbracelet/huh/spinner"
"github.com/urfave/cli/v3"
)

Expand All @@ -36,6 +37,43 @@ const (
claimSessionEndpoint = "/cli/claim"
)

var (
disconnect bool
timeout int64
interval int64
authClient AuthClient
AuthCommands = []*cli.Command{
{
Name: "auth",
Usage: "Authenticate the CLI via the browser to permit advanced actions",
Category: "Core",
Before: createAuthClient,
Action: handleAuth,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "d",
Aliases: []string{"disconnect"},
Destination: &disconnect,
},
&cli.IntFlag{
Name: "t",
Aliases: []string{"timeout"},
Usage: "Number of `SECONDS` to attempt authentication before giving up",
Destination: &timeout,
Value: 60,
},
&cli.IntFlag{
Name: "i",
Aliases: []string{"poll-interval"},
Usage: "Number of `SECONDS` between poll requests to verify authentication",
Destination: &interval,
Value: 4,
},
},
},
}
)

type CreateTokenResponse struct {
Identifier string
Token string
Expand Down Expand Up @@ -78,7 +116,7 @@ func (a *AuthClient) GetVerificationToken(subdomain string) (*CreateTokenRespons
return &a.verificationToken, nil
}

func (a *AuthClient) ClaimSession() (*CreateTokenResponse, error) {
func (a *AuthClient) ClaimSession(ctx context.Context) (*CreateTokenResponse, error) {
if a.verificationToken.Token == "" || time.Now().Unix() > a.verificationToken.Expires {
return nil, errors.New("session expired")
}
Expand All @@ -92,11 +130,20 @@ func (a *AuthClient) ClaimSession() (*CreateTokenResponse, error) {
params.Add("t", a.verificationToken.Token)
reqURL.RawQuery = params.Encode()

resp, err := a.client.Get(reqURL.String())
req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil)
if err != nil {
return nil, err
}
resp, err := a.client.Do(req)
if err != nil {
return nil, err
}

if resp.StatusCode == http.StatusUnauthorized {
// Not yet approved
return nil, nil
}

sessionToken := &CreateTokenResponse{}
err = json.NewDecoder(resp.Body).Decode(&sessionToken)
if err != nil {
Expand All @@ -121,27 +168,6 @@ func NewAuthClient(client *http.Client, baseURL string) *AuthClient {
return a
}

var (
disconnect bool
authClient AuthClient
AuthCommands = []*cli.Command{
{
Name: "auth",
Usage: "Add or remove projects and view existing project properties",
Category: "Core",
Before: createAuthClient,
Action: handleAuth,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "d",
Aliases: []string{"disconnect"},
Destination: &disconnect,
},
},
},
}
)

func createAuthClient(ctx context.Context, cmd *cli.Command) error {
if err := loadProjectConfig(ctx, cmd); err != nil {
return err
Expand Down Expand Up @@ -179,30 +205,37 @@ func tryAuthIfNeeded(ctx context.Context, cmd *cli.Command) error {
params.Add("t", token.Token)
authURL.RawQuery = params.Encode()

fmt.Println(authURL)
fmt.Printf("Please confirm access by visiting:\n\n %s\n\n", authURL.String())

if err := spinner.New().
Title("Awaiting confirmation...").
Action(func() { err = pollClaim(ctx, cmd) }).
Run(); err != nil {
return err
}

return pollClaim(ctx, cmd)
return err
}

func pollClaim(context.Context, *cli.Command) error {
func pollClaim(ctx context.Context, _ *cli.Command) error {
claim := make(chan *CreateTokenResponse)
cancel := make(chan error)
go func() {
for {
fmt.Println("Polling...")
time.Sleep(10 * time.Second)
session, err := authClient.ClaimSession()
time.Sleep(time.Duration(interval) * time.Second)
session, err := authClient.ClaimSession(ctx)
if err != nil {
cancel <- err
return
}
fmt.Println(session)
claim <- session
if session != nil {
claim <- session
}
}
}()

select {
case <-time.After(1 * time.Minute):
case <-time.After(time.Duration(timeout) * time.Second):
return errors.New("session claim timed out")
case err := <-cancel:
return err
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/bubbles v0.18.0 // indirect
github.com/charmbracelet/bubbletea v0.26.4 // indirect
github.com/charmbracelet/huh/spinner v0.0.0-20240714135825-43e9eb5aeab6 // indirect
github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/charmbracelet/x/exp/strings v0.0.0-20240617190524-788ec55faed1 // indirect
github.com/charmbracelet/x/input v0.1.2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkim
github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0=
github.com/charmbracelet/huh v0.5.1 h1:t5j6g9sMjAE2a9AQuc4lNL7pf/0X4WdHiiMGkL8v/aM=
github.com/charmbracelet/huh v0.5.1/go.mod h1:gs7b2brpzXkY0PBWUqJrlzvOowTCL0vNAR6OTItc+kA=
github.com/charmbracelet/huh/spinner v0.0.0-20240714135825-43e9eb5aeab6 h1:Wey8Un1qEEHI18y0HOs3K2HBBb9aEssoDmQo1+Idpuo=
github.com/charmbracelet/huh/spinner v0.0.0-20240714135825-43e9eb5aeab6/go.mod h1:CrXBZnOWs3zpyppOZZS7lu2CpLq2jx6U5chL/frRG/E=
github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
Expand Down

0 comments on commit 55c77b1

Please sign in to comment.