Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature microgateway #2

Merged
merged 35 commits into from
Oct 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
55db34a
Microgateway action
pointlander Oct 17, 2018
a433ee9
Use new flogo code base
pointlander Oct 18, 2018
8d811b7
Use activity interface instead of Service interface
pointlander Oct 18, 2018
30dda49
Added microgateway action test
pointlander Oct 19, 2018
5e6d457
Use expression language from core
pointlander Oct 20, 2018
ac31ec9
Create activities on action initialization
pointlander Oct 21, 2018
c962676
Created expression type
pointlander Oct 21, 2018
50949e9
Removed registry
pointlander Oct 21, 2018
e8f99b2
Removed strings package
pointlander Oct 21, 2018
3aa8d68
Moved code
pointlander Oct 21, 2018
5aa645f
Use log from core
pointlander Oct 21, 2018
90bfd0f
Removed top level routing in microgateway
pointlander Oct 22, 2018
fb4cf86
Cleanup resource loading in action
pointlander Oct 22, 2018
6a5d208
Fixed pattern feature
pointlander Oct 22, 2018
10b5054
Defined microgateway host object
pointlander Oct 22, 2018
cbbc643
Added functions from contrib
pointlander Oct 22, 2018
a35fc42
Fixed example
pointlander Oct 23, 2018
41cb3ae
Updated documentation
pointlander Oct 23, 2018
fcee883
Removed references to mashling
pointlander Oct 23, 2018
39c54b1
Moved code
pointlander Oct 23, 2018
9860e76
Added comments
pointlander Oct 23, 2018
9abb6f4
Added schema validation
pointlander Oct 23, 2018
a568a7c
Added halt condition to step
pointlander Oct 24, 2018
ed07093
Implemented Host Reply/Return
pointlander Oct 24, 2018
1be64f4
Return host error
pointlander Oct 24, 2018
492ffdd
Use action settings as configuration
pointlander Oct 24, 2018
ecafc7e
Moved Async and Pattern to action settings
pointlander Oct 24, 2018
f5b0c51
Support IOMetadata
pointlander Oct 24, 2018
257e2fe
Added microgateway api
pointlander Oct 25, 2018
e0abd58
Moved types to api
pointlander Oct 25, 2018
1d1db2d
Added microgateway benchmark
pointlander Oct 25, 2018
729cdbe
Added api example
pointlander Oct 25, 2018
8eb64fd
Updated readme
pointlander Oct 25, 2018
7511c6b
Added shadow resource manager for api
pointlander Oct 25, 2018
8f972d8
Merge branch 'master' into feature-microgateway
pointlander Oct 26, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Microgateway Action
This is a microgateway action which supports the conditional evaluation of activities. The microgateway has one setting: 'uri' which is the URL of the microgateway JSON resource.

## Resource Schema

The JSON Schema for the Microgateway resource can be found [here](https://github.com/project-flogo/microgateway/tree/master/internal/schema/schema.json).

## Example Flogo JSON Usage of a Microgateway Action

An example of a basic gateway can be found [here](https://github.com/project-flogo/microgateway/tree/master/examples/json/basic-gateway).

## Example Flogo API Usage of a Microgateway Action

An API example can be found [here](https://github.com/project-flogo/microgateway/tree/master/examples/api/basic-gateway).
283 changes: 283 additions & 0 deletions action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
package microgateway

import (
"context"
"encoding/json"
"errors"
"fmt"

_ "github.com/project-flogo/contrib/function"
"github.com/project-flogo/core/action"
"github.com/project-flogo/core/activity"
"github.com/project-flogo/core/app/resource"
"github.com/project-flogo/core/data/expression"
_ "github.com/project-flogo/core/data/expression/script"
"github.com/project-flogo/core/data/mapper"
"github.com/project-flogo/core/data/metadata"
"github.com/project-flogo/core/data/resolve"
"github.com/project-flogo/core/support/logger"
"github.com/project-flogo/microgateway/api"
"github.com/project-flogo/microgateway/internal/core"
_ "github.com/project-flogo/microgateway/internal/function"
"github.com/project-flogo/microgateway/internal/pattern"
"github.com/project-flogo/microgateway/internal/schema"
)

var log = logger.GetLogger("microgateway")

// Action is the microgateway action
type Action struct {
id string
settings Settings
microgateway *core.Microgateway
}

// Manager loads the microgateway definition resource
type Manager struct {
}

func init() {
action.Register(&Action{}, &Factory{})
resource.RegisterLoader("microgateway", &Manager{})
}

var actionMetadata = action.ToMetadata(&Settings{}, &Input{}, &Output{})

// LoadResource loads the microgateway definition
func (m *Manager) LoadResource(config *resource.Config) (*resource.Resource, error) {
data := config.Data

err := schema.Validate(data)
if err != nil {
return nil, fmt.Errorf("error validating schema: %s", err.Error())
}

var definition *api.Microgateway
err = json.Unmarshal(data, &definition)
if err != nil {
return nil, fmt.Errorf("error marshalling microgateway definition resource with id '%s', %s", config.ID, err.Error())
}

return resource.New("microgateway", definition), nil
}

// Factory is a microgateway factory
type Factory struct {
*resource.Manager
}

type initContext struct {
settings map[string]interface{}
}

func (i *initContext) Settings() map[string]interface{} {
return i.settings
}

func (i *initContext) MapperFactory() mapper.Factory {
return nil
}

func (f *Factory) Initialize(ctx action.InitContext) error {
f.Manager = ctx.ResourceManager()
return nil
}

// New creates a new microgateway
func (f *Factory) New(config *action.Config) (action.Action, error) {
act := Action{
id: config.Id,
}
if act.id == "" {
act.id = config.Ref
}

if len(config.Data) > 0 {
err := json.Unmarshal(config.Data, &config.Settings)
if err != nil {
return nil, err
}
}

err := metadata.MapToStruct(config.Settings, &act.settings, true)
if err != nil {
return nil, err
}

var actionData *api.Microgateway
if uri := act.settings.URI; uri != "" {
if resData := api.GetResource(uri); resData != nil {
actionData = resData
} else {
// Load action data from resources
resData := f.Manager.GetResource(uri)
if resData == nil {
return nil, fmt.Errorf("failed to load microgateway URI data: '%s'", config.Id)
}
actionData = resData.Object().(*api.Microgateway)
}
} else if p := act.settings.Pattern; p != "" {
definition, err := pattern.Load(p)
if err != nil {
return nil, err
}
actionData = definition
} else {
return nil, errors.New("no definition found for microgateway")
}

services := make(map[string]*core.Service, len(actionData.Services))
for i := range actionData.Services {
name := actionData.Services[i].Name
if _, ok := services[name]; ok {
return nil, fmt.Errorf("duplicate service name: %s", name)
}

if ref := actionData.Services[i].Ref; ref != "" {
if factory := activity.GetFactory(ref); factory != nil {
actvt, err := factory(&initContext{settings: actionData.Services[i].Settings})
if err != nil {
return nil, err
}
services[name] = &core.Service{
Name: name,
Settings: actionData.Services[i].Settings,
Activity: actvt,
}
continue
}
actvt := activity.Get(ref)
if actvt == nil {
return nil, fmt.Errorf("can't find activity %s", ref)
}
services[name] = &core.Service{
Name: name,
Settings: actionData.Services[i].Settings,
Activity: actvt,
}
} else if handler := actionData.Services[i].Handler; handler != nil {
services[name] = &core.Service{
Name: name,
Settings: actionData.Services[i].Settings,
Activity: &core.Adapter{Handler: handler},
}
} else {
return nil, fmt.Errorf("no ref or handler for service: %s", name)
}
}

expressionFactory := expression.NewFactory(resolve.GetBasicResolver())
getExpression := func(value interface{}) (*core.Expr, error) {
if stringValue, ok := value.(string); ok && len(stringValue) > 0 && stringValue[0] == '=' {
expr, err := expressionFactory.NewExpr(stringValue[1:])
if err != nil {
return nil, err
}
return core.NewExpr(stringValue, expr), nil
}
return core.NewExpr(fmt.Sprintf("%v", value), expression.NewLiteralExpr(value)), nil
}

steps, responses := actionData.Steps, actionData.Responses
microgateway := core.Microgateway{
Name: actionData.Name,
Async: act.settings.Async,
Steps: make([]core.Step, len(steps)),
Responses: make([]core.Response, len(responses)),
Configuration: config.Settings,
}
for j := range steps {
if condition := steps[j].Condition; condition != "" {
expr, err := expressionFactory.NewExpr(condition)
if err != nil {
log.Infof("condition parsing error: %s", condition)
return nil, err
}
microgateway.Steps[j].Condition = core.NewExpr(condition, expr)
}

service := services[steps[j].Service]
if service == nil {
return nil, fmt.Errorf("service not found: %s", steps[j].Service)
}
microgateway.Steps[j].Service = service

input := steps[j].Input
inputExpression := make(map[string]*core.Expr, len(input))
for key, value := range input {
inputExpression[key], err = getExpression(value)
if err != nil {
return nil, err
}
}
microgateway.Steps[j].Input = inputExpression

if condition := steps[j].HaltCondition; condition != "" {
expr, err := expressionFactory.NewExpr(condition)
if err != nil {
log.Infof("halt condition parsing error: %s", condition)
return nil, err
}
microgateway.Steps[j].HaltCondition = core.NewExpr(condition, expr)
}
}

for j := range responses {
if condition := responses[j].Condition; condition != "" {
expr, err := expressionFactory.NewExpr(condition)
if err != nil {
log.Infof("condition parsing error: %s", condition)
return nil, err
}
microgateway.Responses[j].Condition = core.NewExpr(condition, expr)
}

microgateway.Responses[j].Error = responses[j].Error

microgateway.Responses[j].Output.Code, err = getExpression(responses[j].Output.Code)
if err != nil {
return nil, err
}

data := responses[j].Output.Data
if hashMap, ok := data.(map[string]interface{}); ok {
dataExpressions := make(map[string]*core.Expr, len(hashMap))
for key, value := range hashMap {
dataExpressions[key], err = getExpression(value)
if err != nil {
return nil, err
}
}
microgateway.Responses[j].Output.Datum = dataExpressions
} else {
microgateway.Responses[j].Output.Data, err = getExpression(data)
if err != nil {
return nil, err
}
}
}

act.microgateway = &microgateway

return &act, nil
}

// Metadata returns the metadata for the microgateway
func (a *Action) Metadata() *action.Metadata {
return actionMetadata
}

// IOMetadata returns the iometadata for the microgateway
func (a *Action) IOMetadata() *metadata.IOMetadata {
return actionMetadata.IOMetadata
}

// Run executes the microgateway
func (a *Action) Run(ctx context.Context, input map[string]interface{}) (map[string]interface{}, error) {
code, mData, err := core.Execute(a.id, input, a.microgateway, a.IOMetadata())
output := make(map[string]interface{}, 8)
output["code"] = code
output["data"] = mData

return output, err
}
9 changes: 9 additions & 0 deletions action.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "microgateway",
"type": "flogo:action",
"ref": "github.com/project-flogo/microgateway",
"version": "0.0.1",
"title": "Microgateway Action",
"description": "Action implementing the microgateway features.",
"homepage": "https://github.com/project-flogo/microgateway"
}
Loading