package action import ( "slices" lib "git.sr.ht/~cco/go-scopes" "git.sr.ht/~cco/go-scopes/core/message" "git.sr.ht/~cco/go-scopes/logging" ) type BaseSpec = baseSpec type baseSpec struct { handler lib.ActionHandler receivers []lib.Addressable } func (spec *baseSpec) Handler() lib.ActionHandler { return spec.handler } func (spec *baseSpec) Receivers() []lib.Addressable { return spec.receivers } func (spec *baseSpec) AddReceiver(rcv lib.Addressable) lib.ActionSpec { if slices.Index(spec.receivers, rcv) == -1 { spec.receivers = append(spec.receivers, rcv) } return spec } func (spec *baseSpec) RemoveReceiver(rcv lib.Addressable) { rcvs := spec.receivers idx := slices.Index(rcvs, rcv) if idx != -1 { spec.receivers = slices.Delete(rcvs, idx, idx+1) } } func Base(hdlr lib.ActionHandler, rcvs ...string) *baseSpec { spec := baseSpec{handler: hdlr} for _, rcv := range rcvs { spec.receivers = append(spec.receivers, message.SimpleAddress(rcv)) } return &spec } // action selection func Select(ctx lib.Context, msg lib.Message) []lib.Action { var acts []lib.Action for _, ac := range ctx.Config().Actions() { if match(ac, msg) { for _, spec := range ac.Specs() { act := action{ctx, spec, msg} logging.DebugA(&act). Str("pattern", ac.Pattern().String()). Msg("action.Select") acts = append(acts, &act) } } } if len(acts) == 0 { logging.WarnM(ctx, msg).Msg("action.Select: no match") } return acts } func match(ac lib.ActionConfig, msg lib.Message) bool { pat := ac.Pattern().Slice() if len(pat) == 1 { return pat[0] == msg.Action() } mh := msg.Slice() for idx, p := range pat { if p != "" && mh[idx] != p { return false } } return true } // action handling type action struct { ctx lib.Context spec lib.ActionSpec msg lib.Message } func (act *action) Context() lib.Context { return act.ctx } func (act *action) Spec() lib.ActionSpec { return act.spec } func (act *action) Message() lib.Message { return act.msg } func (act *action) Handle() bool { return act.spec.Handler()(act) } // predefined action handlers func Forward(act lib.Action) bool { ctx := act.Context() msg := act.Message() for _, rcv := range act.Spec().Receivers() { message.Send(ctx, rcv, msg) } return true }