105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/asks"
|
|
)
|
|
|
|
// fakeOperator is the operator channel: it keeps the asks made, and answers as the test says. In auto mode it
|
|
// approves every ask the moment it is read (the tests of other behaviour, which are not about the Approve).
|
|
type fakeOperator struct {
|
|
mu sync.Mutex
|
|
now func() time.Time
|
|
auto bool
|
|
asked []asks.Ask
|
|
cancelled []string
|
|
state map[string]string
|
|
warrant map[string]*asks.Warrant
|
|
refuse error
|
|
}
|
|
|
|
func newFakeOperator(now func() time.Time) *fakeOperator {
|
|
return &fakeOperator{now: now, state: map[string]string{}, warrant: map[string]*asks.Warrant{}}
|
|
}
|
|
|
|
func (o *fakeOperator) Ask(a asks.Ask) error {
|
|
o.mu.Lock()
|
|
defer o.mu.Unlock()
|
|
if o.refuse != nil {
|
|
return o.refuse
|
|
}
|
|
if err := a.Check(o.now()); err != nil {
|
|
return err
|
|
}
|
|
o.asked = append(o.asked, a)
|
|
o.state[a.ID] = "open"
|
|
return nil
|
|
}
|
|
|
|
func (o *fakeOperator) Cancel(id string) error {
|
|
o.mu.Lock()
|
|
defer o.mu.Unlock()
|
|
o.cancelled = append(o.cancelled, id)
|
|
o.state[id] = "cancelled"
|
|
return nil
|
|
}
|
|
|
|
func (o *fakeOperator) Where(id string) (string, *asks.Warrant, error) {
|
|
o.mu.Lock()
|
|
defer o.mu.Unlock()
|
|
if o.auto && o.state[id] == "open" {
|
|
o.answerLocked(id, OptionApprove)
|
|
}
|
|
return o.state[id], o.warrant[id], nil
|
|
}
|
|
|
|
func (o *fakeOperator) ask(id string) asks.Ask {
|
|
for _, a := range o.asked {
|
|
if a.ID == id {
|
|
return a
|
|
}
|
|
}
|
|
panic("no ask " + id)
|
|
}
|
|
|
|
func (o *fakeOperator) answerLocked(id, option string) {
|
|
a := o.ask(id)
|
|
opt, _ := a.Option(option)
|
|
o.state[id] = "answered"
|
|
o.warrant[id] = &asks.Warrant{Ask: id, Asker: Module, Outcome: asks.OutcomeChosen, Option: option, Label: opt.Label,
|
|
Level: opt.Level, By: &asks.Person{Who: asks.Operator, Kind: "telegram", Verified: "user id verified"},
|
|
At: o.now(), AskDigest: a.Digest()}
|
|
}
|
|
|
|
// answer is the operator's choice, proven by the router.
|
|
func (o *fakeOperator) answer(id, option string) {
|
|
o.mu.Lock()
|
|
defer o.mu.Unlock()
|
|
o.answerLocked(id, option)
|
|
}
|
|
|
|
// end is an ask that closed without a choice.
|
|
func (o *fakeOperator) end(id string) {
|
|
o.mu.Lock()
|
|
defer o.mu.Unlock()
|
|
o.state[id] = "expired"
|
|
o.warrant[id] = &asks.Warrant{Ask: id, Asker: Module, Outcome: asks.OutcomeExpired, At: o.now()}
|
|
}
|
|
|
|
// open is the ids of the asks waiting for an answer, in the order asked.
|
|
func (o *fakeOperator) open() []string {
|
|
o.mu.Lock()
|
|
defer o.mu.Unlock()
|
|
var out []string
|
|
for _, a := range o.asked {
|
|
if o.state[a.ID] == "open" {
|
|
out = append(out, a.ID)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (o *fakeOperator) count() int { o.mu.Lock(); defer o.mu.Unlock(); return len(o.asked) }
|