Open
Description
We previously had a two other router types in the engine, which were removed during a refactor, so stashing their code here for future use/discussion.
router which always picks the first exit:
package routers
import (
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/goflow/utils"
)
func init() {
RegisterType(TypeFirst, func() flows.Router { return &FirstRouter{} })
}
// TypeFirst is the type for FirstRouters
const TypeFirst string = "first"
// FirstRouter is a simple router that always takes the first exit
type FirstRouter struct {
BaseRouter
}
func NewFirstRouter(resultName string) *FirstRouter {
return &FirstRouter{BaseRouter: newBaseRouter(TypeFirst, resultName)}
}
// Validate validates the arguments on this router
func (r *FirstRouter) Validate(exits []flows.Exit) error {
return utils.Validate(r)
}
// PickRoute always picks the first exit if available for this router
func (r *FirstRouter) PickRoute(run flows.FlowRun, exits []flows.Exit, step flows.Step) (*string, flows.Route, error) {
if len(exits) == 0 {
return nil, flows.NoRoute, nil
}
return nil, flows.NewRoute(exits[0].UUID(), "", nil), nil
}
// Inspect inspects this object and any children
func (r *FirstRouter) Inspect(inspect func(flows.Inspectable)) {
inspect(r)
}
random router which remembers which exits it took previously and doesn't pick the same more than once:
package routers
import (
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/goflow/utils"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
)
func init() {
RegisterType(TypeRandomOnce, func() flows.Router { return &RandomOnceRouter{} })
}
// TypeRandomOnce is the constant for our random once router
const TypeRandomOnce string = "random_once"
// RandomOnceRouter exits of our exits once (randomly) before taking exit
type RandomOnceRouter struct {
BaseRouter
Default flows.CategoryUUID `json:"default_category_uuid" validate:"required,uuid4"`
}
// NewRandomOnceRouter creates a new random-once router
func NewRandomOnceRouter(defaultExit flows.ExitUUID, resultName string) *RandomOnceRouter {
return &RandomOnceRouter{
BaseRouter: newBaseRouter(TypeRandomOnce, resultName),
Default: defaultExit,
}
}
// Validate validates the parameters on this router
func (r *RandomOnceRouter) Validate(exits []flows.Exit) error {
// check the default category is valid
if r.Default != "" && !r.isValidCategory(r.Default) {
return errors.Errorf("default category %s is not a valid category", r.Default)
}
return r.validate(exits)
}
// PickRoute will attempt to take a random exit it hasn't taken before. If all exits have been taken, then it will
// take the exit specified in it's Exit parameter
func (r *RandomOnceRouter) PickRoute(run flows.FlowRun, exits []flows.Exit, step flows.Step) (*string, flows.Route, error) {
if len(exits) == 0 {
return nil, flows.NoRoute, nil
}
// find all the exits we have taken
takenBefore := make(map[flows.ExitUUID]bool)
for _, s := range run.Path() {
if s.NodeUUID() == step.NodeUUID() {
takenBefore[s.ExitUUID()] = true
}
}
// build up a list of the valid exits
var validExits []flows.ExitUUID
for i := range exits {
// this isn't our default exit and we haven't taken it yet
if exits[i].UUID() != r.Default && !takenBefore[exits[i].UUID()] {
validExits = append(validExits, exits[i].UUID())
}
}
// no valid choices? exit!
if len(validExits) == 0 {
return nil, flows.NewRoute(r.Default, "", nil), nil
}
// ok, now pick one randomly
rand := utils.RandDecimal()
exitNum := rand.Mul(decimal.New(int64(len(validExits)), 0)).IntPart()
return nil, flows.NewRoute(validExits[exitNum], rand.String(), nil), nil
}
// Inspect inspects this object and any children
func (r *RandomOnceRouter) Inspect(inspect func(flows.Inspectable)) {
inspect(r)
}
Metadata
Metadata
Assignees
Labels
No labels