Skip to content

Commit

Permalink
checkpoint, use interfaces to parse correct template given input, fix…
Browse files Browse the repository at this point in the history
… tests
  • Loading branch information
bthaile committed Nov 29, 2023
1 parent 23ed3d0 commit f9ff459
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 81 deletions.
2 changes: 1 addition & 1 deletion CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @chasefleming @bjartek
* @chasefleming @bjartek @bthaile
173 changes: 150 additions & 23 deletions flixkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,46 @@ package flixkit

import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/fs"
"log"
"net/http"
"net/url"
"os"

v1_1 "github.com/onflow/flixkit-go/flixkitv1_1"
)

type FlowInteractionTemplateExecution struct {
Network string
Cadence string
IsTransaciton bool
IsScript bool
}

type FlowInteractionTemplateVersion struct {
FVersion string `json:"f_version"`
}

type Generator interface {
Generate(ctx context.Context, code string, preFill *FlowInteractionTemplate) (*FlowInteractionTemplate, error)
}

type FlowInteractionTemplateCadence interface {
GetAndReplaceCadenceImports(templateName string) (*FlowInteractionTemplateExecution, error)
IsTransaction() bool
IsScript() bool
}

type FlixService interface {
GetFlixRaw(ctx context.Context, templateName string) (string, error)
GetFlix(ctx context.Context, templateName string) (*FlowInteractionTemplate, error)
GetFlix(ctx context.Context, templateName string) (string, error)
GetFlixByIDRaw(ctx context.Context, templateID string) (string, error)
GetFlixByID(ctx context.Context, templateID string) (*FlowInteractionTemplate, error)
GetFlixByID(ctx context.Context, templateID string) (string, error)
GetAndReplaceCadenceImports(ctx context.Context, templateName string, network string) (*FlowInteractionTemplateExecution, error)
}

type flixServiceImpl struct {
Expand Down Expand Up @@ -47,48 +70,41 @@ func (s *flixServiceImpl) GetFlixRaw(ctx context.Context, templateName string) (
return FetchFlixWithContext(ctx, url)
}

func (s *flixServiceImpl) GetFlix(ctx context.Context, templateName string) (*FlowInteractionTemplate, error) {
func (s *flixServiceImpl) GetFlix(ctx context.Context, templateName string) (string, error) {
template, err := s.GetFlixRaw(ctx, templateName)
if err != nil {
return nil, err
}

parsedTemplate, err := ParseFlix(template)
if err != nil {
return nil, err
return "", err
}

return parsedTemplate, nil
return template, nil
}

func (s *flixServiceImpl) GetFlixByIDRaw(ctx context.Context, templateID string) (string, error) {
url := fmt.Sprintf("%s/%s", s.config.FlixServerURL, templateID)
return FetchFlixWithContext(ctx, url)
}

func (s *flixServiceImpl) GetFlixByID(ctx context.Context, templateID string) (*FlowInteractionTemplate, error) {
func (s *flixServiceImpl) GetFlixByID(ctx context.Context, templateID string) (string, error) {
template, err := s.GetFlixByIDRaw(ctx, templateID)
if err != nil {
return nil, err
}

parsedTemplate, err := ParseFlix(template)
if err != nil {
return nil, err
return "", err
}

return parsedTemplate, nil
return template, nil
}

func ParseFlix(template string) (*FlowInteractionTemplate, error) {
var flowTemplate FlowInteractionTemplate
func GetTemplateVersion(template string) (string, error) {
var flowTemplate FlowInteractionTemplateVersion

err := json.Unmarshal([]byte(template), &flowTemplate)
if err != nil {
return nil, err
return "", err
}

return &flowTemplate, nil
if flowTemplate.FVersion == "" {
return "", fmt.Errorf("version not found")
}

return flowTemplate.FVersion, nil
}

func FetchFlixWithContext(ctx context.Context, url string) (string, error) {
Expand All @@ -114,3 +130,114 @@ func FetchFlixWithContext(ctx context.Context, url string) (string, error) {

return string(body), nil
}

func (s *flixServiceImpl) GetAndReplaceCadenceImports(ctx context.Context, templateName string, network string) (*FlowInteractionTemplateExecution, error) {
template, err := s.getTemplate(ctx, templateName)
if err != nil {
return nil, err
}
var cadenceCode string
var isScript bool
var isTransaction bool
if parsedTemplate, err := v1_1.ParseFlix(template); err == nil {
cadenceCode, err = parsedTemplate.GetAndReplaceCadenceImports(network)
if err != nil {
return nil, err
}
isScript = parsedTemplate.IsScript()
isTransaction = parsedTemplate.IsTransaction()
}
if parsedTemplate, err := ParseFlix(template); err == nil {
cadenceCode, err = parsedTemplate.GetAndReplaceCadenceImports(network)
if err != nil {
return nil, err
}
isScript = parsedTemplate.IsScript()
isTransaction = parsedTemplate.IsTransaction()
}

return &FlowInteractionTemplateExecution{
Network: network,
Cadence: cadenceCode,
IsTransaciton: isTransaction,
IsScript: isScript,
}, nil
}

type flixQueryTypes string

const (
flixName flixQueryTypes = "name"
flixPath flixQueryTypes = "path"
flixId flixQueryTypes = "id"
flixUrl flixQueryTypes = "url"
)

func isHex(str string) bool {
if len(str) != 64 {
return false
}
_, err := hex.DecodeString(str)
return err == nil
}

func isPath(path string) bool {
_, err := os.Stat(path)
return err == nil
}

func isUrl(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}
func getType(s string) flixQueryTypes {
switch {
case isPath(s):
return flixPath
case isHex(s):
return flixId
case isUrl(s):
return flixUrl
default:
return flixName
}
}

func (s *flixServiceImpl) getTemplate(ctx context.Context, flixQuery string) (string, error) {
var template string
var err error
switch getType(flixQuery) {
case flixId:
template, err = s.GetFlixByID(ctx, flixQuery)
if err != nil {
return "", fmt.Errorf("could not find flix with id %s: %w", flixQuery, err)
}

case flixName:
template, err = s.GetFlix(ctx, flixQuery)
if err != nil {
return "", fmt.Errorf("could not find flix with name %s: %w", flixQuery, err)
}

case flixPath:
file, err := s.config.FileReader.ReadFile(flixQuery)
if err != nil {
return "", fmt.Errorf("could not read flix file %s: %w", flixQuery, err)
}
template = string(file)
if err != nil {
return "", fmt.Errorf("could not parse flix from file %s: %w", flixQuery, err)
}

case flixUrl:
template, err = FetchFlixWithContext(ctx, flixQuery)
if err != nil {
return "", fmt.Errorf("could not parse flix from url %s: %w", flixQuery, err)
}

default:
return "", fmt.Errorf("invalid flix query type: %s", flixQuery)
}

return template, nil
}
48 changes: 46 additions & 2 deletions flixkit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func TestGetFlix(t *testing.T) {
flix, err := flixService.GetFlix(ctx, "templateName")
assert.NoError(err, "GetParsedFlixByName should not return an error")
assert.NotNil(flix, "GetParsedFlixByName should not return a nil Flix")
assert.Equal(parsedTemplate, flix, "GetParsedFlixByName should return the correct Flix")
assert.Equal(flix_template, flix, "GetParsedFlixByName should return the correct Flix")
}

func TestGetFlixByIDRaw(t *testing.T) {
Expand Down Expand Up @@ -313,9 +313,53 @@ func TestGetFlixByID(t *testing.T) {
flix, err := flixService.GetFlixByID(ctx, "templateID")
assert.NoError(err, "GetParsedFlixByID should not return an error")
assert.NotNil(flix, "GetParsedFlixByID should not return a nil Flix")
assert.Equal(parsedTemplate, flix, "GetParsedFlixByID should return the correct Flix")
assert.Equal(flix_template, flix, "GetParsedFlixByID should return the correct Flix")
}

type MapFsReader struct {
FS fs.FS
}

func TestTemplateVersion(t *testing.T) {
assert := assert.New(t)

tests := []struct {
templateStr string
version string
wantErr bool
}{
{
templateStr: `{
"f_version": "1.0.0"
}`,
version: "1.0.0",
wantErr: false,
},
{
templateStr: `{
"f_version": "1.1.0"
}`,
version: "1.1.0",
wantErr: false,
},
{
templateStr: `{
"f_ver": "1.x"
}`,
version: "",
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.templateStr, func(t *testing.T) {
ver, err := GetTemplateVersion(tt.templateStr)
if tt.wantErr {
assert.Error(err, "TemplateVersion should return an error")
} else {
assert.NoError(err, "TemplateVersion should not return an error")
assert.Equal(tt.version, ver, "TemplateVersion should return the correct version")
}
})
}
}
1 change: 1 addition & 0 deletions flixkitv1_1/flixkit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package v1_1
8 changes: 4 additions & 4 deletions flixkitv1_1_0/flixkit_test.go → flixkitv1_1/flixkit_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package v1_1_0
package v1_1

import (
"testing"
Expand Down Expand Up @@ -255,14 +255,14 @@ func TestGetAndReplaceCadenceImports(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cadence, err := parsedTemplate.GetAndReplaceCadenceImports(tt.network)
cadenceCode, err := parsedTemplate.GetAndReplaceCadenceImports(tt.network)
if tt.wantErr {
assert.Error(err, "GetCadenceWithReplacedImports should return an error")
} else {
assert.NoError(err, "GetCadenceWithReplacedImports should not return an error")
assert.NotEmpty(cadence, "Cadence should not be empty")
assert.NotEmpty(cadenceCode, "Cadence should not be empty")

assert.Contains(cadence, tt.wantImport, "Cadence should contain the expected import")
assert.Contains(cadenceCode, tt.wantImport, "Cadence should contain the expected import")
}
})
}
Expand Down
19 changes: 16 additions & 3 deletions flixkitv1_1_0/types.go → flixkitv1_1/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1_1_0
package v1_1

import (
"encoding/json"
"fmt"
"regexp"
)
Expand Down Expand Up @@ -90,7 +91,7 @@ func (t *InteractionTemplate) IsTransaction() bool {
}

func (t *InteractionTemplate) GetAndReplaceCadenceImports(networkName string) (string, error) {
cadence := t.Data.Cadence.Body
var cadence string

for _, Dependence := range t.Data.Dependencies {
for _, contract := range Dependence.Contracts {
Expand All @@ -112,9 +113,21 @@ func (t *InteractionTemplate) GetAndReplaceCadenceImports(networkName string) (s
}

replacement := fmt.Sprintf("import %s from %s", contractName, dependencyAddress)
cadence = re.ReplaceAllString(cadence, replacement)
cadence = re.ReplaceAllString(t.Data.Cadence.Body, replacement)
}
}

return cadence, nil

}

func ParseFlix(template string) (*InteractionTemplate, error) {
var flowTemplate InteractionTemplate

err := json.Unmarshal([]byte(template), &flowTemplate)
if err != nil {
return nil, err
}

return &flowTemplate, nil
}
Loading

0 comments on commit f9ff459

Please sign in to comment.