blasphem/pkg/flow/flow.go

204 lines
4.3 KiB
Go
Raw Normal View History

2022-11-20 08:49:24 -05:00
// flow is the data entry flow.
package flow
import (
"fmt"
"time"
"dynatron.me/x/blasphem/internal/generate"
)
2022-12-27 15:09:20 -05:00
type ResultType string
type FlowID string
type Step string
type HandlerKey string
type Errors interface{}
2022-11-20 08:49:24 -05:00
2022-12-27 15:09:20 -05:00
type FlowStore map[FlowID]Handler
2022-11-20 08:49:24 -05:00
2022-12-27 15:09:20 -05:00
type FlowManager struct {
flows FlowStore
}
2022-11-20 08:49:24 -05:00
2022-12-27 15:09:20 -05:00
type Result struct {
Type ResultType `json:"type"`
ID FlowID `json:"flow_id"`
Handler []*HandlerKey `json:"handler"`
Title *string `json:"title,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
StepID *Step `json:"step_id,omitempty"`
Schema []SchemaItem `json:"data_schema"`
Extra *string `json:"extra,omitempty"`
Required *bool `json:"required,omitempty"`
Errors interface{} `json:"errors"`
Description *string `json:"description,omitempty"`
DescPlace *string `json:"description_placeholders"`
URL *string `json:"url,omitempty"`
Reason *string `json:"reason,omitempty"`
Context *string `json:"context,omitempty"`
Result interface{} `json:"result,omitempty"`
LastStep *string `json:"last_step"`
Options map[string]interface{} `json:"options,omitempty"`
Version *int `json:"version,omitempty"`
}
2022-11-20 08:49:24 -05:00
2022-12-27 15:09:20 -05:00
type Handler interface {
BaseHandler() FlowHandler
FlowID() FlowID
2022-11-20 12:51:26 -05:00
2022-12-27 15:09:20 -05:00
flowCtime() time.Time
}
2022-11-20 08:49:24 -05:00
const (
StepInit Step = "init"
)
2022-12-27 15:09:20 -05:00
func (fs Schema) CheckRequired(rm map[string]interface{}) error {
for _, si := range fs {
2022-11-20 08:49:24 -05:00
if si.Required {
if _, ok := rm[si.Name]; !ok {
return fmt.Errorf("missing required param %s", si.Name)
}
}
}
return nil
}
func NewFlowManager() *FlowManager {
return &FlowManager{
flows: make(FlowStore),
}
}
func stepPtr(s Step) *Step { return &s }
2022-11-20 13:42:10 -05:00
type FlowHandler struct {
2022-11-20 12:51:26 -05:00
ID FlowID // ID is the FlowID
Handler HandlerKey // Handler key
2022-11-20 08:49:24 -05:00
// curStep is the current step set by the flow manager
curStep Step
ctime time.Time
}
2022-11-20 13:42:10 -05:00
func (f *FlowHandler) Step() Step { return f.curStep }
2022-11-20 08:49:24 -05:00
2022-12-17 15:17:05 -05:00
func (f *FlowHandler) BaseHandler() FlowHandler { return *f }
2022-11-20 08:49:24 -05:00
2022-11-20 13:42:10 -05:00
func (f *FlowHandler) FlowID() FlowID {
2022-11-20 08:49:24 -05:00
return f.ID
}
2022-11-20 13:42:10 -05:00
func (f *FlowHandler) flowCtime() time.Time { return f.ctime }
2022-11-20 08:49:24 -05:00
2022-12-27 15:09:20 -05:00
func NewFlowHandlerBase(hand string) FlowHandler {
2022-11-20 13:42:10 -05:00
return FlowHandler{
2022-11-20 12:51:26 -05:00
ID: FlowID(generate.UUID()),
Handler: HandlerKey(hand),
2022-11-20 08:49:24 -05:00
curStep: StepInit,
ctime: time.Now(),
}
}
func (hk *HandlerKey) String() string {
return string(*hk)
}
2022-11-20 13:42:10 -05:00
func (fm *FlowHandler) Handlers() []*HandlerKey {
2022-11-20 08:49:24 -05:00
return []*HandlerKey{&fm.Handler, nil}
}
func resultErrs(e Errors) Errors {
if e == nil {
return []string{}
}
return e
}
2022-12-27 15:09:20 -05:00
type FormOption func(*Result)
func (*FlowHandler) WithErrors(e Errors) FormOption {
return func(r *Result) {
r.Errors = e
}
}
func (*FlowHandler) WithStep(s Step) FormOption {
return func(r *Result) {
r.StepID = stepPtr(s)
}
}
func (*FlowHandler) WithSchema(sch Schemer) FormOption {
return func(r *Result) {
r.Schema = sch.FlowSchema()
}
}
func (fm *FlowHandler) ShowForm(opts ...FormOption) *Result {
2022-11-20 12:51:26 -05:00
res := &Result{
2022-11-20 08:49:24 -05:00
Type: TypeForm,
ID: fm.ID,
StepID: stepPtr(fm.curStep),
Handler: fm.Handlers(),
}
2022-12-27 15:09:20 -05:00
for _, opt := range opts {
opt(res)
}
res.Errors = resultErrs(res.Errors)
2022-11-20 08:49:24 -05:00
return res
}
func (fm *FlowManager) Delete(id FlowID) {
delete(fm.flows, id)
}
const (
2022-11-20 12:51:26 -05:00
TypeForm ResultType = "form"
TypeCreateEntry ResultType = "create_entry"
TypeAbort ResultType = "abort"
TypeExternalStep ResultType = "external"
TypeExternalStepDone ResultType = "external_done"
TypeShowProgress ResultType = "progress"
TypeShowProgressDone ResultType = "progress_done"
TypeMenu ResultType = "menu"
2022-11-20 08:49:24 -05:00
)
2022-11-20 13:42:10 -05:00
func (f *FlowHandler) touch() {
2022-11-20 08:49:24 -05:00
f.ctime = time.Now()
}
func (fm *FlowManager) Register(f Handler) {
fm.flows.cull()
fm.flows[f.FlowID()] = f
}
func (fs *FlowManager) Remove(f Handler) {
delete(fs.flows, f.FlowID())
}
2022-12-18 09:55:08 -05:00
const cullAge = time.Minute * 10
2022-11-20 08:49:24 -05:00
func (fs FlowStore) cull() {
for k, v := range fs {
if time.Now().Sub(v.flowCtime()) > cullAge {
delete(fs, k)
}
}
}
func (fs *FlowManager) Get(id FlowID) Handler {
f, ok := fs.flows[id]
if ok {
return f
}
return nil
}