-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgpiece.go
135 lines (110 loc) · 3.36 KB
/
gpiece.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package statepro
import (
"context"
"fmt"
)
// Action
type tAction[ContextType any] func(context.Context, *ContextType, Event, ActionTool[ContextType]) error
type gAction[ContextType any] struct {
Name string
Act tAction[ContextType]
}
func (a *gAction[ContextType]) do(ctx context.Context, c *ContextType, e Event, at ActionTool[ContextType]) error {
if a.Act == nil {
return fmt.Errorf("action '%s' not found", a.Name)
}
return a.Act(ctx, c, e, at)
}
func castToAct[ContextType any](i any) (tAction[ContextType], error) {
if f, ok := i.(func(context.Context, *ContextType, Event, ActionTool[ContextType]) error); ok {
return f, nil
}
return nil, fmt.Errorf("action '%s' with wrong type. Expected: func(context.Context, ContextType, Event, ActionTool)", i)
}
// Guard
type tPredicate[ContextType any] func(context.Context, *ContextType, Event) (bool, error)
type gGuard[ContextType any] struct {
Condition *string
Target *string // Mandatory
Actions []*gAction[ContextType]
Predicate tPredicate[ContextType]
}
func (g *gGuard[ContextType]) check(ctx context.Context, c *ContextType, e Event, at ActionTool[ContextType]) (string, bool, error) {
// if Condition is nil, then it is an Else or Directly gGuard
if g.Condition == nil {
err := g.doActions(ctx, c, e, at)
if err != nil {
return "", false, err
}
return *g.Target, true, nil
}
// if Predicate is nil, then it is an If or ElseIf gGuard
if g.Predicate == nil {
return "", false, fmt.Errorf("guard '%s' not found", *g.Condition)
}
ok, err := (g.Predicate)(ctx, c, e)
if err != nil {
return "", false, err
}
if ok {
err = g.doActions(ctx, c, e, at)
if err != nil {
return "", false, err
}
return *g.Target, true, nil
}
return "", false, nil
}
func (g *gGuard[ContextType]) doActions(ctx context.Context, c *ContextType, e Event, at ActionTool[ContextType]) error {
for _, a := range g.Actions {
if err := a.do(ctx, c, e, at); err != nil {
return err
}
}
return nil
}
func castPredicate[ContextType any](i any) (tPredicate[ContextType], error) {
if f, ok := i.(func(context.Context, *ContextType, Event) (bool, error)); ok {
return f, nil
}
return nil, fmt.Errorf("predicate '%s' with wrong type", i)
}
// Service
type tInvocation[ContextType any] func(context.Context, ContextType, Event)
type invocationResponse struct {
Target *string
Event Event
Err error
}
type gService[ContextType any] struct {
Id *string // Mandatory
Src *string // Mandatory
Inv tInvocation[ContextType]
OnDone *gTransition[ContextType]
OnError *gTransition[ContextType]
}
func (s *gService[ContextType]) invoke(ctx context.Context, c *ContextType, e Event) {
s.Inv(ctx, *c, e)
}
func castToSrv[ContextType any](i any) (tInvocation[ContextType], error) {
if f, ok := i.(func(context.Context, ContextType, Event)); ok {
return f, nil
}
return nil, fmt.Errorf("service '%s' with wrong type. Expected: func(context.Context, ContextType, Event)", i)
}
// Transition
type gTransition[ContextType any] struct {
Guards []*gGuard[ContextType] // At least one guard is required
}
func (t *gTransition[ContextType]) resolve(ctx context.Context, c *ContextType, e Event, at ActionTool[ContextType]) (*string, error) {
for _, g := range t.Guards {
target, ok, err := g.check(ctx, c, e, at)
if err != nil {
return nil, err
}
if ok {
return &target, nil
}
}
return nil, nil
}