Skip to content

Commit

Permalink
chore: refactoring
Browse files Browse the repository at this point in the history
Signed-off-by: surajgour-d11 <[email protected]>
  • Loading branch information
surajgour-d11 committed Feb 4, 2025
1 parent 0da6266 commit 93afcc8
Show file tree
Hide file tree
Showing 23 changed files with 277 additions and 268 deletions.
46 changes: 0 additions & 46 deletions cmd/deploy/model.go

This file was deleted.

213 changes: 12 additions & 201 deletions cmd/deploy/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,8 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/charmbracelet/bubbles/progress"
"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/dream11/odin/pkg/ui"
"github.com/dream11/odin/pkg/util"
"io"
"os"
"regexp"
"strings"

"github.com/dream11/odin/internal/service"
"github.com/dream11/odin/pkg/config"
Expand Down Expand Up @@ -57,192 +47,23 @@ func init() {

func execute(cmd *cobra.Command) {
env = config.EnsureEnvPresent(env)
// Add program in context
ctx := cmd.Context()
program := tea.NewProgram(
&Model{
ServiceView: ServiceView{
Name: "Initiating service deployment",
},
},
tea.WithAltScreen(),
)

go func() {
if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") {
deployUsingFiles(ctx, program)
} else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") {
deployUsingServiceNameAndVersion(ctx)
} else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") {
if err := validateLabels(labels); err != nil {
log.Fatal("Invalid labels format: ", err)
}
deployUsingServiceNameAndLabels(ctx)
} else {
log.Fatal("Invalid combination of flags. Use either (service name and version) or (service name and labels) or (definitionFile and provisioningFile).")
}
}()

if _, err := program.Run(); err != nil {
os.Exit(1)
}
}

func (m *Model) Init() tea.Cmd {
m.ServiceDisplayMeta.Progress = progress.New(progress.WithDefaultScaledGradient())
m.ServiceDisplayMeta.Progress.PercentageStyle = ui.ProgressBarStyle
m.ServiceDisplayMeta.Progress.SetPercent(100)
m.ServiceDisplayMeta.Cursor = 0
return nil
}

func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var updateCmds []tea.Cmd
switch msg := msg.(type) {
// Handle updates
case Model:
m.ServiceDisplayMeta.Ready = true
m.ServiceView = msg.ServiceView
if len(m.ServiceView.ComponentsView) > len(m.ServiceDisplayMeta.ComponentDisplayMeta) {
for i := len(m.ServiceDisplayMeta.ComponentDisplayMeta); i < len(m.ServiceView.ComponentsView); i++ {
m.ServiceDisplayMeta.ComponentDisplayMeta = append(m.ServiceDisplayMeta.ComponentDisplayMeta, ComponentDisplayMeta{
LogViewPort: viewport.Model{
Width: m.ServiceDisplayMeta.Width,
Height: 10,
},
})
m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner = spinner.New()
m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Style = ui.SpinnerStyle
m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Points
}
}
// Handle key presses
case tea.KeyMsg:
anyToggled := false
for _, component := range m.ServiceDisplayMeta.ComponentDisplayMeta {
if component.Toggle {
anyToggled = true
break
}
}
switch msg.String() {
case "up":
if m.ServiceDisplayMeta.Cursor > 0 && !anyToggled {
m.ServiceDisplayMeta.Cursor--
}
break

case "down":
if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta)-1 && !anyToggled {
m.ServiceDisplayMeta.Cursor++
}
break

case "enter", " ":
if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta) {
m.ServiceDisplayMeta.ComponentDisplayMeta[m.ServiceDisplayMeta.Cursor].Toggle =
!m.ServiceDisplayMeta.ComponentDisplayMeta[m.ServiceDisplayMeta.Cursor].Toggle
}
break

case "q":
return m, tea.Quit
}

// Handle window resizes
case tea.WindowSizeMsg:
m.ServiceDisplayMeta.Height = msg.Height
m.ServiceDisplayMeta.Width = msg.Width
if m.ServiceDisplayMeta.Ready {
for i := range m.ServiceDisplayMeta.ComponentDisplayMeta {
m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Width = msg.Width
m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Height =
max(util.GetAvailableViewPortHeight(msg.Height, lipgloss.Height("text"), len(m.ServiceDisplayMeta.ComponentDisplayMeta)), 10)
}
}
case spinner.TickMsg:
spinnerUpdateCmds := m.updateSpinners(msg)
return m, tea.Batch(spinnerUpdateCmds...)
}

// Handle keyboard and mouse events in the viewport
updateCmds = append(updateCmds, m.tickSpinners()...)
updateCmds = append(updateCmds, m.updateViewPort(msg)...)

return m, tea.Batch(updateCmds...)
}

func (m *Model) updateViewPort(msg tea.Msg) []tea.Cmd {
var cmds []tea.Cmd
var cmd tea.Cmd
for i := range m.ServiceDisplayMeta.ComponentDisplayMeta {
m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort, cmd =
m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Update(msg)
cmds = append(cmds, cmd)
}
return cmds
}

func (m *Model) updateSpinners(msg tea.Msg) []tea.Cmd {
var cmds []tea.Cmd
var cmd tea.Cmd
for i := range m.ServiceDisplayMeta.ComponentDisplayMeta {
m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner, cmd =
m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Update(msg)
cmds = append(cmds, cmd)
}
return cmds
}

func (m *Model) tickSpinners() []tea.Cmd {
var cmds []tea.Cmd
for i := range m.ServiceDisplayMeta.ComponentDisplayMeta {
cmds = append(cmds, m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Tick)
}
return cmds
}

func (m *Model) View() string {
if !m.ServiceDisplayMeta.Ready {
return ui.H1Style.Render("Initializing service deployment...")
}
var builder strings.Builder

// Build Service View
serviceHeader := util.GetHeaderText(m.ServiceView.Name, m.ServiceView.Action, m.ServiceView.Status, "Service")
builder.WriteString(fmt.Sprintf("%s\n", ui.H1Style.Render(serviceHeader)))
m.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + 6 // to accommodate the percentage text
builder.WriteString(fmt.Sprintf("%s\n", m.ServiceDisplayMeta.Progress.ViewAs(100.0)))
builder.WriteString(fmt.Sprintf("Trace Id: %s\n", ui.TextStyle.Render(m.ServiceView.TraceId)))

for i, componentView := range m.ServiceView.ComponentsView {
componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component")
var componentHeaderText string
if i == m.ServiceDisplayMeta.Cursor {
componentHeaderText = ui.SelectedStyle(ui.H2Style).Render(componentHeader)
} else {
componentHeaderText = ui.H2Style.Render(componentHeader)
}
if m.ServiceView.ComponentsView[i].Status != "IN_PROGRESS" {
m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Pulse
}
builder.WriteString(fmt.Sprintf("%s %s\n", componentHeaderText, m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.View()))
if m.ServiceDisplayMeta.ComponentDisplayMeta[i].Toggle {
// Render logs
logsText := strings.Split(componentView.Content, "\\n")
m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.SetContent(ui.InfoStyle.Render(strings.Join(logsText, "\n")))
builder.WriteString(fmt.Sprintf("%s \n", m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.View()))
if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") {
deployUsingFiles(ctx)
} else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") {
deployUsingServiceNameAndVersion(ctx)
} else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") {
if err := validateLabels(labels); err != nil {
log.Fatal("Invalid labels format: ", err)
}
deployUsingServiceNameAndLabels(ctx)
} else {
log.Fatal("Invalid combination of flags. Use either (service name and version) or (service name and labels) or (definitionFile and provisioningFile).")
}

// Add Footer with operating instructions
builder.WriteString("\n\n")
builder.WriteString(ui.FooterStyle.Render("Use ↑ and ↓ to navigate components, Enter to toggle logs, q to quit"))

return builder.String()
}

func deployUsingFiles(ctx context.Context, program *tea.Program) {
func deployUsingFiles(ctx context.Context) {
definitionData, err := os.ReadFile(definitionFile)
if err != nil {
log.Fatal("Error while reading definition file ", err)
Expand All @@ -264,7 +85,7 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) {
ComponentProvisioningConfig: compProvConfigs,
}

stream, err := serviceClient.DeployService(&ctx, &serviceProto.DeployServiceRequest{
err = serviceClient.DeployService(&ctx, &serviceProto.DeployServiceRequest{
EnvName: env,
ServiceDefinition: &definitionProto,
ProvisioningConfig: provisioningProto,
Expand All @@ -273,16 +94,6 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) {
if err != nil {
log.Fatal("Failed to deploy service ", err)
}
for {
response, err := stream.Recv()
if err != nil {
if errors.Is(err, context.Canceled) || err == io.EOF {
break
}
program.Quit()
}
program.Send(GetServiceDeployModel(response))
}
}

func deployUsingServiceNameAndVersion(ctx context.Context) {
Expand Down
42 changes: 39 additions & 3 deletions internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"context"
"errors"
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/dream11/odin/internal/ui"
"io"
"os"

"github.com/briandowns/spinner"
"github.com/dream11/odin/pkg/constant"
Expand All @@ -21,14 +24,47 @@ type Service struct{}

var responseMap = make(map[string]string)

var program = tea.NewProgram(
&ui.Model{
ServiceView: ui.ServiceView{
Name: "Initiating service deployment",
},
},
tea.WithAltScreen(),
)

// DeployService deploys service
func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) (serviceProto.ServiceService_DeployServiceClient, error) {
func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) error {
conn, requestCtx, err := grpcClient(ctx)
if err != nil {
return nil, err
return err
}
client := serviceProto.NewServiceServiceClient(conn)
return client.DeployService(*requestCtx, request)
stream, err := client.DeployService(*requestCtx, request)
if err != nil {
return err
}

go func() {
for {
response, err := stream.Recv()
if err != nil {
if errors.Is(err, context.Canceled) || err == io.EOF {
break
}
log.Errorf("TraceID: %s", (*requestCtx).Value(constant.TraceIDKey))
program.Quit()
}
if response != nil {
program.Send(ui.GetServiceDeployModel(response))
}
}
}()

if _, err := program.Run(); err != nil {
os.Exit(1)
}
return err
}

func logFailedComponentMessagesOnce(response *serviceProto.ServiceResponse) {
Expand Down
Loading

0 comments on commit 93afcc8

Please sign in to comment.