Skip to content

Commit

Permalink
Grpc fix issues (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
mirzakhany authored Aug 21, 2024
1 parent 32e3d69 commit 5a6b8fb
Show file tree
Hide file tree
Showing 9 changed files with 339 additions and 32 deletions.
9 changes: 6 additions & 3 deletions internal/domain/protofiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ type ProtoFile struct {
}

type ProtoFileSpec struct {
Path string `yaml:"path"`
Package string `yaml:"package"`
Services []string `yaml:"services"`
Path string `yaml:"path"`
// TODO should it be a dedicated type?
IsImportPath bool `yaml:"isImportPath"`
Package string `yaml:"package"`
Services []string `yaml:"services"`
}

func NewProtoFile(name string) *ProtoFile {
Expand All @@ -38,6 +40,7 @@ func CompareProtoFiles(a, b *ProtoFile) bool {
func CompareProtoFileSpecs(a, b ProtoFileSpec) bool {
return a.Path == b.Path &&
a.Package == b.Package &&
a.IsImportPath == b.IsImportPath &&
compareStringSlices(a.Services, b.Services)
}

Expand Down
101 changes: 89 additions & 12 deletions internal/grpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -135,17 +136,89 @@ func (s *Service) GetRequestStruct(id, environmentID string) (string, error) {
return "", err
}

request := dynamicpb.NewMessage(md.Input())
reqJSON, err := (protojson.MarshalOptions{
Indent: " ",
EmitUnpopulated: true,
UseProtoNames: true,
}).Marshal(request)
jsonBytes, err := json.MarshalIndent(generateExampleJSON(md.Input()), "", " ")
if err != nil {
return "", err
return "", fmt.Errorf("failed to marshal to JSON: %w", err)
}

return string(reqJSON), nil
return string(jsonBytes), nil
}

func generateExampleJSON(messageDescriptor protoreflect.MessageDescriptor) map[string]interface{} {
out := make(map[string]interface{})

fields := messageDescriptor.Fields()

castField := func(field protoreflect.FieldDescriptor) any {
var out any
switch field.Kind() {
case protoreflect.StringKind:
out = "string"
case protoreflect.DoubleKind, protoreflect.FloatKind:
out = 123.456
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind,
protoreflect.Fixed64Kind, protoreflect.Int32Kind, protoreflect.Sint32Kind,
protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind,
protoreflect.Sfixed64Kind:
out = 123
case protoreflect.BytesKind:
out = "bytes"
case protoreflect.EnumKind:
enum := field.Enum()
out = string(enum.Values().Get(0).Name())
case protoreflect.BoolKind:
out = true
case protoreflect.MessageKind:
nestedMessageDescriptor := field.Message()
out = generateExampleJSON(nestedMessageDescriptor)
default:
out = "string"
}

return out
}

for i := 0; i < fields.Len(); i++ {
field := fields.Get(i)

// Check if the field is repeated
switch {
case field.IsMap():
// Handle map fields
keyField := field.MapKey()
valueField := field.MapValue()

// Generate a key as a string
var mapKey string
switch keyField.Kind() {
case protoreflect.StringKind:
mapKey = "key_string"
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind,
protoreflect.Fixed32Kind, protoreflect.Sfixed32Kind:
mapKey = "123"
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
protoreflect.Fixed64Kind, protoreflect.Sfixed64Kind:
mapKey = "123456789"
default:
mapKey = "key"
}

mapValue := castField(valueField)
out[string(field.Name())] = map[string]interface{}{
mapKey: mapValue,
}
case field.Cardinality() == protoreflect.Repeated:
// Handle repeated fields
var repeatedValues []interface{}
repeatedValues = append(repeatedValues, castField(field))
out[string(field.Name())] = repeatedValues
default:
// Handle singular fields
out[string(field.Name())] = castField(field)
}
}

return out
}

func (s *Service) Invoke(id, activeEnvironmentID string) (*Response, error) {
Expand Down Expand Up @@ -407,7 +480,7 @@ func (s *Service) GetServices(id, activeEnvironmentID string) ([]domain.GRPCServ
return nil, err
}

protoRegistryFiles, err := ProtoFilesFromDisk(s.getImportPaths(protoFiles, req.Spec.GRPC.ServerInfo.ProtoFiles))
protoRegistryFiles, err := ProtoFilesFromDisk(GetImportPaths(protoFiles, req.Spec.GRPC.ServerInfo.ProtoFiles))
if err != nil {
return nil, err
}
Expand All @@ -432,7 +505,7 @@ func (s *Service) getActiveEnvironment(id string) *domain.Environment {
return activeEnvironment
}

func (s *Service) getImportPaths(protoFiles []*domain.ProtoFile, files []string) ([]string, []string) {
func GetImportPaths(protoFiles []*domain.ProtoFile, files []string) ([]string, []string) {
importPaths := make([]string, 0, len(protoFiles)+len(files))
fileNames := make([]string, 0, len(protoFiles)+len(files))
for _, file := range files {
Expand All @@ -442,8 +515,12 @@ func (s *Service) getImportPaths(protoFiles []*domain.ProtoFile, files []string)
}

for _, protoFile := range protoFiles {
importPaths = append(importPaths, filepath.Dir(protoFile.Spec.Path))
fileNames = append(fileNames, filepath.Base(protoFile.Spec.Path))
if protoFile.Spec.IsImportPath {
importPaths = append(importPaths, protoFile.Spec.Path)
} else {
importPaths = append(importPaths, filepath.Dir(protoFile.Spec.Path))
fileNames = append(fileNames, filepath.Base(protoFile.Spec.Path))
}
}

return importPaths, fileNames
Expand Down
4 changes: 4 additions & 0 deletions ui/explorer/explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import (
"gioui.org/x/explorer"
)

var (
ErrUserDecline = explorer.ErrUserDecline
)

type Explorer struct {
expl *explorer.Explorer
w *app.Window
Expand Down
59 changes: 48 additions & 11 deletions ui/pages/protofiles/controller.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package protofiles

import (
"fmt"
"errors"
"path/filepath"

"google.golang.org/protobuf/reflect/protoreflect"
Expand All @@ -11,6 +11,7 @@ import (
"github.com/chapar-rest/chapar/internal/repository"
"github.com/chapar-rest/chapar/internal/state"
"github.com/chapar-rest/chapar/ui/explorer"
"github.com/chapar-rest/chapar/ui/widgets"
)

type Controller struct {
Expand All @@ -33,6 +34,7 @@ func NewController(view *View, state *state.ProtoFiles, repo repository.Reposito
view.SetOnAdd(c.onAdd)
view.SetOnDelete(c.onDelete)
view.SetOnDeleteSelected(c.onDeleteSelected)
view.SetOnAddImportPath(c.addPath)

return c
}
Expand All @@ -47,10 +49,40 @@ func (c *Controller) LoadData() error {
return nil
}

func (c *Controller) showError(title, message string) {
c.view.ShowPrompt(title, message, widgets.ModalTypeErr, func(selectedOption string, remember bool) {
if selectedOption == "Ok" {
c.view.HidePrompt()
return
}
}, []widgets.Option{{Text: "Ok"}}...)
}

func (c *Controller) addPath(path string) {
// get last part of the path as the name
fileName := filepath.Base(path)
proto := domain.NewProtoFile(fileName)
filePath, err := c.repo.GetNewProtoFilePath(fileName)
if err != nil {
c.showError("Failed to get new path", err.Error())
return
}

proto.FilePath = filePath.Path
proto.MetaData.Name = filePath.NewName
proto.Spec.IsImportPath = true
proto.Spec.Path = path
c.state.AddProtoFile(proto)
c.saveProtoFileToDisc(proto.MetaData.ID)
c.view.AddItem(proto)
}

func (c *Controller) onAdd() {
c.explorer.ChoseFile(func(result explorer.Result) {
if result.Error != nil {
fmt.Println("failed to get file", result.Error)
if !errors.Is(result.Error, explorer.ErrUserDecline) {
c.showError("Failed to open file", result.Error.Error())
}
return
}

Expand All @@ -59,13 +91,13 @@ func (c *Controller) onAdd() {
proto := domain.NewProtoFile(fileName)
filePath, err := c.repo.GetNewProtoFilePath(proto.MetaData.Name)
if err != nil {
fmt.Println("failed to get new proto file path", err)
c.showError("Failed to get new proto file path", err.Error())
return
}

pInfo, err := c.getProtoInfo(fileDir, fileName)
if err != nil {
fmt.Println("failed to get proto info", err)
c.showError("Failed to get proto info", err.Error())
return
}

Expand All @@ -87,7 +119,12 @@ type info struct {
}

func (c *Controller) getProtoInfo(path, filename string) (*info, error) {
pInfo, err := grpc.ProtoFilesFromDisk([]string{path}, []string{filename})
protoFiles, err := c.state.LoadProtoFilesFromDisk()
if err != nil {
return nil, err
}

pInfo, err := grpc.ProtoFilesFromDisk(grpc.GetImportPaths(protoFiles, []string{filepath.Join(path, filename)}))
if err != nil {
return nil, err
}
Expand All @@ -108,12 +145,12 @@ func (c *Controller) getProtoInfo(path, filename string) (*info, error) {
func (c *Controller) onDelete(p *domain.ProtoFile) {
pr := c.state.GetProtoFile(p.MetaData.ID)
if pr == nil {
fmt.Println("failed to get proto-file", p.MetaData.ID)
c.showError("Failed to get proto-file", "failed to get proto-file")
return
}

if err := c.state.RemoveProtoFile(pr, false); err != nil {
fmt.Println("failed to remove proto-file", err)
c.showError("Failed to remove proto-file", err.Error())
return
}

Expand All @@ -124,12 +161,12 @@ func (c *Controller) onDeleteSelected(ids []string) {
for _, id := range ids {
pr := c.state.GetProtoFile(id)
if pr == nil {
fmt.Println("failed to get proto-file", id)
c.showError("Failed to get proto-file", "failed to get proto-file")
continue
}

if err := c.state.RemoveProtoFile(pr, false); err != nil {
fmt.Println("failed to remove proto-file", err)
c.showError("Failed to remove proto-file", err.Error())
continue
}

Expand All @@ -140,12 +177,12 @@ func (c *Controller) onDeleteSelected(ids []string) {
func (c *Controller) saveProtoFileToDisc(id string) {
ws := c.state.GetProtoFile(id)
if ws == nil {
fmt.Println("failed to get proto-file", id)
c.showError("Failed to get proto-file", "failed to get proto-file")
return
}

if err := c.state.UpdateProtoFile(ws, false); err != nil {
fmt.Println("failed to update proto-file", err)
c.showError("Failed to update proto-file", err.Error())
return
}
}
Loading

0 comments on commit 5a6b8fb

Please sign in to comment.