package main import ( "fmt" "sync" "time" "git.novox.be/novox/mesh-sdk/go/asks" sdk "git.novox.be/novox/mesh-sdk/go/delivery" ) // fakeOperator is the gate's bucket asks and the teller behind it: it keeps the asks written, and answers as the test says // (the teller's answer under the ask's key). In auto mode it approves every ask the moment it is read (the tests of other // behaviour, which are not about the Approve). An ask is known here by its key (mesh-sdk go/delivery MergeAskKey), as the // delivery keeps it. type fakeOperator struct { mu sync.Mutex now func() time.Time auto bool asked []asks.Ask byKey map[string]sdk.Ask order []string seen map[string]bool cancelled []string state map[string]string answers map[string]*sdk.Answer refuse error } func newFakeOperator(now func() time.Time) *fakeOperator { return &fakeOperator{now: now, byKey: map[string]sdk.Ask{}, seen: map[string]bool{}, state: map[string]string{}, answers: map[string]*sdk.Answer{}} } func (o *fakeOperator) Ask(key string, a sdk.Ask) error { o.mu.Lock() defer o.mu.Unlock() if o.refuse != nil { return o.refuse } if err := a.Ask.Check(o.now()); err != nil { return err } if _, err := sdk.EncodeAsk(a); err != nil { return err } if o.state[key] == "open" && sdk.SameAsk(o.byKey[key], a) { return nil // the same ask is there, as kvOperator leaves it } o.asked = append(o.asked, a.Ask) o.byKey[key] = a if _, known := o.seen[key]; !known { o.order = append(o.order, key) o.seen[key] = true } o.state[key] = "open" delete(o.answers, key) return nil } func (o *fakeOperator) Cancel(key string) error { o.mu.Lock() defer o.mu.Unlock() o.cancelled = append(o.cancelled, key) o.state[key] = "cancelled" return nil } func (o *fakeOperator) Where(key string) (*sdk.Answer, error) { o.mu.Lock() defer o.mu.Unlock() if o.auto && o.state[key] == "open" { o.answerLocked(key, OptionApprove) } return o.answers[key], nil } // ask is the router's ask at a key, as the gate composed it. func (o *fakeOperator) ask(key string) asks.Ask { if a, ok := o.byKey[key]; ok { return a.Ask } panic("no ask " + key) } func (o *fakeOperator) answerLocked(key, option string) { a := o.ask(key) opt, _ := a.Option(option) o.state[key] = "answered" o.answers[key] = &sdk.Answer{Option: option, Warrant: fmt.Sprintf("%s@%s", a.ID, o.now().UTC().Format(time.RFC3339)), Words: "the operator, via telegram, chose " + opt.Label} } // answer is the operator's choice, proven to the teller by the router and written by it. func (o *fakeOperator) answer(key, option string) { o.mu.Lock() defer o.mu.Unlock() o.answerLocked(key, option) } // open is the keys 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 _, k := range o.order { if o.state[k] == "open" { out = append(out, k) } } return out } func (o *fakeOperator) count() int { o.mu.Lock(); defer o.mu.Unlock(); return len(o.asked) }